#define _XOPEN_SOURCE /* glibc2 needs this */
+#include "gpx.h"
#include "viking.h"
#include <expat.h>
#include <string.h>
#include <glib.h>
#include <math.h>
-#define GPX_TIME_FORMAT "%Y-%m-%dT%H:%M:%SZ"
-
typedef enum {
tt_unknown = 0,
const char *tag_name; /* xpath-ish tag name */
} tag_mapping;
+typedef struct {
+ GpxWritingOptions *options;
+ FILE *file;
+} GpxWritingContext;
+
/*
* xpath(ish) mappings between full tag paths and internal identifers.
* These appear in the order they appear in the GPX specification.
static void gpx_end(VikTrwLayer *vtl, const char *el)
{
- static struct tm tm;
+ static GTimeVal tp_time;
+
g_string_truncate ( xpath, xpath->len - strlen(el) - 1 );
switch ( current_tag ) {
break;
case tt_trk_trkseg_trkpt_time:
-
- if ( strptime(c_cdata->str, GPX_TIME_FORMAT, &tm) != c_cdata->str ) { /* it read at least one char */
- c_tp->timestamp = mktime(&tm);
+ if ( g_time_val_from_iso8601(c_cdata->str, &tp_time) ) {
+ c_tp->timestamp = tp_time.tv_sec;
c_tp->has_timestamp = TRUE;
}
g_string_erase ( c_cdata, 0, -1 );
/* export GPX */
-static void gpx_write_waypoint ( const gchar *name, VikWaypoint *wp, FILE *f )
+static void gpx_write_waypoint ( const gchar *name, VikWaypoint *wp, GpxWritingContext *context )
{
+ FILE *f = context->file;
static struct LatLon ll;
gchar *s_lat,*s_lon;
gchar *tmp;
fprintf ( f, "</wpt>\n" );
}
-static void gpx_write_trackpoint ( VikTrackpoint *tp, FILE *f )
+static void gpx_write_trackpoint ( VikTrackpoint *tp, GpxWritingContext *context )
{
+ FILE *f = context->file;
static struct LatLon ll;
gchar *s_lat,*s_lon, *s_alt;
- static gchar time_buf[30];
+ gchar *time_iso8601;
vik_coord_to_latlon ( &(tp->coord), &ll );
if ( tp->newsegment )
s_lat = a_coords_dtostr( ll.lat );
s_lon = a_coords_dtostr( ll.lon );
fprintf ( f, " <trkpt lat=\"%s\" lon=\"%s\">\n", s_lat, s_lon );
- g_free ( s_lat );
- g_free ( s_lon );
+ g_free ( s_lat ); s_lat = NULL;
+ g_free ( s_lon ); s_lon = NULL;
+ s_alt = NULL;
if ( tp->altitude != VIK_DEFAULT_ALTITUDE )
{
s_alt = a_coords_dtostr ( tp->altitude );
}
- else /* Modified to always include altitude, needed for OSM export */
+ else if ( context->options != NULL && context->options->force_ele )
{
s_alt = a_coords_dtostr ( 0 );
}
- fprintf ( f, " <ele>%s</ele>\n", s_alt );
- g_free ( s_alt );
+ if (s_alt != NULL)
+ fprintf ( f, " <ele>%s</ele>\n", s_alt );
+ g_free ( s_alt ); s_alt = NULL;
+ time_iso8601 = NULL;
if ( tp->has_timestamp ) {
- time_buf [ strftime ( time_buf, sizeof(time_buf)-1, GPX_TIME_FORMAT, localtime(&(tp->timestamp)) ) ] = '\0';
+ GTimeVal timestamp;
+ timestamp.tv_sec = tp->timestamp;
+ timestamp.tv_usec = 0;
+
+ time_iso8601 = g_time_val_to_iso8601 ( ×tamp );
}
- else /* Modified to always include time, needed for OSM export */
+ else if ( context->options != NULL && context->options->force_time )
{
- time_t rawtime;
- time ( &rawtime );
+ GTimeVal current;
+ g_get_current_time ( ¤t );
- time_buf [strftime ( time_buf, sizeof(time_buf)-1, GPX_TIME_FORMAT, localtime(&rawtime)) ] ='\0';
+ time_iso8601 = g_time_val_to_iso8601 ( ¤t );
}
- fprintf ( f, " <time>%s</time>\n", time_buf );
+ if ( time_iso8601 != NULL )
+ fprintf ( f, " <time>%s</time>\n", time_iso8601 );
+ g_free(time_iso8601);
+ time_iso8601 = NULL;
if (tp->extended && (tp->fix_mode >= VIK_GPS_MODE_2D)) {
if (!isnan(tp->course)) {
}
-static void gpx_write_track ( const gchar *name, VikTrack *t, FILE *f )
+static void gpx_write_track ( const gchar *name, VikTrack *t, GpxWritingContext *context )
{
+ FILE *f = context->file;
gchar *tmp;
gboolean first_tp_is_newsegment = FALSE; /* must temporarily make it not so, but we want to restore state. not that it matters. */
if ( t->trackpoints && t->trackpoints->data ) {
first_tp_is_newsegment = VIK_TRACKPOINT(t->trackpoints->data)->newsegment;
VIK_TRACKPOINT(t->trackpoints->data)->newsegment = FALSE; /* so we won't write </trkseg><trkseg> already */
- g_list_foreach ( t->trackpoints, (GFunc) gpx_write_trackpoint, f );
+ g_list_foreach ( t->trackpoints, (GFunc) gpx_write_trackpoint, context );
VIK_TRACKPOINT(t->trackpoints->data)->newsegment = first_tp_is_newsegment; /* restore state */
}
void a_gpx_write_file( VikTrwLayer *vtl, FILE *f )
{
+ a_gpx_write_file_options(NULL, vtl, f);
+}
+
+void a_gpx_write_file_options ( GpxWritingOptions *options, VikTrwLayer *vtl, FILE *f )
+{
+ GpxWritingContext context = { options, f };
int i;
gpx_write_header ( f );
+
gpx_gather_waypoints_passalong_t passalong;
passalong.n_wps = g_hash_table_size ( vik_trw_layer_get_waypoints ( vtl ) );
passalong.i = 0;
/* gather waypoints in a list, then sort */
qsort(passalong.wps, passalong.n_wps, sizeof(gpx_waypoint_and_name), gpx_waypoint_and_name_compar);
for ( i = 0; i < passalong.n_wps; i++ )
- gpx_write_waypoint ( passalong.wps[i].name, passalong.wps[i].wp, f);
+ gpx_write_waypoint ( passalong.wps[i].name, passalong.wps[i].wp, &context);
g_free ( passalong.wps );
- g_hash_table_foreach ( vik_trw_layer_get_tracks ( vtl ), (GHFunc) gpx_write_track, f );
+ g_hash_table_foreach ( vik_trw_layer_get_tracks ( vtl ), (GHFunc) gpx_write_track, &context );
gpx_write_footer ( f );
}
void a_gpx_write_track_file ( const gchar *name, VikTrack *t, FILE *f )
{
+ a_gpx_write_track_file_options ( NULL, name, t, f );
+}
+
+void a_gpx_write_track_file_options ( GpxWritingOptions *options, const gchar *name, VikTrack *t, FILE *f )
+{
+ GpxWritingContext context = {options, f};
gpx_write_header ( f );
- gpx_write_track ( name, t, f );
+ gpx_write_track ( name, t, &context );
gpx_write_footer ( f );
}