From e7607ffc2b62bb9a797c6fad0d22b0bee9c3f5fe Mon Sep 17 00:00:00 2001
From: Drasko DRASKOVIC <drasko.draskovic@gmail.com>
Date: Wed, 4 May 2016 22:43:02 +0200
Subject: [PATCH] Add JSON support

This commits adds JSON support by adding Jsmn
(http://zserge.com/jsmn.html), a minimalistic JSON parser.

Signed-off-by: Drasko DRASKOVIC <drasko.draskovic@gmail.com>
---
 .gitmodules                                  |   3 +
 examples/json_jsmn_simple/Makefile           |   4 +
 examples/json_jsmn_simple/json_jsmn_simple.c | 112 +++++++++++++++++++
 extras/jsmn/component.mk                     |  10 ++
 extras/jsmn/jsmn                             |   1 +
 5 files changed, 130 insertions(+)
 create mode 100644 examples/json_jsmn_simple/Makefile
 create mode 100644 examples/json_jsmn_simple/json_jsmn_simple.c
 create mode 100644 extras/jsmn/component.mk
 create mode 160000 extras/jsmn/jsmn

diff --git a/.gitmodules b/.gitmodules
index 8dc737e..52708f8 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -4,3 +4,6 @@
 [submodule "extras/mbedtls/mbedtls"]
 	path = extras/mbedtls/mbedtls
 	url = https://github.com/ARMmbed/mbedtls.git
+[submodule "extras/jsmn/jsmn"]
+	path = extras/jsmn/jsmn
+	url = https://github.com/zserge/jsmn.git
diff --git a/examples/json_jsmn_simple/Makefile b/examples/json_jsmn_simple/Makefile
new file mode 100644
index 0000000..89e6ba7
--- /dev/null
+++ b/examples/json_jsmn_simple/Makefile
@@ -0,0 +1,4 @@
+# Simple makefile for simple example
+PROGRAM=json_jsmn_simple
+EXTRA_COMPONENTS = extras/jsmn
+include ../../common.mk
diff --git a/examples/json_jsmn_simple/json_jsmn_simple.c b/examples/json_jsmn_simple/json_jsmn_simple.c
new file mode 100644
index 0000000..3a65ddf
--- /dev/null
+++ b/examples/json_jsmn_simple/json_jsmn_simple.c
@@ -0,0 +1,112 @@
+/**
+ * Copyright (c) 2010 Serge A. Zaitsev and
+ * 2016 Drasko DRASKOVIC <drasko.draskovic@gmail.com>
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "espressif/esp_common.h"
+#include "esp/uart.h"
+#include "FreeRTOS.h"
+#include "task.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "jsmn.h"
+
+/**
+ * A small example of jsmn parsing when JSON structure is known and number of
+ * tokens is predictable.
+ */
+
+const char *JSON_STRING =
+	"{\"user\": \"johndoe\", \"admin\": false, \"uid\": 1000,\n  "
+	"\"groups\": [\"users\", \"wheel\", \"audio\", \"video\"]}";
+
+static int jsoneq(const char *json, jsmntok_t *tok, const char *s) {
+	if (tok->type == JSMN_STRING && (int) strlen(s) == tok->end - tok->start &&
+			strncmp(json + tok->start, s, tok->end - tok->start) == 0) {
+		return 0;
+	}
+	return -1;
+}
+
+void json_test(void *pvParameters)
+{
+    int i;
+	int r;
+	jsmn_parser p;
+	jsmntok_t t[128]; /* We expect no more than 128 tokens */
+
+	jsmn_init(&p);
+	r = jsmn_parse(&p, JSON_STRING, strlen(JSON_STRING), t, sizeof(t)/sizeof(t[0]));
+	if (r < 0) {
+		printf("Failed to parse JSON: %d\n", r);
+	}
+
+	/* Assume the top-level element is an object */
+	if (r < 1 || t[0].type != JSMN_OBJECT) {
+		printf("Object expected\n");
+	}
+
+	/* Loop over all keys of the root object */
+	for (i = 1; i < r; i++) {
+		if (jsoneq(JSON_STRING, &t[i], "user") == 0) {
+			/* We may use strndup() to fetch string value */
+			printf("- User: %.*s\n", t[i+1].end-t[i+1].start,
+					JSON_STRING + t[i+1].start);
+			i++;
+		} else if (jsoneq(JSON_STRING, &t[i], "admin") == 0) {
+			/* We may additionally check if the value is either "true" or "false" */
+			printf("- Admin: %.*s\n", t[i+1].end-t[i+1].start,
+					JSON_STRING + t[i+1].start);
+			i++;
+		} else if (jsoneq(JSON_STRING, &t[i], "uid") == 0) {
+			/* We may want to do strtol() here to get numeric value */
+			printf("- UID: %.*s\n", t[i+1].end-t[i+1].start,
+					JSON_STRING + t[i+1].start);
+			i++;
+		} else if (jsoneq(JSON_STRING, &t[i], "groups") == 0) {
+			int j;
+			printf("- Groups:\n");
+			if (t[i+1].type != JSMN_ARRAY) {
+				continue; /* We expect groups to be an array of strings */
+			}
+			for (j = 0; j < t[i+1].size; j++) {
+				jsmntok_t *g = &t[i+j+2];
+				printf("  * %.*s\n", g->end - g->start, JSON_STRING + g->start);
+			}
+			i += t[i+1].size + 1;
+		} else {
+			printf("Unexpected key: %.*s\n", t[i].end-t[i].start,
+					JSON_STRING + t[i].start);
+		}
+	}
+
+    while (1)
+        ;
+}
+
+
+void user_init(void)
+{
+    uart_set_baud(0, 115200);
+    printf("SDK version:%s\n", sdk_system_get_sdk_version());
+    xTaskCreate(json_test, (signed char *)"jsont", 1024, NULL, 2, NULL);
+}
diff --git a/extras/jsmn/component.mk b/extras/jsmn/component.mk
new file mode 100644
index 0000000..13beac4
--- /dev/null
+++ b/extras/jsmn/component.mk
@@ -0,0 +1,10 @@
+# Component makefile for extras/jsmn
+
+# expected anyone using jsmn json component includes it as 'jsmn/jsmn.h'
+INC_DIRS += $(jsmn_ROOT)jsmn
+
+# args for passing into compile rule generation
+jsmn_INC_DIR =
+jsmn_SRC_DIR = $(jsmn_ROOT)jsmn
+
+$(eval $(call component_compile_rules,jsmn))
diff --git a/extras/jsmn/jsmn b/extras/jsmn/jsmn
new file mode 160000
index 0000000..bbc6755
--- /dev/null
+++ b/extras/jsmn/jsmn
@@ -0,0 +1 @@
+Subproject commit bbc6755fce14c713f9bb4ba47c688d15efc1394b