diff options
author | Eric S. Raymond <esr@thyrsus.com> | 2009-03-18 15:46:17 +0000 |
---|---|---|
committer | Eric S. Raymond <esr@thyrsus.com> | 2009-03-18 15:46:17 +0000 |
commit | 728bf204eb7900b9c02dbaf4c32a754c8ff9ecaf (patch) | |
tree | b871a3c8b426f5464f0f042df360601a754ccd4b /libgps.c | |
parent | 90cec3a4b8a3b7b1f1871803d1ddbee3548632ff (diff) | |
download | gpsd-728bf204eb7900b9c02dbaf4c32a754c8ff9ecaf.tar.gz |
Attempt to cope with locales where the decimal separator is not dot.
Diffstat (limited to 'libgps.c')
-rw-r--r-- | libgps.c | 32 |
1 files changed, 30 insertions, 2 deletions
@@ -11,6 +11,7 @@ #include <pthread.h> /* pacifies OpenBSD's compiler */ #endif #include <math.h> +#include <locale.h> #include "gpsd_config.h" #include "gpsd.h" @@ -73,11 +74,23 @@ void gps_set_raw_hook(struct gps_data_t *gpsdata, /*@ -branchstate -usereleased @*/ static void gps_unpack(char *buf, struct gps_data_t *gpsdata) -/* unpack a daemon response into a status structure */ +/* unpack a gpsd response into a status structure, buf must be writeable */ { char *ns, *sp, *tp; int i; + /* + * Get the decimal separator for the current application locale. + * This looks thread-unsafe, but it's not. The key is that + * character assignment is atomic. + */ + static char decimal_point = '\0'; + if (decimal_point == '\0') { + struct lconv *locale_data = localeconv(); + if (locale_data != NULL && locale_data->decimal_point[0] != '.') + decimal_point = locale_data->decimal_point[0]; + } + for (ns = buf; ns; ns = strstr(ns+1, "GPSD")) { if (/*@i1@*/strncmp(ns, "GPSD", 4) == 0) { bool eol = false; @@ -90,7 +103,22 @@ static void gps_unpack(char *buf, struct gps_data_t *gpsdata) else *tp = '\0'; - /* note, there's a bit of kip logic after the switch */ + /* + * The daemon always emits the Anglo-American and SI + * decimal point. Hack these into whatever the + * application locale requires if it's not the same. + * This has to happen *after* we grab the next + * comma-delimited response, or we'll lose horribly + * in locales where the decimal separator is comma. + */ + if (decimal_point != '\0') { + char *cp; + for (cp = sp; cp < tp; cp++) + if (*cp == '.') + *cp = decimal_point; + } + + /* note, there's a bit of skip logic after the switch */ switch (*sp) { case 'A': |