]> thyrsus.com Git - microjson.git/commitdiff
Beginnings of documentation, and a worked example.
authorEric S. Raymond <esr@thyrsus.com>
Wed, 17 Sep 2014 17:26:00 +0000 (13:26 -0400)
committerEric S. Raymond <esr@thyrsus.com>
Wed, 17 Sep 2014 17:26:00 +0000 (13:26 -0400)
.gitignore
Makefile
example1.c [new file with mode: 0644]
microjson.asc [new file with mode: 0644]
microjson.c

index 30a9a25fb499074995d9769265aa2a1b6b50c5c4..b9b3be66314c1e25de0d2c423a9151f3a6e5e604 100644 (file)
@@ -1,2 +1,3 @@
 *.o
 test_microjson
+example1
index 080cc4236a4d183fe8a879a52b25c3ee203fdb9a..025db306ac126458f0090c5853d85b7e3aa29b9a 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -15,15 +15,18 @@ test_microjson: test_microjson.o microjson.o
 check: test_microjson
        test_microjson
 
+# Worked example
+example1: example1.c microjson.c
+
 clean:
-       rm -f microjson.o test_json
+       rm -f microjson.o test_json example1
 
 CSUPPRESSIONS = -U__UNUSED__
 cppcheck:
        cppcheck -I. --template gcc --enable=all --suppress=unusedStructMember $(CSUPPRESSIONS) *.[ch]
 
 SOURCES = Makefile *.[ch]
-DOCS = README COPYING
+DOCS = README COPYING microjson.asc
 ALL =  $(SOURCES) $(DOCS)
 microjson-$(VERSION).tar.gz: $(ALL)
        tar --transform='s:^:microjson-$(VERSION)/:' --show-transformed-names -cvzf microjson-$(VERSION).tar.gz $(ALL)
diff --git a/example1.c b/example1.c
new file mode 100644 (file)
index 0000000..4dbd945
--- /dev/null
@@ -0,0 +1,35 @@
+/* example1.c - first example in the programming guide
+ *
+ * This file is Copyright (c) 2010 by the GPSD project
+ * BSD terms apply: see the file COPYING in the distribution root for details.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+
+#include "microjson.h"
+
+static const char *simple = "{\"flag1\":true,\"flag2\":false,\"count\":42}";
+
+static bool flag1, flag2;
+static int count;
+
+static const struct json_attr_t json_attrs[] = {
+    {"count",   t_integer, .addr.integer = &count},
+    {"flag1",   t_boolean, .addr.boolean = &flag1,},
+    {"flag2",   t_boolean, .addr.boolean = &flag2,},
+    {NULL},
+};
+
+int main(int argc, char *argv[])
+{
+    int status = 0;
+
+    puts(simple);
+    json_read_object(simple, json_attrs, NULL);
+    printf("count = %d, flag1 = %d, flag2 = %d\n",
+          count, flag1, flag2);
+}
+
+/* end */
diff --git a/microjson.asc b/microjson.asc
new file mode 100644 (file)
index 0000000..89913f4
--- /dev/null
@@ -0,0 +1,115 @@
+= Building static JSON parsers with microjson =
+Eric S. Raymond <esr@thyrsus.com>
+
+== Overview ==
+
+microjson is a tiny parser for a large subset of JSON (JavaScript Object
+Notation) with the distinguishing feature that it uses entirely
+fixed-extent memory, no malloc().  It is thus very suitable for use in
+memory-constrained environments such as embedded systems; also for
+long-running service daemons that must provably not leak memory.
+
+microjson is extremely well-tested code.  This is essentially the same
+parser used in GPSD and its client libraries, which have hundreds of
+millions of deployments underneath Google Maps in Android phones.
+
+microjson parses JSON from string input and unpacks the content
+directly into static storage declared by the calling program.
+You give it a set of template structures describing the expected shape
+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.
+
+== An Example ==
+
+Here is nearly the simplest possible example:
+
+---------------------------------------------------------------------
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+
+#include "microjson.h"
+
+static const char *simple = "{\"flag1\":true,\"flag2\":false,\"count\":42}";
+
+static bool flag1, flag2;
+static int count;
+
+static const struct json_attr_t json_attrs[] = {
+    {"count",   t_integer, .addr.integer = &count},
+    {"flag1",   t_boolean, .addr.boolean = &flag1,},
+    {"flag2",   t_boolean, .addr.boolean = &flag2,},
+    {NULL},
+};
+
+int main(int argc, char *argv[])
+{
+    int status = 0;
+
+    puts(simple);
+    json_read_object(simple, json_attrs, NULL);
+    printf("count = %d, flag1 = %d, flag2 = %d\n",
+          count, flag1, flag2);
+}
+
+/* end */
+---------------------------------------------------------------------
+
+The +json_read_object()+ call unpacks the values in the example JSON object into
+three static variables.  In many uses the target locations would
+instead be storage in some static structure instance.
+
+In this example, the +json_attrs+ structure array associates each
+possible member name with a type and a target address.  The function
++json_read_object()+ treats this array of constants as parsing
+instructions.
+
+The parser recognizes a wider range of types than this, and the
+template structures can specify defaults when an expected JSON 
+attribute is omitted. Most of the rest is details.
+
+== Theory of Operation ==
+
+The "shape" of a JSON object in the type signature of its
+attributes (and attribute values, and so on recursively down through
+all nestings of objects and arrays).  This parser is indifferent to
+the order of attributes at any level, but you have to tell it in
+advance what the type of each attribute value will be and where the
+parsed value will be stored. The template structures may supply
+default values to be used when an expected attribute is omitted.
+
+The preceding paragraph told one fib.  A single attribute may actually
+have a span of multiple specifications with different syntactically
+distinguishable types (e.g. string vs. real vs. integer vs. boolean,
+but not signed integer vs. unsigned integer).  The parser will match
+the right spec against the actual data.
+
+The dialect this parses has some limitations.  First, it cannot
+recognize the JSON "null" value.  Secondly, arrays may only have
+objects or strings - not reals or integers or floats - as elements
+(this limitation could be easily removed if required). Third, all
+elements of an array must be of the same type.
+
+There are separata entry points for beginning a parse of either JSON
+object or a JSON array. JSON "float" quantities are actually stored as
+doubles.
+
+This parser processes object arrays in one of two different ways,
+defending on whether the array subtype is declared as object or
+structobject.
+
+   Object arrays take one base address per object subfield, and are
+mapped into parallel C arrays (one per subfield).  Strings are not
+supported in this kind of array, as they don't have a "natural" size
+to use as an offset multiplier.
+
+   Structobjects arrays are a way to parse a list of objects to a set
+of modifications to a corresponding array of C structs.  The trick is
+that the array object initialization has to specify both the C struct
+array's base address and the stride length (the size of the C struct).
+If you initialize the offset fields with the correct offsetof calls,
+everything will work. Strings are supported but all string storage
+has to be inline in the struct.
+
+
index de5141893debbe9d8264b922745e524b89113264..8687cda2fceab192fe173c605ce544155edf058f 100644 (file)
@@ -54,7 +54,7 @@ everything will work. Strings are supported but all string storage
 has to be inline in the struct.
 
 PERMISSIONS
-   This file is Copyright (c) 2014 by the Eric S. Raymond
+   This file is Copyright (c) 2014 by Eric S. Raymond
    BSD terms apply: see the file COPYING in the distribution root for details.
 
 ***************************************************************************/