From 585bb022a3f82ab77e1322bba50c1f5ef6e9ea26 Mon Sep 17 00:00:00 2001 From: tsteven4 <13596209+tsteven4@users.noreply.github.com> Date: Mon, 30 Oct 2023 11:52:35 -0600 Subject: [PATCH 01/11] use container for garmin_fs ilinks. and leave memory management up to the copy on write container. --- garmin.cc | 2 +- garmin_fs.cc | 42 +----------------------------------------- garmin_fs.h | 28 ++++++++++++---------------- garmin_gpi.cc | 4 ++-- garmin_txt.cc | 4 ++-- gdb.cc | 47 ++++++++++++++++------------------------------- gpx.cc | 26 ++++++++++++++------------ random.cc | 4 ++-- unicsv.cc | 4 ++-- waypt.cc | 18 ++++++++---------- xcsv.cc | 4 ++-- 11 files changed, 62 insertions(+), 121 deletions(-) diff --git a/garmin.cc b/garmin.cc index 1382f9ead..aafa3b209 100644 --- a/garmin.cc +++ b/garmin.cc @@ -1241,7 +1241,7 @@ d103_icon_number_from_symbol(const QString& s) static void garmin_fs_garmin_after_read(const GPS_PWay way, Waypoint* wpt, const int protoid) { - garmin_fs_t* gmsd = garmin_fs_alloc(protoid); + auto* gmsd = new garmin_fs_t(protoid); wpt->fs.FsChainAdd(gmsd); /* nothing happens until gmsd is allocated some lines above */ diff --git a/garmin_fs.cc b/garmin_fs.cc index 148db9169..46a857d36 100644 --- a/garmin_fs.cc +++ b/garmin_fs.cc @@ -31,46 +31,6 @@ #define MYNAME "garmin_fs" -garmin_fs_t* -garmin_fs_alloc(const int protocol) -{ - auto* result = new garmin_fs_t; - - result->protocol = protocol; - - return result; -} - -garmin_fs_t* garmin_fs_t::clone() const -{ - auto* copy = new garmin_fs_t(*this); - - /* do not deep copy interlinks, only increment the reference counter */ - if (ilinks != nullptr) { - ilinks->ref_count++; - } - -#ifdef GMSD_EXPERIMENTAL - memcopy(subclass, other.subclass, sizeof(subclass)); -#endif - - return copy; -} - -garmin_fs_t::~garmin_fs_t() -{ - garmin_ilink_t* links; - if ((links = ilinks) != nullptr) { - links->ref_count--; - if (links->ref_count <= 0) { - while (links != nullptr) { - garmin_ilink_t* tmp = links; - links = links->next; - xfree(tmp); - } - } - } -} bool garmin_fs_convert_category(const QString& category_name, uint16_t* category) @@ -112,7 +72,7 @@ garmin_fs_merge_category(const QString& category_name, Waypoint* waypt) cat = cat | (garmin_fs_t::get_category(gmsd, 0)); if (gmsd == nullptr) { - gmsd = garmin_fs_alloc(-1); + gmsd = new garmin_fs_t(-1); waypt->fs.FsChainAdd(gmsd); } garmin_fs_t::set_category(gmsd, cat); diff --git a/garmin_fs.h b/garmin_fs.h index 0535d85ac..20c68ccff 100644 --- a/garmin_fs.h +++ b/garmin_fs.h @@ -26,6 +26,7 @@ #include // for int32_t, int16_t, uint16_t +#include // for QList #include // for QString #include "defs.h" @@ -41,9 +42,9 @@ */ struct garmin_ilink_t { - int ref_count; - double lat, lon, alt; - garmin_ilink_t* next; + double lat; + double lon; + double alt; }; struct garmin_fs_flags_t { @@ -117,22 +118,21 @@ class garmin_fs_t : public FormatSpecificData { QString email; /* email address */ unsigned int duration; /* expected travel time to next route point, in seconds, only when auto-routed */ - garmin_ilink_t* ilinks{nullptr}; + QList ilinks; #ifdef GMSD_EXPERIMENTAL char subclass[22]{}; #endif public: garmin_fs_t() : FormatSpecificData(kFsGmsd) {} -private: - garmin_fs_t(const garmin_fs_t& other) = default; -public: - garmin_fs_t& operator=(const garmin_fs_t& rhs) = delete; /* not implemented */ - garmin_fs_t(garmin_fs_t&&) = delete; /* not implemented */ - garmin_fs_t& operator=(garmin_fs_t&&) = delete; /* not implemented */ - ~garmin_fs_t() override; + explicit garmin_fs_t(int p) : garmin_fs_t() {protocol = p;} + + + garmin_fs_t* clone() const override + { + return new garmin_fs_t(*this); + } - garmin_fs_t* clone() const override; static garmin_fs_t* find(const Waypoint* wpt) { return reinterpret_cast(wpt->fs.FsChainFind(kFsGmsd)); } @@ -214,10 +214,6 @@ class garmin_fs_t : public FormatSpecificData { #undef GEN_GMSD_STR_METHODS }; -garmin_fs_t* garmin_fs_alloc(int protocol); -void garmin_fs_destroy(void* fs); -void garmin_fs_copy(void** dest, const void* src); - /* ..convert_category: returns true=OK; false=Unable to convert category */ bool garmin_fs_convert_category(const QString& category_name, uint16_t* category); diff --git a/garmin_gpi.cc b/garmin_gpi.cc index 340c823be..efccc3a3d 100644 --- a/garmin_gpi.cc +++ b/garmin_gpi.cc @@ -41,7 +41,7 @@ #include "defs.h" #include "formspec.h" // for FormatSpecificDataList -#include "garmin_fs.h" // for garmin_fs_t, garmin_fs_alloc +#include "garmin_fs.h" // for garmin_fs_t #include "gbfile.h" // for gbfputint32, gbfgetint32, gbfgetint16, gbfputint16, gbfgetc, gbfputc, gbfread, gbftell, gbfwrite, gbfseek, gbfclose, gbfopen_le, gbfgetuint16, gbsize_t, gbfile #include "jeeps/gpsmath.h" // for GPS_Math_Deg_To_Semi, GPS_Math_Semi_To_Deg @@ -76,7 +76,7 @@ GarminGPIFormat::gpi_gmsd_init(Waypoint* wpt) } garmin_fs_t* gmsd = garmin_fs_t::find(wpt); if (gmsd == nullptr) { - gmsd = garmin_fs_alloc(-1); + gmsd = new garmin_fs_t(-1); wpt->fs.FsChainAdd(gmsd); } return gmsd; diff --git a/garmin_txt.cc b/garmin_txt.cc index c49569445..3dd66e252 100644 --- a/garmin_txt.cc +++ b/garmin_txt.cc @@ -49,7 +49,7 @@ #include "csv_util.h" // for csv_linesplit #include "formspec.h" // for FormatSpecificDataList -#include "garmin_fs.h" // for garmin_fs_t, garmin_fs_alloc, garmin_fs_convert_category, GMSD_SECTION_CATEGORIES +#include "garmin_fs.h" // for garmin_fs_t, garmin_fs_convert_category, GMSD_SECTION_CATEGORIES #include "garmin_tables.h" // for gt_display_modes_e, gt_find_desc_from_icon_number, gt_find_icon_number_from_desc, gt_get_mps_grid_longname, gt_lookup_datum_index, gt_lookup_grid_type, GDB, gt_get_icao_cc, gt_get_icao_country, gt_get_mps_datum_name, gt_waypt_class_names, GT_DISPLAY_MODE... #include "inifile.h" // for inifile_readstr #include "jeeps/gpsmath.h" // for GPS_Math_Known_Datum_To_UTM_EN, GPS_Math_WGS84_To_Known_Datum_M, GPS_Math_WGS84_To_Swiss_EN, GPS_Math_WGS84_To_UKOSMap_M @@ -1102,7 +1102,7 @@ parse_waypoint(const QStringList& lineparts) bind_fields(waypt_header); auto* wpt = new Waypoint; - garmin_fs_t* gmsd = garmin_fs_alloc(-1); + auto* gmsd = new garmin_fs_t(-1); wpt->fs.FsChainAdd(gmsd); for (const auto& str : lineparts) { diff --git a/gdb.cc b/gdb.cc index 5efbb55f3..c9c83f200 100644 --- a/gdb.cc +++ b/gdb.cc @@ -42,7 +42,7 @@ #include "defs.h" // for Waypoint, warning, route_head, fatal, UrlLink, bounds, UrlList, unknown_alt, xfree, waypt_add_to_bounds, waypt_init_bounds, xstrtoi, route_add_wpt, route_disp_all, waypt_bounds_valid, xmalloc, gb_color, WaypointList, find_wa... #include "formspec.h" // for FormatSpecificDataList -#include "garmin_fs.h" // for garmin_fs_t, garmin_ilink_t, garmin_fs_alloc +#include "garmin_fs.h" // for garmin_fs_t, garmin_ilink_t #include "garmin_tables.h" // for gt_waypt_class_map_point, gt_color_index_by_rgb, gt_color_value, gt_waypt_classes_e, gt_find_desc_from_icon_number, gt_find_icon_number_from_desc, gt_gdb_display_mode_symbol, gt_get_icao_country, gt_waypt_class_user_waypoint, GDB, gt_display_mode_symbol #include "gbfile.h" // for gbfgetint32, gbfputint32, gbfgetc, gbfread, gbfwrite, gbfgetdbl, gbfputc, gbfgetcstr, gbfclose, gbfgetnativecstr, gbfopen_le, gbfputint16, gbfile, gbfcopyfrom, gbfputcstr, gbfrewind, gbfseek, gbftell, gbfgetcstr_old, gbfgetint16, gbfgetuint32, gbfputdbl #include "grtcirc.h" // for RAD, gcdist, radtometers @@ -440,7 +440,7 @@ GdbFormat::read_waypoint(gt_waypt_classes_e* waypt_class_out) waypt_ct++; res = new Waypoint; - gmsd = garmin_fs_alloc(-1); + gmsd = new garmin_fs_t(-1); res->fs.FsChainAdd(gmsd); res->shortname = fread_cstr(); wpt_class = (gt_waypt_classes_e) FREAD_i32; @@ -738,46 +738,37 @@ GdbFormat::read_route() } int links = FREAD_i32; - garmin_ilink_t* il_anchor = nullptr; - garmin_ilink_t* il_root = nullptr; + QList il_list; #if GDB_DEBUG DBG(GDB_DBG_RTE, links) printf(MYNAME "-rte_pt \"%s\" (%d): %d interlink step(s)\n", qPrintable(wpt->shortname), wpt_class, links); #endif for (int j = 0; j < links; j++) { - auto* il_step = (garmin_ilink_t*) xmalloc(sizeof(garmin_ilink_t)); + garmin_ilink_t il_step; - il_step->ref_count = 1; - - il_step->lat = FREAD_LATLON; - il_step->lon = FREAD_LATLON; + il_step.lat = FREAD_LATLON; + il_step.lon = FREAD_LATLON; if (FREAD_C == 1) { - il_step->alt = FREAD_DBL; + il_step.alt = FREAD_DBL; } else { - il_step->alt = unknown_alt; + il_step.alt = unknown_alt; } if (j == 0) { - wpt->latitude = il_step->lat; - wpt->longitude = il_step->lon; - wpt->altitude = il_step->alt; + wpt->latitude = il_step.lat; + wpt->longitude = il_step.lon; + wpt->altitude = il_step.alt; } - il_step->next = nullptr; - if (il_anchor == nullptr) { - il_root = il_step; - } else { - il_anchor->next = il_step; - } - il_anchor = il_step; + il_list.append(il_step); #if GDB_DEBUG DBG(GDB_DBG_RTEe, true) { printf(MYNAME "-rte_il \"%s\" (%d of %d): %c%0.6f %c%0.6f\n", qPrintable(wpt->shortname), j + 1, links, - il_step->lat < 0 ? 'S' : 'N', il_step->lat, - il_step->lon < 0 ? 'W' : 'E', il_step->lon); + il_step.lat < 0 ? 'S' : 'N', il_step.lat, + il_step.lon < 0 ? 'W' : 'E', il_step.lon); } #endif } @@ -832,19 +823,13 @@ GdbFormat::read_route() if (wpt != nullptr) { garmin_fs_t* gmsd = garmin_fs_t::find(wpt); if (gmsd == nullptr) { - gmsd = garmin_fs_alloc(-1); + gmsd = new garmin_fs_t(-1); wpt->fs.FsChainAdd(gmsd); } garmin_fs_t::set_wpt_class(gmsd, wpt_class); - gmsd->ilinks = il_root; - il_root = nullptr; + gmsd->ilinks = il_list; } - while (il_root) { - garmin_ilink_t* il = il_root; - il_root = il_root->next; - xfree(il); - } } /* ENDFOR: for (i = 0; i < points; i++) */ /* VERSION DEPENDENT CODE */ diff --git a/gpx.cc b/gpx.cc index de176e454..787b68131 100644 --- a/gpx.cc +++ b/gpx.cc @@ -47,7 +47,7 @@ #include // for qAsConst, QAddConst<>::Type #include "defs.h" -#include "garmin_fs.h" // for garmin_fs_t, garmin_ilink_t, garmin_fs_alloc, garmin_fs_merge_category +#include "garmin_fs.h" // for garmin_fs_t, garmin_ilink_t, garmin_fs_merge_category #include "garmin_tables.h" // for gt_color_index_by_rgb, gt_color_name, gt_color_value_by_name #include "geocache.h" // for Geocache, Geocache::UtfSt... #include "mkshort.h" // for MakeShort @@ -218,7 +218,7 @@ GpxFormat::tag_garmin_fs(tag_type tag, const QString& text, Waypoint* waypt) { garmin_fs_t* gmsd = garmin_fs_t::find(waypt); if (gmsd == nullptr) { - gmsd = garmin_fs_alloc(-1); + gmsd = new garmin_fs_t(-1); waypt->fs.FsChainAdd(gmsd); } @@ -1346,7 +1346,7 @@ GpxFormat::gpx_write_common_extensions(const Waypoint* waypointp, const gpx_poin // Although not required by the schema we assume that gpxx:RoutePointExtension must be a child of gpx:rtept. // Although not required by the schema we assume that gpxx:TrackPointExtension must be a child of gpx:trkpt. // Although not required by the schema we assume that gpxtpx:TrackPointExtension must be a child of gpx:trkpt. - garmin_fs_t* gmsd = garmin_fs_t::find(waypointp); + const garmin_fs_t* gmsd = garmin_fs_t::find(waypointp); switch (point_type) { case gpxpt_waypoint: writer->stackOptionalStartElement(QStringLiteral("gpxx:WaypointExtension")); @@ -1401,19 +1401,21 @@ GpxFormat::gpx_write_common_extensions(const Waypoint* waypointp, const gpx_poin writer->stackEndElement(); // gpxx:WaypointExtension break; case gpxpt_route: - if (gmsd != nullptr && gmsd->ilinks != nullptr) { + if (gmsd != nullptr && !gmsd->ilinks.isEmpty()) { writer->stackOptionalStartElement(QStringLiteral("gpxx:RoutePointExtension")); - garmin_ilink_t* link = gmsd->ilinks; - garmin_ilink_t* prior = nullptr; // GDB files sometime contain repeated point; omit them - while (link != nullptr) { - if (prior == nullptr || prior->lat != link->lat || prior->lon != link->lon) { + double prior_lat; // GDB files sometime contain repeated point; omit them + double prior_lon; + bool first = true; + for (const auto& link : gmsd->ilinks) { + if (first || (prior_lat != link.lat) || (prior_lon != link.lon)) { writer->stackStartElement(QStringLiteral("gpxx:rpt")); - writer->stackAttribute(QStringLiteral("lat"), toString(link->lat)); - writer->stackAttribute(QStringLiteral("lon"), toString(link->lon)); + writer->stackAttribute(QStringLiteral("lat"), toString(link.lat)); + writer->stackAttribute(QStringLiteral("lon"), toString(link.lon)); writer->stackEndElement(); // "gpxx:rpt" + prior_lat = link.lat; + prior_lon = link.lon; + first = false; } - prior = link; - link = link->next; } writer->stackEndElement(); // gpxx:RoutePointExtension } diff --git a/random.cc b/random.cc index 7026a9e53..339c04602 100644 --- a/random.cc +++ b/random.cc @@ -28,7 +28,7 @@ #include "defs.h" #include "random.h" #include "formspec.h" // for FormatSpecificDataList -#include "garmin_fs.h" // for garmin_fs_t, GMSD_SET, garmin_fs_flags_t, garmin_fs_alloc +#include "garmin_fs.h" // for garmin_fs_t, GMSD_SET, garmin_fs_flags_t #include "src/core/datetime.h" // for DateTime @@ -104,7 +104,7 @@ Waypoint* RandomFormat::random_generate_wpt(int i, const QDateTime& time, const Waypoint* prev) { auto* wpt = new Waypoint; - garmin_fs_t* gmsd = garmin_fs_alloc(-1); + auto* gmsd = new garmin_fs_t(-1); wpt->fs.FsChainAdd(gmsd); do { diff --git a/unicsv.cc b/unicsv.cc index 92ca85043..48c483213 100644 --- a/unicsv.cc +++ b/unicsv.cc @@ -42,7 +42,7 @@ #include "defs.h" #include "csv_util.h" // for csv_linesplit, human_to_dec #include "formspec.h" // for FormatSpecificDataList -#include "garmin_fs.h" // for garmin_fs_flags_t, garmin_fs_t, GMSD_GET, GMSD_HAS, GMSD_SETQSTR, GMSD_FIND, garmin_fs_alloc +#include "garmin_fs.h" // for garmin_fs_t #include "garmin_tables.h" // for gt_lookup_datum_index, gt_get_mps_grid_longname, gt_lookup_grid_type #include "geocache.h" // for Geocache, Geocache::status_t, Geoc... #include "jeeps/gpsmath.h" // for GPS_Math_UKOSMap_To_WGS84_M, GPS_Math_EN_To_UKOSNG_Map, GPS_Math_Known_Datum_To_UTM_EN, GPS_Math_Known_Datum_To_WGS84_M, GPS_Math_Swiss_EN_To_WGS84, GPS_Math_UTM_EN_To_Known_Datum, GPS_Math_WGS84_To_Known_Datum_M, GPS_Math_WGS84_To_Swiss_EN, GPS_Math_WGS... @@ -823,7 +823,7 @@ UnicsvFormat::unicsv_parse_one_line(const QString& ibuf) case fld_garmin_facility: gmsd = garmin_fs_t::find(wpt); if (! gmsd) { - gmsd = garmin_fs_alloc(-1); + gmsd = new garmin_fs_t(-1); wpt->fs.FsChainAdd(gmsd); } switch (unicsv_fields_tab[column]) { diff --git a/waypt.cc b/waypt.cc index 8130add75..77a219faa 100644 --- a/waypt.cc +++ b/waypt.cc @@ -230,22 +230,20 @@ double waypt_distance_ex(const Waypoint* A, const Waypoint* B) { double res = 0; - garmin_fs_t* gmsd; if ((A == nullptr) || (B == nullptr)) { return 0; } - if ((gmsd = garmin_fs_t::find(A)) && (gmsd->ilinks != nullptr)) { - garmin_ilink_t* link = gmsd->ilinks; - - res = gcgeodist(A->latitude, A->longitude, link->lat, link->lon); - while (link->next != nullptr) { - garmin_ilink_t* prev = link; - link = link->next; - res += gcgeodist(prev->lat, prev->lon, link->lat, link->lon); + if (const garmin_fs_t* gmsd = garmin_fs_t::find(A); (gmsd != nullptr) && (!gmsd->ilinks.isEmpty())) { + auto prev_lat = A->latitude; + auto prev_lon = A->longitude; + for (const auto& link : gmsd->ilinks) { + res += gcgeodist(prev_lat, prev_lon, link.lat, link.lon); + prev_lat = link.lat; + prev_lon = link.lon; } - res += gcgeodist(link->lat, link->lon, B->latitude, B->longitude); + res += gcgeodist(gmsd->ilinks.last().lat, gmsd->ilinks.last().lon, B->latitude, B->longitude); } else { res = gcgeodist(A->latitude, A->longitude, B->latitude, B->longitude); } diff --git a/xcsv.cc b/xcsv.cc index d2c57e549..4a18e224f 100644 --- a/xcsv.cc +++ b/xcsv.cc @@ -51,7 +51,7 @@ #include "defs.h" #include "csv_util.h" // for csv_stringtrim, dec_to_human, csv_stringclean, human_to_dec, ddmmdir_to_degrees, dec_to_intdeg, decdir_to_dec, intdeg_to_dec, csv_linesplit #include "formspec.h" // for FormatSpecificDataList -#include "garmin_fs.h" // for garmin_fs_t, garmin_fs_alloc +#include "garmin_fs.h" // for garmin_fs_t #include "geocache.h" // for Geocache, Geocache::status_t, Geoc... #include "grtcirc.h" // for RAD, gcdist, radtometers #include "jeeps/gpsmath.h" // for GPS_Math_WGS84_To_UTM_EN, GPS_Lookup_Datum_Index, GPS_Math_Known_Datum_To_WGS84_M, GPS_Math_UTM_EN_To_Known_Datum, GPS_Math_WGS84_To_Known_Datum_M, GPS_Math_WGS84_To_UKOSMap_M @@ -361,7 +361,7 @@ XcsvFormat::gmsd_init(Waypoint* wpt) { garmin_fs_t* gmsd = garmin_fs_t::find(wpt); if (gmsd == nullptr) { - gmsd = garmin_fs_alloc(-1); + gmsd = new garmin_fs_t(-1); wpt->fs.FsChainAdd(gmsd); } return gmsd; From 45961b858175b10435543753cf8cd0360e728e2d Mon Sep 17 00:00:00 2001 From: tsteven4 <13596209+tsteven4@users.noreply.github.com> Date: Mon, 30 Oct 2023 12:39:03 -0600 Subject: [PATCH 02/11] make gmsd const for read only usage. this prevents the possiblity of detachment of the ilinks list. --- garmin.cc | 2 +- garmin_gpi.cc | 2 +- garmin_txt.cc | 4 ++-- gdb.cc | 6 +++--- gdb.h | 2 +- unicsv.cc | 4 ++-- xcsv.cc | 16 ++++++++-------- 7 files changed, 18 insertions(+), 18 deletions(-) diff --git a/garmin.cc b/garmin.cc index aafa3b209..dd04edc42 100644 --- a/garmin.cc +++ b/garmin.cc @@ -1275,7 +1275,7 @@ garmin_fs_garmin_after_read(const GPS_PWay way, Waypoint* wpt, const int protoid static void garmin_fs_garmin_before_write(const Waypoint* wpt, GPS_PWay way, const int protoid) { - garmin_fs_t* gmsd = garmin_fs_t::find(wpt); + const garmin_fs_t* gmsd = garmin_fs_t::find(wpt); (void)protoid; // unused for now. diff --git a/garmin_gpi.cc b/garmin_gpi.cc index efccc3a3d..3f9a824fb 100644 --- a/garmin_gpi.cc +++ b/garmin_gpi.cc @@ -700,7 +700,7 @@ GarminGPIFormat::wdata_compute_size(writer_data_t* data) const res = 23; /* bounds, ... of tag 0x80008 */ foreach (Waypoint* wpt, data->waypt_list) { - garmin_fs_t* gmsd; + const garmin_fs_t* gmsd; res += 12; /* tag/sz/sub-sz */ res += 19; /* poi fixed size */ diff --git a/garmin_txt.cc b/garmin_txt.cc index 3dd66e252..27d32815b 100644 --- a/garmin_txt.cc +++ b/garmin_txt.cc @@ -221,7 +221,7 @@ convert_datum(const Waypoint* wpt, double* dest_lat, double* dest_lon) static void enum_waypt_cb(const Waypoint* wpt) { - garmin_fs_t* gmsd = garmin_fs_t::find(wpt); + const garmin_fs_t* gmsd = garmin_fs_t::find(wpt); int wpt_class = garmin_fs_t::get_wpt_class(gmsd, 0); if (wpt_class < 0x80) { if (gtxt_flags.enum_waypoints) { /* enumerate only */ @@ -528,7 +528,7 @@ write_waypt(const Waypoint* wpt) { const char* wpt_type; - garmin_fs_t* gmsd = garmin_fs_t::find(wpt); + const garmin_fs_t* gmsd = garmin_fs_t::find(wpt); int i = garmin_fs_t::get_display(gmsd, 0); if (i > GT_DISPLAY_MODE_MAX) { diff --git a/gdb.cc b/gdb.cc index c9c83f200..db3bec6a5 100644 --- a/gdb.cc +++ b/gdb.cc @@ -1179,7 +1179,7 @@ GdbFormat::gdb_check_waypt(Waypoint* wpt) void GdbFormat::write_waypoint( - const Waypoint* wpt, const QString& shortname, garmin_fs_t* gmsd, + const Waypoint* wpt, const QString& shortname, const garmin_fs_t* gmsd, const int icon, const int display) { char zbuf[32], ffbuf[32]; @@ -1376,7 +1376,7 @@ GdbFormat::write_route(const route_head* rte, const QString& rte_name) fatal(MYNAME ": Sorry, that should never happen!!!\n"); } - garmin_fs_t* gmsd = garmin_fs_t::find(wpt); + const garmin_fs_t* gmsd = garmin_fs_t::find(wpt); /* extra_data may contain a modified shortname */ gdb_write_cstr((wpt->extra_data) ? *static_cast(wpt->extra_data) : wpt->shortname); @@ -1549,7 +1549,7 @@ GdbFormat::write_waypoint_cb(const Waypoint* refpt) fout = ftmp; /* prepare the waypoint */ - garmin_fs_t* gmsd = garmin_fs_t::find(wpt); + const garmin_fs_t* gmsd = garmin_fs_t::find(wpt); int wpt_class = garmin_fs_t::get_wpt_class(gmsd, -1); if (wpt_class == -1) { diff --git a/gdb.h b/gdb.h index 6697ca592..fc3497401 100644 --- a/gdb.h +++ b/gdb.h @@ -150,7 +150,7 @@ class GdbFormat : public Format void reset_short_handle(const char* defname); void write_header(); static void gdb_check_waypt(Waypoint* wpt); - void write_waypoint(const Waypoint* wpt, const QString& shortname, garmin_fs_t* gmsd, int icon, int display); + void write_waypoint(const Waypoint* wpt, const QString& shortname, const garmin_fs_t* gmsd, int icon, int display); static void route_compute_bounds(const route_head* rte, bounds* bounds); void route_write_bounds(bounds* bounds) const; void write_route(const route_head* rte, const QString& rte_name); diff --git a/unicsv.cc b/unicsv.cc index 48c483213..679c19ad4 100644 --- a/unicsv.cc +++ b/unicsv.cc @@ -1113,7 +1113,7 @@ void UnicsvFormat::unicsv_waypt_enum_cb(const Waypoint* wpt) { const QString& shortname = wpt->shortname; - garmin_fs_t* gmsd = garmin_fs_t::find(wpt); + const garmin_fs_t* gmsd = garmin_fs_t::find(wpt); if (!shortname.isEmpty()) { unicsv_outp_flags[fld_shortname] = true; @@ -1264,7 +1264,7 @@ UnicsvFormat::unicsv_waypt_disp_cb(const Waypoint* wpt) unicsv_waypt_ct++; QString shortname = wpt->shortname; - garmin_fs_t* gmsd = garmin_fs_t::find(wpt); + const garmin_fs_t* gmsd = garmin_fs_t::find(wpt); if (unicsv_datum_idx == kDautmWGS84) { lat = wpt->latitude; diff --git a/xcsv.cc b/xcsv.cc index 4a18e224f..d649fff55 100644 --- a/xcsv.cc +++ b/xcsv.cc @@ -1534,42 +1534,42 @@ XcsvFormat::xcsv_waypt_pr(const Waypoint* wpt) break; /* GMSD ************************************************************/ case XcsvStyle::XT_COUNTRY: { - garmin_fs_t* gmsd = garmin_fs_t::find(wpt); + const garmin_fs_t* gmsd = garmin_fs_t::find(wpt); buff = QString::asprintf(fmp.printfc.constData(), CSTR(garmin_fs_t::get_country(gmsd, ""))); } break; case XcsvStyle::XT_STATE: { - garmin_fs_t* gmsd = garmin_fs_t::find(wpt); + const garmin_fs_t* gmsd = garmin_fs_t::find(wpt); buff = QString::asprintf(fmp.printfc.constData(), CSTR(garmin_fs_t::get_state(gmsd, ""))); } break; case XcsvStyle::XT_CITY: { - garmin_fs_t* gmsd = garmin_fs_t::find(wpt); + const garmin_fs_t* gmsd = garmin_fs_t::find(wpt); buff = QString::asprintf(fmp.printfc.constData(), CSTR(garmin_fs_t::get_city(gmsd, ""))); } break; case XcsvStyle::XT_POSTAL_CODE: { - garmin_fs_t* gmsd = garmin_fs_t::find(wpt); + const garmin_fs_t* gmsd = garmin_fs_t::find(wpt); buff = QString::asprintf(fmp.printfc.constData(), CSTR(garmin_fs_t::get_postal_code(gmsd, ""))); } break; case XcsvStyle::XT_STREET_ADDR: { - garmin_fs_t* gmsd = garmin_fs_t::find(wpt); + const garmin_fs_t* gmsd = garmin_fs_t::find(wpt); buff = QString::asprintf(fmp.printfc.constData(), CSTR(garmin_fs_t::get_addr(gmsd, ""))); } break; case XcsvStyle::XT_PHONE_NR: { - garmin_fs_t* gmsd = garmin_fs_t::find(wpt); + const garmin_fs_t* gmsd = garmin_fs_t::find(wpt); buff = QString::asprintf(fmp.printfc.constData(), CSTR(garmin_fs_t::get_phone_nr(gmsd, ""))); } break; case XcsvStyle::XT_FACILITY: { - garmin_fs_t* gmsd = garmin_fs_t::find(wpt); + const garmin_fs_t* gmsd = garmin_fs_t::find(wpt); buff = QString::asprintf(fmp.printfc.constData(), CSTR(garmin_fs_t::get_facility(gmsd, ""))); } break; case XcsvStyle::XT_EMAIL: { - garmin_fs_t* gmsd = garmin_fs_t::find(wpt); + const garmin_fs_t* gmsd = garmin_fs_t::find(wpt); buff = QString::asprintf(fmp.printfc.constData(), CSTR(garmin_fs_t::get_email(gmsd, ""))); } break; From 50e6745c20984383ef2e69ae9b555c8018dc143c Mon Sep 17 00:00:00 2001 From: tsteven4 <13596209+tsteven4@users.noreply.github.com> Date: Mon, 30 Oct 2023 12:54:32 -0600 Subject: [PATCH 03/11] incorporate some variables and functions into garmin_fs_t --- garmin_fs.cc | 4 ++-- garmin_fs.h | 9 +++++---- garmin_txt.cc | 6 +++--- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/garmin_fs.cc b/garmin_fs.cc index 46a857d36..8001d4ff4 100644 --- a/garmin_fs.cc +++ b/garmin_fs.cc @@ -33,7 +33,7 @@ bool -garmin_fs_convert_category(const QString& category_name, uint16_t* category) +garmin_fs_t::convert_category(const QString& category_name, uint16_t* category) { // Is the name "Category" followed by a number? Use that number. if (category_name.startsWith(u"Category ", Qt::CaseInsensitive)) { @@ -64,7 +64,7 @@ garmin_fs_merge_category(const QString& category_name, Waypoint* waypt) uint16_t cat; // Attempt to get a textual category name to a category number. - if (!garmin_fs_convert_category(category_name, &cat)) { + if (!garmin_fs_t::convert_category(category_name, &cat)) { return false; } diff --git a/garmin_fs.h b/garmin_fs.h index 20c68ccff..96ec4fc65 100644 --- a/garmin_fs.h +++ b/garmin_fs.h @@ -96,6 +96,8 @@ struct garmin_fs_flags_t { class garmin_fs_t : public FormatSpecificData { public: + static constexpr char GMSD_SECTION_CATEGORIES[] = "Garmin Categories"; + garmin_fs_flags_t flags; int protocol{0}; /* ... used by device (-1 is MapSource) */ @@ -212,14 +214,13 @@ class garmin_fs_t : public FormatSpecificData { GEN_GMSD_STR_METHODS(email) #undef GEN_GMSD_STR_METHODS -}; /* ..convert_category: returns true=OK; false=Unable to convert category */ -bool garmin_fs_convert_category(const QString& category_name, uint16_t* category); +static bool convert_category(const QString& category_name, uint16_t* category); + +}; /* ..merge_category: returns true=OK; false=Unable to convert category */ bool garmin_fs_merge_category(const QString& category_name, Waypoint* waypt); -#define GMSD_SECTION_CATEGORIES "Garmin Categories" - #endif diff --git a/garmin_txt.cc b/garmin_txt.cc index 27d32815b..7230afd0e 100644 --- a/garmin_txt.cc +++ b/garmin_txt.cc @@ -49,7 +49,7 @@ #include "csv_util.h" // for csv_linesplit #include "formspec.h" // for FormatSpecificDataList -#include "garmin_fs.h" // for garmin_fs_t, garmin_fs_convert_category, GMSD_SECTION_CATEGORIES +#include "garmin_fs.h" // for garmin_fs_t, GMSD_SECTION_CATEGORIES #include "garmin_tables.h" // for gt_display_modes_e, gt_find_desc_from_icon_number, gt_find_icon_number_from_desc, gt_get_mps_grid_longname, gt_lookup_datum_index, gt_lookup_grid_type, GDB, gt_get_icao_cc, gt_get_icao_country, gt_get_mps_datum_name, gt_waypt_class_names, GT_DISPLAY_MODE... #include "inifile.h" // for inifile_readstr #include "jeeps/gpsmath.h" // for GPS_Math_Known_Datum_To_UTM_EN, GPS_Math_WGS84_To_Known_Datum_M, GPS_Math_WGS84_To_Swiss_EN, GPS_Math_WGS84_To_UKOSMap_M @@ -403,7 +403,7 @@ print_categories(uint16_t categories) QString c; if (global_opts.inifile != nullptr) { QString key = QString::number(i + 1); - c = inifile_readstr(global_opts.inifile, GMSD_SECTION_CATEGORIES, key); + c = inifile_readstr(global_opts.inifile, garmin_fs_t::GMSD_SECTION_CATEGORIES, key); } *fout << QString::asprintf("%s", (count++ > 0) ? "," : ""); @@ -965,7 +965,7 @@ parse_categories(const QString& str) QString cin = catstring.trimmed(); if (!cin.isEmpty()) { uint16_t val; - if (!garmin_fs_convert_category(cin, &val)) { + if (!garmin_fs_t::convert_category(cin, &val)) { warning(MYNAME ": Unable to convert category \"%s\" at line %d!\n", qPrintable(cin), current_line); } else { res = res | val; From 96f59f412403712bc324e263bdbdb4596c90c935 Mon Sep 17 00:00:00 2001 From: tsteven4 <13596209+tsteven4@users.noreply.github.com> Date: Mon, 30 Oct 2023 16:20:23 -0600 Subject: [PATCH 04/11] unify garmin category conversions. --- garmin_fs.cc | 57 ++++++++++++++++++++-------------- garmin_fs.h | 19 +++++++----- garmin_txt.cc | 42 +++++++------------------ gpx.cc | 15 ++++----- reference/garmincategories.gpx | 35 +++++++++++++++++++++ reference/garmincategories.txt | 7 +++++ testo.d/gpx.test | 7 +++++ util.cc | 4 +-- 8 files changed, 115 insertions(+), 71 deletions(-) create mode 100644 reference/garmincategories.gpx create mode 100644 reference/garmincategories.txt diff --git a/garmin_fs.cc b/garmin_fs.cc index 8001d4ff4..525523005 100644 --- a/garmin_fs.cc +++ b/garmin_fs.cc @@ -29,52 +29,61 @@ #include "inifile.h" // for inifile_readstr -#define MYNAME "garmin_fs" - - -bool -garmin_fs_t::convert_category(const QString& category_name, uint16_t* category) +std::optional +garmin_fs_t::convert_category(const QString& category_name) { + std::optional category; + // Is the name "Category" followed by a number? Use that number. if (category_name.startsWith(u"Category ", Qt::CaseInsensitive)) { bool ok; int i = category_name.mid(9).toInt(&ok); if (ok && (i >= 1) && (i <= 16)) { - *category = (1 << --i); - return true; + category = (1 << --i); + return category; } } if (global_opts.inifile != nullptr) { // Do we have a gpsbabel.ini that maps category names to category #'s? for (int i = 0; i < 16; i++) { QString key = QString::number(i + 1); - QString c = inifile_readstr(global_opts.inifile, GMSD_SECTION_CATEGORIES, key); + QString c = inifile_readstr(global_opts.inifile, kGmsdSectionCategories, key); if (c.compare(category_name, Qt::CaseInsensitive) == 0) { - *category = (1 << i); - return true; + category = (1 << i); + return category; } } } - return false; + return category; } -bool -garmin_fs_merge_category(const QString& category_name, Waypoint* waypt) +QStringList +garmin_fs_t::print_categories(uint16_t categories) { - uint16_t cat; + QStringList categoryList; - // Attempt to get a textual category name to a category number. - if (!garmin_fs_t::convert_category(category_name, &cat)) { - return false; + if (categories == 0) { + return categoryList; } - garmin_fs_t* gmsd = garmin_fs_t::find(waypt); - cat = cat | (garmin_fs_t::get_category(gmsd, 0)); + for (int i = 0; i < 16; i++) { + if ((categories & 1) != 0) { + QString c; + if (global_opts.inifile != nullptr) { + QString key = QString::number(i + 1); + c = inifile_readstr(global_opts.inifile, kGmsdSectionCategories, key); + } + + if (c.isNull()) { + categoryList << QString::asprintf("Category %d", i+1); + } +// *fout << QString::asprintf("%s", gps_categories[i]); + else { + categoryList << c; + } - if (gmsd == nullptr) { - gmsd = new garmin_fs_t(-1); - waypt->fs.FsChainAdd(gmsd); + } + categories = categories >> 1; } - garmin_fs_t::set_category(gmsd, cat); - return true; + return categoryList; } diff --git a/garmin_fs.h b/garmin_fs.h index 96ec4fc65..ac74e8957 100644 --- a/garmin_fs.h +++ b/garmin_fs.h @@ -25,6 +25,7 @@ #define GARMIN_FS_H #include // for int32_t, int16_t, uint16_t +#include // for optional #include // for QList #include // for QString @@ -96,7 +97,7 @@ struct garmin_fs_flags_t { class garmin_fs_t : public FormatSpecificData { public: - static constexpr char GMSD_SECTION_CATEGORIES[] = "Garmin Categories"; + /* Data Members */ garmin_fs_flags_t flags; @@ -125,10 +126,12 @@ class garmin_fs_t : public FormatSpecificData { char subclass[22]{}; #endif -public: + /* Special Member Functions */ + garmin_fs_t() : FormatSpecificData(kFsGmsd) {} explicit garmin_fs_t(int p) : garmin_fs_t() {protocol = p;} + /* Member Functions */ garmin_fs_t* clone() const override { @@ -139,6 +142,9 @@ class garmin_fs_t : public FormatSpecificData { return reinterpret_cast(wpt->fs.FsChainFind(kFsGmsd)); } + static std::optional convert_category(const QString& category_name); + static QStringList print_categories(uint16_t categories); + #define GEN_GMSD_METHODS(field) \ static bool has_##field(const garmin_fs_t* gmsd) \ { \ @@ -215,12 +221,9 @@ class garmin_fs_t : public FormatSpecificData { #undef GEN_GMSD_STR_METHODS -/* ..convert_category: returns true=OK; false=Unable to convert category */ -static bool convert_category(const QString& category_name, uint16_t* category); +private: + /* Constants */ + static constexpr char kGmsdSectionCategories[] = "Garmin Categories"; }; - -/* ..merge_category: returns true=OK; false=Unable to convert category */ -bool garmin_fs_merge_category(const QString& category_name, Waypoint* waypt); - #endif diff --git a/garmin_txt.cc b/garmin_txt.cc index 7230afd0e..ff8bdf260 100644 --- a/garmin_txt.cc +++ b/garmin_txt.cc @@ -33,6 +33,7 @@ #include // for abs #include // for strstr, strlen #include // for time_t, gmtime, localtime, strftime +#include // for optional #include // for pair, make_pair #include // for QByteArray @@ -49,7 +50,7 @@ #include "csv_util.h" // for csv_linesplit #include "formspec.h" // for FormatSpecificDataList -#include "garmin_fs.h" // for garmin_fs_t, GMSD_SECTION_CATEGORIES +#include "garmin_fs.h" // for garmin_fs_t #include "garmin_tables.h" // for gt_display_modes_e, gt_find_desc_from_icon_number, gt_find_icon_number_from_desc, gt_get_mps_grid_longname, gt_lookup_datum_index, gt_lookup_grid_type, GDB, gt_get_icao_cc, gt_get_icao_country, gt_get_mps_datum_name, gt_waypt_class_names, GT_DISPLAY_MODE... #include "inifile.h" // for inifile_readstr #include "jeeps/gpsmath.h" // for GPS_Math_Known_Datum_To_UTM_EN, GPS_Math_WGS84_To_Known_Datum_M, GPS_Math_WGS84_To_Swiss_EN, GPS_Math_WGS84_To_UKOSMap_M @@ -393,30 +394,9 @@ print_date_and_time(const time_t time, const bool time_only) static void print_categories(uint16_t categories) { - if (categories == 0) { - return; - } - - int count = 0; - for (int i = 0; i < 16; i++) { - if ((categories & 1) != 0) { - QString c; - if (global_opts.inifile != nullptr) { - QString key = QString::number(i + 1); - c = inifile_readstr(global_opts.inifile, garmin_fs_t::GMSD_SECTION_CATEGORIES, key); - } - - *fout << QString::asprintf("%s", (count++ > 0) ? "," : ""); - if (c.isNull()) { - *fout << QString::asprintf("Category %d", i+1); - } -// *fout << QString::asprintf("%s", gps_categories[i]); - else { - *fout << c; - } - - } - categories = categories >> 1; + const QStringList categoryList = garmin_fs_t::print_categories(categories); + if (!categoryList.isEmpty()) { + *fout << categoryList.join(','); } } @@ -902,7 +882,7 @@ strftime_to_timespec(const char* s) q += "yyyy"; continue; case 'H': - q += "hh"; + q += "HH"; continue; case 'M': q += "mm"; @@ -931,8 +911,11 @@ strftime_to_timespec(const char* s) case 'F': q += "yyyy-MM-dd"; continue; + case 'p': + q += "AP"; + continue; default: - q += s[i+1]; + warning(MYNAME ": omitting unknown strptime conversion \"%%%c\" in \"%s\"\n", s[i], s); break; } } @@ -964,11 +947,10 @@ parse_categories(const QString& str) for (const auto& catstring : catstrings) { QString cin = catstring.trimmed(); if (!cin.isEmpty()) { - uint16_t val; - if (!garmin_fs_t::convert_category(cin, &val)) { + if (std::optional cat = garmin_fs_t::convert_category(cin); !cat.has_value()) { warning(MYNAME ": Unable to convert category \"%s\" at line %d!\n", qPrintable(cin), current_line); } else { - res = res | val; + res = res | *cat; } } } diff --git a/gpx.cc b/gpx.cc index 787b68131..176ecc676 100644 --- a/gpx.cc +++ b/gpx.cc @@ -47,7 +47,7 @@ #include // for qAsConst, QAddConst<>::Type #include "defs.h" -#include "garmin_fs.h" // for garmin_fs_t, garmin_ilink_t, garmin_fs_merge_category +#include "garmin_fs.h" // for garmin_fs_t, garmin_ilink_t #include "garmin_tables.h" // for gt_color_index_by_rgb, gt_color_name, gt_color_value_by_name #include "geocache.h" // for Geocache, Geocache::UtfSt... #include "mkshort.h" // for MakeShort @@ -243,7 +243,10 @@ GpxFormat::tag_garmin_fs(tag_type tag, const QString& text, Waypoint* waypt) } break; case tag_type::garmin_wpt_category: - if (!garmin_fs_merge_category(text, waypt)) { + if (auto cat = garmin_fs_t::convert_category(text); cat.has_value()) { + cat = *cat | (garmin_fs_t::get_category(gmsd, 0)); + garmin_fs_t::set_category(gmsd, *cat); + } else { // There's nothing a user can really do about this (well, they could // create a gpsbabel.ini that mapped them to garmin category numbers // but that feature is so obscure and used in so few outputs that @@ -1379,11 +1382,9 @@ GpxFormat::gpx_write_common_extensions(const Waypoint* waypointp, const gpx_poin if (garmin_fs_t::has_category(gmsd)) { uint16_t cx = gmsd->category; writer->stackStartElement(QStringLiteral("gpxx:Categories")); - for (int i = 0; i < 16; i++) { - if (cx & 1) { - writer->stackTextElement(QStringLiteral("gpxx:Category"), QStringLiteral("Category %1").arg(i+1)); - } - cx = cx >> 1; + const QStringList categoryList = garmin_fs_t::print_categories(cx); + for (const auto& text : categoryList) { + writer->stackTextElement(QStringLiteral("gpxx:Category"), text); } writer->stackEndElement(); // gpxx:Categories } diff --git a/reference/garmincategories.gpx b/reference/garmincategories.gpx new file mode 100644 index 000000000..95b140d19 --- /dev/null +++ b/reference/garmincategories.gpx @@ -0,0 +1,35 @@ + + + + + + + + + Hwy 119 + The Diagonal + The Diagonal + Flag, Blue + + + SymbolAndName + + Slow food + Category 11 + + + + + + + Hwy 72 + The Peak to Peak + The Peak to Peak + Flag, Blue + + + SymbolAndName + + + + diff --git a/reference/garmincategories.txt b/reference/garmincategories.txt new file mode 100644 index 000000000..b7ec5292c --- /dev/null +++ b/reference/garmincategories.txt @@ -0,0 +1,7 @@ +Grid Lat/Lon hddd°mm.mmm' +Datum WGS 84 + +Header Name Description Type Position Altitude Depth Proximity Temperature Display Mode Color Symbol Facility City State Country Date Modified Link Categories + +Waypoint Hwy 119 The Diagonal User Waypoint N39 58.432183 W105 27.951022 Symbol & Name Unknown Flag, Blue 09.03.2013 13:45:12 PM Slow food,Category 11 +Waypoint Hwy 72 The Peak to Peak User Waypoint N40 00.238037 W105 29.937744 Symbol & Name Unknown Flag, Blue 09.03.2013 13:45:02 PM diff --git a/testo.d/gpx.test b/testo.d/gpx.test index 85581adf4..f3b61cf25 100644 --- a/testo.d/gpx.test +++ b/testo.d/gpx.test @@ -79,6 +79,13 @@ compare ${REFERENCE}/gpxpassthrough10~gpx.gpx ${TMPDIR}/gpxpassthrough10~gpx.gpx gpsbabel -i gpx -f ${REFERENCE}/gpxpassthrough11.gpx -o gpx -F ${TMPDIR}/gpxpassthrough11~gpx.gpx compare ${REFERENCE}/gpxpassthrough11~gpx.gpx ${TMPDIR}/gpxpassthrough11~gpx.gpx +# garmin specific categories +gpsbabel -p gpsbabel-sample.ini -i gpx -f ${REFERENCE}/garmincategories.gpx -o garmin_txt -F ${TMPDIR}/garmincategories~gpx.txt +compare ${REFERENCE}/garmincategories.txt ${TMPDIR}/garmincategories~gpx.txt + +gpsbabel -p gpsbabel-sample.ini -i garmin_txt -f ${REFERENCE}/garmincategories.txt -o gpx,garminextensions -F ${TMPDIR}/garmincategories~txt.gpx +compare ${REFERENCE}/garmincategories.gpx ${TMPDIR}/garmincategories~txt.gpx + if [ -z "${VALGRIND}" ]; then set -e if command -v xmllint > /dev/null; diff --git a/util.cc b/util.cc index e1723f533..c625e95d4 100644 --- a/util.cc +++ b/util.cc @@ -623,7 +623,7 @@ convert_human_date_format(const char* human_datef) } if (okay == 0) { - fatal("Invalid character \"%c\" in date format!", *cin); + fatal("Invalid character \"%c\" in date format \"%s\"!\n", *cin, human_datef); } } QString rv(result); @@ -717,7 +717,7 @@ convert_human_time_format(const char* human_timef) } if (okay == 0) { - fatal("Invalid character \"%c\" in time format!", *cin); + fatal("Invalid character \"%c\" in time format \"%s\"!\n", *cin, human_timef); } } QString rv(result); From 573d1689abfbc4cf1e09d4afd1f474f995158090 Mon Sep 17 00:00:00 2001 From: tsteven4 <13596209+tsteven4@users.noreply.github.com> Date: Mon, 30 Oct 2023 16:54:16 -0600 Subject: [PATCH 05/11] fiddle with test time zone sensitivity. --- testo.d/gpx.test | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testo.d/gpx.test b/testo.d/gpx.test index f3b61cf25..ef9c1cc55 100644 --- a/testo.d/gpx.test +++ b/testo.d/gpx.test @@ -80,7 +80,7 @@ gpsbabel -i gpx -f ${REFERENCE}/gpxpassthrough11.gpx -o gpx -F ${TMPDIR}/gpxpass compare ${REFERENCE}/gpxpassthrough11~gpx.gpx ${TMPDIR}/gpxpassthrough11~gpx.gpx # garmin specific categories -gpsbabel -p gpsbabel-sample.ini -i gpx -f ${REFERENCE}/garmincategories.gpx -o garmin_txt -F ${TMPDIR}/garmincategories~gpx.txt +gpsbabel -p gpsbabel-sample.ini -i gpx -f ${REFERENCE}/garmincategories.gpx -o garmin_txt,utc=-7 -F ${TMPDIR}/garmincategories~gpx.txt compare ${REFERENCE}/garmincategories.txt ${TMPDIR}/garmincategories~gpx.txt gpsbabel -p gpsbabel-sample.ini -i garmin_txt -f ${REFERENCE}/garmincategories.txt -o gpx,garminextensions -F ${TMPDIR}/garmincategories~txt.gpx From 99dd6d70c13eaa0979b7512e0e3e17ad9ad2032a Mon Sep 17 00:00:00 2001 From: tsteven4 <13596209+tsteven4@users.noreply.github.com> Date: Mon, 30 Oct 2023 18:08:58 -0600 Subject: [PATCH 06/11] add utc option for garmin_txt reader. --- garmin_txt.cc | 35 ++++++++++++++++++++++++++--------- testo.d/gpx.test | 2 +- 2 files changed, 27 insertions(+), 10 deletions(-) diff --git a/garmin_txt.cc b/garmin_txt.cc index ff8bdf260..c0181d311 100644 --- a/garmin_txt.cc +++ b/garmin_txt.cc @@ -720,6 +720,28 @@ track_disp_wpt_cb(const Waypoint* wpt) * %%% global callbacks called by gpsbabel main process %%% * *******************************************************************************/ +static void +garmin_txt_utc_option() +{ + if (opt_utc != nullptr) { + if (case_ignore_strcmp(opt_utc, "utc") == 0) { + utc_offs = 0; + } else { + utc_offs = xstrtoi(opt_utc, nullptr, 10); + } + utc_offs *= (60 * 60); + gtxt_flags.utc = 1; + } +} + +static void +garmin_txt_adjust_time(QDateTime& dt) +{ + if (gtxt_flags.utc) { + dt = dt.toUTC().addSecs(utc_offs - dt.offsetFromUtc()); + } +} + static void garmin_txt_wr_init(const QString& fname) { @@ -766,15 +788,7 @@ garmin_txt_wr_init(const QString& fname) datum_index = gt_lookup_datum_index(datum_str, MYNAME); } - if (opt_utc != nullptr) { - if (case_ignore_strcmp(opt_utc, "utc") == 0) { - utc_offs = 0; - } else { - utc_offs = xstrtoi(opt_utc, nullptr, 10); - } - utc_offs *= (60 * 60); - gtxt_flags.utc = 1; - } + garmin_txt_utc_option(); } static void @@ -1166,6 +1180,7 @@ parse_waypoint(const QStringList& lineparts) break; case 16: if (QDateTime dt = parse_date_and_time(str); dt.isValid()) { + garmin_txt_adjust_time(dt); wpt->SetCreationTime(dt); } break; @@ -1301,6 +1316,7 @@ parse_track_waypoint(const QStringList& lineparts) break; case 2: if (QDateTime dt = parse_date_and_time(str); dt.isValid()) { + garmin_txt_adjust_time(dt); wpt->SetCreationTime(dt); } break; @@ -1349,6 +1365,7 @@ garmin_txt_rd_init(const QString& fname) grid_index = (grid_type) -1; init_date_and_time_format(); + garmin_txt_utc_option(); } static void diff --git a/testo.d/gpx.test b/testo.d/gpx.test index ef9c1cc55..f917b2a2e 100644 --- a/testo.d/gpx.test +++ b/testo.d/gpx.test @@ -83,7 +83,7 @@ compare ${REFERENCE}/gpxpassthrough11~gpx.gpx ${TMPDIR}/gpxpassthrough11~gpx.gpx gpsbabel -p gpsbabel-sample.ini -i gpx -f ${REFERENCE}/garmincategories.gpx -o garmin_txt,utc=-7 -F ${TMPDIR}/garmincategories~gpx.txt compare ${REFERENCE}/garmincategories.txt ${TMPDIR}/garmincategories~gpx.txt -gpsbabel -p gpsbabel-sample.ini -i garmin_txt -f ${REFERENCE}/garmincategories.txt -o gpx,garminextensions -F ${TMPDIR}/garmincategories~txt.gpx +gpsbabel -p gpsbabel-sample.ini -i garmin_txt,utc=-7 -f ${REFERENCE}/garmincategories.txt -o gpx,garminextensions -F ${TMPDIR}/garmincategories~txt.gpx compare ${REFERENCE}/garmincategories.gpx ${TMPDIR}/garmincategories~txt.gpx if [ -z "${VALGRIND}" ]; then From 6221a7789cdd83b58a30fa9327d7dd54617d628c Mon Sep 17 00:00:00 2001 From: tsteven4 <13596209+tsteven4@users.noreply.github.com> Date: Mon, 30 Oct 2023 18:18:50 -0600 Subject: [PATCH 07/11] correct sign of adjustment --- garmin_txt.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/garmin_txt.cc b/garmin_txt.cc index c0181d311..8c3d2875d 100644 --- a/garmin_txt.cc +++ b/garmin_txt.cc @@ -738,7 +738,7 @@ static void garmin_txt_adjust_time(QDateTime& dt) { if (gtxt_flags.utc) { - dt = dt.toUTC().addSecs(utc_offs - dt.offsetFromUtc()); + dt = dt.toUTC().addSecs(dt.offsetFromUtc() - utc_offs); } } From 6a45ee2c43f7596ac1f7a9f3ee22f9403d0c1c8f Mon Sep 17 00:00:00 2001 From: tsteven4 <13596209+tsteven4@users.noreply.github.com> Date: Tue, 31 Oct 2023 19:36:43 -0600 Subject: [PATCH 08/11] simpify formatting of date/time in garmin_txt. --- defs.h | 2 - garmin_txt.cc | 170 +++++++++------------------------ gpsbabel-sample.ini | 4 +- reference/format3.txt | 4 +- reference/garmincategories.txt | 4 +- reference/help.txt | 4 +- util.cc | 167 +------------------------------- 7 files changed, 56 insertions(+), 299 deletions(-) diff --git a/defs.h b/defs.h index 1ab851799..3c39d2408 100644 --- a/defs.h +++ b/defs.h @@ -966,8 +966,6 @@ QDateTime dotnet_time_to_qdatetime(long long dotnet); long long qdatetime_to_dotnet_time(const QDateTime& dt); QString strip_html(const QString& utfstring); QString strip_nastyhtml(const QString& in); -QString convert_human_date_format(const char* human_datef); /* "MM,YYYY,DD" -> "%m,%Y,%d" */ -QString convert_human_time_format(const char* human_timef); /* "HH+mm+ss" -> "%H+%M+%S" */ QString pretty_deg_format(double lat, double lon, char fmt, const char* sep, bool html); /* decimal -> dd.dddd or dd mm.mmm or dd mm ss */ QString get_filename(const QString& fname); /* extract the filename portion */ diff --git a/garmin_txt.cc b/garmin_txt.cc index 8c3d2875d..fff8694b1 100644 --- a/garmin_txt.cc +++ b/garmin_txt.cc @@ -29,10 +29,9 @@ #include // for toupper #include // for fabs, floor #include // for uint16_t -#include // for sscanf, fprintf, snprintf, stderr -#include // for abs -#include // for strstr, strlen -#include // for time_t, gmtime, localtime, strftime +#include // for sscanf, fprintf, stderr +#include // for abs, div +#include // for strstr #include // for optional #include // for pair, make_pair @@ -52,7 +51,6 @@ #include "formspec.h" // for FormatSpecificDataList #include "garmin_fs.h" // for garmin_fs_t #include "garmin_tables.h" // for gt_display_modes_e, gt_find_desc_from_icon_number, gt_find_icon_number_from_desc, gt_get_mps_grid_longname, gt_lookup_datum_index, gt_lookup_grid_type, GDB, gt_get_icao_cc, gt_get_icao_country, gt_get_mps_datum_name, gt_waypt_class_names, GT_DISPLAY_MODE... -#include "inifile.h" // for inifile_readstr #include "jeeps/gpsmath.h" // for GPS_Math_Known_Datum_To_UTM_EN, GPS_Math_WGS84_To_Known_Datum_M, GPS_Math_WGS84_To_Swiss_EN, GPS_Math_WGS84_To_UKOSMap_M #include "src/core/datetime.h" // for DateTime #include "src/core/logging.h" // for Fatal @@ -84,7 +82,7 @@ static const char* datum_str; static int current_line; static QString date_time_format; static int precision = 3; -static time_t utc_offs = 0; +static int utc_offs = 0; static gtxt_flags_t gtxt_flags; enum header_type { @@ -122,7 +120,7 @@ static std::array>, unknown_header> header_mapping static QStringList header_column_names; static constexpr double kGarminUnknownAlt = 1.0e25; -static constexpr char kDefaultDateFormat[] = "dd/mm/yyyy"; +static constexpr char kDefaultDateFormat[] = "dd/MM/yyyy"; static constexpr char kDefaultTimeFormat[] = "HH:mm:ss"; static bool is_valid_alt(double alt) @@ -141,13 +139,13 @@ static char* opt_grid = nullptr; static QVector garmin_txt_args = { - {"date", &opt_date_format, "Read/Write date format (i.e. yyyy/mm/dd)", nullptr, ARGTYPE_STRING, ARG_NOMINMAX, nullptr}, + {"date", &opt_date_format, "Read/Write date format (e.g. yyyy/MM/dd)", nullptr, ARGTYPE_STRING, ARG_NOMINMAX, nullptr}, {"datum", &opt_datum, "GPS datum (def. WGS 84)", "WGS 84", ARGTYPE_STRING, ARG_NOMINMAX, nullptr}, {"dist", &opt_dist, "Distance unit [m=metric, s=statute]", "m", ARGTYPE_STRING, ARG_NOMINMAX, nullptr}, {"grid", &opt_grid, "Write position using this grid.", nullptr, ARGTYPE_STRING, ARG_NOMINMAX, nullptr}, {"prec", &opt_precision, "Precision of coordinates", "3", ARGTYPE_INT, ARG_NOMINMAX, nullptr}, {"temp", &opt_temp, "Temperature unit [c=Celsius, f=Fahrenheit]", "c", ARGTYPE_STRING, ARG_NOMINMAX, nullptr}, - {"time", &opt_time_format, "Read/Write time format (i.e. HH:mm:ss xx)", nullptr, ARGTYPE_STRING, ARG_NOMINMAX, nullptr}, + {"time", &opt_time_format, "Read/Write time format (e.g. HH:mm:ss)", nullptr, ARGTYPE_STRING, ARG_NOMINMAX, nullptr}, {"utc", &opt_utc, "Write timestamps with offset x to UTC time", nullptr, ARGTYPE_INT, "-23", "+23", nullptr}, }; @@ -155,8 +153,8 @@ class PathInfo { public: double length {0}; - time_t start {0}; - time_t time {0}; + QDateTime start; + int time {0}; double speed {0}; double total {0}; int count {0}; @@ -191,16 +189,9 @@ get_option_val(const char* option, const char* def) static void init_date_and_time_format() { - // This is old, and weird, code.. date_time_format is a global that's - // explicitly malloced and freed elsewhere. This isn't very C++ at all, - // but this format is on its deathbead for deprecation. const char* d = get_option_val(opt_date_format, kDefaultDateFormat); - QString d1 = convert_human_date_format(d); - const char* t = get_option_val(opt_time_format, kDefaultTimeFormat); - QString t1 = convert_human_time_format(t); - - date_time_format = QStringLiteral("%1 %2").arg(d1, t1); + date_time_format = QStringLiteral("%1 %2").arg(d, t); } static void @@ -264,11 +255,11 @@ prework_wpt_cb(const Waypoint* wpt) const Waypoint* prev = cur_info->prev_wpt; if (prev != nullptr) { - cur_info->time += (wpt->GetCreationTime().toTime_t() - prev->GetCreationTime().toTime_t()); + cur_info->time += prev->GetCreationTime().secsTo(wpt->GetCreationTime()); cur_info->length += waypt_distance_ex(prev, wpt); } else { cur_info->first_wpt = wpt; - cur_info->start = wpt->GetCreationTime().toTime_t(); + cur_info->start = wpt->GetCreationTime(); } cur_info->prev_wpt = wpt; cur_info->count++; @@ -365,30 +356,37 @@ print_position(const Waypoint* wpt) } static void -print_date_and_time(const time_t time, const bool time_only) +print_duration(int time) { - std::tm tm{}; - char tbuf[32]; - if (time < 0) { *fout << "\t"; return; } - if (time_only) { - tm = *gmtime(&time); - snprintf(tbuf, sizeof(tbuf), "%d:%02d:%02d", tm.tm_hour, tm.tm_min, tm.tm_sec); - *fout << QString::asprintf("%s", tbuf); - } else if (time != 0) { - if (gtxt_flags.utc) { - time_t t = time + utc_offs; - tm = *gmtime(&t); - } else { - tm = *localtime(&time); - } - strftime(tbuf, sizeof(tbuf), CSTR(date_time_format), &tm); - *fout << QString::asprintf("%s ", tbuf); +#if 1 + // perhaps durations can be longer than the max QTime of 23:59:59 + auto res = std::div(time, 60); + auto sec = res.rem; + res = std::div(res.quot, 60); + *fout << QString::asprintf("%d:%02d:%02d\t", res.quot, res.rem, sec); +#else + QTime qt = QTime(0, 0).addSecs(time); + *fout << qt.toString("H:mm:ss\t"); +#endif +} + +static void +print_date_and_time(const QDateTime& dt) +{ + if (!dt.isValid()) { + *fout << "\t"; + return; } - *fout << "\t"; + if (gtxt_flags.utc) { + *fout << dt.toUTC().addSecs(utc_offs).toString(date_time_format); + } else { + *fout << dt.toLocalTime().toString(date_time_format); + } + *fout << " \t"; } static void @@ -445,7 +443,7 @@ print_distance(const double distance, const bool no_scale, const bool with_tab, } static void -print_speed(const double distance, const time_t time) +print_speed(const double distance, int time) { double dist = distance; const char* unit; @@ -577,7 +575,7 @@ write_waypt(const Waypoint* wpt) print_string("%s\t", garmin_fs_t::get_state(gmsd, "")); const char* country = gt_get_icao_country(garmin_fs_t::get_cc(gmsd, "")); print_string("%s\t", (country != nullptr) ? country : ""); - print_date_and_time(wpt->GetCreationTime().toTime_t(), false); + print_date_and_time(wpt->GetCreationTime()); if (wpt->HasUrlLink()) { UrlLink l = wpt->GetUrlLink(); print_string("%s\t", l.url_); @@ -658,8 +656,8 @@ track_disp_hdr_cb(const route_head* track) *fout << QStringLiteral("\r\n\r\nHeader\t%1\r\n").arg(headers[track_header]); } print_string("\r\nTrack\t%s\t", track->rte_name); - print_date_and_time(cur_info->start, false); - print_date_and_time(cur_info->time, true); + print_date_and_time(cur_info->start); + print_duration(cur_info->time); print_distance(cur_info->length, false, true, 0); print_speed(cur_info->length, cur_info->time); if (track->rte_urls.HasUrlLink()) { @@ -680,13 +678,13 @@ static void track_disp_wpt_cb(const Waypoint* wpt) { const Waypoint* prev = cur_info->prev_wpt; - time_t delta; + int delta; double dist; *fout << "Trackpoint\t"; print_position(wpt); - print_date_and_time(wpt->GetCreationTime().toTime_t(), false); + print_date_and_time(wpt->GetCreationTime()); if (is_valid_alt(wpt->altitude)) { print_distance(wpt->altitude, true, false, 0); } @@ -699,7 +697,7 @@ track_disp_wpt_cb(const Waypoint* wpt) if (prev != nullptr) { *fout << "\t"; - delta = wpt->GetCreationTime().toTime_t() - prev->GetCreationTime().toTime_t(); + delta = prev->GetCreationTime().secsTo(wpt->GetCreationTime()); float temp = wpt->temperature_value_or(-999); if (temp != -999) { print_temperature(temp); @@ -707,7 +705,7 @@ track_disp_wpt_cb(const Waypoint* wpt) *fout << "\t"; dist = waypt_distance_ex(prev, wpt); print_distance(dist, false, true, 0); - print_date_and_time(delta, true); + print_duration(delta); print_speed(dist, delta); print_course(prev, wpt); } @@ -868,88 +866,12 @@ free_headers() [](auto& list)->void { list.clear(); }); } -// Super simple attempt to convert strftime/strptime spec to Qt spec. -// This misses a LOT of cases and vagaries, but the reality is that we -// see very few date formats here. -static QString -strftime_to_timespec(const char* s) -{ - QString q; - int l = strlen(s); - q.reserve(l * 2); // no penalty if our guess is wrong. - - for (int i = 0; i < l; i++) { - switch (s[i]) { - case '%': - if (i < l-1) { - switch (s[++i]) { - case 'd': - q += "dd"; - continue; - case 'm': - q += "MM"; - continue; - case 'y': - q += "yy"; - continue; - case 'Y': - q += "yyyy"; - continue; - case 'H': - q += "HH"; - continue; - case 'M': - q += "mm"; - continue; - case 'S': - q += "ss"; - continue; - case 'A': - q += "dddd"; - continue; - case 'a': - q += "ddd"; - continue; - case 'B': - q += "MMMM"; - continue; - case 'C': - q += "yy"; - continue; - case 'D': - q += "MM/dd/yyyy"; - continue; - case 'T': - q += "hh:mm:ss"; - continue; - case 'F': - q += "yyyy-MM-dd"; - continue; - case 'p': - q += "AP"; - continue; - default: - warning(MYNAME ": omitting unknown strptime conversion \"%%%c\" in \"%s\"\n", s[i], s); - break; - } - } - break; - default: - q += s[i]; - break; - } - } - return q; -} - - /* data parsers */ static QDateTime parse_date_and_time(const QString& str) { - QString timespec = strftime_to_timespec(CSTR(date_time_format)); - return QDateTime::fromString(QString(str).trimmed(), timespec); + return QDateTime::fromString(QString(str).trimmed(), date_time_format); } static uint16_t diff --git a/gpsbabel-sample.ini b/gpsbabel-sample.ini index d2feb0217..7e8358420 100644 --- a/gpsbabel-sample.ini +++ b/gpsbabel-sample.ini @@ -16,8 +16,8 @@ ;------------------------------------------------------------------ [ garmin_txt ] -Date = DD.MM.YYYY -Time = HH:mm:ss XX +Date = dd.MM.yyyy +Time = HH:mm:ss Dist = M Temp = C Prec = 6 diff --git a/reference/format3.txt b/reference/format3.txt index e647cda7f..cd2f43cc5 100644 --- a/reference/format3.txt +++ b/reference/format3.txt @@ -210,7 +210,7 @@ option gdb roadbook Include major turn points (with description) from calculated file rwrwrw garmin_txt txt Garmin MapSource - txt (tab delimited) garmin_txt https://www.gpsbabel.org/WEB_DOC_DIR/fmt_garmin_txt.html -option garmin_txt date Read/Write date format (i.e. yyyy/mm/dd) string https://www.gpsbabel.org/WEB_DOC_DIR/fmt_garmin_txt.html#fmt_garmin_txt_o_date +option garmin_txt date Read/Write date format (e.g. yyyy/MM/dd) string https://www.gpsbabel.org/WEB_DOC_DIR/fmt_garmin_txt.html#fmt_garmin_txt_o_date option garmin_txt datum GPS datum (def. WGS 84) string WGS 84 https://www.gpsbabel.org/WEB_DOC_DIR/fmt_garmin_txt.html#fmt_garmin_txt_o_datum @@ -222,7 +222,7 @@ option garmin_txt prec Precision of coordinates integer 3 https://www.gpsbabel option garmin_txt temp Temperature unit [c=Celsius, f=Fahrenheit] string c https://www.gpsbabel.org/WEB_DOC_DIR/fmt_garmin_txt.html#fmt_garmin_txt_o_temp -option garmin_txt time Read/Write time format (i.e. HH:mm:ss xx) string https://www.gpsbabel.org/WEB_DOC_DIR/fmt_garmin_txt.html#fmt_garmin_txt_o_time +option garmin_txt time Read/Write time format (e.g. HH:mm:ss) string https://www.gpsbabel.org/WEB_DOC_DIR/fmt_garmin_txt.html#fmt_garmin_txt_o_time option garmin_txt utc Write timestamps with offset x to UTC time integer -23 +23 https://www.gpsbabel.org/WEB_DOC_DIR/fmt_garmin_txt.html#fmt_garmin_txt_o_utc diff --git a/reference/garmincategories.txt b/reference/garmincategories.txt index b7ec5292c..ccce49a8b 100644 --- a/reference/garmincategories.txt +++ b/reference/garmincategories.txt @@ -3,5 +3,5 @@ Datum WGS 84 Header Name Description Type Position Altitude Depth Proximity Temperature Display Mode Color Symbol Facility City State Country Date Modified Link Categories -Waypoint Hwy 119 The Diagonal User Waypoint N39 58.432183 W105 27.951022 Symbol & Name Unknown Flag, Blue 09.03.2013 13:45:12 PM Slow food,Category 11 -Waypoint Hwy 72 The Peak to Peak User Waypoint N40 00.238037 W105 29.937744 Symbol & Name Unknown Flag, Blue 09.03.2013 13:45:02 PM +Waypoint Hwy 119 The Diagonal User Waypoint N39 58.432183 W105 27.951022 Symbol & Name Unknown Flag, Blue 09.03.2013 13:45:12 Slow food,Category 11 +Waypoint Hwy 72 The Peak to Peak User Waypoint N40 00.238037 W105 29.937744 Symbol & Name Unknown Flag, Blue 09.03.2013 13:45:02 diff --git a/reference/help.txt b/reference/help.txt index 8a6f24c5e..fe8c1794e 100644 --- a/reference/help.txt +++ b/reference/help.txt @@ -110,13 +110,13 @@ File Types (-i and -o options): dropwpt (0/1) Don't create waypoints for non-user points roadbook (0/1) Include major turn points (with description) from garmin_txt Garmin MapSource - txt (tab delimited) - date Read/Write date format (i.e. yyyy/mm/dd) + date Read/Write date format (e.g. yyyy/MM/dd) datum GPS datum (def. WGS 84) dist Distance unit [m=metric, s=statute] grid Write position using this grid. prec Precision of coordinates temp Temperature unit [c=Celsius, f=Fahrenheit] - time Read/Write time format (i.e. HH:mm:ss xx) + time Read/Write time format (e.g. HH:mm:ss) utc Write timestamps with offset x to UTC time garmin_poi Garmin POI database snlen Max synthesized shortname length diff --git a/util.cc b/util.cc index c625e95d4..3d6f776db 100644 --- a/util.cc +++ b/util.cc @@ -20,13 +20,13 @@ */ #include // for sort -#include // for isspace, isalpha, ispunct, tolower, toupper +#include // for isspace, tolower #include // for errno #include // for INT_MAX, INT_MIN #include // for fabs, floor #include // for size_t, vsnprintf, FILE, fopen, printf, sprintf, stderr, stdin, stdout #include // for abs, calloc, free, malloc, realloc -#include // for strlen, strcat, strstr, memcpy, strcmp, strcpy, strdup, strchr, strerror +#include // for strcmp, strstr, memcpy, strdup, strchr, strerror, strlen #include // for QByteArray #include // for QChar, operator<=, operator>= @@ -563,169 +563,6 @@ rot13(const QString& s) return r; } -/* - * Convert a human readable date format (i.e. "YYYY/MM/DD") into - * a format usable for strftime and others - */ - -QString -convert_human_date_format(const char* human_datef) -{ - char* result = (char*) xcalloc((2*strlen(human_datef)) + 1, 1); - char* cout = result; - char prev = '\0'; - int ylen = 0; - - for (const char* cin = human_datef; *cin; cin++) { - char okay = 1; - - if (toupper(*cin) != 'Y') { - ylen = 0; - } - if (isalpha(*cin)) { - switch (*cin) { - case 'y': - case 'Y': - if (prev != 'Y') { - strcat(cout, "%y"); - cout += 2; - prev = 'Y'; - } - ylen++; - if (ylen > 2) { - *(cout-1) = 'Y'; - } - break; - case 'm': - case 'M': - if (prev != 'M') { - strcat(cout, "%m"); - cout += 2; - prev = 'M'; - } - break; - case 'd': - case 'D': - if (prev != 'D') { - strcat(cout, "%d"); - cout += 2; - prev = 'D'; - } - break; - default: - okay = 0; - } - } else if (ispunct(*cin)) { - *cout++ = *cin; - prev = '\0'; - } else { - okay = 0; - } - - if (okay == 0) { - fatal("Invalid character \"%c\" in date format \"%s\"!\n", *cin, human_datef); - } - } - QString rv(result); - xfree(result); - return rv; -} - -/* - * Convert a human readable time format (i.e. "HH:mm:ss") into - * a format usable for strftime and others - */ - -QString -convert_human_time_format(const char* human_timef) -{ - char* result = (char*) xcalloc((2*strlen(human_timef)) + 1, 1); - char* cout = result; - char prev = '\0'; - - for (const char* cin = human_timef; *cin; cin++) { - int okay = 1; - - if (isalpha(*cin)) { - switch (*cin) { - case 'S': - case 's': - if (prev != 'S') { - strcat(cout, "%S"); - cout += 2; - prev = 'S'; - } - break; - - case 'M': - case 'm': - if (prev != 'M') { - strcat(cout, "%M"); - cout += 2; - prev = 'M'; - } - break; - - case 'h': /* 12-hour-clock */ - if (prev != 'H') { - strcat(cout, "%l"); /* 1 .. 12 */ - cout += 2; - prev = 'H'; - } else { - *(cout-1) = 'I'; /* 01 .. 12 */ - } - break; - - case 'H': /* 24-hour-clock */ - if (prev != 'H') { - strcat(cout, "%k"); - cout += 2; - prev = 'H'; - } else { - *(cout-1) = 'H'; - } - break; - - case 'x': - if (prev != 'X') { - strcat(cout, "%P"); - cout += 2; - prev = 'X'; - } else { - *(cout-1) = 'P'; - } - break; - - case 'X': - if (prev != 'X') { - strcat(cout, "%p"); - cout += 2; - prev = 'X'; - } else { - *(cout-1) = 'p'; - } - break; - - default: - okay = 0; - } - } else if (ispunct(*cin) || isspace(*cin)) { - *cout++ = *cin; - prev = '\0'; - } else { - okay = 0; - } - - if (okay == 0) { - fatal("Invalid character \"%c\" in time format \"%s\"!\n", *cin, human_timef); - } - } - QString rv(result); - xfree(result); - return rv; -} - - /* * Return a decimal degree pair as * DD.DDDDD DD MM.MMM or DD MM SS.S From f540d29abc4d2b01269b1787651d7630ab784a84 Mon Sep 17 00:00:00 2001 From: tsteven4 <13596209+tsteven4@users.noreply.github.com> Date: Wed, 1 Nov 2023 07:55:30 -0600 Subject: [PATCH 09/11] use QDateTime::setOffsetFromUtc(), toOffsetFromUtc() to implement the garmin_txt utc option. --- garmin_txt.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/garmin_txt.cc b/garmin_txt.cc index fff8694b1..19e79b6b1 100644 --- a/garmin_txt.cc +++ b/garmin_txt.cc @@ -382,7 +382,7 @@ print_date_and_time(const QDateTime& dt) return; } if (gtxt_flags.utc) { - *fout << dt.toUTC().addSecs(utc_offs).toString(date_time_format); + *fout << dt.toOffsetFromUtc(utc_offs).toString(date_time_format); } else { *fout << dt.toLocalTime().toString(date_time_format); } @@ -736,7 +736,7 @@ static void garmin_txt_adjust_time(QDateTime& dt) { if (gtxt_flags.utc) { - dt = dt.toUTC().addSecs(dt.offsetFromUtc() - utc_offs); + dt.setOffsetFromUtc(utc_offs); } } From 36f6c112ce28c5eea8fe6b194d2a519ff10aad73 Mon Sep 17 00:00:00 2001 From: tsteven4 <13596209+tsteven4@users.noreply.github.com> Date: Wed, 1 Nov 2023 08:56:36 -0600 Subject: [PATCH 10/11] udpate garmin txt date and time option documentation. --- xmldoc/formats/options/garmin_txt-date.xml | 8 ++++++-- xmldoc/formats/options/garmin_txt-time.xml | 10 ++++++++-- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/xmldoc/formats/options/garmin_txt-date.xml b/xmldoc/formats/options/garmin_txt-date.xml index 188eb225d..dbe78cd2d 100644 --- a/xmldoc/formats/options/garmin_txt-date.xml +++ b/xmldoc/formats/options/garmin_txt-date.xml @@ -1,4 +1,8 @@ -This option specifies the input and output format for the date. The format -is written similarly to those in Windows. An example format is "YYYY/MM/DD". +This option specifies the input and output format for the date. +Examples are + +"yyyy/MM/dd" - four digit year, month with leading zero, day with leading zero. +"M/d/yy" - month without leading zero, day without leading zero, two digit year. + diff --git a/xmldoc/formats/options/garmin_txt-time.xml b/xmldoc/formats/options/garmin_txt-time.xml index 21675249b..0b4e13822 100644 --- a/xmldoc/formats/options/garmin_txt-time.xml +++ b/xmldoc/formats/options/garmin_txt-time.xml @@ -1,4 +1,10 @@ -This option specifies the input and output format for the time. The format -is written similarly to those in Windows. An example format is "hh:mm:ss xx". +This option specifies the input and output format for the time. +Examples are: + +"h:mm:ss AP" - hour without leading zero and range 1-12, AM/PM display. +"hh:mm:ss AP" - hour with leading zero and range 1-12, AM/PM display. +"H:mm:ss" - hour without leading zero and range 0-23. +"HH:mm:ss" - hour with leading zero and range 0-23. + From 46c40c7de1af61cb18c09ef72a6ba82197bdc0ed Mon Sep 17 00:00:00 2001 From: tsteven4 <13596209+tsteven4@users.noreply.github.com> Date: Wed, 1 Nov 2023 08:59:01 -0600 Subject: [PATCH 11/11] reduce variable scope to appease cppcheck. --- garmin_txt.cc | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/garmin_txt.cc b/garmin_txt.cc index 19e79b6b1..f1d5fe50d 100644 --- a/garmin_txt.cc +++ b/garmin_txt.cc @@ -678,8 +678,6 @@ static void track_disp_wpt_cb(const Waypoint* wpt) { const Waypoint* prev = cur_info->prev_wpt; - int delta; - double dist; *fout << "Trackpoint\t"; @@ -697,13 +695,13 @@ track_disp_wpt_cb(const Waypoint* wpt) if (prev != nullptr) { *fout << "\t"; - delta = prev->GetCreationTime().secsTo(wpt->GetCreationTime()); + int delta = prev->GetCreationTime().secsTo(wpt->GetCreationTime()); float temp = wpt->temperature_value_or(-999); if (temp != -999) { print_temperature(temp); } *fout << "\t"; - dist = waypt_distance_ex(prev, wpt); + double dist = waypt_distance_ex(prev, wpt); print_distance(dist, false, true, 0); print_duration(delta); print_speed(dist, delta);