From e002c3060c0adb5d66a917a3e798b54e9ce8f0ef Mon Sep 17 00:00:00 2001
From: Kubat <mael.martin31@gmail.com>
Date: Sun, 17 Jan 2021 13:07:36 +0100
Subject: [PATCH] BASE: Add a basic json parser suited for our needs

---
 inc/lektor/json.h | 26 ++++++++++++++
 src/base/json.c   | 89 +++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 115 insertions(+)
 create mode 100644 inc/lektor/json.h
 create mode 100644 src/base/json.c

diff --git a/inc/lektor/json.h b/inc/lektor/json.h
new file mode 100644
index 00000000..2ae81839
--- /dev/null
+++ b/inc/lektor/json.h
@@ -0,0 +1,26 @@
+#if ! defined(__LKT_JSON_H__)
+#define __LKT_JSON_H__
+
+/* LIMITATIONS AND SPECIFICATIONS:
+ * - parse only one level at the time
+ * - values can't be arrays or json objects
+ * - " toto tata" => one string ' toto tata'
+ * - toto tata => two strings 'toto' and 'tata'
+ * - to separate a value from a key, the '=' and ':' separators are not
+ *   mendatory, a simple space is enaugth
+ * - all values are be strings */
+
+// *INDENT-OFF*
+typedef void(*json_parse_callback)(
+        const char *key,        /* Json key, a string                       */
+        const char *value,      /* Json value, a string                     */
+        int new_obj,            /* 1 when encountered a new object          */
+        void *user              /* The user pointer from the parse function */
+);
+// *INDENT-ON*
+
+/* Parse only one level of json, simple but only what we need for lektor. The
+ * callback is used when a couple key/value is found for the correct level. */
+int json_parse(const char *str, int level, json_parse_callback, void *user);
+
+#endif /* __LKT_JSON_H__ */
diff --git a/src/base/json.c b/src/base/json.c
new file mode 100644
index 00000000..5f2de939
--- /dev/null
+++ b/src/base/json.c
@@ -0,0 +1,89 @@
+#define _POSIX_C_SOURCE 200809L
+
+#include <lektor/common.h>
+#include <lektor/json.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+
+#define __JSON_SPACE " \n\t:=,"
+#define __JSON_BEGIN "{["
+#define __JSON_END   "}]"
+
+static inline char *
+strip(char *s)
+{
+    char *p = s + strlen(s);
+    while (p > s && isspace(*(--p)))
+        *p = 0;
+    return s;
+}
+
+static inline char *
+skip(char *s)
+{
+    while (*s && isspace(*s))
+        s++;
+    return s;
+}
+
+#define __SKIP_JSON(str) (str = &str[strspn(str, __JSON_SPACE)])
+
+int
+json_parse(const char *str, int asked_level, json_parse_callback call, void *user)
+{
+    int level   = 0;
+    int new_obj = 1;
+    char key[LKT_LINE_MAX];
+    char val[LKT_LINE_MAX];
+
+    for (;;) {
+        size_t len = 0;
+        __SKIP_JSON(str);
+
+        /* Begin of a block */
+        if ((len = strspn(str, __JSON_BEGIN))) {
+            new_obj = 1;
+            level  += len;
+            str    += len;
+        }
+
+        /* End of a block */
+        else if ((len = strspn(str, __JSON_END))) {
+            new_obj = 1;
+            str    += len;
+            level  -= len;
+        }
+
+        /* Key Value */
+        else {
+            memset(key, 0, sizeof(key));
+            memset(val, 0, sizeof(val));
+
+            len = strcspn(str, __JSON_SPACE __JSON_BEGIN __JSON_END);
+            if (level == asked_level && len < LKT_LINE_MAX - 1)
+                strncpy(key, str, len);
+            str += len;
+
+            __SKIP_JSON(str);
+
+            len = strcspn(str, __JSON_SPACE __JSON_BEGIN __JSON_END);
+            if (level == asked_level && len < LKT_LINE_MAX - 1)
+                strncpy(val, str, len);
+            str += len;
+
+            if (asked_level == level)
+                call(key, val, new_obj, user);
+
+            if (new_obj)
+                new_obj = 0;
+
+        }
+
+        if (level <= 0) {
+            return 0;
+        }
+    }
+    return 1;
+}
-- 
GitLab