From e91613e46430c7d1459647d33b950a7793899b3f Mon Sep 17 00:00:00 2001 From: "Eric S. Raymond" Date: Tue, 18 Aug 2009 17:05:46 +0000 Subject: Add check-string attributes to JSON parser. Add JSON unit test to default test sequence. --- Makefile.am | 4 ++++ gps_json.h | 2 +- json.c | 14 ++++++++++++-- json.h | 5 +++-- libgps.c | 2 +- libgps_json.c | 20 ++++++++++++-------- test_json.c | 27 ++++++++++++++------------- 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 #include -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 #include #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); -- cgit v1.2.1