summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.am4
-rw-r--r--gps_json.h2
-rw-r--r--json.c14
-rw-r--r--json.h5
-rw-r--r--libgps.c2
-rw-r--r--libgps_json.c20
-rw-r--r--test_json.c27
7 files changed, 47 insertions, 27 deletions
diff --git a/Makefile.am b/Makefile.am
index a85b7d1f..64da5a3d 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -542,6 +542,10 @@ unpack-makeregress: libgps
@echo "Rebuilding the clent sentence-unpacker test..."
@$(srcdir)/libgps -u >test/unpack.chk
+# Unit-test the JSON parsing
+json-regress: test_json
+ test_json
+
# Unit-test the bitfield extractor - not in normal tests
bits-regress: test_bits
test_bits
diff --git a/gps_json.h b/gps_json.h
index 0af21456..de701e05 100644
--- a/gps_json.h
+++ b/gps_json.h
@@ -21,6 +21,6 @@ int json_watch_read(struct policy_t *, const char *, const char **);
void json_watch_dump(struct policy_t *, char *, size_t);
int json_configdev_read(struct devconfig_t *, const char *, const char **);
void json_configdev_dump(struct gps_device_t *, char *, size_t);
-void libgps_json_unpack(char *, struct gps_data_t *);
+int libgps_json_unpack(const char *, struct gps_data_t *);
/* gps_json.h ends here */
diff --git a/json.c b/json.c
index 283894f5..1b8ad3bd 100644
--- a/json.c
+++ b/json.c
@@ -46,7 +46,7 @@ int json_read_object(const char *cp, const struct json_attr_t *attrs, int offset
char attrbuf[JSON_ATTR_MAX+1], *pattr = NULL;
char valbuf[JSON_VAL_MAX+1], *pval = NULL;
const struct json_attr_t *cursor;
- int substatus;
+ int substatus, maxlen;
/* stuff fields with defaults in case they're omitted in the JSON input */
for (cursor = attrs; cursor->attribute != NULL; cursor++)
@@ -68,6 +68,7 @@ int json_read_object(const char *cp, const struct json_attr_t *attrs, int offset
break;
case object: /* silences a compiler warning */
case array:
+ case check:
break;
}
@@ -137,13 +138,17 @@ int json_read_object(const char *cp, const struct json_attr_t *attrs, int offset
}
break;
case in_val_string:
+ if (cursor->type == string)
+ maxlen = cursor->addr.string.len - 1;
+ else if (cursor->type == check)
+ maxlen = strlen(cursor->dflt.check);
if (*cp == '"') {
*pval = '\0';
#ifdef JSONDEBUG
(void) printf("Collected string value %s\n", valbuf);
#endif /* JSONDEBUG */
state = post_val;
- } else if (pval > valbuf + JSON_VAL_MAX - 1 || pval > valbuf + cursor->addr.string.len - 1)
+ } else if (pval > valbuf + JSON_VAL_MAX - 1 || pval > valbuf + maxlen)
return JSON_ERR_STRLONG; /* value too long */
else
*pval++ = *cp;
@@ -177,6 +182,9 @@ int json_read_object(const char *cp, const struct json_attr_t *attrs, int offset
case boolean:
cursor->addr.boolean[offset] = (bool)!strcmp(valbuf, "true");
break;
+ case check:
+ if (strcmp(cursor->dflt.check, valbuf)!=0)
+ return JSON_ERR_CHECKFAIL;
case object: /* silences a compiler warning */
case array:
break;
@@ -260,6 +268,7 @@ int json_read_array(const char *cp, const struct json_array_t *arr, const char *
case real:
case boolean:
case array:
+ case check:
return JSON_ERR_SUBTYPE;
}
if (arr->count != NULL)
@@ -302,6 +311,7 @@ const char *json_error_string(int err)
"garbage while expecting array comma",
"unsupported array element type",
"error while string parsing",
+ "check attribute not matched",
};
if (err <= 0 || err >= (int)(sizeof(errors)/sizeof(errors[0])))
diff --git a/json.h b/json.h
index d3002ed0..8910e3b1 100644
--- a/json.h
+++ b/json.h
@@ -4,7 +4,7 @@
#include <stdbool.h>
#include <ctype.h>
-typedef enum {integer, real, string, boolean, object, array} json_type;
+typedef enum {integer, real, string, boolean, object, array, check} json_type;
#define nullbool -1 /* not true, not false */
@@ -38,8 +38,8 @@ struct json_attr_t {
union {
int integer;
double real;
- char string;
bool boolean;
+ char *check;
} dflt;
};
@@ -65,5 +65,6 @@ const char *json_error_string(int);
#define JSON_ERR_BADSUBTRAIL 13 /* garbage while expecting array comma */
#define JSON_ERR_SUBTYPE 14 /* unsupported array element type */
#define JSON_ERR_BADSTRING 15 /* error while string parsing */
+#define JSON_ERR_CHECKFAIL 16 /* check attribute not matched */
/* json.h ends here */
diff --git a/libgps.c b/libgps.c
index 35f64300..49cfcf61 100644
--- a/libgps.c
+++ b/libgps.c
@@ -85,7 +85,7 @@ static void gps_unpack(char *buf, struct gps_data_t *gpsdata)
#ifdef GPSDNG_ENABLE
/* detect and process a JSON response */
if (buf[0] == '{' && (sp = strchr(buf, '='))!= NULL) {
- libgps_json_unpack(buf, gpsdata);
+ (void)libgps_json_unpack(buf, gpsdata);
}
#endif /* GPSDNG_ENABLE */
#if defined(OLDSTYLE_ENABLE) && defined(GPSDNG_ENABLE)
diff --git a/libgps_json.c b/libgps_json.c
index 5732af56..7048333d 100644
--- a/libgps_json.c
+++ b/libgps_json.c
@@ -23,6 +23,7 @@ static int json_tpv_read(const char *buf,
{
int status;
const struct json_attr_t json_attrs_1[] = {
+ {"class", check, .dflt.check = "TPV"},
{"device", string, .addr.string.ptr = gpsdata->gps_device,
.addr.string.len = sizeof(gpsdata->gps_device)},
{"tag", string, .addr.string.ptr = gpsdata->tag,
@@ -108,6 +109,7 @@ static int json_sky_read(const char *buf,
{NULL},
};
const struct json_attr_t json_attrs_2[] = {
+ {"class", check, .dflt.check = "SKY"},
{"device", string, .addr.string.ptr = gpsdata->gps_device,
.addr.string.len = PATH_MAX},
{"tag", string, .addr.string.ptr = gpsdata->tag,
@@ -150,6 +152,7 @@ static int json_devices_read(const char *buf,
};
// FIXME: Can we abolish the hard limit on the number of devices?
const struct json_attr_t json_attrs_devices[] = {
+ {"class", check, .dflt.check = "DEVICES"},
{"devices", array, .addr.array.element_type = object,
.addr.array.arr.subtype = json_attrs_subdevices,
.addr.array.maxlen = GPS_JSON_DEVICES_MAX},
@@ -167,16 +170,17 @@ static int json_devices_read(const char *buf,
return 0;
}
-void libgps_json_unpack(char *buf, struct gps_data_t *gpsdata)
+int libgps_json_unpack(const char *buf, struct gps_data_t *gpsdata)
/* the only entry point - unpack a JSON object into C structs */
{
- if (strstr(buf, "\"class\":\"TPV\"") == 0) {
- json_tpv_read(buf, gpsdata, NULL);
- } else if (strstr(buf, "\"class\":\"SKY\"") == 0) {
- json_sky_read(buf, gpsdata, NULL);
- } else if (strstr(buf, "\"class\":\"DEVICES\"") == 0) {
- json_devices_read(buf, gpsdata, NULL);
- }
+ if (strstr(buf, "\"class\":\"TPV\"") != 0) {
+ return json_tpv_read(buf, gpsdata, NULL);
+ } else if (strstr(buf, "\"class\":\"SKY\"") != 0) {
+ return json_sky_read(buf, gpsdata, NULL);
+ } else if (strstr(buf, "\"class\":\"DEVICES\"") != 0) {
+ return json_devices_read(buf, gpsdata, NULL);
+ } else
+ return -1;
}
/* libgps_json.c ends here */
diff --git a/test_json.c b/test_json.c
index d0819076..c0a0263a 100644
--- a/test_json.c
+++ b/test_json.c
@@ -6,16 +6,16 @@
#include <stdlib.h>
#include <string.h>
#include "gpsd_config.h"
-#include "gps.h"
+#include "gpsd.h"
#include "gps_json.h"
#include "strl.c"
static void ASSERT_CASE(int num, int status)
{
- if (status < 0)
+ if (status != 0)
{
- (void)fprintf(stderr, "case %d FAILED, status %d.\n", num, status);
+ (void)fprintf(stderr, "case %d FAILED, status %d (%s).\n", num, status, json_error_string(status));
exit(1);
}
}
@@ -24,7 +24,7 @@ static void ASSERT_STRING(char *attr, char *fld, char *val)
{
if (strcmp(fld, val))
{
- (void)fprintf(stderr, "'%s' attribute eval failed, value = %s.\n", attr, fld);
+ (void)fprintf(stderr, "'%s' string attribute eval failed, value = %s.\n", attr, fld);
exit(1);
}
}
@@ -33,7 +33,7 @@ static void ASSERT_INTEGER(char *attr, int fld, int val)
{
if (fld != val)
{
- (void)fprintf(stderr, "'%s' attribute eval failed, value = %d.\n", attr, fld);
+ (void)fprintf(stderr, "'%s' integer attribute eval failed, value = %d.\n", attr, fld);
exit(1);
}
}
@@ -42,7 +42,7 @@ static void ASSERT_BOOLEAN(char *attr, bool fld, bool val)
{
if (fld != val)
{
- (void)fprintf(stderr, "'%s' attribute eval failed, value = %s.\n", attr, fld ? "true" : "false");
+ (void)fprintf(stderr, "'%s' boolean attribute eval failed, value = %s.\n", attr, fld ? "true" : "false");
exit(1);
}
}
@@ -55,7 +55,7 @@ static void ASSERT_REAL(char *attr, double fld, double val)
{
if (fld != val)
{
- (void)fprintf(stderr, "'%s' attribute eval failed, value = %f.\n", attr, fld);
+ (void)fprintf(stderr, "'%s' real attribute eval failed, value = %f.\n", attr, fld);
exit(1);
}
}
@@ -64,14 +64,15 @@ static struct gps_data_t gpsdata;
/* Case 1: TPV report */
-const char *json_str1 = "{\"device\":\"GPS#1\",\"tag\":\"MID2\",\
+const char *json_str1 = "{\"class\":\"TPV\",\
+ \"device\":\"GPS#1\",\"tag\":\"MID2\", \
\"time\":1119197561.890,\"lon\":46.498203637,\"lat\":7.568074350,\
- \"alt\":1327.780,\"eph\":21.000,\"epv\":124.484,\"mode\":3,\
- \"flag1\":true,\"flag2\":false}";
+ \"alt\":1327.780,\"eph\":21.000,\"epv\":124.484,\"mode\":3}";
/* Case 2: SKY report */
-const char *json_str2 = "{\"tag\":\"MID4\",\"time\":1119197562.890,\
+const char *json_str2 = "{\"class\":\"SKY\",\
+ \"tag\":\"MID4\",\"time\":1119197562.890, \
\"reported\":7,\
\"satellites\":[\
{\"PRN\":10,\"el\":45,\"az\":196,\"ss\":34,\"used\":true},\
@@ -121,7 +122,7 @@ int main(int argc UNUSED, char *argv[] UNUSED)
(void)fprintf(stderr, "JSON unit test ");
- status = json_tpv_read(json_str1, &gpsdata);
+ status = libgps_json_unpack(json_str1, &gpsdata);
ASSERT_CASE(1, status);
ASSERT_STRING("device", gpsdata.gps_device, "GPS#1");
ASSERT_STRING("tag", gpsdata.tag, "MID2");
@@ -130,7 +131,7 @@ int main(int argc UNUSED, char *argv[] UNUSED)
ASSERT_REAL("lon", gpsdata.fix.longitude, 46.498203637);
ASSERT_REAL("lat", gpsdata.fix.latitude, 7.568074350);
- status = json_sky_read(json_str2, &gpsdata);
+ status = libgps_json_unpack(json_str2, &gpsdata);
ASSERT_CASE(2, status);
ASSERT_STRING("tag", gpsdata.tag, "MID4");
ASSERT_INTEGER("reported", gpsdata.satellites_used, 7);