"Initial commit to Gerrit"
[profile/ivi/gpsd.git] / gpsdclient.c
1 /*
2  * gpsdclient.c -- support functions for GPSD clients
3  *
4  * This file is Copyright (c) 2010 by the GPSD project
5  * BSD terms apply: see the file COPYING in the distribution root for details.
6  */
7 #include <sys/time.h>
8 #include <stdio.h>
9 #ifndef S_SPLINT_S
10 #include <unistd.h>
11 #endif /* S_SPLINT_S */
12 #include <stdlib.h>
13 #include <string.h>
14 #include <errno.h>
15 #include <stdarg.h>
16 #include <math.h>
17 #include <assert.h>
18
19 #include "gpsd_config.h"
20 #include "gps.h"
21 #include "gpsdclient.h"
22
23 #ifdef HAVE_SETLOCALE
24 #include <locale.h>
25 #endif
26
27 /* convert double degrees to a static string and return a pointer to it
28  *
29  * deg_str_type:
30  *      deg_dd     : return DD.dddddd
31  *      deg_ddmm   : return DD MM.mmmm'
32  *      deg_ddmmss : return DD MM' SS.sss"
33  *
34  */
35 /*@observer@*/ char *deg_to_str(enum deg_str_type type, double f)
36 {
37     static char str[40];
38     int dsec, sec, deg, min;
39     long frac_deg;
40     double fdsec, fsec, fdeg, fmin;
41
42     if (f < 0 || f > 360) {
43         (void)strlcpy(str, "nan", 40);
44         return str;
45     }
46
47     fmin = modf(f, &fdeg);
48     deg = (int)fdeg;
49     frac_deg = (long)(fmin * 1000000);
50
51     if (deg_dd == type) {
52         /* DD.dddddd */
53         (void)snprintf(str, sizeof(str), "%3d.%06ld", deg, frac_deg);
54         return str;
55     }
56     fsec = modf(fmin * 60, &fmin);
57     min = (int)fmin;
58     sec = (int)(fsec * 10000.0);
59
60     if (deg_ddmm == type) {
61         /* DD MM.mmmm */
62         (void)snprintf(str, sizeof(str), "%3d %02d.%04d'", deg, min, sec);
63         return str;
64     }
65     /* else DD MM SS.sss */
66     fdsec = modf(fsec * 60, &fsec);
67     sec = (int)fsec;
68     dsec = (int)(fdsec * 1000.0);
69     (void)snprintf(str, sizeof(str), "%3d %02d' %02d.%03d\"", deg, min, sec,
70                    dsec);
71
72     return str;
73 }
74
75 /* 
76  * check the environment to determine proper GPS units
77  *
78  * clients should only call this if no user preference is specified on 
79  * the command line or via X resources.
80  *
81  * return imperial    - Use miles/feet
82  *        nautical    - Use knots/feet
83  *        metric      - Use km/meters
84  *        unspecified - use compiled default
85  * 
86  * In order check these environment vars:
87  *    GPSD_UNITS one of: 
88  *              imperial   = miles/feet
89  *              nautical   = knots/feet
90  *              metric     = km/meters
91  *    LC_MEASUREMENT
92  *              en_US      = miles/feet
93  *              C          = miles/feet
94  *              POSIX      = miles/feet
95  *              [other]    = km/meters
96  *    LANG
97  *              en_US      = miles/feet
98  *              C          = miles/feet
99  *              POSIX      = miles/feet
100  *              [other]    = km/meters
101  *
102  * if none found then return compiled in default
103  */
104 enum unit gpsd_units(void)
105 {
106     char *envu = NULL;
107
108 #ifdef HAVE_SETLOCALE
109     (void)setlocale(LC_NUMERIC, "C");
110 #endif
111     if ((envu = getenv("GPSD_UNITS")) != NULL && *envu != '\0') {
112         if (0 == strcasecmp(envu, "imperial")) {
113             return imperial;
114         }
115         if (0 == strcasecmp(envu, "nautical")) {
116             return nautical;
117         }
118         if (0 == strcasecmp(envu, "metric")) {
119             return metric;
120         }
121         /* unrecognized, ignore it */
122     }
123     if (((envu = getenv("LC_MEASUREMENT")) != NULL && *envu != '\0')
124         || ((envu = getenv("LANG")) != NULL && *envu != '\0')) {
125         if (strncasecmp(envu, "en_US", 5) == 0
126             || strcasecmp(envu, "C") == 0 || strcasecmp(envu, "POSIX") == 0) {
127             return imperial;
128         }
129         /* Other, must be metric */
130         return metric;
131     }
132     /* TODO: allow a compile time default here */
133     return unspecified;
134 }
135
136 /*@ -observertrans -statictrans -mustfreeonly -branchstate -kepttrans @*/
137 void gpsd_source_spec(const char *arg, struct fixsource_t *source)
138 /* standard parsing of a GPS data source spec */
139 {
140     source->server = "localhost";
141     source->port = DEFAULT_GPSD_PORT;
142     source->device = NULL;
143
144     /*@-usedef@ Sigh, splint is buggy */
145     if (arg != NULL) {
146         char *colon1, *skipto, *rbrk;
147         source->spec = strdup(arg);
148         assert(source->spec != NULL);
149
150         skipto = source->spec;
151         if (*skipto == '[' && (rbrk = strchr(skipto, ']')) != NULL) {
152             skipto = rbrk;
153         }
154         colon1 = strchr(skipto, ':');
155
156         if (colon1 != NULL) {
157             char *colon2;
158             *colon1 = '\0';
159             if (colon1 != source->spec) {
160                 source->server = source->spec;
161             }
162             source->port = colon1 + 1;
163             colon2 = strchr(source->port, ':');
164             if (colon2 != NULL) {
165                 *colon2 = '\0';
166                 source->device = colon2 + 1;
167             }
168         } else if (strchr(source->spec, '/') != NULL) {
169             source->device = source->spec;
170         } else {
171             source->server = source->spec;
172         }
173     }
174
175     /*@-modobserver@*/
176     if (*source->server == '[') {
177         char *rbrk = strchr(source->server, ']');
178         ++source->server;
179         if (rbrk != NULL)
180             *rbrk = '\0';
181     }
182     /*@+modobserver@*/
183     /*@+usedef@*/
184 }
185
186 /*@ +observertrans -statictrans +mustfreeonly +branchstate +kepttrans @*/
187
188 /* gpsclient.c ends here */