]> thyrsus.com Git - microjson.git/commitdiff
There are now three worked examples.
authorEric S. Raymond <esr@thyrsus.com>
Tue, 23 Sep 2014 15:26:08 +0000 (11:26 -0400)
committerEric S. Raymond <esr@thyrsus.com>
Tue, 23 Sep 2014 15:26:08 +0000 (11:26 -0400)
.gitignore
Makefile
example1.c
example2.c [new file with mode: 0644]
example3.c [new file with mode: 0644]
microjson.asc
microjson.h

index b9b3be66314c1e25de0d2c423a9151f3a6e5e604..902731f45a827145234d5950aa732d934954d574 100644 (file)
@@ -1,3 +1,3 @@
 *.o
 test_microjson
-example1
+example[123]
index 4f4e62b8f6f2ac2b509f9c9cddc0e8907883574a..9de50ef3ac29093b550995d2b0296eefcc6e64a2 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -15,8 +15,10 @@ test_microjson: test_microjson.o microjson.o
 check: test_microjson
        test_microjson
 
-# Worked example
+# Worked examples
 example1: example1.c microjson.c
+example2: example2.c microjson.c
+example3: example3.c microjson.c
 
 clean:
        rm -f microjson.o test_microjson.o test_microjson example1
index 96aa855609c50291d5add940363beb90edc7fb6b..81d370ac78dbe8dd2507130d1b996162c7618d3c 100644 (file)
@@ -1,6 +1,6 @@
 /* example1.c - first example in the programming guide
  *
- * This file is Copyright (c) 2010 by the GPSD project
+ * This file is Copyright (c) 2014 by Eric S. Raymond
  * BSD terms apply: see the file COPYING in the distribution root for details.
  */
 
diff --git a/example2.c b/example2.c
new file mode 100644 (file)
index 0000000..8780619
--- /dev/null
@@ -0,0 +1,50 @@
+/* example2.c - second example in the programming guide
+ *
+ * This file is Copyright (c) 2014 by Eric S. Raymond
+ * BSD terms apply: see the file COPYING in the distribution root for details.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "microjson.h"
+
+#define MAXCHANNELS 72
+
+static bool usedflags[MAXCHANNELS];
+static int PRN[MAXCHANNELS];
+static int elevation[MAXCHANNELS];
+static int azimuth[MAXCHANNELS];
+static int visible;
+
+const struct json_attr_t sat_attrs[] = {
+    {"PRN",    t_integer, .addr.integer = PRN},
+    {"el",     t_integer, .addr.integer = elevation},
+    {"az",     t_integer, .addr.integer = azimuth},
+    {"used",   t_boolean, .addr.boolean = usedflags},
+    {NULL},
+};
+
+const struct json_attr_t json_attrs_sky[] = {
+    {"class",      t_check,   .dflt.check = "SKY"},
+    {"satellites", t_array,   .addr.array.element_type = t_object,
+                             .addr.array.arr.objects.subtype=sat_attrs,
+                             .addr.array.maxlen = MAXCHANNELS,
+                             .addr.array.count = &visible},
+    {NULL},
+    };
+
+int main(int argc, char *argv[])
+{
+    int i, status = 0;
+
+    status = json_read_object(argv[1], json_attrs_sky, NULL);
+    printf("%d satellites:\n", visible);
+    for (i = 0; i < visible; i++)
+       printf("PRN = %d, elevation = %d, azimuth = %d\n", 
+              PRN[i], elevation[i], azimuth[i]);
+
+    if (status != 0)
+       puts(json_error_string(status));
+}
+
+/* end */
diff --git a/example3.c b/example3.c
new file mode 100644 (file)
index 0000000..9b4c8e1
--- /dev/null
@@ -0,0 +1,68 @@
+/* example2.c - first example in the programming guide
+ *
+ * This file is Copyright (c) 2014 by Eric S. Raymond
+ * BSD terms apply: see the file COPYING in the distribution root for details.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <limits.h>
+#include <string.h>
+
+#include "microjson.h"
+
+#define MAXUSERDEVS    4
+
+struct devconfig_t {
+    char path[PATH_MAX];
+    double activated;
+};
+
+struct devlist_t {
+    int ndevices;
+    struct devconfig_t list[MAXUSERDEVS];
+};
+
+static struct devlist_t devicelist;
+
+static int json_devicelist_read(const char *buf)
+{
+    const struct json_attr_t json_attrs_subdevice[] = {
+       {"path",       t_string,     STRUCTOBJECT(struct devconfig_t, path),
+                                       .len = sizeof(devicelist.list[0].path)},
+       {"activated",  t_time,       STRUCTOBJECT(struct devconfig_t, activated)},
+       {"activated",  t_real,       STRUCTOBJECT(struct devconfig_t, activated)},
+       {NULL},
+    };
+    const struct json_attr_t json_attrs_devices[] = {
+       {"class", t_check,.dflt.check = "DEVICES"},
+       {"devices", t_array, STRUCTARRAY(devicelist.list,
+                                        json_attrs_subdevice,
+                                        &devicelist.ndevices)},
+       {NULL},
+    };
+    int status;
+
+    memset(&devicelist, '\0', sizeof(devicelist));
+    status = json_read_object(buf, json_attrs_devices, NULL);
+    if (status != 0) {
+       return status;
+    }
+    return 0;
+}
+
+int main(int argc, char *argv[])
+{
+    int i, status = 0;
+
+    status = json_devicelist_read(argv[1]);
+    printf("%d devices:\n", devicelist.ndevices);
+    for (i = 0; i < devicelist.ndevices; i++)
+       printf("%s @ %f\n", 
+              devicelist.list[i].path, devicelist.list[i].activated);
+
+    if (status != 0)
+       puts(json_error_string(status));
+}
+
+/* end */
index c97053abc567d55b479537aee9fcb3bfe09157fb..78d543f3562c2cc6c12252c2573089252f9a4f4a 100644 (file)
@@ -20,11 +20,27 @@ of the incoming JSON, and it will error out if that shape is not
 matched.  When the parse succeeds, attribute values will be extracted
 into static locations specified in the template structures.
 
+== How To Use This Document ==
+
+This is a fast tutorial for working programmers.  It teaches by
+examples; if you read the code carefully it will tell you 
+more than the accompanying test. Just read it in sequence, trying not
+to skip anything.
+
+All the examples are shipped in the microjson distribution.  They are
+not synthetic toys, but stripped-down versions of working code from
+GPS. Copy them freely.
+
 == An Example ==
 
 Here is nearly the simplest possible example:
 
+.Example 1
 ---------------------------------------------------------------------
+/*
+ * Parse JSON shaped like '{"flag1":true,"flag2":false,"count":42}'
+ */
+
 #include <stdio.h>
 #include <stdlib.h>
 #include <stdbool.h>
@@ -143,7 +159,7 @@ t_array: Value of this attribute is expected to be a homogenous array.
 Another field of the structure specifies the array's element type,
 which can be any simple type or t_object (meaning a JSON subobject).
 
-If the array has simple elements, two three additional things must be
+If the array has simple elements, three additional things must be
 specified: the base address of the array's storage, the maximum number
 of elements it can have, and an integer address where the parser will
 place a count of elements filled in.
@@ -154,12 +170,20 @@ for booleans, and NULL for strings.
 The array element type may be +t_object+, as in the +satellites+ field
 in this example:  
 
+.Example 2
 ------------------------------------------------------------------------
-bool usedflags[MAXCHANNELS];
-int PRN[MAXCHANNELS];
-int elevation[MAXCHANNELS];
-int azimuth[MAXCHANNELS];
-int visible;
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "microjson.h"
+
+#define MAXCHANNELS 72
+
+static bool usedflags[MAXCHANNELS];
+static int PRN[MAXCHANNELS];
+static int elevation[MAXCHANNELS];
+static int azimuth[MAXCHANNELS];
+static int visible;
 
 const struct json_attr_t sat_attrs[] = {
     {"PRN",    t_integer, .addr.integer = PRN},
@@ -177,20 +201,31 @@ const struct json_attr_t json_attrs_sky[] = {
                              .addr.array.count = &visible},
     {NULL},
     };
+
+int main(int argc, char *argv[])
+{
+    int i, status = 0;
+
+    status = json_read_object(argv[1], json_attrs_sky, NULL);
+    printf("%d satellites:\n", visible);
+    for (i = 0; i < visible; i++)
+       printf("PRN = %d, elevation = %d, azimuth = %d\n", 
+              PRN[i], elevation[i], azimuth[i]);
+
+    if (status != 0)
+       puts(json_error_string(status));
+}
 ------------------------------------------------------------------------
 
-An example of the shape of JSON this would unpack is:
+Here's an example invocation (string literal folded for readability):
 
 --------------------------------------------------------
-{"class":"SKY","satellites":[
-         {"PRN":10,"el":45,"az":196,"used":true},
-         {"PRN":29,"el":67,"az":310,"used":true},
-         {"PRN":28,"el":59,"az":108,"used":true},
-         {"PRN":26,"el":51,"az":304,"used":true},
-         {"PRN":8, "el":44,"az":58, "used":true},
-         {"PRN":27,"el":16,"az":66, "used":true},
-         {"PRN":21,"el":10,"az":301,"used":false}
-]}
+$ example2 '{"class":"SKY","satellites":
+              [{"PRN":10,"el":45,"az":196,"used":true},
+               {"PRN":29,"el":67,"az":310,"used":true}]}'
+2 satellites:
+PRN = 10, elevation = 45, azimuth = 196
+PRN = 29, elevation = 67, azimuth = 310
 --------------------------------------------------------
 
 In this case, the parser needs to be told where to find a template
@@ -201,10 +236,89 @@ sub-objects to parse or would exceed the +maxlen+ count of elements.
 
 ==== Structure arrays ====
 
-t_structobject: this also parses 
+There's a different way to parse arrays that can unpack an
+array of JSON objects directly into an array of C structs.
 
+.Example 3:
+--------------------------------------------------------
+#include <stdio.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <limits.h>
+#include <string.h>
+
+#include "microjson.h"
 
+#define MAXUSERDEVS    4
+
+struct devconfig_t {
+    char path[PATH_MAX];
+    double activated;
+};
+
+struct devlist_t {
+    int ndevices;
+    struct devconfig_t list[MAXUSERDEVS];
+};
+
+static struct devlist_t devicelist;
+
+static int json_devicelist_read(const char *buf)
+{
+    const struct json_attr_t json_attrs_subdevice[] = {
+       {"path",       t_string,     STRUCTOBJECT(struct devconfig_t, path),
+                                       .len = sizeof(devicelist.list[0].path)},
+       {"activated",  t_time,       STRUCTOBJECT(struct devconfig_t, activated)},
+       {"activated",  t_real,       STRUCTOBJECT(struct devconfig_t, activated)},
+       {NULL},
+    };
+    const struct json_attr_t json_attrs_devices[] = {
+       {"class", t_check,.dflt.check = "DEVICES"},
+       {"devices", t_array, STRUCTARRAY(devicelist.list,
+                                        json_attrs_subdevice,
+                                        &devicelist.ndevices)},
+       {NULL},
+    };
+    int status;
+
+    memset(&devicelist, '\0', sizeof(devicelist));
+    status = json_read_object(buf, json_attrs_devices, NULL);
+    if (status != 0) {
+       return status;
+    }
+    return 0;
+}
+
+int main(int argc, char *argv[])
+{
+    int i, status = 0;
+
+    status = json_devicelist_read(argv[1]);
+    printf("%d devices:\n", devicelist.ndevices);
+    for (i = 0; i < devicelist.ndevices; i++)
+       printf("%s @ %f\n", 
+              devicelist.list[i].path, devicelist.list[i].activated);
+
+    if (status != 0)
+       puts(json_error_string(status));
+}
+--------------------------------------------------------
+
+Here is an example:
+
+--------------------------------------------------------
+$ example3 '{"devices":[{"path":"/dev/ttyUSB0",
+            "activated":"2014-09-23T10:32:20"}]}'
+1 devices:
+/dev/ttyUSB0 @ 1411468340.000000
+--------------------------------------------------------
 
+In this case, the STRUCTARRAY and STRUCTOBJECT macros are clues to
+what is going on.  STRUCTOBJECT is a thin wrapper around offsetof();
+STRUCTARRAY sets up the parser to walk through the array of
+structures, filling each element as it goes.
 
 
 
index 0629811bb2079a59d9182cb43ce14e6b35f04fae..8323d959d3bd0016ea87f1b9151e466fda441062 100644 (file)
@@ -134,6 +134,6 @@ void json_enable_debug(int, FILE *);
        .addr.array.arr.objects.base = (char*)a, \
        .addr.array.arr.objects.stride = sizeof(a[0]), \
        .addr.array.count = n, \
-       .addr.array.maxlen = NITEMS(a)
+       .addr.array.maxlen = (int)(sizeof(a)/sizeof(a[0]))
 
 /* json.h ends here */