1 /*
2 Access to PsiTrex text files.
3 Based on information provided by Ian Cowley.
4
5 Copyright (C) 2003 Mark Bradley, mrcb.gpsb@osps.net
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 */
21
22 #include <cctype> // for isspace
23 #include <cstdio> // for sscanf, EOF, size_t
24 #include <cstdlib> // for atof, atoi
25 #include <cstring> // for strcmp, strlen, strcpy
26 #include <ctime> // for gmtime
27
28 #include <QtCore/QChar> // for QChar
29 #include <QtCore/QLatin1String> // for QLatin1String
30 #include <QtCore/QString> // for QString
31 #include <QtCore/QtGlobal> // for foreach, uint
32
33 #include "defs.h"
34 #include "garmin_tables.h" // for gt_find_desc_from_icon_number, gt_find_icon_number_from_desc, PCX
35 #include "gbfile.h" // for gbfprintf, gbfeof, gbfile, gbfgetc, gbfclose, gbfgets, gbfopen, gbfputs
36 #include "src/core/datetime.h" // for DateTime
37
38
39 #define MYNAME "PSITREX"
40
41 enum psit_tokenSep_type {
42 ltrimEOL = 1 , /* skip spaces & tabs to start; ends on EOL */
43 EOL, /* don't skip spaces and tabs to start; end on EOL */
44 comma, /* skip spaces & tabs to start; ends on comma or EOL */
45 whitespace, /* skip spaces & tabs to start; ends on white space or EOL */
46 wscomma /* skip spaces & tabs to start; ends on white space, comma or EOL */
47 };
48
49 struct psit_icon_mapping_t {
50 int value;
51 const char* icon;
52 };
53
54 static gbfile* psit_file_in;
55 static gbfile* psit_file_out;
56 static short_handle mkshort_handle;
57
58 /* 2 = not written any tracks out
59 1 = change of track to write out track header
60 0 = in the middle of writing out track datapoints, so don't write a header */
61 static int psit_track_state = 2;
62
63 static char psit_current_token[256];
64
65 static char* snlen;
66
67 static
68 QVector<arglist_t> psit_args = {
69 /* {"snlen", &snlen, "Length of generated shortnames",
70 NULL, ARGTYPE_INT, "1", NULL }, */
71 };
72
73 /* Taken from PsiTrex 1.13 */
74 static
75 const psit_icon_mapping_t psit_icon_value_table[] = {
76 { 0x00, "anchor" },
77 { 0x06, "dollar" },
78 { 0x07, "fish" },
79 { 0x08, "fuel" },
80 { 0x0a, "house" },
81 { 0x0b, "knife" },
82 { 0x0d, "mug" },
83 { 0x0e, "skull" },
84 { 0x12, "wpt_dot" },
85 { 0x13, "wreck" },
86 { 0x15, "mob" },
87 { 0x0096, "boat_ramp" },
88 { 0x0097, "camp" },
89 { 0x0098, "restrooms" },
90 { 0x0099, "showers" },
91 { 0x009a, "drinking_wtr" },
92 { 0x009b, "phone" },
93 { 0x009c, "1st_aid" },
94 { 0x009d, "info" },
95 { 0x009e, "parking" },
96 { 0x009f, "park" },
97 { 0x00a0, "picnic" },
98 { 0x00a1, "scenic" },
99 { 0x00a2, "skiing" },
100 { 0x00a3, "swimming" },
101 { 0x00a4, "dam" },
102 { 0x00a6, "danger" },
103 { 0x00a9, "ball" },
104 { 0x00aa, "car" },
105 { 0x00ab, "deer" },
106 { 0x00ac, "shpng_cart" },
107 { 0x00ad, "lodging" },
108 { 0x00ae, "mine" },
109 { 0x00af, "trail_head" },
110 { 0x00b0, "truck_stop" },
111 { 0x00b2, "flag" },
112 { 0x2005, "golf" },
113 { 0x2006, "sml_cty" },
114 { 0x2007, "med_cty" },
115 { 0x2008, "lrg_cty" },
116 { 0x200c, "amuse_pk" },
117 { 0x200d, "bowling" },
118 { 0x200e, "car_rental" },
119 { 0x200f, "car_repair" },
120 { 0x2010, "fastfood" },
121 { 0x2011, "fitness" },
122 { 0x2012, "movie" },
123 { 0x2013, "museum" },
124 { 0x2014, "pharmacy" },
125 { 0x2015, "pizza" }, /* how specific does this really need to be? C'mon! */
126 { 0x2016, "post_ofc" },
127 { 0x2017, "rv_park" },
128 { 0x2018, "school" },
129 { 0x2019, "stadium" },
130 { 0x201a, "store" },
131 { 0x201b, "zoo" },
132 { 0x201c, "gas_plus" },
133 { 0x201d, "faces" },
134 { 0x2022, "weigh_sttn" },
135 { 0x2023, "toll_booth" },
136 { 0x2029, "bridge" },
137 { 0x202a, "building" },
138 { 0x202b, "cemetery" },
139 { 0x202c, "church" },
140 { 0x202e, "crossing" },
141 { 0x2032, "oil_field" },
142 { 0x2033, "tunnel" },
143 { 0x2035, "forest" },
144 { 0x2036, "summit" },
145 { 0x203f, "geocache" },
146 { 0x2040, "geocache_fnd" },
147 { 0x4000, "airport" },
148 { 0x4007, "tall_tower" },
149 { 0x4008, "short_tower" },
150 { 0x4009, "glider" },
151 { 0x400a, "ultralight" },
152 { 0x400b, "parachute" },
153 { 0x4012, "seaplane" },
154 { -1, nullptr }
155 };
156
157 static const char*
psit_find_desc_from_icon_number(const int icon)158 psit_find_desc_from_icon_number(const int icon)
159 {
160 for (const psit_icon_mapping_t* i = psit_icon_value_table; i->icon; i++) {
161 if (icon == i->value) {
162 return i->icon;
163 }
164 }
165 return "";
166 }
167
168 static int
psit_find_icon_number_from_desc(const char * desc)169 psit_find_icon_number_from_desc(const char* desc)
170 {
171 int def_icon = 18;
172
173 if (!desc) {
174 return def_icon;
175 }
176
177 for (const psit_icon_mapping_t* i = psit_icon_value_table; i->icon; i++) {
178 if (case_ignore_strcmp(desc,i->icon) == 0) {
179 return i->value;
180 }
181 }
182 if (atoi(desc) > 0) {
183 return atoi(desc);
184 }
185 return def_icon;
186 }
187
188 static void
psit_rd_init(const QString & fname)189 psit_rd_init(const QString& fname)
190 {
191 psit_file_in = gbfopen(fname, "r", MYNAME);
192 }
193
194 static void
psit_rd_deinit()195 psit_rd_deinit()
196 {
197 gbfclose(psit_file_in);
198 }
199
200 static void
psit_wr_init(const QString & fname)201 psit_wr_init(const QString& fname)
202 {
203 psit_file_out = gbfopen(fname, "w", MYNAME);
204 }
205
206 static void
psit_wr_deinit()207 psit_wr_deinit()
208 {
209 gbfclose(psit_file_out);
210 }
211
212 /*
213 * get characters until and including terminating NULL from psit_file_in
214 * and write into buf.
215 */
216 static void
psit_getToken(gbfile * psit_file,char * buf,size_t sz,psit_tokenSep_type delimType)217 psit_getToken(gbfile* psit_file, char* buf, size_t sz, psit_tokenSep_type delimType)
218 {
219 int c = -1;
220
221 *buf = 0;
222
223 if (delimType != EOL) {
224 while ((c = gbfgetc(psit_file)) != EOF) {
225 if (!isspace(c)) {
226 break;
227 }
228 }
229 }
230
231 if (gbfeof(psit_file)) {
232 return;
233 }
234
235 if (delimType == EOL) {
236 c = gbfgetc(psit_file);
237 }
238
239 if (c == '#') {
240 if (gbfgets(buf, sz, psit_file) == nullptr) {
241 *buf = 0;
242 return;
243 }
244 /* use recursion to skip multiple comment lines or just to return the next token */
245 psit_getToken(psit_file, buf, sz, delimType);
246 return;
247 }
248
249 if ((delimType == EOL) || (delimType == ltrimEOL)) {
250 *buf = c;
251 buf++;
252 gbfgets(buf, sz-1, psit_file);
253 return;
254 }
255
256 while (sz--) {
257 *buf++ = c;
258 if ((c = gbfgetc(psit_file)) == EOF) {
259 *buf = 0;
260 return;
261 }
262 if (((c == 0) || isspace(c)) &&
263 ((delimType == whitespace) || (delimType == wscomma))) {
264 *buf = 0;
265 return;
266 }
267 if (((delimType == comma) || (delimType == wscomma)) &&
268 (c == ',')) {
269 *buf = 0;
270 return;
271 }
272 }
273 }
274
275
276 /*
277 * test if a token is known
278 *
279 */
280 static int
psit_isKnownToken(char * buf)281 psit_isKnownToken(char* buf)
282 {
283 if (strcmp(buf, "Track:") == 0) {
284 return 0;
285 }
286 if (strcmp(buf, "Route:") == 0) {
287 return 0;
288 }
289 if (strcmp(buf, "Waypoint:") == 0) {
290 return 0;
291 }
292 if (strcmp(buf, "Map:") == 0) {
293 return 0;
294 }
295 return 1;
296 }
297
298 /*
299 * read in from file a waypoint record
300 * MRCB
301 */
302 static void
psit_waypoint_r(gbfile * psit_file,Waypoint **)303 psit_waypoint_r(gbfile* psit_file, Waypoint**)
304 {
305 if (strlen(psit_current_token) > 0) {
306 auto* thisWaypoint = new Waypoint;
307
308 thisWaypoint->latitude = atof(psit_current_token);
309
310 psit_getToken(psit_file,psit_current_token,sizeof(psit_current_token), comma);
311 thisWaypoint->longitude = atof(psit_current_token);
312
313 psit_getToken(psit_file,psit_current_token,sizeof(psit_current_token), comma);
314 if (psit_current_token[0] == '*') {
315 thisWaypoint->altitude = unknown_alt;
316 } else {
317 thisWaypoint->altitude = atof(psit_current_token);
318 }
319
320 /* the name */
321 psit_getToken(psit_file,psit_current_token,sizeof(psit_current_token), comma);
322 rtrim(psit_current_token);
323 thisWaypoint->shortname = psit_current_token;
324 thisWaypoint->description = "";
325
326 psit_getToken(psit_file,psit_current_token,sizeof(psit_current_token), ltrimEOL);
327 rtrim(psit_current_token);
328 /* since PsiTrex only deals with Garmins, let's use the "proper" Garmin icon name */
329 /* convert the PsiTrex name to the number, which is the PCX one; from there to Garmin desc */
330 int garmin_icon_num = psit_find_icon_number_from_desc(psit_current_token);
331 thisWaypoint->icon_descr = gt_find_desc_from_icon_number(garmin_icon_num, PCX);
332
333 waypt_add(thisWaypoint);
334
335 psit_getToken(psit_file,psit_current_token,sizeof(psit_current_token), wscomma);
336 }
337 }
338
339 /*
340 * write out to file a waypoint record
341 * MRCB
342 */
343 static void
psit_waypoint_w(gbfile * psit_file,const Waypoint * wpt)344 psit_waypoint_w(gbfile* psit_file, const Waypoint* wpt)
345 {
346 gbfprintf(psit_file, "%11.6f,%11.6f,",
347 wpt->latitude,
348 wpt->longitude);
349
350 if (wpt->altitude == unknown_alt) {
351 gbfprintf(psit_file, "********,");
352 } else
353 gbfprintf(psit_file, "%8.2f,",
354 wpt->altitude);
355
356 const char* ident = global_opts.synthesize_shortnames ?
357 mkshort(mkshort_handle, "WPT", false) :
358 xstrdup(wpt->shortname);
359
360 gbfprintf(psit_file, " %-6s, ", ident);
361 xfree(ident);
362
363 int icon = gt_find_icon_number_from_desc(wpt->icon_descr, PCX);
364
365 if (get_cache_icon(wpt) && wpt->icon_descr.compare(QLatin1String("Geocache Found")) != 0) {
366 icon = gt_find_icon_number_from_desc(get_cache_icon(wpt), PCX);
367 }
368
369 ident = psit_find_desc_from_icon_number(icon);
370 if (strlen(ident) == 0) {
371 gbfprintf(psit_file, "%1d\n", icon);
372 } else {
373 gbfprintf(psit_file, "%s\n", ident);
374 }
375
376 }
377
378 static void
psit_waypoint_w_wrapper(const Waypoint * wpt)379 psit_waypoint_w_wrapper(const Waypoint* wpt)
380 {
381 psit_waypoint_w(psit_file_out, wpt);
382 }
383
384 /*
385 * read in from file a route record
386 * MRCB
387 */
388 static void
psit_route_r(gbfile * psit_file,route_head ** rte)389 psit_route_r(gbfile* psit_file, route_head** rte)
390 {
391 char rtename[256];
392
393 psit_getToken(psit_file,psit_current_token,sizeof(psit_current_token), ltrimEOL);
394
395 if (strlen(psit_current_token) == 0) {
396 strcpy(rtename, "ROUTE");
397 } else {
398 strcpy(rtename, psit_current_token);
399 }
400
401 rtrim(rtename);
402
403 auto* rte_head = new route_head;
404 rte_head->rte_name = rtename;
405 route_add_head(rte_head);
406 *rte = rte_head;
407
408 psit_getToken(psit_file,psit_current_token,sizeof(psit_current_token), wscomma);
409
410 while (psit_isKnownToken(psit_current_token) != 0) {
411 if (strlen(psit_current_token) > 0) {
412 auto* thisWaypoint = new Waypoint;
413
414 thisWaypoint->latitude = atof(psit_current_token);
415
416 psit_getToken(psit_file,psit_current_token,sizeof(psit_current_token), comma);
417 thisWaypoint->longitude = atof(psit_current_token);
418
419 psit_getToken(psit_file,psit_current_token,sizeof(psit_current_token), comma);
420 if (psit_current_token[0] == '*') {
421 thisWaypoint->altitude = unknown_alt;
422 } else {
423 thisWaypoint->altitude = atof(psit_current_token);
424 }
425
426 /* the name */
427 psit_getToken(psit_file,psit_current_token,sizeof(psit_current_token), comma);
428 rtrim(psit_current_token);
429 thisWaypoint->shortname = psit_current_token;
430 thisWaypoint->description = "";
431
432 psit_getToken(psit_file,psit_current_token,sizeof(psit_current_token), ltrimEOL);
433 rtrim(psit_current_token);
434 /* since PsiTrex only deals with Garmins, let's use the "proper" Garmin icon name */
435 /* convert the PsiTrex name to the number, which is the PCX one; from there to Garmin desc */
436 int garmin_icon_num = psit_find_icon_number_from_desc(psit_current_token);
437 thisWaypoint->icon_descr = gt_find_desc_from_icon_number(garmin_icon_num, PCX);
438
439 route_add_wpt(rte_head, thisWaypoint);
440
441 if (gbfeof(psit_file)) {
442 break;
443 }
444
445 psit_getToken(psit_file,psit_current_token,sizeof(psit_current_token), wscomma);
446 } else {
447 break;
448 }
449 }
450 }
451
452 /*
453 * write out to file a route header
454 * MRCB
455 */
456 static void
psit_routehdr_w(gbfile * psit_file,const route_head * rte)457 psit_routehdr_w(gbfile* psit_file, const route_head* rte)
458 {
459 QString rname;
460
461 /* total nodes (waypoints) this route */
462 //if (rte->waypoint_list.next) {
463 if (true) {
464 // this test doesn't do what I w ant i.e test if this is a valid
465 // route - treat as a placeholder for now .
466 time_t uniqueValue = 0;
467 unsigned int rte_datapoints = 0;
468 foreach (const Waypoint* testwpt, rte->waypoint_list) {
469 if (rte_datapoints == 0) {
470 uniqueValue = testwpt->GetCreationTime().toTime_t();
471 }
472 rte_datapoints++;
473 }
474
475 if (uniqueValue == 0) {
476 uniqueValue = current_time().toTime_t();
477 }
478
479 /* route name */
480 if (rte->rte_name.isEmpty()) {
481 rname = QString("Route%1").arg((uint) uniqueValue, 4, 16, QChar('0'));
482 } else {
483 rname = rte->rte_name;
484 }
485 /* check for psitrex comment sign; replace with '$' */
486 rname = rname.replace(QChar('#'), QChar('$'));
487
488 gbfputs(QString("Route: %1\n").arg(rname), psit_file);
489 }
490 }
491
492 static void
psit_routehdr_w_wrapper(const route_head * rte)493 psit_routehdr_w_wrapper(const route_head* rte)
494 {
495 psit_routehdr_w(psit_file_out, rte);
496 }
497
498
499 /*
500 * read in from file a track record
501 * MRCB
502 */
503 static void
psit_track_r(gbfile * psit_file,route_head **)504 psit_track_r(gbfile* psit_file, route_head**)
505 {
506 char trkname[256];
507
508 struct tm tmTime;
509
510 psit_getToken(psit_file,psit_current_token,sizeof(psit_current_token), ltrimEOL);
511 if (strlen(psit_current_token) == 0) {
512 strcpy(trkname, "TRACK");
513 } else {
514 strcpy(trkname, psit_current_token);
515 }
516
517 rtrim(trkname);
518
519 unsigned int trk_num = 0;
520 route_head* track_head = nullptr;
521
522 psit_getToken(psit_file,psit_current_token,sizeof(psit_current_token), wscomma);
523
524 while (psit_isKnownToken(psit_current_token) != 0) {
525 if (strlen(psit_current_token) > 0) {
526 auto* thisWaypoint = new Waypoint;
527
528 thisWaypoint->latitude = atof(psit_current_token);
529
530 psit_getToken(psit_file,psit_current_token,sizeof(psit_current_token), comma);
531 thisWaypoint->longitude = atof(psit_current_token);
532
533 psit_getToken(psit_file,psit_current_token,sizeof(psit_current_token), comma);
534 if (psit_current_token[0] == '*') {
535 thisWaypoint->altitude = unknown_alt;
536 } else {
537 thisWaypoint->altitude = atof(psit_current_token);
538 }
539
540 /* date portion of the date time DD/MM/YY */
541 psit_getToken(psit_file, psit_current_token,
542 sizeof(psit_current_token), whitespace);
543 sscanf(psit_current_token, "%02d/%02d/%02d",
544 &(tmTime.tm_mday) , &(tmTime.tm_mon),
545 &(tmTime.tm_year));
546
547 /* years are less 1900 in the tm struct */
548 tmTime.tm_year += (tmTime.tm_year > 50 ? 0 : 100);
549 /* months are 0 to 11 in the tm struct */
550 tmTime.tm_mon--;
551 /* time portion of the date time hh:mm:ss */
552 psit_getToken(psit_file,psit_current_token,
553 sizeof(psit_current_token), wscomma);
554 sscanf(psit_current_token, "%02d:%02d:%02d",
555 &(tmTime.tm_hour) , &(tmTime.tm_min),
556 &(tmTime.tm_sec));
557
558 tmTime.tm_isdst = 0;
559 time_t dateTime = mkgmtime(&tmTime);
560
561 psit_getToken(psit_file,psit_current_token,sizeof(psit_current_token), whitespace);
562
563 if ((strcmp(psit_current_token, "1") == 0) || (track_head == nullptr)) {
564 track_head = new route_head;
565 /* Add a number to the track name. With Garmins, the "first"
566 tracklog is usually ACTIVE LOG
567 the second is ACTIVE LOG001 and so on */
568 if (trk_num > 0) {
569 track_head->rte_name = QString::asprintf("%s%03d", trkname, trk_num);
570 } else {
571 track_head->rte_name = trkname;
572 }
573 trk_num++;
574 track_add_head(track_head);
575 }
576
577 thisWaypoint->SetCreationTime(dateTime);
578 track_add_wpt(track_head, thisWaypoint);
579
580 if (gbfeof(psit_file)) {
581 break;
582 }
583
584 psit_getToken(psit_file,psit_current_token,sizeof(psit_current_token), wscomma);
585 } else {
586 break;
587 }
588 }
589 }
590
591 /*
592 * write out to file a tracklog header
593 * MRCB
594 */
595 static void
psit_trackhdr_w(gbfile * psit_file,const route_head * trk)596 psit_trackhdr_w(gbfile* psit_file, const route_head* trk)
597 {
598 QString tname;
599 time_t uniqueValue = 0;
600
601 if (psit_track_state == 2) {
602 /* total nodes (waypoints) this track */
603 //if (trk->waypoint_list.next) { /* this test doesn't do what I want i.e test if this is a valid track - treat as a placeholder for now */
604 if (true) {
605
606 unsigned int trk_datapoints = 0;
607 foreach (const Waypoint* testwpt, trk->waypoint_list) {
608 if (trk_datapoints == 0) {
609 uniqueValue = testwpt->GetCreationTime().toTime_t();
610 }
611 trk_datapoints++;
612 }
613
614 if (uniqueValue == 0) {
615 uniqueValue = current_time().toTime_t();
616 }
617
618 /* track name */
619 if (trk->rte_name.isEmpty()) {
620 tname = QString("Track%1").arg((uint) uniqueValue, 4, 16, QChar('0'));
621 } else {
622 tname = trk->rte_name;
623 }
624
625 /* check for psitrex comment sign; replace with '$' */
626 tname = tname.replace(QChar('#'), QChar('$'));
627
628 gbfputs(QString("Track: %1\n").arg(tname), psit_file);
629 }
630 }
631 psit_track_state = 1;
632 }
633
634 static void
psit_trackhdr_w_wrapper(const route_head * trk)635 psit_trackhdr_w_wrapper(const route_head* trk)
636 {
637 psit_trackhdr_w(psit_file_out, trk);
638 }
639
640
641 /*
642 * write out to file a tracklog datapoint
643 * MRCB
644 */
645 static void
psit_trackdatapoint_w(gbfile * psit_file,const Waypoint * wpt)646 psit_trackdatapoint_w(gbfile* psit_file, const Waypoint* wpt)
647 {
648 time_t t = wpt->GetCreationTime().toTime_t();
649 struct tm* tmTime = gmtime(&t);
650
651 gbfprintf(psit_file, "%11.6f,%11.6f,",
652 wpt->latitude,
653 wpt->longitude);
654
655 if (wpt->altitude == unknown_alt) {
656 gbfprintf(psit_file, "********, ");
657 } else
658 gbfprintf(psit_file, "%8.2f, ",
659 wpt->altitude);
660
661 /* Following date time format is fixed and reveals the origin of PsiTrex (i.e. the UK) */
662 gbfprintf(psit_file, "%02d/%02d/%02d %02d:%02d:%02d,",
663 tmTime->tm_mday,
664 tmTime->tm_mon+1,
665 tmTime->tm_year % 100,
666 tmTime->tm_hour,
667 tmTime->tm_min,
668 tmTime->tm_sec);
669
670 gbfprintf(psit_file," %d\n", psit_track_state);
671 psit_track_state = 0;
672 }
673
674 static void
psit_trackdatapoint_w_wrapper(const Waypoint * wpt)675 psit_trackdatapoint_w_wrapper(const Waypoint* wpt)
676 {
677 psit_trackdatapoint_w(psit_file_out, wpt);
678 }
679
680
681 static void
psit_read()682 psit_read()
683 {
684 Waypoint* wpt;
685 route_head* rte;
686 route_head* trk;
687
688 #ifdef DUMP_ICON_TABLE
689 printf("static icon_mapping_t icon_table[] = {\n");
690 #endif
691
692 psit_getToken(psit_file_in, psit_current_token, sizeof(psit_current_token), whitespace);
693
694 do {
695 if (strlen(psit_current_token) == 0) {
696 break;
697 }
698
699 if (strcmp(psit_current_token, "Track:") == 0) {
700 if (global_opts.objective == trkdata) {
701 psit_track_r(psit_file_in, &trk);
702 } else {
703 break; /* psitrex files only have one format in; */
704 }
705 /* if this is a track file and we don't want them, them bail out */
706 } else if (strcmp(psit_current_token, "Route:") == 0) {
707 if (global_opts.objective == rtedata) {
708 psit_route_r(psit_file_in, &rte);
709 } else {
710 break; /* ditto, but for routes */
711 }
712 } else {
713 /* Must be waypoints in this file */
714 if (global_opts.objective == wptdata) {
715 psit_waypoint_r(psit_file_in, &wpt);
716 #ifdef DUMP_ICON_TABLE
717 printf("\t{ %4u, \"%s\" },\n", icon, wpt->shortname);
718 #endif
719
720 } else {
721 break;
722 }
723 }
724 } while (!gbfeof(psit_file_in));
725
726 #ifdef DUMP_ICON_TABLE
727 printf("\t{ -1, NULL },\n");
728 printf("};\n");
729 #endif
730 }
731
732 static void
psit_write()733 psit_write()
734 {
735 int short_length;
736
737 if (snlen) {
738 short_length = atoi(snlen);
739 } else {
740 short_length = 10;
741 }
742
743 mkshort_handle = mkshort_new_handle();
744
745 setshort_length(mkshort_handle, short_length);
746 setshort_whitespace_ok(mkshort_handle, 0);
747
748 psit_track_state = 2;
749
750 if (global_opts.objective == wptdata) {
751 waypt_disp_all(psit_waypoint_w_wrapper);
752 }
753 if (global_opts.objective == rtedata) {
754 route_disp_all(psit_routehdr_w_wrapper, nullptr, psit_waypoint_w_wrapper);
755 }
756 if (global_opts.objective == trkdata) {
757 track_disp_all(psit_trackhdr_w_wrapper,
758 nullptr, psit_trackdatapoint_w_wrapper);
759 }
760
761 mkshort_del_handle(&mkshort_handle);
762
763 }
764
765 ff_vecs_t psit_vecs = {
766 ff_type_file,
767 FF_CAP_RW_ALL,
768 psit_rd_init,
769 psit_wr_init,
770 psit_rd_deinit,
771 psit_wr_deinit,
772 psit_read,
773 psit_write,
774 nullptr,
775 &psit_args,
776 CET_CHARSET_ASCII, 0 /* CET-REVIEW */
777 , NULL_POS_OPS,
778 nullptr
779 };
780