diff --git a/Subsurface-mobile.pro b/Subsurface-mobile.pro index 7f416b25a..1eae8080b 100644 --- a/Subsurface-mobile.pro +++ b/Subsurface-mobile.pro @@ -95,7 +95,7 @@ SOURCES += subsurface-mobile-main.cpp \ core/string-format.cpp \ core/strtod.cpp \ core/tag.cpp \ - core/taxonomy.c \ + core/taxonomy.cpp \ core/time.cpp \ core/trip.c \ core/units.cpp \ diff --git a/backend-shared/exportfuncs.cpp b/backend-shared/exportfuncs.cpp index 7bc545ae5..50cf45e3f 100644 --- a/backend-shared/exportfuncs.cpp +++ b/backend-shared/exportfuncs.cpp @@ -145,10 +145,10 @@ void export_TeX(const char *filename, bool selected_only, bool plain, ExportCall struct tm tm; utc_mkdate(dive->when, &tm); - const char *country = NULL; + std::string country; dive_site *site = dive->dive_site; if (site) - country = taxonomy_get_country(&site->taxonomy); + country = taxonomy_get_country(site->taxonomy); pressure_t delta_p = {.mbar = 0}; QString star = "*"; @@ -180,7 +180,7 @@ void export_TeX(const char *filename, bool selected_only, bool plain, ExportCall site ? put_format(&buf, "\\def\\%sgpslat{%f}\n", ssrf, site->location.lat.udeg / 1000000.0) : put_format(&buf, "\\def\\%sgpslat{}\n", ssrf); site ? put_format(&buf, "\\def\\%sgpslon{%f}\n", ssrf, site->location.lon.udeg / 1000000.0) : put_format(&buf, "\\def\\gpslon{}\n"); put_format(&buf, "\\def\\%scomputer{%s}\n", ssrf, dive->dc.model); - put_format(&buf, "\\def\\%scountry{%s}\n", ssrf, country ?: ""); + put_format(&buf, "\\def\\%scountry{%s}\n", ssrf, country.c_str()); put_format(&buf, "\\def\\%stime{%u:%02u}\n", ssrf, FRACTION_TUPLE(dive->duration.seconds, 60)); put_format(&buf, "\n%% Dive Profile Details:\n"); diff --git a/commands/command_divelist.cpp b/commands/command_divelist.cpp index 6ca13f5f9..22a8706e9 100644 --- a/commands/command_divelist.cpp +++ b/commands/command_divelist.cpp @@ -125,7 +125,7 @@ DivesAndTripsToAdd DiveListBase::removeDives(DivesAndSitesToRemove &divesAndSite { std::vector divesToAdd; std::vector tripsToAdd; - std::vector sitesToAdd; + std::vector> sitesToAdd; divesToAdd.reserve(divesAndSitesToDelete.dives.size()); sitesToAdd.reserve(divesAndSitesToDelete.sites.size()); @@ -216,7 +216,7 @@ DivesAndSitesToRemove DiveListBase::addDives(DivesAndTripsToAdd &toAdd) toAdd.trips.clear(); // Finally, add any necessary dive sites - for (OwningDiveSitePtr &ds: toAdd.sites) { + for (std::unique_ptr &ds: toAdd.sites) { sites.push_back(ds.get()); int idx = register_dive_site(ds.release()); // Return ownership to backend emit diveListNotifier.diveSiteAdded(sites.back(), idx); diff --git a/commands/command_divelist.h b/commands/command_divelist.h index 43713fd58..bb47af725 100644 --- a/commands/command_divelist.h +++ b/commands/command_divelist.h @@ -24,7 +24,7 @@ struct DiveToAdd { struct DivesAndTripsToAdd { std::vector dives; std::vector trips; - std::vector sites; + std::vector> sites; }; // Dives and sites that have to be removed for a command @@ -111,7 +111,7 @@ private: struct device_table devicesToAddAndRemove; // For redo - std::vector sitesToAdd; + std::vector> sitesToAdd; std::vector> filterPresetsToAdd; diff --git a/commands/command_divesite.cpp b/commands/command_divesite.cpp index b89bb0b86..76f88a175 100644 --- a/commands/command_divesite.cpp +++ b/commands/command_divesite.cpp @@ -15,13 +15,13 @@ namespace Command { // Add a set of dive sites to the core. The dives that were associated with // that dive site will be restored to that dive site. -static std::vector addDiveSites(std::vector &sites) +static std::vector addDiveSites(std::vector> &sites) { std::vector res; QVector changedDives; res.reserve(sites.size()); - for (OwningDiveSitePtr &ds: sites) { + for (std::unique_ptr &ds: sites) { // Readd the dives that belonged to this site for (int i = 0; i < ds->dives.nr; ++i) { // TODO: send dive site changed signal @@ -47,9 +47,9 @@ static std::vector addDiveSites(std::vector &sit // Remove a set of dive sites. Get owning pointers to them. The dives are set to // being at no dive site, but the dive site will retain a list of dives, so // that the dives can be readded to the site on undo. -static std::vector removeDiveSites(std::vector &sites) +static std::vector> removeDiveSites(std::vector &sites) { - std::vector res; + std::vector> res; QVector changedDives; res.reserve(sites.size()); @@ -77,7 +77,7 @@ static std::vector removeDiveSites(std::vector & AddDiveSite::AddDiveSite(const QString &name) { setText(Command::Base::tr("add dive site")); - sitesToAdd.emplace_back(alloc_dive_site()); + sitesToAdd.push_back(std::make_unique()); sitesToAdd.back()->name = copy_qstring(name); } @@ -107,7 +107,7 @@ ImportDiveSites::ImportDiveSites(struct dive_site_table *sites, const QString &s // the same name. We might want to be smarter here and merge dive site data, etc. struct dive_site *old_ds = get_same_dive_site(new_ds); if (old_ds) { - free_dive_site(new_ds); + delete new_ds; continue; } sitesToAdd.emplace_back(new_ds); @@ -256,20 +256,20 @@ void EditDiveSiteNotes::undo() } EditDiveSiteCountry::EditDiveSiteCountry(dive_site *dsIn, const QString &country) : ds(dsIn), - value(country) + value(country.toStdString()) { setText(Command::Base::tr("Edit dive site country")); } bool EditDiveSiteCountry::workToBeDone() { - return !same_string(qPrintable(value), taxonomy_get_country(&ds->taxonomy)); + return value == taxonomy_get_country(ds->taxonomy); } void EditDiveSiteCountry::redo() { - QString old = taxonomy_get_country(&ds->taxonomy); - taxonomy_set_country(&ds->taxonomy, qPrintable(value), taxonomy_origin::GEOMANUAL); + std::string old = taxonomy_get_country(ds->taxonomy); + taxonomy_set_country(ds->taxonomy, value, taxonomy_origin::GEOMANUAL); value = old; emit diveListNotifier.diveSiteChanged(ds, LocationInformationModel::TAXONOMY); // Inform frontend of changed dive site. } @@ -310,14 +310,11 @@ void EditDiveSiteLocation::undo() EditDiveSiteTaxonomy::EditDiveSiteTaxonomy(dive_site *dsIn, taxonomy_data &taxonomy) : ds(dsIn), value(taxonomy) { - // We did a dumb copy. Erase the source to remove double references to strings. - memset(&taxonomy, 0, sizeof(taxonomy)); setText(Command::Base::tr("Edit dive site taxonomy")); } EditDiveSiteTaxonomy::~EditDiveSiteTaxonomy() { - free_taxonomy(&value); } bool EditDiveSiteTaxonomy::workToBeDone() @@ -364,7 +361,7 @@ void MergeDiveSites::redo() // The dives of the above dive sites were reset to no dive sites. // Add them to the merged-into dive site. Thankfully, we remember // the dives in the sitesToAdd vector. - for (const OwningDiveSitePtr &site: sitesToAdd) { + for (const std::unique_ptr &site: sitesToAdd) { for (int i = 0; i < site->dives.nr; ++i) { add_dive_to_dive_site(site->dives.dives[i], ds); divesChanged.push_back(site->dives.dives[i]); @@ -380,7 +377,7 @@ void MergeDiveSites::undo() // Before readding the dive sites, unregister the corresponding dives so that they can be // readded to their old dive sites. - for (const OwningDiveSitePtr &site: sitesToAdd) { + for (const std::unique_ptr &site: sitesToAdd) { for (int i = 0; i < site->dives.nr; ++i) { unregister_dive_from_dive_site(site->dives.dives[i]); divesChanged.push_back(site->dives.dives[i]); diff --git a/commands/command_divesite.h b/commands/command_divesite.h index c81397410..b40ee2908 100644 --- a/commands/command_divesite.h +++ b/commands/command_divesite.h @@ -31,7 +31,7 @@ private: std::vector sitesToRemove; // For redo - std::vector sitesToAdd; + std::vector> sitesToAdd; }; class ImportDiveSites : public Base { @@ -47,7 +47,7 @@ private: std::vector sitesToRemove; // For redo - std::vector sitesToAdd; + std::vector> sitesToAdd; }; class DeleteDiveSites : public Base { @@ -62,7 +62,7 @@ private: std::vector sitesToRemove; // For undo - std::vector sitesToAdd; + std::vector> sitesToAdd; }; class PurgeUnusedDiveSites : public Base { @@ -77,7 +77,7 @@ private: std::vector sitesToRemove; // For undo - std::vector sitesToAdd; + std::vector> sitesToAdd; }; class EditDiveSiteName : public Base { @@ -125,7 +125,7 @@ private: void redo() override; dive_site *ds; - QString value; // Value to be set + std::string value; // Value to be set }; class EditDiveSiteLocation : public Base { @@ -167,7 +167,7 @@ private: std::vector sitesToRemove; // For undo - std::vector sitesToAdd; + std::vector> sitesToAdd; }; class ApplyGPSFixes : public Base { @@ -183,7 +183,7 @@ private: std::vector sitesToRemove; // For redo - std::vector sitesToAdd; + std::vector> sitesToAdd; // For redo and undo struct SiteAndLocation { diff --git a/commands/command_edit.cpp b/commands/command_edit.cpp index 5b28c05e3..47d05a03c 100644 --- a/commands/command_edit.cpp +++ b/commands/command_edit.cpp @@ -376,7 +376,7 @@ void EditDiveSite::redo() static struct dive_site *createDiveSite(const QString &name) { - struct dive_site *ds = alloc_dive_site(); + struct dive_site *ds = new dive_site; struct dive_site *old = current_dive ? current_dive->dive_site : nullptr; if (old) { copy_dive_site(old, ds); diff --git a/commands/command_edit.h b/commands/command_edit.h index 529313037..deab84252 100644 --- a/commands/command_edit.h +++ b/commands/command_edit.h @@ -208,7 +208,7 @@ public: // deriving from it and hooks into undo() and redo() to add / remove the dive site. class EditDiveSiteNew : public EditDiveSite { public: - OwningDiveSitePtr diveSiteToAdd; + std::unique_ptr diveSiteToAdd; struct dive_site *diveSiteToRemove; EditDiveSiteNew(const QString &newName, bool currentDiveOnly); void undo() override; @@ -470,7 +470,7 @@ private: int changedFields; dive_site *siteToRemove; - OwningDiveSitePtr siteToAdd; + std::unique_ptr siteToAdd; dive_site *siteToEdit; location_t dsLocation; diff --git a/commands/command_pictures.cpp b/commands/command_pictures.cpp index 98f09e3c8..6c5ef8ea1 100644 --- a/commands/command_pictures.cpp +++ b/commands/command_pictures.cpp @@ -171,9 +171,8 @@ AddPictures::AddPictures(const std::vector &pictures) : if (!ds) { // This dive doesn't yet have a dive site -> add a new dive site. QString name = Command::Base::tr("unnamed dive site"); - dive_site *ds = alloc_dive_site_with_gps(qPrintable(name), &it->location); - sitesToAdd.emplace_back(ds); - sitesToSet.push_back({ p.d, ds }); + sitesToAdd.push_back(std::make_unique(qPrintable(name), &it->location)); + sitesToSet.push_back({ p.d, sitesToAdd.back().get() }); } else if (!dive_site_has_gps_location(ds)) { // This dive has a dive site, but without coordinates. Let's add them. sitesToEdit.push_back({ ds, it->location }); @@ -228,7 +227,7 @@ void AddPictures::undo() void AddPictures::redo() { // Add dive sites - for (OwningDiveSitePtr &siteToAdd: sitesToAdd) { + for (std::unique_ptr &siteToAdd: sitesToAdd) { sitesToRemove.push_back(siteToAdd.get()); int idx = register_dive_site(siteToAdd.release()); // Return ownership to backend. emit diveListNotifier.diveSiteAdded(sitesToRemove.back(), idx); // Inform frontend of new dive site. diff --git a/commands/command_pictures.h b/commands/command_pictures.h index 472a92565..e85cf0409 100644 --- a/commands/command_pictures.h +++ b/commands/command_pictures.h @@ -48,7 +48,7 @@ private: location_t location; }; std::vector picturesToAdd; // for redo - std::vector sitesToAdd; //for redo + std::vector> sitesToAdd; //for redo std::vector picturesToRemove; // for undo std::vector sitesToRemove; // for undo std::vector sitesToSet; // for redo and undo diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt index 4b0d672aa..9d0cab87f 100644 --- a/core/CMakeLists.txt +++ b/core/CMakeLists.txt @@ -179,7 +179,7 @@ set(SUBSURFACE_CORE_LIB_SRCS subsurfacesysinfo.h tag.cpp tag.h - taxonomy.c + taxonomy.cpp taxonomy.h time.cpp trip.c diff --git a/core/dive.cpp b/core/dive.cpp index 05dd1e4f1..47718bc03 100644 --- a/core/dive.cpp +++ b/core/dive.cpp @@ -3335,10 +3335,10 @@ extern "C" struct dive_site *get_dive_site_for_dive(const struct dive *dive) return dive->dive_site; } -extern "C" const char *get_dive_country(const struct dive *dive) +std::string get_dive_country(const struct dive *dive) { struct dive_site *ds = dive->dive_site; - return ds ? taxonomy_get_country(&ds->taxonomy) : NULL; + return ds ? taxonomy_get_country(ds->taxonomy) : std::string(); } extern "C" const char *get_dive_location(const struct dive *dive) diff --git a/core/dive.h b/core/dive.h index e85f19bed..ec326e40b 100644 --- a/core/dive.h +++ b/core/dive.h @@ -13,6 +13,7 @@ #include #ifdef __cplusplus +#include extern "C" { #endif @@ -114,7 +115,11 @@ extern depth_t gas_mnd(struct gasmix mix, depth_t end, const struct dive *dive, extern struct dive *get_dive(int nr); extern struct dive *get_dive_from_table(int nr, const struct dive_table *dt); extern struct dive_site *get_dive_site_for_dive(const struct dive *dive); -extern const char *get_dive_country(const struct dive *dive); +#ifdef __cplusplus +} // TODO: remove +extern std::string get_dive_country(const struct dive *dive); +extern "C" { +#endif extern const char *get_dive_location(const struct dive *dive); extern unsigned int number_of_computers(const struct dive *dive); extern struct divecomputer *get_dive_dc(struct dive *dive, int nr); @@ -227,7 +232,6 @@ extern void update_setpoint_events(const struct dive *dive, struct divecomputer * QVariants and through QML. */ #include -#include Q_DECLARE_METATYPE(struct dive *); extern std::string existing_filename; diff --git a/core/divelist.cpp b/core/divelist.cpp index bdd4cac64..ab694b997 100644 --- a/core/divelist.cpp +++ b/core/divelist.cpp @@ -1144,7 +1144,7 @@ void process_imported_dives(struct divelog *import_log, int flags, if (j == import_log->dives->nr) { /* Dive site not even used - free it and go to next. */ - free_dive_site(new_ds); + delete new_ds; continue; } @@ -1159,7 +1159,7 @@ void process_imported_dives(struct divelog *import_log, int flags, if (import_log->dives->dives[j]->dive_site == new_ds) import_log->dives->dives[j]->dive_site = old_ds; } - free_dive_site(new_ds); + delete new_ds; } import_log->sites->nr = 0; /* All dive sites were consumed */ diff --git a/core/divesite-helper.cpp b/core/divesite-helper.cpp index bed0297ce..d9c06e9c0 100644 --- a/core/divesite-helper.cpp +++ b/core/divesite-helper.cpp @@ -3,11 +3,11 @@ #include "pref.h" #include "gettextfromc.h" -QString constructLocationTags(struct taxonomy_data *taxonomy, bool for_maintab) +QString constructLocationTags(taxonomy_data &taxonomy, bool for_maintab) { QString locationTag; - if (!taxonomy->nr) + if (taxonomy.empty()) return locationTag; /* Check if the user set any of the 3 geocoding categories */ @@ -33,11 +33,10 @@ QString constructLocationTags(struct taxonomy_data *taxonomy, bool for_maintab) for (int i = 0; i < 3; i++) { if (prefs.geocoding.category[i] == TC_NONE) continue; - for (int j = 0; j < taxonomy->nr; j++) { - if (taxonomy->category[j].category == prefs.geocoding.category[i]) { - QString tag = taxonomy->category[j].value; - if (!tag.isEmpty()) { - locationTag += connector + tag; + for (auto const &t: taxonomy) { + if (t.category == prefs.geocoding.category[i]) { + if (!t.value.empty()) { + locationTag += connector + QString::fromStdString(t.value); connector = " / "; } break; diff --git a/core/divesite.cpp b/core/divesite.cpp index 5c23b2f22..e2830991b 100644 --- a/core/divesite.cpp +++ b/core/divesite.cpp @@ -12,7 +12,7 @@ #include -extern "C" int get_divesite_idx(const struct dive_site *ds, struct dive_site_table *ds_table) +int get_divesite_idx(const struct dive_site *ds, struct dive_site_table *ds_table) { int i; const struct dive_site *d; @@ -26,7 +26,7 @@ extern "C" int get_divesite_idx(const struct dive_site *ds, struct dive_site_tab } // TODO: keep table sorted by UUID and do a binary search? -extern "C" struct dive_site *get_dive_site_by_uuid(uint32_t uuid, struct dive_site_table *ds_table) +struct dive_site *get_dive_site_by_uuid(uint32_t uuid, struct dive_site_table *ds_table) { int i; struct dive_site *ds; @@ -37,7 +37,7 @@ extern "C" struct dive_site *get_dive_site_by_uuid(uint32_t uuid, struct dive_si } /* there could be multiple sites of the same name - return the first one */ -extern "C" struct dive_site *get_dive_site_by_name(const char *name, struct dive_site_table *ds_table) +struct dive_site *get_dive_site_by_name(const char *name, struct dive_site_table *ds_table) { int i; struct dive_site *ds; @@ -49,7 +49,7 @@ extern "C" struct dive_site *get_dive_site_by_name(const char *name, struct dive } /* there could be multiple sites at the same GPS fix - return the first one */ -extern "C" struct dive_site *get_dive_site_by_gps(const location_t *loc, struct dive_site_table *ds_table) +struct dive_site *get_dive_site_by_gps(const location_t *loc, struct dive_site_table *ds_table) { int i; struct dive_site *ds; @@ -63,7 +63,7 @@ extern "C" struct dive_site *get_dive_site_by_gps(const location_t *loc, struct /* to avoid a bug where we have two dive sites with different name and the same GPS coordinates * and first get the gps coordinates (reading a V2 file) and happen to get back "the other" name, * this function allows us to verify if a very specific name/GPS combination already exists */ -extern "C" struct dive_site *get_dive_site_by_gps_and_name(const char *name, const location_t *loc, struct dive_site_table *ds_table) +struct dive_site *get_dive_site_by_gps_and_name(const char *name, const location_t *loc, struct dive_site_table *ds_table) { int i; struct dive_site *ds; @@ -75,7 +75,7 @@ extern "C" struct dive_site *get_dive_site_by_gps_and_name(const char *name, con } // Calculate the distance in meters between two coordinates. -extern "C" unsigned int get_distance(const location_t *loc1, const location_t *loc2) +unsigned int get_distance(const location_t *loc1, const location_t *loc2) { double lat1_r = udeg_to_radians(loc1->lat.udeg); double lat2_r = udeg_to_radians(loc2->lat.udeg); @@ -93,7 +93,7 @@ extern "C" unsigned int get_distance(const location_t *loc1, const location_t *l } /* find the closest one, no more than distance meters away - if more than one at same distance, pick the first */ -extern "C" struct dive_site *get_dive_site_by_gps_proximity(const location_t *loc, int distance, struct dive_site_table *ds_table) +struct dive_site *get_dive_site_by_gps_proximity(const location_t *loc, int distance, struct dive_site_table *ds_table) { int i; struct dive_site *ds, *res = NULL; @@ -108,7 +108,7 @@ extern "C" struct dive_site *get_dive_site_by_gps_proximity(const location_t *lo return res; } -extern "C" int register_dive_site(struct dive_site *ds) +int register_dive_site(struct dive_site *ds) { return add_dive_site_to_table(ds, divelog.sites); } @@ -123,6 +123,11 @@ static int site_less_than(const struct dive_site *a, const struct dive_site *b) return compare_sites(a, b) < 0; } +static void free_dive_site(struct dive_site *ds) +{ + delete ds; +} + static MAKE_GROW_TABLE(dive_site_table, struct dive_site *, dive_sites) static MAKE_GET_INSERTION_INDEX(dive_site_table, struct dive_site *, dive_sites, site_less_than) static MAKE_ADD_TO(dive_site_table, struct dive_site *, dive_sites) @@ -133,7 +138,7 @@ static MAKE_REMOVE(dive_site_table, struct dive_site *, dive_site) MAKE_CLEAR_TABLE(dive_site_table, dive_sites, dive_site) MAKE_MOVE_TABLE(dive_site_table, dive_sites) -extern "C" int add_dive_site_to_table(struct dive_site *ds, struct dive_site_table *ds_table) +int add_dive_site_to_table(struct dive_site *ds, struct dive_site_table *ds_table) { /* If the site doesn't yet have an UUID, create a new one. * Make this deterministic for testing. */ @@ -158,35 +163,35 @@ extern "C" int add_dive_site_to_table(struct dive_site *ds, struct dive_site_tab return idx; } -extern "C" struct dive_site *alloc_dive_site() +dive_site::dive_site() { - return (struct dive_site *)calloc(1, sizeof(struct dive_site)); } -extern "C" struct dive_site *alloc_dive_site_with_name(const char *name) +dive_site::dive_site(const char *name) : name(copy_string(name)) { - struct dive_site *ds = alloc_dive_site(); - ds->name = copy_string(name); - return ds; } -extern "C" struct dive_site *alloc_dive_site_with_gps(const char *name, const location_t *loc) +dive_site::dive_site(const char *name, const location_t *loc) : name(copy_string(name)), location(*loc) { - struct dive_site *ds = alloc_dive_site_with_name(name); - ds->location = *loc; +} - return ds; +dive_site::~dive_site() +{ + free(name); + free(notes); + free(description); + free(dives.dives); } /* when parsing, dive sites are identified by uuid */ -extern "C" struct dive_site *alloc_or_get_dive_site(uint32_t uuid, struct dive_site_table *ds_table) +struct dive_site *alloc_or_get_dive_site(uint32_t uuid, struct dive_site_table *ds_table) { struct dive_site *ds; if (uuid && (ds = get_dive_site_by_uuid(uuid, ds_table)) != NULL) return ds; - ds = alloc_dive_site(); + ds = new dive_site; ds->uuid = uuid; add_dive_site_to_table(ds, ds_table); @@ -194,12 +199,12 @@ extern "C" struct dive_site *alloc_or_get_dive_site(uint32_t uuid, struct dive_s return ds; } -extern "C" int nr_of_dives_at_dive_site(struct dive_site *ds) +int nr_of_dives_at_dive_site(struct dive_site *ds) { return ds->dives.nr; } -extern "C" bool is_dive_site_selected(struct dive_site *ds) +bool is_dive_site_selected(struct dive_site *ds) { int i; @@ -210,49 +215,37 @@ extern "C" bool is_dive_site_selected(struct dive_site *ds) return false; } -extern "C" void free_dive_site(struct dive_site *ds) -{ - if (ds) { - free(ds->name); - free(ds->notes); - free(ds->description); - free(ds->dives.dives); - free_taxonomy(&ds->taxonomy); - free(ds); - } -} - -extern "C" int unregister_dive_site(struct dive_site *ds) +int unregister_dive_site(struct dive_site *ds) { return remove_dive_site(ds, divelog.sites); } -extern "C" void delete_dive_site(struct dive_site *ds, struct dive_site_table *ds_table) +void delete_dive_site(struct dive_site *ds, struct dive_site_table *ds_table) { if (!ds) return; remove_dive_site(ds, ds_table); - free_dive_site(ds); + delete ds; } /* allocate a new site and add it to the table */ -extern "C" struct dive_site *create_dive_site(const char *name, struct dive_site_table *ds_table) +struct dive_site *create_dive_site(const char *name, struct dive_site_table *ds_table) { - struct dive_site *ds = alloc_dive_site_with_name(name); + struct dive_site *ds = new dive_site(name); add_dive_site_to_table(ds, ds_table); return ds; } /* same as before, but with GPS data */ -extern "C" struct dive_site *create_dive_site_with_gps(const char *name, const location_t *loc, struct dive_site_table *ds_table) +struct dive_site *create_dive_site_with_gps(const char *name, const location_t *loc, struct dive_site_table *ds_table) { - struct dive_site *ds = alloc_dive_site_with_gps(name, loc); + struct dive_site *ds = new dive_site(name, loc); add_dive_site_to_table(ds, ds_table); return ds; } /* if all fields are empty, the dive site is pointless */ -extern "C" bool dive_site_is_empty(struct dive_site *ds) +bool dive_site_is_empty(struct dive_site *ds) { return !ds || (empty_string(ds->name) && @@ -261,7 +254,7 @@ extern "C" bool dive_site_is_empty(struct dive_site *ds) !has_location(&ds->location)); } -extern "C" void copy_dive_site(struct dive_site *orig, struct dive_site *copy) +void copy_dive_site(struct dive_site *orig, struct dive_site *copy) { free(copy->name); free(copy->notes); @@ -271,7 +264,7 @@ extern "C" void copy_dive_site(struct dive_site *orig, struct dive_site *copy) copy->name = copy_string(orig->name); copy->notes = copy_string(orig->notes); copy->description = copy_string(orig->description); - copy_taxonomy(&orig->taxonomy, ©->taxonomy); + copy->taxonomy = orig->taxonomy; } static void merge_string(char **a, char **b) @@ -307,7 +300,7 @@ static bool same_dive_site(const struct dive_site *a, const struct dive_site *b) && same_string(a->notes, b->notes); } -extern "C" struct dive_site *get_same_dive_site(const struct dive_site *site) +struct dive_site *get_same_dive_site(const struct dive_site *site) { int i; struct dive_site *ds; @@ -317,20 +310,18 @@ extern "C" struct dive_site *get_same_dive_site(const struct dive_site *site) return NULL; } -extern "C" void merge_dive_site(struct dive_site *a, struct dive_site *b) +void merge_dive_site(struct dive_site *a, struct dive_site *b) { if (!has_location(&a->location)) a->location = b->location; merge_string(&a->name, &b->name); merge_string(&a->notes, &b->notes); merge_string(&a->description, &b->description); - if (!a->taxonomy.category) { - a->taxonomy = b->taxonomy; - memset(&b->taxonomy, 0, sizeof(b->taxonomy)); - } + if (a->taxonomy.empty()) + a->taxonomy = std::move(b->taxonomy); } -extern "C" struct dive_site *find_or_create_dive_site_with_name(const char *name, struct dive_site_table *ds_table) +struct dive_site *find_or_create_dive_site_with_name(const char *name, struct dive_site_table *ds_table) { int i; struct dive_site *ds; @@ -343,7 +334,7 @@ extern "C" struct dive_site *find_or_create_dive_site_with_name(const char *name return create_dive_site(name, ds_table); } -extern "C" void purge_empty_dive_sites(struct dive_site_table *ds_table) +void purge_empty_dive_sites(struct dive_site_table *ds_table) { int i, j; struct dive *d; @@ -360,7 +351,7 @@ extern "C" void purge_empty_dive_sites(struct dive_site_table *ds_table) } } -extern "C" void add_dive_to_dive_site(struct dive *d, struct dive_site *ds) +void add_dive_to_dive_site(struct dive *d, struct dive_site *ds) { int idx; if (!d) { @@ -382,7 +373,7 @@ extern "C" void add_dive_to_dive_site(struct dive *d, struct dive_site *ds) d->dive_site = ds; } -extern "C" struct dive_site *unregister_dive_from_dive_site(struct dive *d) +struct dive_site *unregister_dive_from_dive_site(struct dive *d) { struct dive_site *ds = d->dive_site; if (!ds) diff --git a/core/divesite.h b/core/divesite.h index 29002587f..237f60085 100644 --- a/core/divesite.h +++ b/core/divesite.h @@ -10,20 +10,20 @@ #ifdef __cplusplus #include #include -extern "C" { -#else -#include -#endif struct dive_site { - uint32_t uuid; - char *name; - struct dive_table dives; - location_t location; - char *description; - char *notes; - struct taxonomy_data taxonomy; + uint32_t uuid = 0; + char *name = nullptr; + struct dive_table dives = { 0, 0, nullptr }; + location_t location = { { 9 }, { 0 } }; + char *description = nullptr; + char *notes = nullptr; + taxonomy_data taxonomy; + dive_site(); + dive_site(const char *name); + dive_site(const char *name, const location_t *loc); + ~dive_site(); }; typedef struct dive_site_table { @@ -50,11 +50,8 @@ void sort_dive_site_table(struct dive_site_table *ds_table); int add_dive_site_to_table(struct dive_site *ds, struct dive_site_table *ds_table); struct dive_site *alloc_or_get_dive_site(uint32_t uuid, struct dive_site_table *ds_table); struct dive_site *alloc_dive_site(); -struct dive_site *alloc_dive_site_with_name(const char *name); -struct dive_site *alloc_dive_site_with_gps(const char *name, const location_t *loc); int nr_of_dives_at_dive_site(struct dive_site *ds); bool is_dive_site_selected(struct dive_site *ds); -void free_dive_site(struct dive_site *ds); int unregister_dive_site(struct dive_site *ds); int register_dive_site(struct dive_site *ds); void delete_dive_site(struct dive_site *ds, struct dive_site_table *ds_table); @@ -77,9 +74,7 @@ void move_dive_site_table(struct dive_site_table *src, struct dive_site_table *d void add_dive_to_dive_site(struct dive *d, struct dive_site *ds); struct dive_site *unregister_dive_from_dive_site(struct dive *d); -#ifdef __cplusplus -} -QString constructLocationTags(struct taxonomy_data *taxonomy, bool for_maintab); +QString constructLocationTags(taxonomy_data &taxonomy, bool for_maintab); /* Make pointer-to-dive_site a "Qt metatype" so that we can pass it through QVariants */ Q_DECLARE_METATYPE(dive_site *); diff --git a/core/divesitehelpers.cpp b/core/divesitehelpers.cpp index aee24d9eb..e4fd4af4e 100644 --- a/core/divesitehelpers.cpp +++ b/core/divesitehelpers.cpp @@ -84,14 +84,14 @@ taxonomy_data reverseGeoLookup(degrees_t latitude, degrees_t longitude) QString url; QJsonObject obj; - taxonomy_data taxonomy = { 0, 0 }; + taxonomy_data taxonomy; // check the oceans API to figure out the body of water url = geonamesOceanURL.arg(getUiLanguage().section(QRegularExpression("[-_ ]"), 0, 0)).arg(latitude.udeg / 1000000.0).arg(longitude.udeg / 1000000.0); obj = doAsyncRESTGetRequest(url, 5000); // 5 secs. timeout QVariantMap oceanName = obj.value("ocean").toVariant().toMap(); if (oceanName["name"].isValid()) - taxonomy_set_category(&taxonomy, TC_OCEAN, qPrintable(oceanName["name"].toString()), taxonomy_origin::GEOCODED); + taxonomy_set_category(taxonomy, TC_OCEAN, oceanName["name"].toString().toStdString(), taxonomy_origin::GEOCODED); // check the findNearbyPlaces API from geonames - that should give us country, state, city url = geonamesNearbyPlaceNameURL.arg(getUiLanguage().section(QRegularExpression("[-_ ]"), 0, 0)).arg(latitude.udeg / 1000000.0).arg(longitude.udeg / 1000000.0); @@ -110,16 +110,16 @@ taxonomy_data reverseGeoLookup(degrees_t latitude, degrees_t longitude) for (int idx = TC_COUNTRY; idx < TC_NR_CATEGORIES; idx++) { if (firstData[taxonomy_api_names[idx]].isValid()) { QString value = firstData[taxonomy_api_names[idx]].toString(); - taxonomy_set_category(&taxonomy, (taxonomy_category)idx, qPrintable(value), taxonomy_origin::GEOCODED); + taxonomy_set_category(taxonomy, (taxonomy_category)idx, value.toStdString(), taxonomy_origin::GEOCODED); } } - const char *l3 = taxonomy_get_value(&taxonomy, TC_ADMIN_L3); - const char *lt = taxonomy_get_value(&taxonomy, TC_LOCALNAME); - if (empty_string(l3) && !empty_string(lt)) { + std::string l3 = taxonomy_get_value(taxonomy, TC_ADMIN_L3); + std::string lt = taxonomy_get_value(taxonomy, TC_LOCALNAME); + if (!l3.empty() && !lt.empty()) { // basically this means we did get a local name (what we call town), but just like most places // we didn't get an adminName_3 - which in some regions is the actual city that town belongs to, // then we copy the town into the city - taxonomy_set_category(&taxonomy, TC_ADMIN_L3, lt, taxonomy_origin::GEOCOPIED); + taxonomy_set_category(taxonomy, TC_ADMIN_L3, lt, taxonomy_origin::GEOCOPIED); } } else { report_error("geonames.org did not provide reverse lookup information"); diff --git a/core/fulltext.cpp b/core/fulltext.cpp index 8a9c956d7..101ac876f 100644 --- a/core/fulltext.cpp +++ b/core/fulltext.cpp @@ -141,9 +141,9 @@ static std::vector getWords(const dive *d) // take the tokens from a cache. if (d->dive_site) { tokenize(d->dive_site->name, res); - const char *country = taxonomy_get_country(&d->dive_site->taxonomy); - if (country) - tokenize(country, res); + std::string country = taxonomy_get_country(d->dive_site->taxonomy); + if (!country.empty()) + tokenize(country.c_str(), res); } // TODO: We should index trips separately! if (d->divetrip) diff --git a/core/load-git.cpp b/core/load-git.cpp index ba25794e1..becae6f58 100644 --- a/core/load-git.cpp +++ b/core/load-git.cpp @@ -332,8 +332,8 @@ static void parse_site_geo(char *line, struct git_parser_state *state) int origin; int category; sscanf(line, "cat %d origin %d \"", &category, &origin); - taxonomy_set_category(&state->active_site->taxonomy, (taxonomy_category)category, - get_first_converted_string(state).c_str(), (taxonomy_origin)origin); + taxonomy_set_category(state->active_site->taxonomy, (taxonomy_category)category, + get_first_converted_string(state), (taxonomy_origin)origin); } static std::string pop_cstring(struct git_parser_state *state, const char *err) diff --git a/core/owning_ptrs.h b/core/owning_ptrs.h index 6f591d144..3ba5dc0a5 100644 --- a/core/owning_ptrs.h +++ b/core/owning_ptrs.h @@ -16,7 +16,6 @@ struct event; extern "C" void free_dive(struct dive *); extern "C" void free_trip(struct dive_trip *); -extern "C" void free_dive_site(struct dive_site *); // Classes used to automatically call the appropriate free_*() function for owning pointers that go out of scope. struct DiveDeleter { @@ -25,9 +24,6 @@ struct DiveDeleter { struct TripDeleter { void operator()(dive_trip *t) { free_trip(t); } }; -struct DiveSiteDeleter { - void operator()(dive_site *ds) { free_dive_site(ds); } -}; struct EventDeleter { void operator()(event *ev) { free(ev); } }; @@ -35,7 +31,6 @@ struct EventDeleter { // Owning pointers to dive, dive_trip, dive_site and event objects. using OwningDivePtr = std::unique_ptr; using OwningTripPtr = std::unique_ptr; -using OwningDiveSitePtr = std::unique_ptr; using OwningEventPtr = std::unique_ptr; #endif diff --git a/core/parse-xml.cpp b/core/parse-xml.cpp index 8988d9602..f25d4533c 100644 --- a/core/parse-xml.cpp +++ b/core/parse-xml.cpp @@ -1410,7 +1410,7 @@ static void try_to_fill_trip(dive_trip_t *dive_trip, const char *name, char *buf /* We're processing a divesite entry - try to fill the components */ static void try_to_fill_dive_site(struct parser_state *state, const char *name, char *buf) { - struct dive_site *ds = state->cur_dive_site; + auto &ds = state->cur_dive_site; std::string taxonomy_value; start_match("divesite", name, buf); @@ -1423,7 +1423,7 @@ static void try_to_fill_dive_site(struct parser_state *state, const char *name, return; if (MATCH("notes", utf8_string, &ds->notes)) return; - if (MATCH("gps", gps_location, ds)) + if (MATCH("gps", gps_location, ds.get())) return; if (MATCH("cat.geo", get_index, &state->taxonomy_category)) return; @@ -1436,8 +1436,8 @@ static void try_to_fill_dive_site(struct parser_state *state, const char *name, if (state->taxonomy_category < 0 || state->taxonomy_origin < 0) { report_error("Warning: taxonomy value without origin or category"); } else { - taxonomy_set_category(&ds->taxonomy, (taxonomy_category)state->taxonomy_category, - taxonomy_value.c_str(), (taxonomy_origin)state->taxonomy_origin); + taxonomy_set_category(ds->taxonomy, (taxonomy_category)state->taxonomy_category, + taxonomy_value, (taxonomy_origin)state->taxonomy_origin); } state->taxonomy_category = state->taxonomy_origin = -1; return; diff --git a/core/parse.cpp b/core/parse.cpp index bd48157d9..bb493d5a5 100644 --- a/core/parse.cpp +++ b/core/parse.cpp @@ -19,11 +19,14 @@ #include "device.h" #include "gettext.h" +parser_state::parser_state() +{ +} + parser_state::~parser_state() { free_dive(cur_dive); free_trip(cur_trip); - free_dive_site(cur_dive_site); } /* @@ -188,7 +191,7 @@ void dive_site_start(struct parser_state *state) return; state->taxonomy_category = -1; state->taxonomy_origin = -1; - state->cur_dive_site = (dive_site *)calloc(1, sizeof(struct dive_site)); + state->cur_dive_site = std::make_unique(); } void dive_site_end(struct parser_state *state) @@ -197,13 +200,12 @@ void dive_site_end(struct parser_state *state) return; struct dive_site *ds = alloc_or_get_dive_site(state->cur_dive_site->uuid, state->log->sites); - merge_dive_site(ds, state->cur_dive_site); + merge_dive_site(ds, state->cur_dive_site.get()); if (verbose > 3) printf("completed dive site uuid %x8 name {%s}\n", ds->uuid, ds->name); - free_dive_site(state->cur_dive_site); - state->cur_dive_site = NULL; + state->cur_dive_site.reset(); } void filter_preset_start(struct parser_state *state) diff --git a/core/parse.h b/core/parse.h index ebd8af7a6..7cc1385e9 100644 --- a/core/parse.h +++ b/core/parse.h @@ -64,7 +64,7 @@ struct parser_state { struct divecomputer *cur_dc = nullptr; /* non-owning */ struct dive *cur_dive = nullptr; /* owning */ - struct dive_site *cur_dive_site = nullptr; /* owning */ + std::unique_ptr cur_dive_site; /* owning */ location_t cur_location { 0 }; struct dive_trip *cur_trip = nullptr; /* owning */ struct sample *cur_sample = nullptr; /* non-owning */ @@ -96,6 +96,7 @@ struct parser_state { sqlite3 *sql_handle = nullptr; /* for SQL based parsers */ bool event_active = false; event_allocation_t event_allocation; + parser_state(); ~parser_state(); }; diff --git a/core/pref.h b/core/pref.h index b649ffc74..ac9c5e0b3 100644 --- a/core/pref.h +++ b/core/pref.h @@ -2,15 +2,15 @@ #ifndef PREF_H #define PREF_H +#include "units.h" +#include "taxonomy.h" + #ifdef __cplusplus extern "C" { #else #include #endif -#include "units.h" -#include "taxonomy.h" - typedef struct { bool po2; diff --git a/core/save-git.cpp b/core/save-git.cpp index ff838dda5..dbc4a21bb 100644 --- a/core/save-git.cpp +++ b/core/save-git.cpp @@ -933,11 +933,10 @@ static void save_divesites(git_repository *repo, struct dir *tree) show_utf8(&b, "description ", ds->description, "\n"); show_utf8(&b, "notes ", ds->notes, "\n"); put_location(&b, &ds->location, "gps ", "\n"); - for (int j = 0; j < ds->taxonomy.nr; j++) { - struct taxonomy *t = &ds->taxonomy.category[j]; - if (t->category != TC_NONE && t->value) { - put_format(&b, "geo cat %d origin %d ", t->category, t->origin); - show_utf8(&b, "", t->value, "\n" ); + for (const auto &t: ds->taxonomy) { + if (t.category != TC_NONE && !t.value.empty()) { + put_format(&b, "geo cat %d origin %d ", t.category, t.origin); + show_utf8(&b, "", t.value.c_str(), "\n" ); } } blob_insert(repo, subdir, &b, mb_cstring(&site_file_name)); diff --git a/core/save-xml.cpp b/core/save-xml.cpp index 21ed7e089..5b4037875 100644 --- a/core/save-xml.cpp +++ b/core/save-xml.cpp @@ -716,15 +716,12 @@ static void save_dives_buffer(struct membuffer *b, bool select_only, bool anonym show_utf8_blanked(b, ds->description, " description='", "'", 1, anonymize); put_format(b, ">\n"); show_utf8_blanked(b, ds->notes, " ", " \n", 0, anonymize); - if (ds->taxonomy.nr) { - for (int j = 0; j < ds->taxonomy.nr; j++) { - struct taxonomy *t = &ds->taxonomy.category[j]; - if (t->category != TC_NONE && t->value) { - put_format(b, " category); - put_format(b, " origin='%d'", t->origin); - show_utf8_blanked(b, t->value, " value='", "'", 1, anonymize); - put_format(b, "/>\n"); - } + for (auto const &t: ds->taxonomy) { + if (t.category != TC_NONE && !t.value.empty()) { + put_format(b, " \n"); } } put_format(b, "\n"); @@ -921,15 +918,12 @@ static void save_dive_sites_buffer(struct membuffer *b, const struct dive_site * show_utf8_blanked(b, ds->description, " description='", "'", 1, anonymize); put_format(b, ">\n"); show_utf8_blanked(b, ds->notes, " ", " \n", 0, anonymize); - if (ds->taxonomy.nr) { - for (int j = 0; j < ds->taxonomy.nr; j++) { - struct taxonomy *t = &ds->taxonomy.category[j]; - if (t->category != TC_NONE && t->value) { - put_format(b, " category); - put_format(b, " origin='%d'", t->origin); - show_utf8_blanked(b, t->value, " value='", "'", 1, anonymize); - put_format(b, "/>\n"); - } + for (const auto &t: ds->taxonomy) { + if (t.category != TC_NONE && !t.value.empty()) { + put_format(b, " \n"); } } put_format(b, "\n"); diff --git a/core/string-format.cpp b/core/string-format.cpp index 1dd9dd3e4..a81d35ae5 100644 --- a/core/string-format.cpp +++ b/core/string-format.cpp @@ -133,6 +133,12 @@ static void addStringToSortedList(QStringList &l, const std::string &s) l.insert(it, qs); } +// Safely treat null-strings. Remove once everyhting is converted to std::string +static std::string c_to_std(const char *s) +{ + return s ? std::string(s) : std::string(); +} + QStringList formatFullCylinderList() { QStringList cylinders; @@ -140,7 +146,7 @@ QStringList formatFullCylinderList() int i = 0; for_each_dive (i, d) { for (int j = 0; j < d->cylinders.nr; j++) - addStringToSortedList(cylinders, get_cylinder(d, j)->type.description); + addStringToSortedList(cylinders, c_to_std(get_cylinder(d, j)->type.description)); } for (const auto &ti: tank_info_table) diff --git a/core/taxonomy.c b/core/taxonomy.c deleted file mode 100644 index c21a2e644..000000000 --- a/core/taxonomy.c +++ /dev/null @@ -1,111 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#include "taxonomy.h" -#include "gettext.h" -#include "subsurface-string.h" -#include -#include - -char *taxonomy_category_names[TC_NR_CATEGORIES] = { - QT_TRANSLATE_NOOP("gettextFromC", "None"), - QT_TRANSLATE_NOOP("gettextFromC", "Ocean"), - QT_TRANSLATE_NOOP("gettextFromC", "Country"), - QT_TRANSLATE_NOOP("gettextFromC", "State"), - QT_TRANSLATE_NOOP("gettextFromC", "County"), - QT_TRANSLATE_NOOP("gettextFromC", "Town"), - QT_TRANSLATE_NOOP("gettextFromC", "City") -}; - -// these are the names for geoname.org -char *taxonomy_api_names[TC_NR_CATEGORIES] = { - "none", - "name", - "countryName", - "adminName1", - "adminName2", - "toponymName", - "adminName3" -}; - -static void alloc_taxonomy_table(struct taxonomy_data *t) -{ - if (!t->category) - t->category = calloc(TC_NR_CATEGORIES, sizeof(struct taxonomy)); -} - -void free_taxonomy(struct taxonomy_data *t) -{ - if (t) { - for (int i = 0; i < t->nr; i++) - free((void *)t->category[i].value); - free(t->category); - t->category = NULL; - t->nr = 0; - } -} - -void copy_taxonomy(const struct taxonomy_data *orig, struct taxonomy_data *copy) -{ - if (orig->category == NULL) { - free_taxonomy(copy); - } else { - alloc_taxonomy_table(copy); - for (int i = 0; i < TC_NR_CATEGORIES; i++) { - if (i < copy->nr) { - free((void *)copy->category[i].value); - copy->category[i].value = NULL; - } - if (i < orig->nr) { - copy->category[i] = orig->category[i]; - copy->category[i].value = copy_string(orig->category[i].value); - } - } - copy->nr = orig->nr; - } -} - -static int taxonomy_index_for_category(const struct taxonomy_data *t, enum taxonomy_category cat) -{ - for (int i = 0; i < t->nr; i++) { - if (t->category[i].category == cat) - return i; - } - return -1; -} - -const char *taxonomy_get_value(const struct taxonomy_data *t, enum taxonomy_category cat) -{ - int idx = taxonomy_index_for_category(t, cat); - return idx >= 0 ? t->category[idx].value : NULL; -} - -const char *taxonomy_get_country(const struct taxonomy_data *t) -{ - return taxonomy_get_value(t, TC_COUNTRY); -} - -void taxonomy_set_category(struct taxonomy_data *t, enum taxonomy_category category, const char *value, enum taxonomy_origin origin) -{ - int idx = taxonomy_index_for_category(t, category); - - if (idx < 0) { - alloc_taxonomy_table(t); // make sure we have taxonomy data allocated - if (t->nr == TC_NR_CATEGORIES - 1) { - // can't add another one - fprintf(stderr, "Error adding taxonomy category\n"); - return; - } - idx = t->nr++; - } else { - free((void *)t->category[idx].value); - t->category[idx].value = NULL; - } - t->category[idx].value = strdup(value); - t->category[idx].origin = origin; - t->category[idx].category = category; -} - -void taxonomy_set_country(struct taxonomy_data *t, const char *country, enum taxonomy_origin origin) -{ - fprintf(stderr, "%s: set the taxonomy country to %s\n", __func__, country); - taxonomy_set_category(t, TC_COUNTRY, country, origin); -} diff --git a/core/taxonomy.cpp b/core/taxonomy.cpp new file mode 100644 index 000000000..18f589b6b --- /dev/null +++ b/core/taxonomy.cpp @@ -0,0 +1,59 @@ +// SPDX-License-Identifier: GPL-2.0 +#include "taxonomy.h" +#include "errorhelper.h" +#include "gettext.h" +#include "subsurface-string.h" +#include +#include +#include +#include // for QT_TRANSLATE_NOOP + +const char *taxonomy_category_names[TC_NR_CATEGORIES] = { + QT_TRANSLATE_NOOP("gettextFromC", "None"), + QT_TRANSLATE_NOOP("gettextFromC", "Ocean"), + QT_TRANSLATE_NOOP("gettextFromC", "Country"), + QT_TRANSLATE_NOOP("gettextFromC", "State"), + QT_TRANSLATE_NOOP("gettextFromC", "County"), + QT_TRANSLATE_NOOP("gettextFromC", "Town"), + QT_TRANSLATE_NOOP("gettextFromC", "City") +}; + +// these are the names for geoname.org +const char *taxonomy_api_names[TC_NR_CATEGORIES] = { + "none", + "name", + "countryName", + "adminName1", + "adminName2", + "toponymName", + "adminName3" +}; + +std::string taxonomy_get_value(const taxonomy_data &t, enum taxonomy_category cat) +{ + auto it = std::find_if(t.begin(), t.end(), [cat] (const taxonomy &tax) { return tax.category == cat; }); + return it != t.end() ? it->value : std::string(); +} + +std::string taxonomy_get_country(const taxonomy_data &t) +{ + return taxonomy_get_value(t, TC_COUNTRY); +} + +void taxonomy_set_category(taxonomy_data &t, enum taxonomy_category cat, const std::string &value, enum taxonomy_origin origin) +{ + auto it = std::find_if(t.begin(), t.end(), [cat] (const taxonomy &tax) { return tax.category == cat; }); + if (it == t.end()) { + t.emplace_back(); + it = std::prev(t.end()); + } + it->value = value; + it->origin = origin; + it->category = cat; +} + +void taxonomy_set_country(taxonomy_data &t, const std::string &country, enum taxonomy_origin origin) +{ + report_info("%s: set the taxonomy country to %s\n", __func__, country.c_str()); + taxonomy_set_category(t, TC_COUNTRY, country, origin); +} diff --git a/core/taxonomy.h b/core/taxonomy.h index a2c03220c..6c61d91e1 100644 --- a/core/taxonomy.h +++ b/core/taxonomy.h @@ -3,8 +3,9 @@ #define TAXONOMY_H #ifdef __cplusplus -extern "C" { -#endif + +#include +#include enum taxonomy_category { TC_NONE, @@ -24,29 +25,22 @@ enum taxonomy_origin { GEOCOPIED }; -extern char *taxonomy_category_names[TC_NR_CATEGORIES]; -extern char *taxonomy_api_names[TC_NR_CATEGORIES]; +extern const char *taxonomy_category_names[TC_NR_CATEGORIES]; +extern const char *taxonomy_api_names[TC_NR_CATEGORIES]; struct taxonomy { - int category; /* the category for this tag: ocean, country, admin_l1, admin_l2, localname, etc */ - const char *value; /* the value returned, parsed, or manually entered for that category */ - enum taxonomy_origin origin; + taxonomy_category category; /* the category for this tag: ocean, country, admin_l1, admin_l2, localname, etc */ + std::string value; /* the value returned, parsed, or manually entered for that category */ + taxonomy_origin origin; }; -/* the data block contains 3 taxonomy structures - unused ones have a tag value of NONE */ -struct taxonomy_data { - int nr; - struct taxonomy *category; -}; +/* the data block contains taxonomy structures - unused ones have a tag value of NONE */ +using taxonomy_data = std::vector; -void free_taxonomy(struct taxonomy_data *t); -void copy_taxonomy(const struct taxonomy_data *orig, struct taxonomy_data *copy); -const char *taxonomy_get_value(const struct taxonomy_data *t, enum taxonomy_category cat); -const char *taxonomy_get_country(const struct taxonomy_data *t); -void taxonomy_set_category(struct taxonomy_data *t, enum taxonomy_category category, const char *value, enum taxonomy_origin origin); -void taxonomy_set_country(struct taxonomy_data *t, const char *country, enum taxonomy_origin origin); +std::string taxonomy_get_value(const taxonomy_data &t, enum taxonomy_category cat); +std::string taxonomy_get_country(const taxonomy_data &t); +void taxonomy_set_category(taxonomy_data &t, enum taxonomy_category category, const std::string &value, enum taxonomy_origin origin); +void taxonomy_set_country(taxonomy_data &t, const std::string &country, enum taxonomy_origin origin); -#ifdef __cplusplus -} #endif #endif // TAXONOMY_H diff --git a/core/uploadDiveLogsDE.cpp b/core/uploadDiveLogsDE.cpp index 0589934c2..e4660a94f 100644 --- a/core/uploadDiveLogsDE.cpp +++ b/core/uploadDiveLogsDE.cpp @@ -116,13 +116,14 @@ bool uploadDiveLogsDE::prepareDives(const QString &tempfile, bool selected) put_format(&mb, "'"); put_location(&mb, &ds->location, " gps='", "'"); put_format(&mb, ">\n"); - if (ds->taxonomy.nr) { - for (int j = 0; j < ds->taxonomy.nr; j++) { - struct taxonomy *t = &ds->taxonomy.category[j]; - if (t->category != TC_NONE && t->category == prefs.geocoding.category[j] && t->value) { - put_format(&mb, " category); - put_format(&mb, " origin='%d' value='", t->origin); - put_quoted(&mb, t->value, 1, 0); + for (int i = 0; i < 3; i++) { + if (prefs.geocoding.category[i] == TC_NONE) + continue; + for (auto const &t: ds->taxonomy) { + if (t.category == prefs.geocoding.category[i] && !t.value.empty()) { + put_format(&mb, " \n"); } } diff --git a/desktop-widgets/divesiteimportdialog.cpp b/desktop-widgets/divesiteimportdialog.cpp index 66f003253..3ab94732e 100644 --- a/desktop-widgets/divesiteimportdialog.cpp +++ b/desktop-widgets/divesiteimportdialog.cpp @@ -67,7 +67,7 @@ void DivesiteImportDialog::on_ok_clicked() struct dive_site_table selectedSites = empty_dive_site_table; for (int i = 0; i < importedSites.nr; i++) if (divesiteImportedModel->data(divesiteImportedModel->index(i, 0), Qt::CheckStateRole) == Qt::Checked) { - struct dive_site *newSite = alloc_dive_site(); + struct dive_site *newSite = new dive_site; copy_dive_site(importedSites.dive_sites[i], newSite); add_dive_site_to_table(newSite, &selectedSites); } diff --git a/desktop-widgets/locationinformation.cpp b/desktop-widgets/locationinformation.cpp index d2ece3f17..dc5131da4 100644 --- a/desktop-widgets/locationinformation.cpp +++ b/desktop-widgets/locationinformation.cpp @@ -133,9 +133,9 @@ void LocationInformationWidget::updateLabels() ui.diveSiteName->setText(diveSite->name); else ui.diveSiteName->clear(); - const char *country = taxonomy_get_country(&diveSite->taxonomy); - if (country) - ui.diveSiteCountry->setText(country); + std::string country = taxonomy_get_country(diveSite->taxonomy); + if (!country.empty()) + ui.diveSiteCountry->setText(QString::fromStdString(country)); else ui.diveSiteCountry->clear(); if (diveSite->description) @@ -152,7 +152,7 @@ void LocationInformationWidget::updateLabels() ui.diveSiteCoordinates->clear(); coordinatesSetWarning(false); - ui.locationTags->setText(constructLocationTags(&diveSite->taxonomy, false)); + ui.locationTags->setText(constructLocationTags(diveSite->taxonomy, false)); } void LocationInformationWidget::unitsChanged() @@ -181,8 +181,8 @@ void LocationInformationWidget::diveSiteChanged(struct dive_site *ds, int field) ui.diveSiteNotes->setText(diveSite->notes); return; case LocationInformationModel::TAXONOMY: - ui.diveSiteCountry->setText(taxonomy_get_country(&diveSite->taxonomy)); - ui.locationTags->setText(constructLocationTags(&diveSite->taxonomy, false)); + ui.diveSiteCountry->setText(QString::fromStdString(taxonomy_get_country(diveSite->taxonomy))); + ui.locationTags->setText(constructLocationTags(diveSite->taxonomy, false)); return; case LocationInformationModel::LOCATION: filter_model.setCoordinates(diveSite->location); @@ -342,10 +342,8 @@ void LocationInformationWidget::reverseGeocode() if (!ds || !has_location(&location)) return; taxonomy_data taxonomy = reverseGeoLookup(location.lat, location.lon); - if (ds != diveSite) { - free_taxonomy(&taxonomy); + if (ds != diveSite) return; - } // This call transfers ownership of the taxonomy memory into an EditDiveSiteTaxonomy object Command::editDiveSiteTaxonomy(ds, taxonomy); } diff --git a/desktop-widgets/modeldelegates.cpp b/desktop-widgets/modeldelegates.cpp index 5317e413a..e9365c365 100644 --- a/desktop-widgets/modeldelegates.cpp +++ b/desktop-widgets/modeldelegates.cpp @@ -461,12 +461,12 @@ void LocationFilterDelegate::paint(QPainter *painter, const QStyleOptionViewItem for (int i = 0; i < 3; i++) { if (prefs.geocoding.category[i] == TC_NONE) continue; - const char *value = taxonomy_get_value(&ds->taxonomy, prefs.geocoding.category[i]); - if (empty_string(value)) + std::string value = taxonomy_get_value(ds->taxonomy, prefs.geocoding.category[i]); + if (!value.empty()) continue; if(!bottomText.isEmpty()) bottomText += " / "; - bottomText += QString(value); + bottomText += QString::fromStdString(value); } if (bottomText.isEmpty()) diff --git a/desktop-widgets/tab-widgets/TabDiveNotes.cpp b/desktop-widgets/tab-widgets/TabDiveNotes.cpp index 8135cd8af..3e4b995e5 100644 --- a/desktop-widgets/tab-widgets/TabDiveNotes.cpp +++ b/desktop-widgets/tab-widgets/TabDiveNotes.cpp @@ -178,7 +178,7 @@ void TabDiveNotes::updateDiveSite(struct dive *d) struct dive_site *ds = d->dive_site; ui.location->setCurrentDiveSite(d); if (ds) { - ui.locationTags->setText(constructLocationTags(&ds->taxonomy, true)); + ui.locationTags->setText(constructLocationTags(ds->taxonomy, true)); if (ui.locationTags->text().isEmpty() && has_location(&ds->location)) ui.locationTags->setText(printGPSCoords(&ds->location)); diff --git a/mobile-widgets/qmlmanager.cpp b/mobile-widgets/qmlmanager.cpp index 7d75a55c3..685696a4a 100644 --- a/mobile-widgets/qmlmanager.cpp +++ b/mobile-widgets/qmlmanager.cpp @@ -908,7 +908,7 @@ void QMLManager::refreshDiveList() // The following structure describes such a change caused by a dive edit. // Hopefully, we can remove this in due course by using finer-grained undo-commands. struct DiveSiteChange { - OwningDiveSitePtr createdDs; // not-null if we created a dive site. + std::unique_ptr createdDs; // not-null if we created a dive site. dive_site *editDs = nullptr; // not-null if we are supposed to edit an existing dive site. location_t location = zero_location; // new value of the location if we edit an existing dive site. @@ -923,7 +923,7 @@ static void setupDivesite(DiveSiteChange &res, struct dive *d, struct dive_site res.editDs = ds; res.location = location; } else { - res.createdDs.reset(alloc_dive_site_with_name(locationtext)); + res.createdDs = std::make_unique(locationtext); res.createdDs->location = location; d->dive_site = res.createdDs.get(); } @@ -1072,7 +1072,7 @@ bool QMLManager::checkLocation(DiveSiteChange &res, struct dive *d, QString loca if (oldLocation != location) { ds = get_dive_site_by_name(qPrintable(location), divelog.sites); if (!ds && !location.isEmpty()) { - res.createdDs.reset(alloc_dive_site_with_name(qPrintable(location))); + res.createdDs = std::make_unique(qPrintable(location)); res.changed = true; ds = res.createdDs.get(); } diff --git a/qt-models/divesiteimportmodel.cpp b/qt-models/divesiteimportmodel.cpp index 07c763bb5..4854fbb6b 100644 --- a/qt-models/divesiteimportmodel.cpp +++ b/qt-models/divesiteimportmodel.cpp @@ -63,7 +63,7 @@ QVariant DivesiteImportedModel::data(const QModelIndex &index, int role) const case LOCATION: return printGPSCoords(&ds->location); case COUNTRY: - return taxonomy_get_country(&ds->taxonomy); + return QString::fromStdString(taxonomy_get_country(ds->taxonomy)); case NEAREST: { // 40075000 is circumference of the earth in meters struct dive_site *nearest_ds = diff --git a/qt-models/divetripmodel.cpp b/qt-models/divetripmodel.cpp index 12929b605..0ddc0e8bb 100644 --- a/qt-models/divetripmodel.cpp +++ b/qt-models/divetripmodel.cpp @@ -351,7 +351,7 @@ QVariant DiveTripModelBase::diveData(const struct dive *d, int column, int role) case PHOTOS: break; case COUNTRY: - return QString(get_dive_country(d)); + return QString::fromStdString(get_dive_country(d)); case BUDDIES: return QString(d->buddy); case DIVEGUIDE: @@ -1770,7 +1770,7 @@ bool DiveTripModelList::lessThan(const QModelIndex &i1, const QModelIndex &i2) c case PHOTOS: return lessThanHelper(countPhotos(d1) - countPhotos(d2), row_diff); case COUNTRY: - return lessThanHelper(strCmp(get_dive_country(d1), get_dive_country(d2)), row_diff); + return lessThanHelper(strCmp(get_dive_country(d1).c_str(), get_dive_country(d2).c_str()), row_diff); case BUDDIES: return lessThanHelper(strCmp(d1->buddy, d2->buddy), row_diff); case DIVEGUIDE: