1 /*
2 Support for PathAway Palm Database,
3 Copyright (C) 2005-2006 Olaf Klein, o.b.klein@gpsbabel.org
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18
19 */
20
21 /*
22 remarks:
23
24 The german release 3.0 of PathAway violates the PathAway standards:
25 * N.. .... O.. .... instead of N.. .... E.. ....
26 * date is formatted in DDMMYYYY instead of YYYYMMDD
27
28 Release 4.x store only numeric coordinates and uses a six-number date.
29
30 Modified by by Andrei Boros <slackware@andrix.ro> 2008-11-07
31 * added information about database vehicle icon
32 * Pathaway 4.x can handle invalid date/time and date format apparently
33 has changed slightly between revisions :
34 131502.29 26102008 = HHMMSS.MS DDMMYYYY
35 * work around errors reading date/time information
36 (real life data collected by Pathaway sometimes has the date/time field
37 contain some missing/invalid data. This information can be safely
38 ignored most of the time. So far gpsbabel stopped processing files
39 when encountering such invalid data)
40 - date/time field may contain one or more spaces between fields
41 - date/time field may start with one or more spaces
42 - date/time field may contain invalid characters -> ignore
43 - invalid or missing date/time -> ignore
44 - only time may be present (some older versions of Pathaway 4)
45
46 (this is still incomplete, but solved most of my problems when converting
47 pathaway .pdb files)
48
49 */
50
51
52 #include <ctype.h>
53 #include <math.h>
54
55 #include "defs.h"
56 #if PDBFMTS_ENABLED
57 #include "csv_util.h"
58 #include "pdbfile.h"
59 #include "strptime.h"
60
61 #define MYNAME "pathaway"
62
63 #define PPDB_MAGIC_TRK 0x55735472 /* UsTr */
64 #define PPDB_MAGIC_WPT 0x506f4c69 /* PoLi */
65 #define PPDB_MAGIC 0x4b6e5772 /* KwNr */
66
67 #define VEHICLE_LEN 100
68
69 static pdbfile *file_in, *file_out;
70 static char *fname_out;
71 static short_handle mkshort_handle;
72 static gpsdata_type ppdb_type;
73 static unsigned char german_release = 0;
74 static char *datefmt;
75 static int ct;
76 static int warn_ = 0;
77
78 typedef struct ppdb_appdata {
79 unsigned char reservedA[274]; /* all 0 */
80 unsigned char dirtyFlag;
81 unsigned char dataBaseSubType; /* 0 = Track, 1 = Route */
82 short int dbAttributes; /* 0 */
83 char vehicleStr[VEHICLE_LEN];
84 unsigned char reservedB[100]; /* all 0 */
85 } ppdb_appdata_t;
86
87 #define PPDB_APPINFO_SIZE sizeof(struct ppdb_appdata)
88 static ppdb_appdata_t *appinfo;
89
90 static char *opt_dbname = NULL;
91 static char *opt_dbicon = NULL;
92 static char *opt_deficon = NULL;
93 static char *opt_snlen = NULL;
94 static char *opt_date = NULL;
95
96 static arglist_t ppdb_args[] = {
97 {"date", &opt_date, "Read/Write date format (i.e. DDMMYYYY)", NULL, ARGTYPE_STRING, ARG_NOMINMAX},
98 {"dbname", &opt_dbname, "Database name", NULL, ARGTYPE_STRING, ARG_NOMINMAX},
99 {"dbicon", &opt_dbicon, "Database vehicle icon name", NULL, ARGTYPE_STRING, ARG_NOMINMAX},
100 {"deficon", &opt_deficon, "Default icon name", NULL, ARGTYPE_STRING, ARG_NOMINMAX},
101 {"snlen", &opt_snlen, "Length of generated shortnames", "10", ARGTYPE_INT, "1", NULL },
102 ARG_TERMINATOR
103 };
104
105 /*#undef PPDB_DEBUG*/
106 #define PPDB_DEBUG 1
107
108 #if PPDB_DEBUG
109 static void
internal_debug1(const char * filename,int fileline)110 internal_debug1(const char *filename, int fileline)
111 {
112 static int ct=1;
113 printf("DBG(%d): file %s, line %d: ", ct++, filename, fileline);
114 }
115 static void
internal_debug2(const char * format,...)116 internal_debug2(const char *format, ...)
117 {
118 va_list args;
119
120 va_start(args, format);
121 vprintf(format, args);
122 puts("");
123 va_end(args);
124 }
125 #define DBG(args) internal_debug1(__FILE__, __LINE__);internal_debug2 args
126 #else
127 #define DBG(args) ;
128 #endif
129
130
131 #define CHECK_INP(i, j, k, l) is_fatal((i != j), "Error in data structure (in %s? Value is : %s).", (k), (l))
132
133 /*
134 * utilities
135 */
136
137 static
ppdb_strcat(char * dest,const char * src,const char * def,int * size)138 char *ppdb_strcat(char *dest, const char *src, const char *def, int *size)
139 {
140 int len;
141 char *res;
142 const char *tmp;
143
144 tmp = src;
145 if (tmp == NULL) {
146 tmp = def;
147 if (tmp == NULL) {
148 return dest;
149 }
150 }
151 if (*tmp == '\0') {
152 return dest;
153 }
154
155 len = strlen(dest) + strlen(tmp) + 1;
156 if (len > *size) {
157 *size = len;
158 res = (char*) xrealloc(dest, *size);
159 } else {
160 res = dest;
161 }
162 strcat(res, tmp);
163 return res;
164 }
165
166 #define STR_POOL_SIZE 16 /* !!! any power of 2 !!! */
167
168 static char *str_pool[STR_POOL_SIZE];
169 static size_t str_pool_s[STR_POOL_SIZE];
170 static int str_poolp = -1;
171
172 static
str_pool_init(void)173 void str_pool_init(void)
174 {
175 int i;
176 for (i = 0; i < STR_POOL_SIZE; i++) {
177 str_pool[i] = NULL;
178 str_pool_s[i] = 0;
179 }
180 }
181
182 static
str_pool_deinit(void)183 void str_pool_deinit(void)
184 {
185 int i;
186
187 for (i = 0; i < STR_POOL_SIZE; i++)
188 if (str_pool_s[i] != 0) {
189 xfree(str_pool[i]);
190 str_pool[i] = NULL;
191 str_pool_s[i] = 0;
192 }
193 }
194
195 static
str_pool_get(size_t size)196 char *str_pool_get(size_t size)
197 {
198 char *tmp;
199
200 str_poolp = ((str_poolp + 1) & (STR_POOL_SIZE - 1));
201 tmp = str_pool[str_poolp];
202
203 if (str_pool_s[str_poolp] == 0) {
204 tmp = (char*) xmalloc(size);
205 } else if (str_pool_s[str_poolp] < size) {
206 tmp = (char*) xrealloc(tmp, size);
207 } else {
208 return tmp;
209 }
210
211 str_pool[str_poolp] = tmp;
212 str_pool_s[str_poolp] = size;
213
214 return tmp;
215 }
216
217 static
str_pool_getcpy(const char * src,const char * def)218 char *str_pool_getcpy(const char *src, const char *def)
219 {
220 char *res;
221
222 if (src == NULL) {
223 src = def;
224 if (src == NULL) {
225 src = "";
226 }
227 }
228 res = str_pool_get(strlen(src) + 1);
229 strcpy(res, src);
230
231 return res;
232 }
233
234 /*
235 * decoding/formatting functions
236 */
237
238 static
ppdb_fmt_float(const double val)239 char *ppdb_fmt_float(const double val)
240 {
241 char *str = str_pool_get(32);
242 char *c;
243 snprintf(str, 32, "%.8f", val);
244 c = str + strlen(str) - 1;
245 while ((c > str) && (*c == '0')) {
246 *c = '\0';
247 c--;
248 if (*c == '.') {
249 c++;
250 *c = '0';
251 break;
252 }
253 }
254 return str;
255 }
256
257 static
ppdb_fmt_degrees(char dir,double val)258 char *ppdb_fmt_degrees(char dir, double val)
259 {
260 char *str = str_pool_get(32);
261 int deg = fabs(val);
262 double min = 60.0 * (fabs(val) - deg);
263 char *tmp;
264
265 snprintf(str, 31, "%c%0*d %.8f", dir, (deg > 99) ? 3 : 2, deg, min);
266
267 tmp = str + strlen(str) - 1; /* trim trailing nulls */
268 while ((tmp > str) && (*tmp == '0')) {
269 *tmp = '\0';
270 tmp--;
271 if (*tmp == '.') {
272 tmp++;
273 *tmp = '0';
274 break;
275 }
276 }
277 return str;
278 }
279
280 static
ppdb_decode_coord(const char * str)281 double ppdb_decode_coord(const char *str)
282 {
283 double val;
284 int deg;
285 char dir;
286
287 if (*str < 'A') { /* only numeric */
288 CHECK_INP(1, sscanf(str,"%lf", &val), "decode_coord(1) DD.dddd", str);
289 return val;
290 } else {
291 const char *tmp;
292
293 if (*str == 'O') {
294 german_release = 1;
295 }
296
297 tmp = strchr(str, ' ');
298 if ((tmp) && (tmp - str < 5)) {
299 CHECK_INP(3, sscanf(str,"%c%d %lf", &dir, °, &val), "decode_coord(2) DD MM.mmm", str);
300 val = deg + (val / 60.0);
301 } else {
302 CHECK_INP(2, sscanf(str,"%c%lf", &dir, &val), "decode_coord(3) DD.dddd", str);
303 }
304 if ((dir == 'S') || (dir == 'W')) {
305 val = -val;
306 }
307 }
308 return val;
309 }
310
311 static
ppdb_decode_tm(char * str,struct tm * tm)312 int ppdb_decode_tm(char *str, struct tm *tm)
313 {
314 int msec, d1, d2, d3, d4;
315 int year;
316 int temp=0;
317 char *cx;
318
319 str = lrtrim(str); /* time field may start/end with spaces, drop them */
320
321 if (*str == '\0') {
322 if (global_opts.debug_level > 0) {
323 warning(MYNAME ": Time value missing, reseting to 0\n");
324 warn_ = 1;
325 }
326 return 0; /* empty time field */
327 }
328
329 if (strchr(str, '.')) { /* time in hhmmss.ms */
330 CHECK_INP(4, sscanf(str, "%02d%02d%02d.%d",
331 &tm->tm_hour, &tm->tm_min, &tm->tm_sec, &msec),
332 "decode_tm(1) hhmmss.ss", str);
333 } else if (sscanf(str,"%06d",&temp)==1)
334 /* WORKAROUND read time info only if a valid 6 digit string found */
335 {
336 CHECK_INP(3, sscanf(str, "%02d%02d%02d",
337 &tm->tm_hour, &tm->tm_min, &tm->tm_sec),
338 "decode_tm(2) hhmmss", str);
339 } else {
340 if (global_opts.debug_level > 0) {
341 warning(MYNAME ": Invalid time value, reseting to 0\n");
342 warn_ = 1;
343 }
344 return 0; /* WORKAROUND maybe invalid time, just ignore it and continue */
345 }
346 cx = strchr(str, ' ');
347
348 if (cx == NULL) {
349 if (global_opts.debug_level > 0) {
350 warning(MYNAME ": Date value missing, reseting to 0\n");
351 warn_ = 1;
352 }
353 return 0; /* empty date field */
354 }
355
356 cx = lrtrim(cx);
357 if (*cx == '\0') {
358 if (global_opts.debug_level > 0) {
359 warning(MYNAME ": Date value missing, found only spaces, reseting to 0\n");
360 warn_ = 1;
361 }
362 return 0; /* empty date field */
363 }
364
365 if (datefmt) {
366 struct tm tm2;
367
368 if (NULL == strptime(cx, datefmt, &tm2)) {
369 fatal(MYNAME ": Unable to convert date '%s' using format '%s' (%s)!\n", cx, datefmt, opt_date);
370 }
371
372 tm->tm_year = tm2.tm_year + 1900;
373 tm->tm_mon = tm2.tm_mon + 1;
374 tm->tm_mday = tm2.tm_mday;
375 } else {
376 time_t tnow;
377 struct tm now;
378
379
380 tnow = current_time().toTime_t();
381 now = *localtime(&tnow);
382 now.tm_year += 1900;
383 now.tm_mon++;
384
385 if (strlen(cx) == 8) {
386 CHECK_INP(4, sscanf(cx, "%02d%02d%02d%02d", &d1, &d2, &d3, &d4), "decode_tm(3) invalid date (YYYYMMDD)", cx);
387
388 year = (d1 * 100) + d2;
389 /* the coordinates comes before date and time in
390 the dataset, so the flag "german_release" is set yet. */
391
392 /* next code works for most, except for 19. and 20. of month */
393
394 if ((german_release != 0) || (year < 1980) || (year > now.tm_year)) { /* YYYYMMDD or DDMMYYYY ????? */
395 tm->tm_year = (d3 * 100) + d4;
396 tm->tm_mon = d2;
397 tm->tm_mday = d1;
398 } else {
399 tm->tm_year = (d1 * 100) + d2;
400 tm->tm_mon = d3;
401 tm->tm_mday = d4;
402 }
403 } else if (strlen(cx) == 6) {
404 CHECK_INP(3, sscanf(cx, "%02d%02d%02d", &d1, &d2, &d3), "decode_tm(3) invalid date (DDMMYY)", cx);
405 if (d3 < 1970) { /* Usual Y2K interpretation */
406 year = d3 + 2000;
407 } else {
408 year = d3 + 1900;
409 }
410
411 /* I don't know how a german release handles this
412 * so for now I will assume only DDMMYY if date has 6 digits
413 */
414 tm->tm_year = year;
415 tm->tm_mon = d2;
416 tm->tm_mday = d1;
417 } else { /* date string is neither 8 nor 6 digits */
418 printf(MYNAME ": Date from first record is %s.\n", cx);
419 printf(MYNAME ": Please use option 'date' to specify how this is formatted.\n");
420 fatal(MYNAME ": (... -i pathaway,date=DDMMYY ...)\n");
421 }
422 }
423 return 1;
424 }
425
426 static
ppdb_read_wpt(route_head * head,int isRoute)427 int ppdb_read_wpt(route_head *head, int isRoute)
428 {
429 char *data, *str;
430 double altfeet;
431 struct tm tm;
432
433 while (pdb_read_rec(file_in, NULL, NULL, NULL, (void **)&data) >= 0) {
434 waypoint *wpt_tmp = waypt_new();
435 int line = 0;
436 char *tmp = data;
437
438 /* Print the whole input record. All input records are printed before processing. */
439 if (global_opts.debug_level >= 5) {
440 DBG(("\n\
441 --- BEGIN Input data record -----------------------------------------------\n\
442 %s\n\
443 --- END Input data record -------------------------------------------------\n",data));
444 }
445
446 while ((str = csv_lineparse(tmp, ",", "\"", line++))) {
447 tmp = NULL;
448 switch (line) {
449 case 1: /* latitude */
450 wpt_tmp->latitude = ppdb_decode_coord(str);
451 break;
452 case 2: /* longitude */
453 wpt_tmp->longitude = ppdb_decode_coord(str);
454 break;
455 case 3: /* altitude */
456 if (*str != '\0') {
457 CHECK_INP(1, sscanf(str, "%lf", &altfeet), "altitude", str);
458 if (altfeet != -9999) {
459 wpt_tmp->altitude = FEET_TO_METERS(altfeet);
460 }
461 }
462 break;
463 case 4: /* time and date (optional) */
464 memset(&tm, 0, sizeof(tm));
465 if (ppdb_decode_tm(str, &tm)) {
466 tm.tm_year -= 1900;
467 tm.tm_mon--;
468 wpt_tmp->SetCreationTime(mkgmtime(&tm));
469 }
470 break;
471 case 5: /* name */
472 if (*str != '\0') {
473 wpt_tmp->shortname = xstrdup(str);
474 }
475 break;
476 case 6: /* icon */
477 if (*str != '\0') {
478 wpt_tmp->icon_descr = str;
479 }
480 break;
481 case 7: /* notes */
482 if (*str != '\0') {
483 wpt_tmp->notes = xstrdup(str);
484 }
485 break;
486
487 }
488 }
489
490 /* Print the whole input record, should a warning be triggered.
491 * Use warning() here instead of DBG() to print the data record
492 * right after the warning is issued.
493 */
494 if (warn_ && (global_opts.debug_level > 1) && (global_opts.debug_level < 5)) {
495 warning("Faulty input data record : %s\n",data);
496 warn_ = 0;
497 }
498
499 if (head && isRoute) {
500 route_add_wpt(head, wpt_tmp);
501 } else if (head) {
502 track_add_wpt(head, wpt_tmp);
503 } else {
504 waypt_add(wpt_tmp);
505 }
506
507 }
508 return 0;
509 }
510
511 /* ============================================================================================
512 * &&& gobal callbacks &&&
513 * ----------------------------------------------------------------------------------------- */
514
ppdb_rd_init(const char * fname)515 static void ppdb_rd_init(const char *fname)
516 {
517 str_pool_init();
518 file_in = pdb_open(fname, MYNAME);
519 ct = 0;
520
521 if (opt_date) {
522 datefmt = convert_human_date_format(opt_date);
523 } else {
524 datefmt = NULL;
525 }
526 }
527
ppdb_rd_deinit(void)528 static void ppdb_rd_deinit(void)
529 {
530 pdb_close(file_in);
531 str_pool_deinit();
532 if (datefmt) {
533 xfree(datefmt);
534 }
535 }
536
ppdb_read(void)537 static void ppdb_read(void)
538 {
539 ppdb_appdata_t *info = NULL;
540 route_head *track_head, *route_head;
541 const char *descr = NULL;
542
543 if (file_in->creator != PPDB_MAGIC) { /* identify the database */
544 fatal(MYNAME ": Not a PathAway pdb file.\n");
545 }
546
547 if (file_in->version != 3) { /* Currently we support only version 3 */
548 fatal(MYNAME ": This file is from an untested version (%d) of PathAway and is unsupported.\n", file_in->version);
549 }
550
551 if ((file_in->appinfo_len > 0) && (file_in->appinfo != NULL)) {
552 info = (ppdb_appdata_t *) file_in->appinfo;
553 descr = info->vehicleStr;
554 }
555 switch (file_in->type) {
556 case PPDB_MAGIC_TRK:
557 ppdb_type = trkdata; /* as default */
558 if (info != NULL) {
559 switch (info->dataBaseSubType) {
560 case 0:
561 ppdb_type = trkdata;
562 break;
563 case 1:
564 ppdb_type = rtedata;
565 break;
566 default:
567 fatal(MYNAME": Invalid database subtype.\n");
568 }
569 }
570 break;
571
572 case PPDB_MAGIC_WPT:
573 ppdb_type = wptdata;
574 break;
575
576 default:
577 fatal(MYNAME ": It looks like a PathAway pdb, but has no gps magic.\n");
578 }
579
580 switch (ppdb_type) {
581 case trkdata:
582 track_head = route_head_alloc();
583 track_add_head(track_head);
584 track_head->rte_name = xstrdup(file_in->name);
585 ppdb_read_wpt(track_head, 0);
586 break;
587 case rtedata:
588 route_head = route_head_alloc();
589 route_add_head(route_head);
590 route_head->rte_name = xstrdup(file_in->name);
591 ppdb_read_wpt(route_head, 1);
592 break;
593 case wptdata:
594 case unknown_gpsdata:
595 ppdb_read_wpt(NULL, 0);
596 break;
597 case posndata:
598 fatal(MYNAME ": Realtime positioning not supported.\n");
599 break;
600 }
601 }
602
603 /* ============================================================================================
604 * PPDB: Write support
605 * -------------------------------------------------------------------------------------------*/
606
ppdb_wr_init(const char * fname)607 static void ppdb_wr_init(const char *fname)
608 {
609 int len;
610
611 fname_out = xstrdup(fname);
612 str_pool_init();
613 file_out = pdb_create(fname, MYNAME);
614 mkshort_handle = mkshort_new_handle();
615 ct = 0;
616 appinfo = NULL;
617
618 if (global_opts.synthesize_shortnames != 0) {
619 len = atoi(opt_snlen);
620 setshort_length(mkshort_handle, len);
621 setshort_mustupper(mkshort_handle, 1);
622 setshort_badchars(mkshort_handle, ",");
623 setshort_whitespace_ok(mkshort_handle, 0);
624 }
625 if (opt_date) {
626 char *c = convert_human_date_format(opt_date);
627 xasprintf(&datefmt, "%s %s", "%H%M%S", c);
628 xfree(c);
629 } else {
630 datefmt = xstrdup("%H%M%S %Y%m%d");
631 }
632 }
633
ppdb_wr_deinit(void)634 static void ppdb_wr_deinit(void)
635 {
636 mkshort_del_handle(&mkshort_handle);
637 pdb_close(file_out);
638 str_pool_deinit();
639 xfree(fname_out);
640 if (datefmt) {
641 xfree(datefmt);
642 }
643 if (appinfo) {
644 xfree(appinfo);
645 }
646 }
647
648 /*
649 * ppdb_write_wpt: callback for waypoint output
650 */
651
652 #define REC_SIZE 128
653
ppdb_write_wpt(const waypoint * wpt)654 static void ppdb_write_wpt(const waypoint *wpt)
655 {
656 char *buff, *tmp;
657 char latdir, longdir;
658 int len;
659 struct tm tm;
660
661 buff = (char *) xcalloc(REC_SIZE, 1);
662
663 if (wpt->latitude < 0) {
664 latdir = 'S';
665 } else {
666 latdir = 'N';
667 }
668 if (wpt->longitude < 0) {
669 longdir = 'W';
670 } else {
671 longdir = 'E';
672 }
673 /* 1 latitude,
674 2 longitude */
675
676 snprintf(buff, REC_SIZE, "%s,%s,",
677 ppdb_fmt_degrees(latdir, wpt->latitude),
678 ppdb_fmt_degrees(longdir, wpt->longitude)
679 );
680
681 len = REC_SIZE; /* we have coordinates in buff, now optional stuff */
682 /* 3 altitude */
683
684 if (fabs(wpt->altitude) < 9999.0) {
685 tmp = str_pool_get(32);
686 snprintf(tmp, 32, "%s", ppdb_fmt_float(METERS_TO_FEET(wpt->altitude)));
687 buff = ppdb_strcat(buff, tmp, NULL, &len);
688 }
689 buff = ppdb_strcat(buff, ",", NULL, &len);
690 /* 4 time, date */
691
692 if (wpt->creation_time.isValid()) {
693 tmp = str_pool_get(20);
694 const time_t tt = wpt->GetCreationTime().toTime_t();
695 tm = *gmtime(&tt);
696 strftime(tmp, 20, datefmt, &tm);
697 buff = ppdb_strcat(buff, tmp, NULL, &len);
698 }
699 buff = ppdb_strcat(buff, ",", NULL, &len);
700 /* 5 name */
701
702 if (global_opts.synthesize_shortnames != 0) {
703 tmp = mkshort_from_wpt(mkshort_handle, wpt);
704 DBG(("shortname %s from %s", tmp, wpt->shortname));
705 } else {
706 tmp = str_pool_getcpy(wpt->shortname, "");
707 while (strchr(tmp, ',') != NULL) {
708 *strchr(tmp, ',') = '.';
709 }
710 }
711 buff = ppdb_strcat(buff, tmp, "", &len);
712
713 buff = ppdb_strcat(buff, ",", NULL, &len);
714 /* 6 icon */
715
716 tmp = str_pool_getcpy(wpt->icon_descr.toUtf8().data(), opt_deficon); /* point icon or deficon from options */
717 buff = ppdb_strcat(buff, tmp, NULL, &len);
718 buff = ppdb_strcat(buff, ",", NULL, &len);
719 /* 7 description */
720
721 tmp = str_pool_getcpy(wpt->description, "");
722 if (strchr(tmp, ',') != NULL) {
723 buff = ppdb_strcat(buff, "\"", NULL, &len);
724 while (strchr(tmp, '"') != NULL) {
725 *strchr(tmp, '"') = '\'';
726 }
727 buff = ppdb_strcat(buff, tmp, NULL, &len);
728 buff = ppdb_strcat(buff, "\"", NULL, &len);
729 } else {
730 buff = ppdb_strcat(buff, tmp, "", &len);
731 }
732
733 len = strlen(buff) + 1;
734 pdb_write_rec(file_out, 0, 0, ct++, buff, len);
735
736 xfree(buff);
737 }
738
739 /*
740 * track and route write callbacks
741 */
742
ppdb_write(void)743 static void ppdb_write(void)
744 {
745
746 if (opt_dbname) {
747 strncpy(file_out->name, opt_dbname, PDB_DBNAMELEN);
748 }
749
750 file_out->attr = PDB_FLAG_BACKUP;
751 file_out->ctime = file_out->mtime = current_time().toTime_t() + 2082844800U;
752 file_out->creator = PPDB_MAGIC;
753 file_out->version = 3;
754
755 /* Waypoint target does use vehicleStr from appinfo block
756 * Actually, all 3 types have vehicle information.
757 * if (global_opts.objective != wptdata) / * Waypoint target do not need appinfo block * /
758 * {
759 */
760 appinfo = (ppdb_appdata_t *) xcalloc(1, sizeof(*appinfo));
761 file_out->appinfo = (void *)appinfo;
762 file_out->appinfo_len = PPDB_APPINFO_SIZE;
763 /* }
764 */
765 if (opt_dbicon != NULL) {
766 strncpy(appinfo->vehicleStr, opt_dbicon, VEHICLE_LEN);
767 }
768
769 switch (global_opts.objective) { /* Only one target is possible */
770 case wptdata:
771 case unknown_gpsdata:
772 if (opt_dbname == NULL) {
773 strncpy(file_out->name, "PathAway Waypoints", PDB_DBNAMELEN);
774 }
775 file_out->type = PPDB_MAGIC_WPT;
776 waypt_disp_all(ppdb_write_wpt);
777 break;
778 case trkdata:
779 if (opt_dbname == NULL) {
780 strncpy(file_out->name, "PathAway Track", PDB_DBNAMELEN);
781 }
782 file_out->type = PPDB_MAGIC_TRK;
783 appinfo->dataBaseSubType = 0;
784 track_disp_all(NULL, NULL, ppdb_write_wpt);
785 break;
786 case rtedata:
787 if (opt_dbname == NULL) {
788 strncpy(file_out->name, "PathAway Route", PDB_DBNAMELEN);
789 }
790 file_out->type = PPDB_MAGIC_TRK;
791 appinfo->dataBaseSubType = 1;
792 route_disp_all(NULL, NULL, ppdb_write_wpt);
793 break;
794 case posndata:
795 fatal(MYNAME ": Realtime positioning not supported.\n");
796 break;
797 }
798 }
799
800
801 ff_vecs_t ppdb_vecs = {
802 ff_type_file,
803 FF_CAP_RW_ALL,
804 ppdb_rd_init,
805 ppdb_wr_init,
806 ppdb_rd_deinit,
807 ppdb_wr_deinit,
808 ppdb_read,
809 ppdb_write,
810 NULL,
811 ppdb_args,
812 CET_CHARSET_ASCII, 0 /* CET-REVIEW */
813 };
814 #endif
815