]> git.street.me.uk Git - andy/viking.git/blob - src/gpspoint.c
Don't remove project name if one decides not to delete all layers.
[andy/viking.git] / src / gpspoint.c
1 /*
2  * viking -- GPS Data and Topo Analyzer, Explorer, and Manager
3  *
4  * Copyright (C) 2003-2005, Evan Battaglia <gtoevan@gmx.net>
5  * Copyright (C) 2012-2013, Rob Norris <rw_norris@hotmail.com>
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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  *
21  */
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25
26 #ifdef HAVE_MATH_H
27 #include <math.h>
28 #endif
29
30 #include "viking.h"
31
32 #include <ctype.h>
33 #ifdef HAVE_STRING_H
34 #include <string.h>
35 #endif
36
37 #include <stdlib.h>
38 /* strtod */
39
40 typedef struct {
41   FILE *f;
42   gboolean is_route;
43 } TP_write_info_type;
44
45 static void a_gpspoint_write_track ( const gpointer id, const VikTrack *t, FILE *f );
46 static void a_gpspoint_write_trackpoint ( VikTrackpoint *tp, TP_write_info_type *write_info );
47 static void a_gpspoint_write_waypoint ( const gpointer id, const VikWaypoint *wp, FILE *f );
48
49 /* outline for file gpspoint.c
50
51 reading file:
52
53 take a line.
54 get first tag, if not type, skip it.
55 if type, record type.  if waypoint list, etc move on. if track, make a new track, make it current track, add it, etc.
56 if waypoint, read on and store to the waypoint.
57 if trackpoint, make trackpoint, store to current track (error / skip if none)
58
59 */
60
61 /* Thanks to etrex-cache's gpsbabel's gpspoint.c for starting me off! */
62
63 static char line_buffer[2048];
64
65 #define GPSPOINT_TYPE_NONE 0
66 #define GPSPOINT_TYPE_WAYPOINT 1
67 #define GPSPOINT_TYPE_TRACKPOINT 2
68 #define GPSPOINT_TYPE_ROUTEPOINT 3
69 #define GPSPOINT_TYPE_TRACK 4
70 #define GPSPOINT_TYPE_ROUTE 5
71
72 static VikTrack *current_track; /* pointer to pointer to first GList */
73
74 static gint line_type = GPSPOINT_TYPE_NONE;
75 static struct LatLon line_latlon;
76 static gchar *line_name;
77 static gchar *line_comment;
78 static gchar *line_description;
79 static gchar *line_color;
80 static gint line_name_label = 0;
81 static gint line_dist_label = 0;
82 static gchar *line_image;
83 static gchar *line_symbol;
84 static gboolean line_newsegment = FALSE;
85 static gboolean line_has_timestamp = FALSE;
86 static time_t line_timestamp = 0;
87 static gdouble line_altitude = VIK_DEFAULT_ALTITUDE;
88 static gboolean line_visible = TRUE;
89
90 static gboolean line_extended = FALSE;
91 static gdouble line_speed = NAN;
92 static gdouble line_course = NAN;
93 static gint line_sat = 0;
94 static gint line_fix = 0;
95 /* other possible properties go here */
96
97
98 static void gpspoint_process_tag ( const gchar *tag, gint len );
99 static void gpspoint_process_key_and_value ( const gchar *key, gint key_len, const gchar *value, gint value_len );
100
101 static gchar *slashdup(const gchar *str)
102 {
103   guint16 len = strlen(str);
104   guint16 need_bs_count, i, j;
105   gchar *rv;
106   for ( i = 0, need_bs_count = 0; i < len; i++ )
107     if ( str[i] == '\\' || str[i] == '"' )
108       need_bs_count++;
109   rv = g_malloc ( (len+need_bs_count+1) * sizeof(gchar) );
110   for ( i = 0, j = 0; i < len; i++, j++ )
111   {
112     if ( str[i] == '\\' || str[i] == '"' )
113       rv[j++] = '\\';
114     rv[j] = str[i];
115   }
116   rv[j] = '\0';
117   return rv;
118 }
119
120 static gchar *deslashndup ( const gchar *str, guint16 len )
121 {
122   guint16 i,j, bs_count, new_len;
123   gboolean backslash = FALSE;
124   gchar *rv;
125
126   if ( len < 1 )
127     return NULL;
128
129   for ( i = 0, bs_count = 0; i < len; i++ )
130    if ( str[i] == '\\' )
131    {
132      bs_count++;
133      i++;
134    }
135
136   if ( str[i-1] == '\\' && (len == 1 || str[i-2] != '\\') )
137     bs_count--;
138
139   new_len = len - bs_count;
140   rv = g_malloc ( (new_len+1) * sizeof(gchar) );
141   for ( i = 0, j = 0; i < len && j < new_len; i++ )
142     if ( str[i] == '\\' && !backslash )
143       backslash = TRUE;
144     else
145     {
146       rv[j++] = str[i];
147       backslash = FALSE;
148     }
149
150   rv[new_len] = '\0';
151   return rv;
152 }
153
154 /*
155  * Returns whether file read was a success
156  * No obvious way to test for a 'gpspoint' file,
157  *  thus set a flag if any actual tag found during processing of the file
158  */
159 gboolean a_gpspoint_read_file(VikTrwLayer *trw, FILE *f, const gchar *dirpath ) {
160   VikCoordMode coord_mode = vik_trw_layer_get_coord_mode ( trw );
161   gchar *tag_start, *tag_end;
162   g_assert ( f != NULL && trw != NULL );
163   line_type = 0;
164   line_timestamp = 0;
165   line_newsegment = FALSE;
166   line_image = NULL;
167   line_symbol = NULL;
168   current_track = NULL;
169   gboolean have_read_something = FALSE;
170
171   while (fgets(line_buffer, 2048, f))
172   {
173     gboolean inside_quote = 0;
174     gboolean backslash = 0;
175
176     line_buffer[strlen(line_buffer)-1] = '\0'; /* chop off newline */
177
178     /* for gpspoint files wrapped inside */
179     if ( strlen(line_buffer) >= 13 && strncmp ( line_buffer, "~EndLayerData", 13 ) == 0 ) {
180       // Even just a blank TRW is ok when in a .vik file
181       have_read_something = TRUE;
182       break;
183     }
184
185     /* each line: nullify stuff, make thing if nes, free name if ness */
186     tag_start = line_buffer;
187     for (;;)
188     {
189       /* my addition: find first non-whitespace character. if the null, skip line. */
190       while (*tag_start != '\0' && isspace(*tag_start))
191         tag_start++;
192       if (*tag_start == '\0')
193         break;
194
195       if (*tag_start == '#')
196         break;
197
198       tag_end = tag_start;
199         if (*tag_end == '"')
200           inside_quote = !inside_quote;
201       while (*tag_end != '\0' && (!isspace(*tag_end) || inside_quote)) {
202         tag_end++;
203         if (*tag_end == '\\' && !backslash)
204           backslash = TRUE;
205         else if (backslash)
206           backslash = FALSE;
207         else if (*tag_end == '"')
208           inside_quote = !inside_quote;
209       }
210
211       // Won't have super massively long strings, so potential truncation in cast to gint is acceptable.
212       gint len = (gint)(tag_end - tag_start);
213       gpspoint_process_tag ( tag_start, len );
214
215       if (*tag_end == '\0' )
216         break;
217       else
218         tag_start = tag_end+1;
219     }
220     if (line_type == GPSPOINT_TYPE_WAYPOINT && line_name)
221     {
222       have_read_something = TRUE;
223       VikWaypoint *wp = vik_waypoint_new();
224       wp->visible = line_visible;
225       wp->altitude = line_altitude;
226       wp->has_timestamp = line_has_timestamp;
227       wp->timestamp = line_timestamp;
228
229       vik_coord_load_from_latlon ( &(wp->coord), coord_mode, &line_latlon );
230
231       vik_trw_layer_filein_add_waypoint ( trw, line_name, wp );
232       g_free ( line_name );
233       line_name = NULL;
234
235       if ( line_comment )
236         vik_waypoint_set_comment ( wp, line_comment );
237
238       if ( line_description )
239         vik_waypoint_set_description ( wp, line_description );
240
241       if ( line_image ) {
242         // Ensure the filename is absolute
243         if ( g_path_is_absolute ( line_image ) )
244           vik_waypoint_set_image ( wp, line_image );
245         else {
246           // Otherwise create the absolute filename from the directory of the .vik file & and the relative filename
247           gchar *full = g_strconcat(dirpath, G_DIR_SEPARATOR_S, line_image, NULL);
248           gchar *absolute = file_realpath_dup ( full ); // resolved into the canonical name
249           vik_waypoint_set_image ( wp, absolute );
250           g_free ( absolute );
251           g_free ( full );
252         }
253       }
254
255       if ( line_symbol )
256         vik_waypoint_set_symbol ( wp, line_symbol );
257     }
258     else if ((line_type == GPSPOINT_TYPE_TRACK || line_type == GPSPOINT_TYPE_ROUTE) && line_name)
259     {
260       have_read_something = TRUE;
261       VikTrack *pl = vik_track_new();
262       // NB don't set defaults here as all properties are stored in the GPS_POINT format
263       //vik_track_set_defaults ( pl );
264
265       /* Thanks to Peter Jones for this Fix */
266       if (!line_name) line_name = g_strdup("UNK");
267
268       pl->visible = line_visible;
269       pl->is_route = (line_type == GPSPOINT_TYPE_ROUTE);
270
271       if ( line_comment )
272         vik_track_set_comment ( pl, line_comment );
273
274       if ( line_description )
275         vik_track_set_description ( pl, line_description );
276
277       if ( line_color )
278       {
279         if ( gdk_color_parse ( line_color, &(pl->color) ) )
280         pl->has_color = TRUE;
281       }
282
283       pl->draw_name_mode = line_name_label;
284       pl->max_number_dist_labels = line_dist_label;
285
286       pl->trackpoints = NULL;
287       vik_trw_layer_filein_add_track ( trw, line_name, pl );
288       g_free ( line_name );
289       line_name = NULL;
290
291       current_track = pl;
292     }
293     else if ((line_type == GPSPOINT_TYPE_TRACKPOINT || line_type == GPSPOINT_TYPE_ROUTEPOINT) && current_track)
294     {
295       have_read_something = TRUE;
296       VikTrackpoint *tp = vik_trackpoint_new();
297       vik_coord_load_from_latlon ( &(tp->coord), coord_mode, &line_latlon );
298       tp->newsegment = line_newsegment;
299       tp->has_timestamp = line_has_timestamp;
300       tp->timestamp = line_timestamp;
301       tp->altitude = line_altitude;
302       vik_trackpoint_set_name ( tp, line_name );
303       if (line_extended) {
304         tp->speed = line_speed;
305         tp->course = line_course;
306         tp->nsats = line_sat;
307         tp->fix_mode = line_fix;
308       }
309       current_track->trackpoints = g_list_append ( current_track->trackpoints, tp );
310     }
311
312     if (line_name) 
313       g_free ( line_name );
314     line_name = NULL;
315     if (line_comment)
316       g_free ( line_comment );
317     if (line_description)
318       g_free ( line_description );
319     if (line_color)
320       g_free ( line_color );
321     if (line_image)
322       g_free ( line_image );
323     if (line_symbol)
324       g_free ( line_symbol );
325     line_comment = NULL;
326     line_description = NULL;
327     line_color = NULL;
328     line_image = NULL;
329     line_symbol = NULL;
330     line_type = GPSPOINT_TYPE_NONE;
331     line_newsegment = FALSE;
332     line_has_timestamp = FALSE;
333     line_timestamp = 0;
334     line_altitude = VIK_DEFAULT_ALTITUDE;
335     line_visible = TRUE;
336     line_symbol = NULL;
337
338     line_extended = FALSE;
339     line_speed = NAN;
340     line_course = NAN;
341     line_sat = 0;
342     line_fix = 0;
343     line_name_label = 0;
344     line_dist_label = 0;
345   }
346
347   return have_read_something;
348 }
349
350 /* Tag will be of a few defined forms:
351    ^[:alpha:]*=".*"$
352    ^[:alpha:]*=.*$
353
354    <invalid tag>
355
356 So we must determine end of tag name, start of value, end of value.
357 */
358 static void gpspoint_process_tag ( const gchar *tag, gint len )
359 {
360   const gchar *key_end, *value_start, *value_end;
361
362   /* Searching for key end */
363   key_end = tag;
364
365   while (++key_end - tag < len)
366     if (*key_end == '=')
367       break;
368
369   if (key_end - tag == len)
370     return; /* no good */
371
372   if (key_end - tag == len + 1)
373     value_start = value_end = 0; /* size = 0 */
374   else
375   {
376     value_start = key_end + 1; /* equal_sign plus one */
377
378     if (*value_start == '"')
379     {
380       value_start++;
381       if (*value_start == '"')
382         value_start = value_end = 0; /* size = 0 */
383       else
384       {
385         if (*(tag+len-1) == '"')
386         value_end = tag + len - 1;
387         else
388           return; /* bogus */
389       }
390     }
391     else
392       value_end = tag + len; /* value start really IS value start. */
393
394     gpspoint_process_key_and_value(tag, key_end - tag, value_start, value_end - value_start);
395   }
396 }
397
398 /*
399 value = NULL for none
400 */
401 static void gpspoint_process_key_and_value ( const gchar *key, gint key_len, const gchar *value, gint value_len )
402 {
403   if (key_len == 4 && strncasecmp( key, "type", key_len ) == 0 )
404   {
405     if (value == NULL)
406       line_type = GPSPOINT_TYPE_NONE;
407     else if (value_len == 5 && strncasecmp( value, "track", value_len ) == 0 )
408       line_type = GPSPOINT_TYPE_TRACK;
409     else if (value_len == 10 && strncasecmp( value, "trackpoint", value_len ) == 0 )
410       line_type = GPSPOINT_TYPE_TRACKPOINT;
411     else if (value_len == 8 && strncasecmp( value, "waypoint", value_len ) == 0 )
412       line_type = GPSPOINT_TYPE_WAYPOINT;
413     else if (value_len == 5 && strncasecmp( value, "route", value_len ) == 0 )
414       line_type = GPSPOINT_TYPE_ROUTE;
415     else if (value_len == 10 && strncasecmp( value, "routepoint", value_len ) == 0 )
416       line_type = GPSPOINT_TYPE_ROUTEPOINT;
417     else
418       /* all others are ignored */
419       line_type = GPSPOINT_TYPE_NONE;
420   }
421   else if (key_len == 4 && strncasecmp( key, "name", key_len ) == 0 && value != NULL)
422   {
423     if (line_name == NULL)
424     {
425       line_name = deslashndup ( value, value_len );
426     }
427   }
428   else if (key_len == 7 && strncasecmp( key, "comment", key_len ) == 0 && value != NULL)
429   {
430     if (line_comment == NULL)
431       line_comment = deslashndup ( value, value_len );
432   }
433   else if (key_len == 11 && strncasecmp( key, "description", key_len ) == 0 && value != NULL)
434   {
435     if (line_description == NULL)
436       line_description = deslashndup ( value, value_len );
437   }
438   else if (key_len == 5 && strncasecmp( key, "color", key_len ) == 0 && value != NULL)
439   {
440     if (line_color == NULL)
441       line_color = deslashndup ( value, value_len );
442   }
443   else if (key_len == 14 && strncasecmp( key, "draw_name_mode", key_len ) == 0 && value != NULL)
444   {
445     line_name_label = atoi(value);
446   }
447   else if (key_len == 18 && strncasecmp( key, "number_dist_labels", key_len ) == 0 && value != NULL)
448   {
449     line_dist_label = atoi(value);
450   }
451   else if (key_len == 5 && strncasecmp( key, "image", key_len ) == 0 && value != NULL)
452   {
453     if (line_image == NULL)
454       line_image = deslashndup ( value, value_len );
455   }
456   else if (key_len == 8 && strncasecmp( key, "latitude", key_len ) == 0 && value != NULL)
457   {
458     line_latlon.lat = g_ascii_strtod(value, NULL);
459   }
460   else if (key_len == 9 && strncasecmp( key, "longitude", key_len ) == 0 && value != NULL)
461   {
462     line_latlon.lon = g_ascii_strtod(value, NULL);
463   }
464   else if (key_len == 8 && strncasecmp( key, "altitude", key_len ) == 0 && value != NULL)
465   {
466     line_altitude = g_ascii_strtod(value, NULL);
467   }
468   else if (key_len == 7 && strncasecmp( key, "visible", key_len ) == 0 && value != NULL && value[0] != 'y' && value[0] != 'Y' && value[0] != 't' && value[0] != 'T')
469   {
470     line_visible = FALSE;
471   }
472   else if (key_len == 6 && strncasecmp( key, "symbol", key_len ) == 0 && value != NULL)
473   {
474     line_symbol = g_strndup ( value, value_len );
475   }
476   else if (key_len == 8 && strncasecmp( key, "unixtime", key_len ) == 0 && value != NULL)
477   {
478     line_timestamp = g_ascii_strtod(value, NULL);
479     if ( line_timestamp != 0x80000000 )
480       line_has_timestamp = TRUE;
481   }
482   else if (key_len == 10 && strncasecmp( key, "newsegment", key_len ) == 0 && value != NULL)
483   {
484     line_newsegment = TRUE;
485   }
486   else if (key_len == 8 && strncasecmp( key, "extended", key_len ) == 0 && value != NULL)
487   {
488     line_extended = TRUE;
489   }
490   else if (key_len == 5 && strncasecmp( key, "speed", key_len ) == 0 && value != NULL)
491   {
492     line_speed = g_ascii_strtod(value, NULL);
493   }
494   else if (key_len == 6 && strncasecmp( key, "course", key_len ) == 0 && value != NULL)
495   {
496     line_course = g_ascii_strtod(value, NULL);
497   }
498   else if (key_len == 3 && strncasecmp( key, "sat", key_len ) == 0 && value != NULL)
499   {
500     line_sat = atoi(value);
501   }
502   else if (key_len == 3 && strncasecmp( key, "fix", key_len ) == 0 && value != NULL)
503   {
504     line_fix = atoi(value);
505   }
506 }
507
508 static void a_gpspoint_write_waypoint ( const gpointer id, const VikWaypoint *wp, FILE *f )
509 {
510   static struct LatLon ll;
511   gchar *s_lat, *s_lon;
512   // Sanity clauses
513   if ( !wp )
514     return;
515   if ( !(wp->name) )
516     return;
517
518   vik_coord_to_latlon ( &(wp->coord), &ll );
519   s_lat = a_coords_dtostr(ll.lat);
520   s_lon = a_coords_dtostr(ll.lon);
521   gchar *tmp_name = slashdup(wp->name);
522   fprintf ( f, "type=\"waypoint\" latitude=\"%s\" longitude=\"%s\" name=\"%s\"", s_lat, s_lon, tmp_name );
523   g_free ( tmp_name );
524   g_free ( s_lat ); 
525   g_free ( s_lon );
526
527   if ( wp->altitude != VIK_DEFAULT_ALTITUDE ) {
528     gchar *s_alt = a_coords_dtostr(wp->altitude);
529     fprintf ( f, " altitude=\"%s\"", s_alt );
530     g_free(s_alt);
531   }
532   if ( wp->has_timestamp )
533     fprintf ( f, " unixtime=\"%ld\"", wp->timestamp );
534   if ( wp->comment )
535   {
536     gchar *tmp_comment = slashdup(wp->comment);
537     fprintf ( f, " comment=\"%s\"", tmp_comment );
538     g_free ( tmp_comment );
539   }
540   if ( wp->description )
541   {
542     gchar *tmp_description = slashdup(wp->description);
543     fprintf ( f, " description=\"%s\"", tmp_description );
544     g_free ( tmp_description );
545   }
546   if ( wp->image )
547   {
548     gchar *tmp_image = NULL;
549     gchar *cwd = NULL;
550     if ( a_vik_get_file_ref_format() == VIK_FILE_REF_FORMAT_RELATIVE ) {
551       cwd = g_get_current_dir();
552       if ( cwd )
553         tmp_image = g_strdup ( file_GetRelativeFilename ( cwd, wp->image ) );
554     }
555
556     // if cwd not available - use image filename as is
557     // this should be an absolute path as set in thumbnails
558     if ( !cwd )
559       tmp_image = slashdup(wp->image);
560
561     if ( tmp_image )
562       fprintf ( f, " image=\"%s\"", tmp_image );
563
564     g_free ( cwd );
565     g_free ( tmp_image );
566   }
567   if ( wp->symbol )
568   {
569     // Due to changes in garminsymbols - the symbol name is now in Title Case
570     // However to keep newly generated .vik files better compatible with older Viking versions
571     //   The symbol names will always be lowercase
572     gchar *tmp_symbol = g_utf8_strdown(wp->symbol, -1);
573     fprintf ( f, " symbol=\"%s\"", tmp_symbol );
574     g_free ( tmp_symbol );
575   }
576   if ( ! wp->visible )
577     fprintf ( f, " visible=\"n\"" );
578   fprintf ( f, "\n" );
579 }
580
581 static void a_gpspoint_write_trackpoint ( VikTrackpoint *tp, TP_write_info_type *write_info )
582 {
583   static struct LatLon ll;
584   gchar *s_lat, *s_lon;
585   vik_coord_to_latlon ( &(tp->coord), &ll );
586
587   FILE *f = write_info->f;
588
589   /* TODO: modify a_coords_dtostr() to accept (optional) buffer
590    * instead of doing malloc/free everytime */
591   s_lat = a_coords_dtostr(ll.lat);
592   s_lon = a_coords_dtostr(ll.lon);
593   fprintf ( f, "type=\"%spoint\" latitude=\"%s\" longitude=\"%s\"", write_info->is_route ? "route" : "track", s_lat, s_lon );
594   g_free ( s_lat ); 
595   g_free ( s_lon );
596
597   if ( tp->name ) {
598     gchar *name = slashdup(tp->name);
599     fprintf ( f, " name=\"%s\"", name );
600     g_free(name);
601   }
602
603   if ( tp->altitude != VIK_DEFAULT_ALTITUDE ) {
604     gchar *s_alt = a_coords_dtostr(tp->altitude);
605     fprintf ( f, " altitude=\"%s\"", s_alt );
606     g_free(s_alt);
607   }
608   if ( tp->has_timestamp )
609     fprintf ( f, " unixtime=\"%ld\"", tp->timestamp );
610   if ( tp->newsegment )
611     fprintf ( f, " newsegment=\"yes\"" );
612
613   if (!isnan(tp->speed) || !isnan(tp->course) || tp->nsats > 0) {
614     fprintf ( f, " extended=\"yes\"" );
615     if (!isnan(tp->speed)) {
616       gchar *s_speed = a_coords_dtostr(tp->speed);
617       fprintf ( f, " speed=\"%s\"", s_speed );
618       g_free(s_speed);
619     }
620     if (!isnan(tp->course)) {
621       gchar *s_course = a_coords_dtostr(tp->course);
622       fprintf ( f, " course=\"%s\"", s_course );
623       g_free(s_course);
624     }
625     if (tp->nsats > 0)
626       fprintf ( f, " sat=\"%d\"", tp->nsats );
627     if (tp->fix_mode > 0)
628       fprintf ( f, " fix=\"%d\"", tp->fix_mode );
629   }
630   fprintf ( f, "\n" );
631 }
632
633
634 static void a_gpspoint_write_track ( const gpointer id, const VikTrack *trk, FILE *f )
635 {
636   // Sanity clauses
637   if ( !trk )
638     return;
639   if ( !(trk->name) )
640     return;
641
642   gchar *tmp_name = slashdup(trk->name);
643   fprintf ( f, "type=\"%s\" name=\"%s\"", trk->is_route ? "route" : "track", tmp_name );
644   g_free ( tmp_name );
645
646   if ( trk->comment ) {
647     gchar *tmp = slashdup(trk->comment);
648     fprintf ( f, " comment=\"%s\"", tmp );
649     g_free ( tmp );
650   }
651
652   if ( trk->description ) {
653     gchar *tmp = slashdup(trk->description);
654     fprintf ( f, " description=\"%s\"", tmp );
655     g_free ( tmp );
656   }
657
658   if ( trk->has_color ) {
659     fprintf ( f, " color=#%.2x%.2x%.2x", (int)(trk->color.red/256),(int)(trk->color.green/256),(int)(trk->color.blue/256));
660   }
661
662   if ( trk->draw_name_mode > 0 )
663     fprintf ( f, " draw_name_mode=\"%d\"", trk->draw_name_mode );
664
665   if ( trk->max_number_dist_labels > 0 )
666     fprintf ( f, " number_dist_labels=\"%d\"", trk->max_number_dist_labels );
667
668   if ( ! trk->visible ) {
669     fprintf ( f, " visible=\"n\"" );
670   }
671   fprintf ( f, "\n" );
672
673   TP_write_info_type tp_write_info = { f, trk->is_route };
674   g_list_foreach ( trk->trackpoints, (GFunc) a_gpspoint_write_trackpoint, &tp_write_info );
675   fprintf ( f, "type=\"%send\"\n", trk->is_route ? "route" : "track" );
676 }
677
678 void a_gpspoint_write_file ( VikTrwLayer *trw, FILE *f )
679 {
680   GHashTable *tracks = vik_trw_layer_get_tracks ( trw );
681   GHashTable *routes = vik_trw_layer_get_routes ( trw );
682   GHashTable *waypoints = vik_trw_layer_get_waypoints ( trw );
683
684   fprintf ( f, "type=\"waypointlist\"\n" );
685   g_hash_table_foreach ( waypoints, (GHFunc) a_gpspoint_write_waypoint, f );
686   fprintf ( f, "type=\"waypointlistend\"\n" );
687   g_hash_table_foreach ( tracks, (GHFunc) a_gpspoint_write_track, f );
688   g_hash_table_foreach ( routes, (GHFunc) a_gpspoint_write_track, f );
689 }