Squashed 'third_party/jsont/' content from commit 1536152d7

Change-Id: I51a80190772b74ca0d45fd3fadc130e872b57cc0
git-subtree-dir: third_party/jsont
git-subtree-split: 1536152d7c1926448d42e4a691acd9a15940b20c
diff --git a/example2.c b/example2.c
new file mode 100644
index 0000000..5077f85
--- /dev/null
+++ b/example2.c
@@ -0,0 +1,183 @@
+//
+// This is an example of parsing and building strict documents into C structs.
+//
+// The general approach is that each object type has a struct type and a
+// builder function. The struct type has members which represents its
+// properties. The builder function is more intresting: It takes a tokenizer
+// state and a struct instance. The builder function then reads each field
+// name from the tokenizer and calls other builder functions (this is how this
+// parser does flow control), and eventually stores the values into the struct
+// instance.
+//
+#include <jsont.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdbool.h>
+
+// A simple array type
+typedef struct my_array {
+  size_t size;
+  size_t count;
+  void** items;
+} my_array_t;
+
+// Represents a user object
+typedef struct my_user {
+  const char* id;
+  const char* name;
+} my_user_t;
+
+// Represents a response from our imaginary service
+typedef struct my_response {
+  int64_t timestamp;
+  const char* viewer_id;
+  my_array_t users;
+} my_response_t;
+
+// A helper macro for allocating a new struct instance
+#define MY_NEW(T) (T*)malloc(sizeof(T))
+
+// Some helper macros for dealing with growing arrays
+#define MY_ARRAY_ALLOC(A, _size) do {\
+    (A).items = (void*)malloc(sizeof(void*)*_size); \
+    (A).count = 0; \
+    (A).size = _size; \
+  } while(0)
+#define MY_ARRAY_RESIZE(A, _size) do {\
+    (A).items = (void*)realloc((A).items, sizeof(void*)*_size); \
+    (A).size = _size; \
+  } while(0)
+#define MY_ARRAY_APPEND(A, item) (A).items[(A).count++] = (void*)(item)
+#define MY_NEXT_EXPECT(S, TOKTYPE) do { \
+  if ((tok = jsont_next(S)) != TOKTYPE) { \
+    printf("Error: Builder expected token " #TOKTYPE " (%d)\n", __LINE__); \
+    return false; \
+  }} while (0)
+
+// Builder function for user objects
+bool my_user_build(jsont_ctx_t* S, my_user_t* obj) {
+  jsont_tok_t tok = jsont_current(S);
+  if (tok != JSONT_OBJECT_START) return false;
+  
+  // for each field
+  while ((tok = jsont_next(S)) == JSONT_FIELD_NAME) {
+    const uint8_t* fieldname = 0;
+    size_t len = jsont_data_value(S, &fieldname);
+
+    if (memcmp("id", fieldname, len) == 0) {
+      MY_NEXT_EXPECT(S, JSONT_STRING);
+      obj->id = jsont_strcpy_value(S);
+    
+    } else if (memcmp("name", fieldname, len) == 0) {
+      MY_NEXT_EXPECT(S, JSONT_STRING);
+      obj->name = jsont_strcpy_value(S);
+
+    } else {
+      printf("%s: Unexpected field: \"%.*s\"\n", __FUNCTION__,
+        (int)len, (const char*)fieldname);
+      return false;
+    }
+  }
+
+  return true;
+}
+
+// Builder function for response objects
+bool my_response_build(jsont_ctx_t* S, my_response_t* obj) {
+  jsont_tok_t tok = jsont_current(S);
+  if (tok != JSONT_OBJECT_START) return false;
+
+  // for each field
+  while ((tok = jsont_next(S)) == JSONT_FIELD_NAME) {
+    const uint8_t* fieldname = 0;
+    size_t len = jsont_data_value(S, &fieldname);
+
+    if (memcmp("timestamp", fieldname, len) == 0) {
+      MY_NEXT_EXPECT(S, JSONT_NUMBER_INT);
+      obj->timestamp = jsont_int_value(S);
+
+    } else if (memcmp("viewer_id", fieldname, len) == 0) {
+      MY_NEXT_EXPECT(S, JSONT_STRING);
+      obj->viewer_id = jsont_strcpy_value(S);
+
+    } else if (memcmp("users", fieldname, len) == 0) {
+      MY_NEXT_EXPECT(S, JSONT_ARRAY_START);
+      MY_ARRAY_ALLOC(obj->users, 10);
+
+      // for each user object
+      while ((tok = jsont_next(S)) == JSONT_OBJECT_START) {
+        if (obj->users.count == obj->users.size)
+          MY_ARRAY_RESIZE(obj->users, obj->users.size * 2);
+        my_user_t* user = MY_NEW(my_user_t);
+        if (!my_user_build(S, user))
+          return false;
+        MY_ARRAY_APPEND(obj->users, user);
+      }
+    } else {
+      printf("%s: Unexpected field: \"%.*s\"\n", __FUNCTION__,
+        (int)len, (const char*)fieldname);
+      return false;
+    }
+  }
+  
+  return true;
+}
+
+// Our simple response parser entry point. Returns NULL on error.
+my_response_t* my_parse_response(jsont_ctx_t* S) {
+if (jsont_next(S) != JSONT_OBJECT_START) {
+    printf("Expected JSON input to start with an object.\n");
+    return 0;
+  }
+  my_response_t* rsp = MY_NEW(my_response_t);
+  if (!my_response_build(S, rsp)) {
+    free(rsp);
+    return 0;
+  }
+  return rsp;
+}
+
+int main(int argc, const char** argv) {
+  // Create a new reusable tokenizer
+  jsont_ctx_t* S = jsont_create(0);
+
+  // Sample "response" data
+  const char* inbuf = "{"
+    "\"viewer_id\": \"abc123\","
+    "\"timestamp\": 1234567890,"
+    "\"users\":["
+      "{\"name\": \"John Smith\", \"id\": \"12c39a\"},\n"
+      "{\"name\": \"John Doe\",   \"id\": \"01dk2\"},\n"
+      "{\"name\": \"Kate Smith\", \"id\": \"apru1\"},\n"
+      "{\"name\": \"Rebecca Doe\",\"id\": \"aRm26\"}\n"
+    "]"
+  "}";
+
+  // Parse the sample "response" data
+  jsont_reset(S, (const uint8_t*)inbuf, strlen(inbuf));
+  my_response_t* rsp = my_parse_response(S);
+
+  // Epic success?
+  if (rsp) {
+    printf("Built response structure.\n");
+    printf("rsp->users.items[2]->name => \"%s\"\n",
+      ((my_user_t*)rsp->users.items[2])->name );
+
+  } else {
+    printf("Failed to build response structure.\n");
+    if (jsont_error_info(S) != 0) {
+      fprintf(stderr, "Error: %s ('%c' at offset %lu)\n",
+              jsont_error_info(S),
+              (char)jsont_current_byte(S),
+              (unsigned long)jsont_current_offset(S));
+    }
+    // Exit with error. Note: In a real application, you should call
+    // `jsont_destroy` on the reusable tokenizer when done with it. Here we
+    // just exit the program.
+    return 1;
+  }
+
+  // Destroy our reusable tokenizer and exit
+  jsont_destroy(S);
+  return 0;
+}