summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGary E. Miller <gem@rellim.com>2019-02-22 18:17:57 -0800
committerGary E. Miller <gem@rellim.com>2019-02-22 18:17:57 -0800
commit59935603ccb54f12758672f2c077109523aeeaa7 (patch)
tree1f32c0ccf61986344e4fffa007c2873fcb9c6d8d
parentae2ebe25de183ddd576615fa80682d6d6a5b0ffe (diff)
downloadgpsd-59935603ccb54f12758672f2c077109523aeeaa7.tar.gz
deg_to_str2(): Add new function. Thread safe, handles suffix.
-rw-r--r--doc/explan_gpsdclient.c.xml18
-rw-r--r--gpsdclient.c86
-rw-r--r--gpsdclient.h5
-rw-r--r--tests/test_gpsdclient.c120
4 files changed, 179 insertions, 50 deletions
diff --git a/doc/explan_gpsdclient.c.xml b/doc/explan_gpsdclient.c.xml
index babd2499..4825fd3d 100644
--- a/doc/explan_gpsdclient.c.xml
+++ b/doc/explan_gpsdclient.c.xml
@@ -33,6 +33,24 @@
</entry>
</row>
<row>
+ <entry>
+ <function>char *deg_to_str2(enum deg_str_type type, double f, char *buf,
+ unsigned int buf_size, const char *suffix_pos, const char *suffix_neg)
+ </function>
+ </entry>
+ <entry>
+ <para>Convert the absolute value of double degrees to a string
+ and place in the buffer "buf". Return a pointer to the buffer.
+ "buf_size" is the size of the buffer.</para>
+ <para>Makes a simple check on invalid degree values (not more
+ than 360) and returns "nan" on error.</para>
+ <para>For valid values, it generates the appropriate string according
+ to the string type enumeration: dd, ddmm or ddmmss. If the
+ degrees are positive, append "suffix_pos", else append "suffix_neg".
+ </para>
+ </entry>
+</row>
+<row>
<entry><function>enum unit gpsd_units(void)</function></entry>
<entry><para>Simple check of the environment to determine what units are required. If all else fails, use compiled in units.</para></entry>
</row>
diff --git a/gpsdclient.c b/gpsdclient.c
index b97acc03..8b729d85 100644
--- a/gpsdclient.c
+++ b/gpsdclient.c
@@ -28,34 +28,52 @@ static struct exportmethod_t exportmethods[] = {
#endif /* SOCKET_EXPORT_ENABLE */
};
-/* convert double degrees to a static string and return a pointer to it
- * WARNING: not thread safe!
+/* convert value of double degrees to a buffer.
+ * add suffix_pos or suffix_neg depending on sign.
+ * buffer should be at least 20 bytes.
+ * Return a pointer to the buffer.
*
* deg_str_type:
- * deg_dd : return DD.ddddddd
- * deg_ddmm : return DD MM.mmmmmm'
- * deg_ddmmss : return DD MM' SS.sssss"
+ * deg_dd : return DD.ddddddd[suffix]
+ * deg_ddmm : return DD MM.mmmmmm'[suffix]
+ * deg_ddmmss : return DD MM' SS.sssss"[suffix]
*
- * returns 'nan' for 0 > f or 360 < f
+ * returns 'nan' for 360 < f or -360 > f
*
- * NOTE: degrees must be positive.
- * 360.0 is rolled over to 0.0
+ * NOTE: 360.0 is rolled over to 0.0
*
* for cm level accuracy, at sea level, we need degrees
* to 7+ decimal places
* Ref: https://en.wikipedia.org/wiki/Decimal_degrees
*
*/
-char *deg_to_str(enum deg_str_type type, double f)
+char *deg_to_str2(enum deg_str_type type, double f,
+ char *buf, unsigned int buf_size,
+ const char *suffix_pos, const char *suffix_neg)
+
{
- static char str[40];
int dsec, sec, deg, min;
double fdsec, fsec, fdeg, fmin;
+ const char *suffix = "";
+
+ if (20 > buf_size) {
+ (void)strlcpy(buf, "Err", buf_size);
+ return buf;
+ }
- f = fabs(f);
- if (!isfinite(f) || 360.0 < f) {
- (void)strlcpy(str, "nan", sizeof(str));
- return str;
+ if (!isfinite(f) || 360.0 < fabs(f)) {
+ (void)strlcpy(buf, "nan", buf_size);
+ return buf;
+ }
+
+ /* suffix? */
+ if (0.0 > f) {
+ f = -f;
+ if (NULL != suffix_neg) {
+ suffix = suffix_neg;
+ }
+ } else if (NULL != suffix_pos) {
+ suffix = suffix_pos;
}
/* add rounding quanta */
@@ -91,8 +109,8 @@ char *deg_to_str(enum deg_str_type type, double f)
/* DD.dddddddd */
long frac_deg = (long)(fmin * 100000000.0);
/* cm level accuracy requires the %08ld */
- (void)snprintf(str, sizeof(str), "%3d.%08ld", deg, frac_deg);
- return str;
+ (void)snprintf(buf, buf_size, "%3d.%08ld%s", deg, frac_deg, suffix);
+ return buf;
}
fsec = modf(fmin * 60, &fmin);
@@ -101,17 +119,43 @@ char *deg_to_str(enum deg_str_type type, double f)
if (deg_ddmm == type) {
/* DD MM.mmmmmm */
sec = (int)(fsec * 1000000.0);
- (void)snprintf(str, sizeof(str), "%3d %02d.%06d'", deg, min, sec);
- return str;
+ (void)snprintf(buf, buf_size, "%3d %02d.%06d'%s", deg, min, sec,
+ suffix);
+ return buf;
}
/* else DD MM SS.sss */
fdsec = modf(fsec * 60.0, &fsec);
sec = (int)fsec;
dsec = (int)(fdsec * 100000.0);
- (void)snprintf(str, sizeof(str), "%3d %02d' %02d.%05d\"", deg, min, sec,
- dsec);
+ (void)snprintf(buf, buf_size, "%3d %02d' %02d.%05d\"%s", deg, min, sec,
+ dsec, suffix);
+
+ return buf;
+}
+
+/* convert absolute value of double degrees to a static string.
+ * Return a pointer to the static string.
+ * WARNING: Not thread safe.
+ *
+ * deg_str_type:
+ * deg_dd : return DD.ddddddd
+ * deg_ddmm : return DD MM.mmmmmm'
+ * deg_ddmmss : return DD MM' SS.sssss"
+ *
+ * returns 'nan' for 360 < f
+ *
+ * NOTE: 360.0 is rolled over to 0.0
+ *
+ * for cm level accuracy, at sea level, we need degrees
+ * to 7+ decimal places
+ * Ref: https://en.wikipedia.org/wiki/Decimal_degrees
+ *
+ */
+char *deg_to_str(enum deg_str_type type, double f)
+{
+ static char buf[20];
- return str;
+ return deg_to_str2(type, f, buf, sizeof(buf), "", "");
}
/*
diff --git a/gpsdclient.h b/gpsdclient.h
index e4e5dae2..e1066611 100644
--- a/gpsdclient.h
+++ b/gpsdclient.h
@@ -34,8 +34,11 @@ enum unit gpsd_units(void);
enum deg_str_type { deg_dd, deg_ddmm, deg_ddmmss };
float true2magnetic(double, double, double);
-/* Warning: not thread safe */
+/* Warning: deg_to_str() not thread safe */
extern char *deg_to_str(enum deg_str_type type, double f);
+extern char *deg_to_str2(enum deg_str_type type, double f,
+ char *buf, unsigned int buf_size,
+ const char *suffix_pos, const char *suffix_neg);
extern void gpsd_source_spec(const char *fromstring,
struct fixsource_t *source);
diff --git a/tests/test_gpsdclient.c b/tests/test_gpsdclient.c
index f4c93379..deda6d2c 100644
--- a/tests/test_gpsdclient.c
+++ b/tests/test_gpsdclient.c
@@ -20,8 +20,11 @@
struct test {
double deg;
char dd[20];
+ char dd2[20];
char ddmm[20];
+ char ddmm2[20];
char ddmmss[20];
+ char ddmmss2[20];
};
#define NANFLAG 9999
@@ -29,78 +32,118 @@ struct test {
struct test tests[] = {
/* 1.999999995 sec */
{(1.999999995),
- " 2.00000000", /* rounded up */
- " 2 00.000000'", /* rounded up */
- " 1 59' 59.99998\""},
+ " 2.00000000", /* rounded up */
+ " 2.00000000 E", /* rounded up */
+ " 2 00.000000'", /* rounded up */
+ " 2 00.000000' E", /* rounded up */
+ " 1 59' 59.99998\"",
+ " 1 59' 59.99998\" N"},
/* 3.999999999 sec */
{(3.999999994),
- " 3.99999999", /* not rounded up */
- " 4 00.000000'", /* rounded up */
- " 3 59' 59.99998\""},
+ " 3.99999999", /* not rounded up */
+ " 3.99999999 E", /* not rounded up */
+ " 4 00.000000'", /* rounded up */
+ " 4 00.000000' E", /* rounded up */
+ " 3 59' 59.99998\"",
+ " 3 59' 59.99998\" N"},
/* 5 degree, 1.99999960 arcmin */
{(5.0 + 1.999999600/60.0),
" 5.03333333",
- " 5 02.000000'", /* rounded up */
- " 5 01' 59.99998\""},
+ " 5.03333333 E",
+ " 5 02.000000'", /* rounded up */
+ " 5 02.000000' E", /* rounded up */
+ " 5 01' 59.99998\"",
+ " 5 01' 59.99998\" N"},
/* 6 degree, 1.99999940 arcmin */
{(6.0 + 1.999999400/60.0),
" 6.03333332",
- " 6 01.999999'", /* not rounded up */
- " 6 01' 59.99996\""},
+ " 6.03333332 E",
+ " 6 01.999999'", /* not rounded up */
+ " 6 01.999999' E", /* not rounded up */
+ " 6 01' 59.99996\"",
+ " 6 01' 59.99996\" N"},
/* 7 degree, 59.99999960 arcmin */
{(7.0 + 59.999999600/60.0),
" 7.99999999",
- " 8 00.000000'", /* rounded up */
- " 7 59' 59.99998\""},
+ " 7.99999999 E",
+ " 8 00.000000'", /* rounded up */
+ " 8 00.000000' E", /* rounded up */
+ " 7 59' 59.99998\"",
+ " 7 59' 59.99998\" N"},
/* 9 degree, 59.99999940 arcmin */
{(9.0 + 59.999999400/60.0),
" 9.99999999",
- " 9 59.999999'", /* not rounded up */
- " 9 59' 59.99996\""},
+ " 9.99999999 E",
+ " 9 59.999999'", /* not rounded up */
+ " 9 59.999999' E", /* not rounded up */
+ " 9 59' 59.99996\"",
+ " 9 59' 59.99996\" N"},
/* 11 degree, 1 arcminute, 1.99999600 arcsec */
{(11.0 + 1.0/60.0 + 1.99999600/3600.0),
" 11.01722222",
+ " 11.01722222 E",
" 11 01.033333'",
- " 11 01' 02.00000\""}, /* rounded up */
+ " 11 01.033333' E",
+ " 11 01' 02.00000\"", /* rounded up */
+ " 11 01' 02.00000\" N"}, /* rounded up */
/* 12 deg, 2 min, 2.99999400 sec */
{(12.0 + 2.0/60.0 + 2.99999400/3600.0),
" 12.03416667",
+ " 12.03416667 E",
" 12 02.050000'",
- " 12 02' 02.99999\""}, /* not rounded up */
+ " 12 02.050000' E",
+ " 12 02' 02.99999\"", /* not rounded up */
+ " 12 02' 02.99999\" N"}, /* not rounded up */
/* -44.99999999999 */
/* fabs() */
{-44.0,
" 44.00000000",
+ " 44.00000000 W",
" 44 00.000000'",
- " 44 00' 00.00000\""},
+ " 44 00.000000' W",
+ " 44 00' 00.00000\"",
+ " 44 00' 00.00000\" S"},
/* 359.99999999999 */
{359.99999999999,
- " 0.00000000", /* rounded up, and rolled over */
+ " 0.00000000", /* rounded up, and rolled over */
+ " 0.00000000 E", /* rounded up, and rolled over */
" 0 00.000000'",
- " 0 00' 00.00000\""},
+ " 0 00.000000' E",
+ " 0 00' 00.00000\"",
+ " 0 00' 00.00000\" N"},
/* 361 */
/* nan because out of range */
{361,
"nan",
"nan",
+ "nan",
+ "nan",
+ "nan",
"nan"},
/* -361 */
/* nan, just because */
{NANFLAG,
"nan",
"nan",
+ "nan",
+ "nan",
+ "nan",
"nan"},
/* FP_INFINITE */
/* gcc too 'smart' to let us put a Nan here */
{9999,
"nan",
"nan",
+ "nan",
+ "nan",
+ "nan",
"nan"},
};
int main(int argc, char **argv)
{
+ char buf[20];
char *s;
unsigned int i;
int verbose = 0;
@@ -133,30 +176,51 @@ int main(int argc, char **argv)
/* make it a NaN */
tests[i].deg = nan("a");
}
- s = deg_to_str (deg_dd, tests[i].deg);
+ s = deg_to_str(deg_dd, tests[i].deg);
if (0 != strcmp(s, tests[i].dd)) {
printf("ERROR: %s s/b %s\n", s, tests[i].dd);
fail_count++;
- }
- if (0 < verbose) {
+ } else if (0 < verbose) {
printf("%s s/b %s\n", s, tests[i].dd);
}
- s = deg_to_str (deg_ddmm, tests[i].deg);
+ s = deg_to_str2(deg_dd, tests[i].deg, buf,
+ sizeof(buf), " E", " W");
+ if (0 != strcmp(s, tests[i].dd2)) {
+ printf("ERROR: %s s/b %s\n", s, tests[i].dd2);
+ fail_count++;
+ } else if (0 < verbose) {
+ printf("%s s/b %s\n", s, tests[i].dd2);
+ }
+ s = deg_to_str(deg_ddmm, tests[i].deg);
if (0 != strcmp(s, tests[i].ddmm)) {
printf("ERROR: %s s/b %s\n", s, tests[i].ddmm);
fail_count++;
- }
- if (0 < verbose) {
+ } else if (0 < verbose) {
printf("%s s/b %s\n", s, tests[i].ddmm);
}
- s = deg_to_str (deg_ddmmss, tests[i].deg);
+ s = deg_to_str2(deg_ddmm, tests[i].deg, buf,
+ sizeof(buf), " E", " W");
+ if (0 != strcmp(s, tests[i].ddmm2)) {
+ printf("ERROR: %s s/b %s\n", s, tests[i].ddmm2);
+ fail_count++;
+ } else if (0 < verbose) {
+ printf("%s s/b %s\n", s, tests[i].ddmm2);
+ }
+ s = deg_to_str(deg_ddmmss, tests[i].deg);
if (0 != strcmp(s, tests[i].ddmmss)) {
printf("ERROR: %s s/b %s\n", s, tests[i].ddmmss);
fail_count++;
- }
- if (0 < verbose) {
+ } else if (0 < verbose) {
printf("%s s/b %s\n", s, tests[i].ddmmss);
}
+ s = deg_to_str2(deg_ddmmss, tests[i].deg, buf,
+ sizeof(buf), " N", " S");
+ if (0 != strcmp(s, tests[i].ddmmss2)) {
+ printf("ERROR: %s s/b %s\n", s, tests[i].ddmmss2);
+ fail_count++;
+ } else if (0 < verbose) {
+ printf("%s s/b %s\n", s, tests[i].ddmmss2);
+ }
}
exit(fail_count);