You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

garmin_txt.cc 34KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436
  1. /*
  2. Support for MapSource Text Export (Tab delimited) files.
  3. Copyright (C) 2006 Olaf Klein, o.b.klein@gpsbabel.org
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program; if not, write to the Free Software
  14. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA
  15. */
  16. #include "defs.h"
  17. #if CSVFMTS_ENABLED
  18. #include "cet_util.h"
  19. #include "csv_util.h"
  20. #include "garmin_fs.h"
  21. #include "garmin_tables.h"
  22. #include "grtcirc.h"
  23. #include "inifile.h"
  24. #include "jeeps/gpsmath.h"
  25. #include "strptime.h"
  26. #include <cmath>
  27. #include <stdlib.h> // qsort
  28. #define MYNAME "garmin_txt"
  29. typedef struct gtxt_flags_s {
  30. unsigned int metric:1;
  31. unsigned int celsius:1;
  32. unsigned int utc:1;
  33. unsigned int enum_waypoints:1;
  34. unsigned int route_header_written:1;
  35. unsigned int track_header_written:1;
  36. } gtxt_flags_t;
  37. static gbfile* fin, *fout;
  38. static route_head* current_trk, *current_rte;
  39. static int waypoints;
  40. static int routepoints;
  41. static Waypoint** wpt_a;
  42. static int wpt_a_ct;
  43. static grid_type grid_index;
  44. static int datum_index;
  45. static const char* datum_str;
  46. static int current_line;
  47. static char* date_time_format = NULL;
  48. static int precision = 3;
  49. static time_t utc_offs = 0;
  50. // Having a Windows background, this software encodes degree marks in
  51. // Windows CP-1252. We don't attempt to handle all the subtleties of that,
  52. // but since we write degree marks and we know how they're encoded, use this.
  53. static const int kDegreeSymbol = 0xB0;
  54. static gtxt_flags_t gtxt_flags;
  55. typedef enum {
  56. waypt_header = 0,
  57. rtept_header,
  58. trkpt_header,
  59. route_header,
  60. track_header,
  61. unknown_header
  62. } header_type;
  63. #if __cplusplus
  64. inline header_type operator++(header_type& rs, int)
  65. {
  66. return rs = (header_type)((int)rs + 1);
  67. }
  68. inline gt_display_modes_e operator++(gt_display_modes_e& rs, int)
  69. {
  70. return rs = (gt_display_modes_e)((int)rs + 1);
  71. }
  72. #endif
  73. #define MAX_HEADER_FIELDS 36
  74. static char* header_lines[unknown_header + 1][MAX_HEADER_FIELDS];
  75. static int header_fields[unknown_header + 1][MAX_HEADER_FIELDS];
  76. static int header_ct[unknown_header + 1];
  77. #define GARMIN_UNKNOWN_ALT 1.0e25f
  78. #define DEFAULT_DISPLAY garmin_display_symbol_and_name
  79. #define DEFAULT_DATE_FORMAT "dd/mm/yyyy"
  80. #define DEFAULT_TIME_FORMAT "HH:mm:ss"
  81. /* macros */
  82. #define IS_VALID_ALT(a) (((a) != unknown_alt) && ((a) < GARMIN_UNKNOWN_ALT))
  83. #define DUPSTR(a) (((a) != NULL) && ((a)[0] != 0)) ? ((a)) : NULL
  84. static char* opt_datum = NULL;
  85. static char* opt_dist = NULL;
  86. static char* opt_temp = NULL;
  87. static char* opt_date_format = NULL;
  88. static char* opt_time_format = NULL;
  89. static char* opt_precision = NULL;
  90. static char* opt_utc = NULL;
  91. static char* opt_grid = NULL;
  92. static
  93. arglist_t garmin_txt_args[] = {
  94. {"date", &opt_date_format, "Read/Write date format (i.e. yyyy/mm/dd)", NULL, ARGTYPE_STRING, ARG_NOMINMAX},
  95. {"datum", &opt_datum, "GPS datum (def. WGS 84)", "WGS 84", ARGTYPE_STRING, ARG_NOMINMAX},
  96. {"dist", &opt_dist, "Distance unit [m=metric, s=statute]", "m", ARGTYPE_STRING, ARG_NOMINMAX},
  97. {"grid", &opt_grid, "Write position using this grid.", NULL, ARGTYPE_STRING, ARG_NOMINMAX},
  98. {"prec", &opt_precision, "Precision of coordinates", "3", ARGTYPE_INT, ARG_NOMINMAX},
  99. {"temp", &opt_temp, "Temperature unit [c=Celsius, f=Fahrenheit]", "c", ARGTYPE_STRING, ARG_NOMINMAX},
  100. {"time", &opt_time_format, "Read/Write time format (i.e. HH:mm:ss xx)", NULL, ARGTYPE_STRING, ARG_NOMINMAX},
  101. {"utc", &opt_utc, "Write timestamps with offset x to UTC time", NULL, ARGTYPE_INT, "-23", "+23"},
  102. ARG_TERMINATOR
  103. };
  104. typedef struct info_s {
  105. double length;
  106. time_t start;
  107. time_t time;
  108. double speed;
  109. double total;
  110. int count;
  111. Waypoint* prev_wpt;
  112. Waypoint* first_wpt;
  113. Waypoint* last_wpt;
  114. } info_t;
  115. static info_t* route_info;
  116. static int route_idx;
  117. static info_t* cur_info;
  118. static const char* headers[] = {
  119. "Name\tDescription\tType\tPosition\tAltitude\tDepth\tProximity\tTemperature\t"
  120. "Display Mode\tColor\tSymbol\tFacility\tCity\tState\tCountry\t"
  121. "Date Modified\tLink\tCategories",
  122. "Waypoint Name\tDistance\tLeg Length\tCourse",
  123. "Position\tTime\tAltitude\tDepth\tTemperature\tLeg Length\tLeg Time\tLeg Speed\tLeg Course",
  124. "Name\tLength\tCourse\tWaypoints\tLink",
  125. "Name\tStart Time\tElapsed Time\tLength\tAverage Speed\tLink",
  126. NULL
  127. };
  128. /* helpers */
  129. static const char*
  130. get_option_val(const char* option, const char* def)
  131. {
  132. const char* c = (option != NULL) ? option : def;
  133. return c;
  134. }
  135. static void
  136. init_date_and_time_format(void)
  137. {
  138. const char* f;
  139. const char* c;
  140. f = get_option_val(opt_date_format, DEFAULT_DATE_FORMAT);
  141. date_time_format = convert_human_date_format(f);
  142. date_time_format = xstrappend(date_time_format, " ");
  143. f = get_option_val(opt_time_format, DEFAULT_TIME_FORMAT);
  144. c = convert_human_time_format(f);
  145. date_time_format = xstrappend(date_time_format, c);
  146. xfree((void*) c);
  147. }
  148. static void
  149. convert_datum(const Waypoint* wpt, double* dest_lat, double* dest_lon)
  150. {
  151. double alt;
  152. if (datum_index == DATUM_WGS84) {
  153. *dest_lat = wpt->latitude;
  154. *dest_lon = wpt->longitude;
  155. } else GPS_Math_WGS84_To_Known_Datum_M(wpt->latitude, wpt->longitude, 0.0,
  156. dest_lat, dest_lon, &alt, datum_index);
  157. }
  158. /* WRITER *****************************************************************/
  159. /* Waypoint preparation */
  160. static void
  161. enum_waypt_cb(const Waypoint* wpt)
  162. {
  163. garmin_fs_p gmsd;
  164. int wpt_class;
  165. gmsd = GMSD_FIND(wpt);
  166. wpt_class = GMSD_GET(wpt_class, 0);
  167. if (wpt_class < 0x80) {
  168. int i;
  169. if (gtxt_flags.enum_waypoints) { /* enumerate only */
  170. waypoints++;
  171. return;
  172. }
  173. for (i = 0; i < wpt_a_ct; i++) { /* check for duplicates */
  174. Waypoint* tmp = wpt_a[i];
  175. if (case_ignore_strcmp(tmp->shortname, wpt->shortname) == 0) {
  176. wpt_a[i] = (Waypoint*)wpt;
  177. waypoints--;
  178. return;
  179. }
  180. }
  181. wpt_a[wpt_a_ct++] = (Waypoint*)wpt;
  182. }
  183. }
  184. static int
  185. sort_waypt_cb(const void* a, const void* b)
  186. {
  187. const Waypoint* wa = *(Waypoint**)a;
  188. const Waypoint* wb = *(Waypoint**)b;
  189. return wa->shortname.compare(wb->shortname, Qt::CaseInsensitive);
  190. }
  191. /* common route and track pre-work */
  192. static void
  193. prework_hdr_cb(const route_head* rte)
  194. {
  195. cur_info = &route_info[route_idx];
  196. cur_info->prev_wpt = NULL;
  197. cur_info->length = 0;
  198. cur_info->time = 0;
  199. }
  200. static void
  201. prework_tlr_cb(const route_head* rte)
  202. {
  203. cur_info->last_wpt = cur_info->prev_wpt;
  204. route_idx++;
  205. }
  206. static void
  207. prework_wpt_cb(const Waypoint* wpt)
  208. {
  209. Waypoint* prev = cur_info->prev_wpt;
  210. if (prev != NULL) {
  211. cur_info->time += (wpt->GetCreationTime().toTime_t() - prev->GetCreationTime().toTime_t());
  212. cur_info->length += waypt_distance_ex(prev, wpt);
  213. } else {
  214. cur_info->first_wpt = (Waypoint*)wpt;
  215. cur_info->start = wpt->GetCreationTime().toTime_t();
  216. }
  217. cur_info->prev_wpt = (Waypoint*)wpt;
  218. cur_info->count++;
  219. routepoints++;
  220. }
  221. /* output helpers */
  222. static void
  223. print_position(const Waypoint* wpt)
  224. {
  225. int valid = 1;
  226. double lat, lon, north, east;
  227. char latsig, lonsig;
  228. double latmin, lonmin, latsec, lonsec;
  229. int latint, lonint, zone;
  230. char map[3], zonec;
  231. convert_datum(wpt, &lat, &lon);
  232. /* ----------------------------------------------------------------------------*/
  233. /* the following code is from pretty_deg_format (util.c) */
  234. /* ----------------------------------------------------------------------------*/
  235. /* !ToDo! generate common code for calculating of degrees, minutes and seconds */
  236. /* ----------------------------------------------------------------------------*/
  237. latsig = lat < 0 ? 'S':'N';
  238. lonsig = lon < 0 ? 'W':'E';
  239. latint = abs((int) lat);
  240. lonint = abs((int) lon);
  241. latmin = 60.0 * (fabs(lat) - latint);
  242. lonmin = 60.0 * (fabs(lon) - lonint);
  243. latsec = 60.0 * (latmin - floor(latmin));
  244. lonsec = 60.0 * (lonmin - floor(lonmin));
  245. switch (grid_index) {
  246. case grid_lat_lon_ddd:
  247. gbfprintf(fout, "%c%0.*f %c%0.*f\t",
  248. latsig, precision, fabs(lat),
  249. lonsig, precision, fabs(lon));
  250. break;
  251. case grid_lat_lon_dmm:
  252. gbfprintf(fout, "%c%d %0*.*f %c%d %0*.*f\t",
  253. latsig, latint, precision + 3, precision, latmin,
  254. lonsig, lonint, precision + 3, precision, lonmin);
  255. break;
  256. case grid_lat_lon_dms:
  257. gbfprintf(fout, "%c%d %d %.*f %c%d %d %.*f\t",
  258. latsig, latint, (int)latmin, precision, latsec,
  259. lonsig, lonint, (int)lonmin, precision, lonsec);
  260. break;
  261. case grid_bng:
  262. valid = GPS_Math_WGS84_To_UKOSMap_M(wpt->latitude, wpt->longitude, &east, &north, map);
  263. if (valid) {
  264. gbfprintf(fout, "%s %5.0f %5.0f\t", map, east, north);
  265. }
  266. break;
  267. case grid_utm:
  268. valid = GPS_Math_Known_Datum_To_UTM_EN(lat, lon,
  269. &east, &north, &zone, &zonec, datum_index);
  270. if (valid) {
  271. gbfprintf(fout, "%02d %c %.0f %.0f\t", zone, zonec, east, north);
  272. }
  273. break;
  274. case grid_swiss:
  275. valid = GPS_Math_WGS84_To_Swiss_EN(wpt->latitude, wpt->longitude, &east, &north);
  276. if (valid) {
  277. gbfprintf(fout, "%.f %.f\t", east, north);
  278. }
  279. break;
  280. default:
  281. fatal("ToDo\n");
  282. }
  283. if (! valid) {
  284. gbfprintf(fout, "#####\n");
  285. fatal(MYNAME ": %s (%s) is outside of convertable area \"%s\"!\n",
  286. wpt->shortname.isEmpty() ? "Waypoint" : qPrintable(wpt->shortname),
  287. pretty_deg_format(wpt->latitude, wpt->longitude, 'd', NULL, 0),
  288. gt_get_mps_grid_longname(grid_index, MYNAME));
  289. }
  290. }
  291. static void
  292. print_date_and_time(const time_t time, const int time_only)
  293. {
  294. struct tm tm;
  295. char tbuf[32];
  296. if (time < 0) {
  297. gbfprintf(fout, "\t");
  298. return;
  299. }
  300. if (time_only) {
  301. tm = *gmtime(&time);
  302. snprintf(tbuf, sizeof(tbuf), "%d:%02d:%02d", tm.tm_hour, tm.tm_min, tm.tm_sec);
  303. gbfprintf(fout, "%s", tbuf);
  304. } else if (time != 0) {
  305. if (gtxt_flags.utc) {
  306. time_t t = time + utc_offs;
  307. tm = *gmtime(&t);
  308. } else {
  309. tm = *localtime(&time);
  310. }
  311. strftime(tbuf, sizeof(tbuf), date_time_format, &tm);
  312. gbfprintf(fout, "%s ", tbuf);
  313. }
  314. gbfprintf(fout, "\t");
  315. }
  316. static void
  317. print_categories(uint16_t categories)
  318. {
  319. int i, count;
  320. char* c;
  321. if (categories == 0) {
  322. return;
  323. }
  324. count = 0;
  325. for (i = 0; i < 16; i++) {
  326. if ((categories & 1) != 0) {
  327. if (global_opts.inifile != NULL) {
  328. char key[3];
  329. snprintf(key, sizeof(key), "%d", i + 1);
  330. c = inifile_readstr(global_opts.inifile, GMSD_SECTION_CATEGORIES, key);
  331. } else {
  332. c = NULL;
  333. }
  334. gbfprintf(fout, "%s", (count++ > 0) ? "," : "");
  335. if (c == NULL) {
  336. gbfprintf(fout, "Category %d", i+1);
  337. }
  338. // gbfprintf(fout, "%s", gps_categories[i]);
  339. else {
  340. gbfprintf(fout, "%s", c);
  341. }
  342. }
  343. categories = categories >> 1;
  344. }
  345. }
  346. static void
  347. print_course(const Waypoint* A, const Waypoint* B) /* seems to be okay */
  348. {
  349. if ((A != NULL) && (B != NULL) && (A != B)) {
  350. int course;
  351. course = si_round(waypt_course(A, B));
  352. gbfprintf(fout, "%d%c true", course, kDegreeSymbol);
  353. }
  354. }
  355. static void
  356. print_distance(const double distance, const int no_scale, const int with_tab, const int decis)
  357. {
  358. double dist = distance;
  359. if (gtxt_flags.metric == 0) {
  360. dist = METERS_TO_FEET(dist);
  361. if ((dist < 5280) || no_scale) {
  362. gbfprintf(fout, "%.*f ft", decis, dist);
  363. } else {
  364. dist = METERS_TO_MILES(distance);
  365. if (dist < (double)100) {
  366. gbfprintf(fout, "%.1f mi", dist);
  367. } else {
  368. gbfprintf(fout, "%d mi", si_round(dist));
  369. }
  370. }
  371. } else {
  372. if ((dist < 1000) || no_scale) {
  373. gbfprintf(fout, "%.*f m", decis, dist);
  374. } else {
  375. dist = dist / (double)1000.0;
  376. if (dist < (double)100) {
  377. gbfprintf(fout, "%.1f km", dist);
  378. } else {
  379. gbfprintf(fout, "%d km", si_round(dist));
  380. }
  381. }
  382. }
  383. if (with_tab) {
  384. gbfprintf(fout, "\t");
  385. }
  386. }
  387. static void
  388. print_speed(double* distance, time_t* time)
  389. {
  390. int idist;
  391. double dist = *distance;
  392. const char* unit;
  393. if (!gtxt_flags.metric) {
  394. dist = METERS_TO_MILES(dist) * 1000.0;
  395. unit = "mph";
  396. } else {
  397. unit = "kph";
  398. }
  399. idist = si_round(dist);
  400. if ((*time != 0) && (idist > 0)) {
  401. double speed = MPS_TO_KPH(dist / (double)*time);
  402. int ispeed = si_round(speed);
  403. if (speed < (double)0.01) {
  404. gbfprintf(fout, "0 %s", unit);
  405. } else if (ispeed < 2) {
  406. gbfprintf(fout, "%.1f %s", speed, unit);
  407. } else {
  408. gbfprintf(fout, "%d %s", ispeed, unit);
  409. }
  410. } else {
  411. gbfprintf(fout, "0 %s", unit);
  412. }
  413. gbfprintf(fout, "\t");
  414. }
  415. static void
  416. print_temperature(const float temperature)
  417. {
  418. if (gtxt_flags.celsius) {
  419. gbfprintf(fout, "%.f C", temperature);
  420. } else {
  421. gbfprintf(fout, "%.f F", (temperature * 1.8) + 32);
  422. }
  423. }
  424. static void
  425. print_string(const char* fmt, const char* string)
  426. {
  427. char* c;
  428. char* buff;
  429. buff = xstrdup(string);
  430. /* remove unwanted characters from source string */
  431. for (c = buff; *c; c++) {
  432. if (iscntrl(*c)) {
  433. *c = ' ';
  434. }
  435. }
  436. gbfprintf(fout, fmt, buff);
  437. xfree(buff);
  438. }
  439. static void
  440. print_string(const char* fmt, const QString& string)
  441. {
  442. print_string(fmt, CSTR(string));
  443. }
  444. /* main cb's */
  445. static void
  446. write_waypt(const Waypoint* wpt)
  447. {
  448. unsigned char wpt_class;
  449. garmin_fs_p gmsd;
  450. const char* wpt_type;
  451. const char* dspl_mode;
  452. const char* country;
  453. double x;
  454. int i, icon;
  455. gmsd = GMSD_FIND(wpt);
  456. i = GMSD_GET(display, 0);
  457. if (i > GT_DISPLAY_MODE_MAX) {
  458. i = 0;
  459. }
  460. dspl_mode = gt_display_mode_names[i];
  461. wpt_class = GMSD_GET(wpt_class, 0);
  462. if (wpt_class <= gt_waypt_class_map_line) {
  463. wpt_type = gt_waypt_class_names[wpt_class];
  464. } else {
  465. wpt_type = gt_waypt_class_names[0];
  466. }
  467. gbfprintf(fout, "Waypoint\t%s\t", CSTRc(wpt->shortname));
  468. if (wpt_class <= gt_waypt_class_airport_ndb) {
  469. QString temp = wpt->notes;
  470. if (temp.isEmpty()) {
  471. if (wpt->description != wpt->shortname) {
  472. temp = wpt->description;
  473. } else {
  474. temp = "";
  475. }
  476. }
  477. print_string("%s\t", temp);
  478. } else {
  479. gbfprintf(fout, "\t");
  480. }
  481. gbfprintf(fout, "%s\t", wpt_type);
  482. print_position(wpt);
  483. if IS_VALID_ALT(wpt->altitude) {
  484. print_distance(wpt->altitude, 1, 0, 0);
  485. }
  486. gbfprintf(fout, "\t");
  487. x = WAYPT_GET(wpt, depth, unknown_alt);
  488. if (x != unknown_alt) {
  489. print_distance(x, 1, 0, 1);
  490. }
  491. gbfprintf(fout, "\t");
  492. x = WAYPT_GET(wpt, proximity, unknown_alt);
  493. if (x != unknown_alt) {
  494. print_distance(x, 0, 0, 0);
  495. }
  496. gbfprintf(fout, "\t");
  497. x = WAYPT_GET(wpt, temperature, -999);
  498. if (x != -999) {
  499. print_temperature(x);
  500. }
  501. gbfprintf(fout, "\t%s\t", dspl_mode);
  502. gbfprintf(fout, "Unknown\t"); /* Color is fixed: Unknown */
  503. icon = GMSD_GET(icon, -1);
  504. if (icon == -1) {
  505. icon = gt_find_icon_number_from_desc(wpt->icon_descr, GDB);
  506. }
  507. print_string("%s\t", gt_find_desc_from_icon_number(icon, GDB));
  508. print_string("%s\t", GMSD_GET(facility, ""));
  509. print_string("%s\t", GMSD_GET(city, ""));
  510. print_string("%s\t", GMSD_GET(state, ""));
  511. country = gt_get_icao_country(GMSD_GET(cc, ""));
  512. print_string("%s\t", (country != NULL) ? country : "");
  513. print_date_and_time(wpt->GetCreationTime().toTime_t(), 0);
  514. if (wpt->HasUrlLink()) {
  515. UrlLink l = wpt->GetUrlLink();
  516. print_string("%s\t", l.url_);
  517. } else {
  518. print_string("%s\t", "");
  519. }
  520. print_categories(GMSD_GET(category, 0));
  521. gbfprintf(fout, "\r\n");
  522. }
  523. static void
  524. route_disp_hdr_cb(const route_head* rte)
  525. {
  526. current_trk = (route_head*)rte;
  527. cur_info = &route_info[route_idx];
  528. cur_info->prev_wpt = NULL;
  529. cur_info->total = 0;
  530. if (rte->rte_waypt_ct <= 0) {
  531. return;
  532. }
  533. if (!gtxt_flags.route_header_written) {
  534. gtxt_flags.route_header_written = 1;
  535. gbfprintf(fout, "\r\n\r\nHeader\t%s\r\n", headers[route_header]);
  536. }
  537. print_string("\r\nRoute\t%s\t", current_trk->rte_name);
  538. print_distance(cur_info->length, 0, 1, 0);
  539. print_course(cur_info->first_wpt, cur_info->last_wpt);
  540. gbfprintf(fout, "\t%d waypoints\t", cur_info->count);
  541. print_string("%s\r\n", rte->rte_url);
  542. gbfprintf(fout, "\r\nHeader\t%s\r\n\r\n", headers[rtept_header]);
  543. }
  544. static void
  545. route_disp_tlr_cb(const route_head* rte)
  546. {
  547. route_idx++;
  548. }
  549. static void
  550. route_disp_wpt_cb(const Waypoint* wpt)
  551. {
  552. Waypoint* prev = cur_info->prev_wpt;
  553. gbfprintf(fout, "Route Waypoint\t");
  554. gbfprintf(fout, "%s\t", CSTRc(wpt->shortname));
  555. if (prev != NULL) {
  556. double dist = waypt_distance_ex(prev, wpt);
  557. cur_info->total += dist;
  558. print_distance(cur_info->total, 0, 1, 0);
  559. print_distance(dist, 0, 1, 0);
  560. print_course(prev, wpt);
  561. } else {
  562. print_distance(0, 1, 0, 0);
  563. }
  564. gbfprintf(fout, "\r\n");
  565. cur_info->prev_wpt = (Waypoint*)wpt;
  566. }
  567. static void
  568. track_disp_hdr_cb(const route_head* track)
  569. {
  570. cur_info = &route_info[route_idx];
  571. cur_info->prev_wpt = NULL;
  572. cur_info->total = 0;
  573. current_trk = (route_head*)track;
  574. if (track->rte_waypt_ct <= 0) {
  575. return;
  576. }
  577. if (!gtxt_flags.track_header_written) {
  578. gtxt_flags.track_header_written = 1;
  579. gbfprintf(fout, "\r\n\r\nHeader\t%s\r\n", headers[track_header]);
  580. }
  581. print_string("\r\nTrack\t%s\t", current_trk->rte_name);
  582. print_date_and_time(cur_info->start, 0);
  583. print_date_and_time(cur_info->time, 1);
  584. print_distance(cur_info->length, 0, 1, 0);
  585. print_speed(&cur_info->length, &cur_info->time);
  586. print_string("%s", track->rte_url);
  587. gbfprintf(fout, "\r\n\r\nHeader\t%s\r\n\r\n", headers[trkpt_header]);
  588. }
  589. static void
  590. track_disp_tlr_cb(const route_head* track)
  591. {
  592. route_idx++;
  593. }
  594. static void
  595. track_disp_wpt_cb(const Waypoint* wpt)
  596. {
  597. Waypoint* prev = cur_info->prev_wpt;
  598. time_t delta;
  599. double dist, depth;
  600. gbfprintf(fout, "Trackpoint\t");
  601. print_position(wpt);
  602. print_date_and_time(wpt->GetCreationTime().toTime_t(), 0);
  603. if IS_VALID_ALT(wpt->altitude) {
  604. print_distance(wpt->altitude, 1, 0, 0);
  605. }
  606. gbfprintf(fout, "\t");
  607. depth = WAYPT_GET(wpt, depth, unknown_alt);
  608. if (depth != unknown_alt) {
  609. print_distance(depth, 1, 0, 1);
  610. }
  611. if (prev != NULL) {
  612. float temp;
  613. gbfprintf(fout, "\t");
  614. delta = wpt->GetCreationTime().toTime_t() - prev->GetCreationTime().toTime_t();
  615. temp = WAYPT_GET(wpt, temperature, -999);
  616. if (temp != -999) {
  617. print_temperature(temp);
  618. }
  619. gbfprintf(fout, "\t");
  620. dist = waypt_distance_ex(prev, wpt);
  621. print_distance(dist, 0, 1, 0);
  622. print_date_and_time(delta, 1);
  623. print_speed(&dist, &delta);
  624. print_course(prev, wpt);
  625. }
  626. gbfprintf(fout, "\r\n");
  627. cur_info->prev_wpt = (Waypoint*)wpt;
  628. }
  629. /*******************************************************************************
  630. * %%% global callbacks called by gpsbabel main process %%% *
  631. *******************************************************************************/
  632. static void
  633. garmin_txt_wr_init(const QString& fname)
  634. {
  635. const char* grid_str;
  636. memset(&gtxt_flags, 0, sizeof(gtxt_flags));
  637. fout = gbfopen(fname, "wb", MYNAME);
  638. gtxt_flags.metric = (toupper(*get_option_val(opt_dist, "m")) == 'M');
  639. gtxt_flags.celsius = (toupper(*get_option_val(opt_temp, "c")) == 'C');
  640. init_date_and_time_format();
  641. if (opt_precision) {
  642. precision = atoi(opt_precision);
  643. is_fatal(precision < 0, MYNAME ": Invalid precision (%s)!", opt_precision);
  644. }
  645. datum_str = get_option_val(opt_datum, NULL);
  646. grid_str = get_option_val(opt_grid, NULL);
  647. grid_index = grid_lat_lon_dmm;
  648. if (grid_str != NULL) {
  649. int i;
  650. if (sscanf(grid_str, "%d", &i)) {
  651. grid_index = (grid_type) i;
  652. if ((grid_index < GRID_INDEX_MIN) || (grid_index > GRID_INDEX_MAX))
  653. fatal(MYNAME ": Grid index out of range (%d..%d)!",
  654. (int)GRID_INDEX_MIN, (int)GRID_INDEX_MAX);
  655. } else {
  656. grid_index = gt_lookup_grid_type(grid_str, MYNAME);
  657. }
  658. }
  659. switch (grid_index) {
  660. case grid_bng: /* force datum to "Ord Srvy Grt Britn" */
  661. datum_index = DATUM_OSGB36;
  662. break;
  663. case grid_swiss: /* force datum to "Ord Srvy Grt Britn" */
  664. datum_index = DATUM_WGS84;
  665. break;
  666. default:
  667. datum_index = gt_lookup_datum_index(datum_str, MYNAME);
  668. }
  669. if (opt_utc != NULL) {
  670. if (case_ignore_strcmp(opt_utc, "utc") == 0) {
  671. utc_offs = 0;
  672. } else {
  673. utc_offs = atoi(opt_utc);
  674. }
  675. utc_offs *= (60 * 60);
  676. gtxt_flags.utc = 1;
  677. }
  678. }
  679. static void
  680. garmin_txt_wr_deinit(void)
  681. {
  682. gbfclose(fout);
  683. xfree(date_time_format);
  684. }
  685. static void
  686. garmin_txt_write(void)
  687. {
  688. char* grid_str, *c;
  689. const char* datum_str;
  690. grid_str = xstrdup(gt_get_mps_grid_longname(grid_index, MYNAME));
  691. while ((c = strchr(grid_str, '*'))) {
  692. *c = kDegreeSymbol; /* degree sign */
  693. }
  694. gbfprintf(fout, "Grid\t%s\r\n", grid_str);
  695. xfree(grid_str);
  696. datum_str = gt_get_mps_datum_name(datum_index);
  697. gbfprintf(fout, "Datum\t%s\r\n\r\n", datum_str);
  698. waypoints = 0;
  699. gtxt_flags.enum_waypoints = 1; /* enum all waypoints */
  700. waypt_disp_all(enum_waypt_cb);
  701. route_disp_all(NULL, NULL, enum_waypt_cb);
  702. gtxt_flags.enum_waypoints = 0;
  703. if (waypoints > 0) {
  704. int i;
  705. wpt_a_ct = 0;
  706. wpt_a = (Waypoint**)xcalloc(waypoints, sizeof(*wpt_a));
  707. waypt_disp_all(enum_waypt_cb);
  708. route_disp_all(NULL, NULL, enum_waypt_cb);
  709. qsort(wpt_a, waypoints, sizeof(*wpt_a), sort_waypt_cb);
  710. gbfprintf(fout, "Header\t%s\r\n\r\n", headers[waypt_header]);
  711. for (i = 0; i < waypoints; i++) {
  712. Waypoint* wpt = wpt_a[i];
  713. write_waypt(wpt);
  714. }
  715. xfree(wpt_a);
  716. route_idx = 0;
  717. route_info = (info_t*) xcalloc(route_count(), sizeof(struct info_s));
  718. routepoints = 0;
  719. route_disp_all(prework_hdr_cb, prework_tlr_cb, prework_wpt_cb);
  720. if (routepoints > 0) {
  721. route_idx = 0;
  722. route_disp_all(route_disp_hdr_cb, route_disp_tlr_cb, route_disp_wpt_cb);
  723. }
  724. xfree(route_info);
  725. }
  726. route_idx = 0;
  727. route_info = (info_t*) xcalloc(track_count(), sizeof(struct info_s));
  728. routepoints = 0;
  729. track_disp_all(prework_hdr_cb, prework_tlr_cb, prework_wpt_cb);
  730. if (routepoints > 0) {
  731. route_idx = 0;
  732. track_disp_all(track_disp_hdr_cb, track_disp_tlr_cb, track_disp_wpt_cb);
  733. }
  734. xfree(route_info);
  735. }
  736. /* READER *****************************************************************/
  737. /* helpers */
  738. static void
  739. free_header(const header_type ht)
  740. {
  741. int i;
  742. for (i = 0; i < MAX_HEADER_FIELDS; i++) {
  743. char* c = header_lines[ht][i];
  744. if (c != NULL) {
  745. xfree(c);
  746. header_lines[ht][i] = NULL;
  747. }
  748. }
  749. header_ct[ht] = 0;
  750. memset(header_fields[ht], 0, sizeof(header_fields[ht]));
  751. }
  752. /* data parsers */
  753. static int
  754. parse_date_and_time(char* str, time_t* value)
  755. {
  756. struct tm tm;
  757. char* cerr, *cin;
  758. memset(&tm, 0, sizeof(tm));
  759. cin = lrtrim(str);
  760. if (*cin == '\0') {
  761. return 0;
  762. }
  763. cerr = strptime(cin, date_time_format, &tm);
  764. if (cerr == NULL) {
  765. cerr = strptime(cin, "%m/%d/%Y %I:%M:%S %p", &tm);
  766. is_fatal(cerr == NULL, MYNAME ": Invalid date or/and time \"%s\" at line %d!", cin, current_line);
  767. }
  768. // printf(MYNAME "_parse_date_and_time: %02d.%02d.%04d, %02d:%02d:%02d\n",
  769. // tm.tm_mday, tm.tm_mon+1, tm.tm_year+1900, tm.tm_hour, tm.tm_min, tm.tm_sec);
  770. *value = mklocaltime(&tm);
  771. return 1;
  772. }
  773. static uint16_t
  774. parse_categories(const char* str)
  775. {
  776. char buff[256];
  777. uint16_t val;
  778. uint16_t res = 0;
  779. char* cin, *cx;
  780. if (*str == '\0') {
  781. return 0;
  782. }
  783. strncpy(buff, str, sizeof(buff));
  784. cin = lrtrim(buff);
  785. if (*cin == '\0') {
  786. return 0;
  787. }
  788. strcat(cin, ",");
  789. while ((cx = strchr(cin, ','))) {
  790. *cx++ = '\0';
  791. cin = lrtrim(cin);
  792. if (*cin != '\0') {
  793. if (!garmin_fs_convert_category(cin, &val)) {
  794. warning(MYNAME ": Unable to convert category \"%s\" at line %d!\n", cin, current_line);
  795. } else {
  796. res = res | val;
  797. }
  798. }
  799. cin = cx;
  800. }
  801. return res;
  802. }
  803. static int
  804. parse_temperature(const char* str, double* temperature)
  805. {
  806. double value;
  807. unsigned char unit;
  808. if ((str == NULL) || (*str == '\0')) {
  809. return 0;
  810. }
  811. if (sscanf(str, "%lf %c", &value, &unit) == 2) {
  812. unit = toupper(unit);
  813. switch (unit) {
  814. case 'C':
  815. *temperature = value;
  816. break;
  817. case 'F':
  818. *temperature = FAHRENHEIT_TO_CELSIUS(value);
  819. break;
  820. default:
  821. fatal(MYNAME ": Unknown temperature unit \"%c\" at line %d!\n", unit, current_line);
  822. }
  823. return 1;
  824. } else {
  825. fatal(MYNAME ": Invalid temperature \"%s\" at line %d!\n", str, current_line);
  826. }
  827. return 0;
  828. }
  829. static void
  830. parse_header(void)
  831. {
  832. char* str;
  833. int column = -1;
  834. free_header(unknown_header);
  835. while ((str = csv_lineparse(NULL, "\t", "", column++))) {
  836. header_lines[unknown_header][column] = strupper(xstrdup(str));
  837. header_ct[unknown_header]++;
  838. if (header_ct[unknown_header] >= MAX_HEADER_FIELDS) {
  839. break;
  840. }
  841. }
  842. }
  843. static int
  844. parse_display(const char* str, int* val)
  845. {
  846. gt_display_modes_e i;
  847. if ((str == NULL) || (*str == '\0')) {
  848. return 0;
  849. }
  850. for (i = GT_DISPLAY_MODE_MIN; i <= GT_DISPLAY_MODE_MAX; i++) {
  851. if (case_ignore_strcmp(str, gt_display_mode_names[i]) == 0) {
  852. *val = i;
  853. return 1;
  854. }
  855. }
  856. warning(MYNAME ": Unknown display mode \"%s\" at line %d.\n", str, current_line);
  857. return 0;
  858. }
  859. static void
  860. bind_fields(const header_type ht)
  861. {
  862. int i;
  863. char* fields, *c;
  864. is_fatal((grid_index < 0) || (datum_index < 0), MYNAME ": Incomplete or invalid file header!");
  865. if (header_ct[unknown_header] <= 0) {
  866. return;
  867. }
  868. free_header(ht);
  869. /* make a copy of headers[ht], uppercase, replace "\t" with "\0" */
  870. i = strlen(headers[ht]);
  871. fields = (char*) xmalloc(i + 2);
  872. strcpy(fields, headers[ht]);
  873. strcat(fields, "\t");
  874. c = strupper(fields);
  875. while ((c = strchr(c, '\t'))) {
  876. *c++ = '\0';
  877. }
  878. for (i = 0; i < header_ct[unknown_header]; i++) {
  879. char* name;
  880. int field_no;
  881. name = header_lines[ht][i] = header_lines[unknown_header][i];
  882. header_lines[unknown_header][i] = NULL;
  883. c = fields;
  884. field_no = 1;
  885. while (*c) {
  886. if (strcmp(c, name) == 0) {
  887. header_fields[ht][i] = field_no;
  888. #if 0
  889. printf("Binding field \"%s\" to internal number %d (%d,%d)\n", name, field_no, ht, i);
  890. #endif
  891. break;
  892. }
  893. field_no++;
  894. c = c + strlen(c) + 1;
  895. }
  896. }
  897. header_ct[unknown_header] = 0;
  898. xfree(fields);
  899. }
  900. static void
  901. parse_grid(void)
  902. {
  903. char* str = csv_lineparse(NULL, "\t", "", 1);
  904. if (str != NULL) {
  905. if (strstr(str, "dd.ddddd") != 0) {
  906. grid_index = grid_lat_lon_ddd;
  907. } else if (strstr(str, "mm.mmm") != 0) {
  908. grid_index = grid_lat_lon_dmm;
  909. } else if (strstr(str, "mm'ss.s") != 0) {
  910. grid_index = grid_lat_lon_dms;
  911. } else {
  912. grid_index = gt_lookup_grid_type(str, MYNAME);
  913. }
  914. } else {
  915. fatal(MYNAME ": Missing grid headline!\n");
  916. }
  917. }
  918. static void
  919. parse_datum(void)
  920. {
  921. char* str = csv_lineparse(NULL, "\t", "", 1);
  922. if (str != NULL) {
  923. datum_index = gt_lookup_datum_index(str, MYNAME);
  924. } else {
  925. fatal(MYNAME ": Missing GPS datum headline!\n");
  926. }
  927. }
  928. static void
  929. parse_waypoint(void)
  930. {
  931. char* str;
  932. int column = -1;
  933. Waypoint* wpt;
  934. garmin_fs_p gmsd = NULL;
  935. bind_fields(waypt_header);
  936. wpt = new Waypoint;
  937. gmsd = garmin_fs_alloc(-1);
  938. fs_chain_add(&wpt->fs, (format_specific_data*) gmsd);
  939. while ((str = csv_lineparse(NULL, "\t", "", column++))) {
  940. int i;
  941. double d;
  942. int field_no = header_fields[waypt_header][column];
  943. switch (field_no) {
  944. case 1:
  945. wpt->shortname = DUPSTR(str);
  946. break;
  947. case 2:
  948. wpt->notes = DUPSTR(str);
  949. break;
  950. case 3:
  951. for (i = 0; i <= gt_waypt_class_map_line; i++) {
  952. if (case_ignore_strcmp(str, gt_waypt_class_names[i]) == 0) {
  953. GMSD_SET(wpt_class, i);
  954. break;
  955. }
  956. }
  957. break;
  958. case 4:
  959. parse_coordinates(str, datum_index, grid_index,
  960. &wpt->latitude, &wpt->longitude, MYNAME);
  961. break;
  962. case 5:
  963. if (parse_distance(str, &d, 1, MYNAME)) {
  964. wpt->altitude = d;
  965. }
  966. break;
  967. case 6:
  968. if (parse_distance(str, &d, 1, MYNAME)) {
  969. WAYPT_SET(wpt, depth, d);
  970. }
  971. break;
  972. case 7:
  973. if (parse_distance(str, &d, 1, MYNAME)) {
  974. WAYPT_SET(wpt, proximity, d);
  975. }
  976. break;
  977. case 8:
  978. if (parse_temperature(str, &d)) {
  979. WAYPT_SET(wpt, temperature, d);
  980. }
  981. break;
  982. case 9:
  983. if (parse_display(str, &i)) {
  984. GMSD_SET(display, i);
  985. }
  986. break;
  987. case 10:
  988. break; /* skip color */
  989. case 11:
  990. i = gt_find_icon_number_from_desc(str, GDB);
  991. GMSD_SET(icon, i);
  992. wpt->icon_descr = gt_find_desc_from_icon_number(i, GDB);
  993. break;
  994. case 12:
  995. GMSD_SETSTR(facility, str);
  996. break;
  997. case 13:
  998. GMSD_SETSTR(city, str);
  999. break;
  1000. case 14:
  1001. GMSD_SETSTR(state, str);
  1002. break;
  1003. case 15:
  1004. GMSD_SETSTR(country, str);
  1005. GMSD_SETSTR(cc, gt_get_icao_cc(str, wpt->shortname));
  1006. break;
  1007. case 16: {
  1008. time_t ct;
  1009. if (parse_date_and_time(str, &ct)) {
  1010. wpt->SetCreationTime(ct);
  1011. }
  1012. }
  1013. break;
  1014. case 17: {
  1015. wpt->AddUrlLink(str);
  1016. }
  1017. break;
  1018. case 18:
  1019. GMSD_SET(category, parse_categories(str));
  1020. break;
  1021. default:
  1022. break;
  1023. }
  1024. }
  1025. waypt_add(wpt);
  1026. }
  1027. static void
  1028. parse_route_header(void)
  1029. {
  1030. char* str;
  1031. int column = -1;
  1032. route_head* rte;
  1033. rte = route_head_alloc();
  1034. bind_fields(route_header);
  1035. while ((str = csv_lineparse(NULL, "\t", "", column++))) {
  1036. int field_no = header_fields[route_header][column];
  1037. switch (field_no) {
  1038. case 1:
  1039. rte->rte_name = DUPSTR(str);
  1040. break;
  1041. case 5:
  1042. rte->rte_url = str;
  1043. break;
  1044. }
  1045. }
  1046. route_add_head(rte);
  1047. current_rte = rte;
  1048. }
  1049. static void
  1050. parse_track_header(void)
  1051. {
  1052. char* str;
  1053. int column = -1;
  1054. route_head* trk;
  1055. bind_fields(track_header);
  1056. trk = route_head_alloc();
  1057. while ((str = csv_lineparse(NULL, "\t", "", column++))) {
  1058. int field_no = header_fields[track_header][column];
  1059. switch (field_no) {
  1060. case 1:
  1061. trk->rte_name = DUPSTR(str);
  1062. break;
  1063. case 6:
  1064. trk->rte_url = str;
  1065. break;
  1066. }
  1067. }
  1068. track_add_head(trk);
  1069. current_trk = trk;
  1070. }
  1071. static void
  1072. parse_route_waypoint(void)
  1073. {
  1074. char* str;
  1075. int column = -1;
  1076. Waypoint* wpt = NULL;
  1077. bind_fields(rtept_header);
  1078. while ((str = csv_lineparse(NULL, "\t", "", column++))) {
  1079. int field_no = header_fields[rtept_header][column];
  1080. switch (field_no) {
  1081. case 1:
  1082. is_fatal((*str == '\0'), MYNAME ": Route waypoint without name at line %d!\n", current_line);
  1083. wpt = find_waypt_by_name(str);
  1084. is_fatal((wpt == NULL), MYNAME ": Route waypoint \"%s\" not in waypoint list (line %d)!\n", str, current_line);
  1085. wpt = new Waypoint(*wpt);
  1086. break;
  1087. }
  1088. }
  1089. if (wpt != NULL) {
  1090. route_add_wpt(current_rte, wpt);
  1091. }
  1092. }
  1093. static void
  1094. parse_track_waypoint(void)
  1095. {
  1096. char* str;
  1097. int column = -1;
  1098. Waypoint* wpt;
  1099. bind_fields(trkpt_header);
  1100. wpt = new Waypoint;
  1101. while ((str = csv_lineparse(NULL, "\t", "", column++))) {
  1102. int field_no;
  1103. double x;
  1104. if (! *str) {
  1105. continue;
  1106. }
  1107. field_no = header_fields[trkpt_header][column];
  1108. switch (field_no) {
  1109. case 1:
  1110. parse_coordinates(str, datum_index, grid_index,
  1111. &wpt->latitude, &wpt->longitude, MYNAME);
  1112. break;
  1113. case 2: {
  1114. time_t ct;
  1115. if (parse_date_and_time(str, &ct)) {
  1116. wpt->SetCreationTime(ct);
  1117. }
  1118. }
  1119. break;
  1120. case 3:
  1121. if (parse_distance(str, &x, 1, MYNAME)) {
  1122. wpt->altitude = x;
  1123. }
  1124. break;
  1125. case 4:
  1126. if (parse_distance(str, &x, 1, MYNAME)) {
  1127. WAYPT_SET(wpt, depth, x);
  1128. }
  1129. break;
  1130. case 5:
  1131. if (parse_temperature(str, &x)) {
  1132. WAYPT_SET(wpt, temperature, x);
  1133. }
  1134. break;
  1135. case 8:
  1136. if (parse_speed(str, &x, 1, MYNAME)) {
  1137. WAYPT_SET(wpt, speed, x);
  1138. }
  1139. break;
  1140. case 9:
  1141. WAYPT_SET(wpt, course, atoi(str));
  1142. break;
  1143. }
  1144. }
  1145. track_add_wpt(current_trk, wpt);
  1146. }
  1147. /***************************************************************/
  1148. static void
  1149. garmin_txt_rd_init(const QString& fname)
  1150. {
  1151. memset(&gtxt_flags, 0, sizeof(gtxt_flags));
  1152. fin = gbfopen(fname, "rb", MYNAME);
  1153. memset(&header_ct, 0, sizeof(header_ct));
  1154. datum_index = -1;
  1155. grid_index = (grid_type) -1;
  1156. init_date_and_time_format();
  1157. }
  1158. static void
  1159. garmin_txt_rd_deinit(void)
  1160. {
  1161. header_type h;
  1162. for (h = waypt_header; h <= unknown_header; h++) {
  1163. free_header(h);
  1164. }
  1165. gbfclose(fin);
  1166. xfree(date_time_format);
  1167. }
  1168. static void
  1169. garmin_txt_read(void)
  1170. {
  1171. char* buff;
  1172. current_line = 0;
  1173. while ((buff = gbfgetstr(fin))) {
  1174. char* cin;
  1175. if ((current_line++ == 0) && fin->unicode) {
  1176. cet_convert_init(CET_CHARSET_UTF8, 1);
  1177. }
  1178. cin = lrtrim(buff);
  1179. if (*cin == '\0') {
  1180. continue;
  1181. }
  1182. cin = csv_lineparse(cin, "\t", "", 0);
  1183. if (cin == NULL) {
  1184. continue;
  1185. }
  1186. if (case_ignore_strcmp(cin, "Header") == 0) {
  1187. parse_header();
  1188. } else if (case_ignore_strcmp(cin, "Grid") == 0) {
  1189. parse_grid();
  1190. } else if (case_ignore_strcmp(cin, "Datum") == 0) {
  1191. parse_datum();
  1192. } else if (case_ignore_strcmp(cin, "Waypoint") == 0) {
  1193. parse_waypoint();
  1194. } else if (case_ignore_strcmp(cin, "Route Waypoint") == 0) {
  1195. parse_route_waypoint();
  1196. } else if (case_ignore_strcmp(cin, "Trackpoint") == 0) {
  1197. parse_track_waypoint();
  1198. } else if (case_ignore_strcmp(cin, "Route") == 0) {
  1199. parse_route_header();
  1200. } else if (case_ignore_strcmp(cin, "Track") == 0) {
  1201. parse_track_header();
  1202. } else if (case_ignore_strcmp(cin, "Map") == 0) /* do nothing */ ;
  1203. else {
  1204. fatal(MYNAME ": Unknwon identifier (%s) at line %d!\n", cin, current_line);
  1205. }
  1206. /* flush pending data */
  1207. while (csv_lineparse(NULL, "\t", "", 0));
  1208. }
  1209. }
  1210. ff_vecs_t garmin_txt_vecs = {
  1211. ff_type_file,
  1212. FF_CAP_RW_ALL,
  1213. garmin_txt_rd_init,
  1214. garmin_txt_wr_init,
  1215. garmin_txt_rd_deinit,
  1216. garmin_txt_wr_deinit,
  1217. garmin_txt_read,
  1218. garmin_txt_write,
  1219. NULL,
  1220. garmin_txt_args,
  1221. CET_CHARSET_MS_ANSI, 0
  1222. };
  1223. #endif // CSVFMTS_ENABLED