aboutsummaryrefslogtreecommitdiff
path: root/jslinux-2019-12-21/tinyemu-2019-12-21/json.c
diff options
context:
space:
mode:
authorMitchell Riedstra <mitch@riedstra.dev>2025-12-24 19:49:57 -0500
committerMitchell Riedstra <mitch@riedstra.dev>2025-12-24 19:49:57 -0500
commit939ac4319cb047a37ba46f84eff81948063f6954 (patch)
tree5112cf8aad73125a13f5b52c0290a7f26f948b52 /jslinux-2019-12-21/tinyemu-2019-12-21/json.c
parent3a1b5ba15b89c907f9bf66a0761ffdd73b32208b (diff)
downloadunixv4-939ac4319cb047a37ba46f84eff81948063f6954.tar.gz
unixv4-939ac4319cb047a37ba46f84eff81948063f6954.tar.xz
Add working webpage for unix v4
Diffstat (limited to 'jslinux-2019-12-21/tinyemu-2019-12-21/json.c')
-rw-r--r--jslinux-2019-12-21/tinyemu-2019-12-21/json.c464
1 files changed, 464 insertions, 0 deletions
diff --git a/jslinux-2019-12-21/tinyemu-2019-12-21/json.c b/jslinux-2019-12-21/tinyemu-2019-12-21/json.c
new file mode 100644
index 0000000..d1ebe82
--- /dev/null
+++ b/jslinux-2019-12-21/tinyemu-2019-12-21/json.c
@@ -0,0 +1,464 @@
+/*
+ * Pseudo JSON parser
+ *
+ * Copyright (c) 2017 Fabrice Bellard
+ *
+ * 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 <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <inttypes.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <unistd.h>
+#include <time.h>
+#include <ctype.h>
+
+#include "cutils.h"
+#include "json.h"
+#include "fs_utils.h"
+
+static JSONValue parse_string(const char **pp)
+{
+ char buf[4096], *q;
+ const char *p;
+ int c, h;
+
+ q = buf;
+ p = *pp;
+ p++;
+ for(;;) {
+ c = *p++;
+ if (c == '\0' || c == '\n') {
+ return json_error_new("unterminated string");
+ } else if (c == '\"') {
+ break;
+ } else if (c == '\\') {
+ c = *p++;
+ switch(c) {
+ case '\'':
+ case '\"':
+ case '\\':
+ goto add_char;
+ case 'n':
+ c = '\n';
+ goto add_char;
+ case 'r':
+ c = '\r';
+ goto add_char;
+ case 't':
+ c = '\t';
+ goto add_char;
+ case 'x':
+ h = from_hex(*p++);
+ if (h < 0)
+ return json_error_new("invalig hex digit");
+ c = h << 4;
+ h = from_hex(*p++);
+ if (h < 0)
+ return json_error_new("invalig hex digit");
+ c |= h;
+ goto add_char;
+ default:
+ return json_error_new("unknown escape code");
+ }
+ } else {
+ add_char:
+ if (q >= buf + sizeof(buf) - 1)
+ return json_error_new("string too long");
+ *q++ = c;
+ }
+ }
+ *q = '\0';
+ *pp = p;
+ return json_string_new(buf);
+}
+
+static JSONProperty *json_object_get2(JSONObject *obj, const char *name)
+{
+ JSONProperty *f;
+ int i;
+ for(i = 0; i < obj->len; i++) {
+ f = &obj->props[i];
+ if (!strcmp(f->name.u.str->data, name))
+ return f;
+ }
+ return NULL;
+}
+
+JSONValue json_object_get(JSONValue val, const char *name)
+{
+ JSONProperty *f;
+ JSONObject *obj;
+
+ if (val.type != JSON_OBJ)
+ return json_undefined_new();
+ obj = val.u.obj;
+ f = json_object_get2(obj, name);
+ if (!f)
+ return json_undefined_new();
+ return f->value;
+}
+
+int json_object_set(JSONValue val, const char *name, JSONValue prop_val)
+{
+ JSONObject *obj;
+ JSONProperty *f;
+ int new_size;
+
+ if (val.type != JSON_OBJ)
+ return -1;
+ obj = val.u.obj;
+ f = json_object_get2(obj, name);
+ if (f) {
+ json_free(f->value);
+ f->value = prop_val;
+ } else {
+ if (obj->len >= obj->size) {
+ new_size = max_int(obj->len + 1, obj->size * 3 / 2);
+ obj->props = realloc(obj->props, new_size * sizeof(JSONProperty));
+ obj->size = new_size;
+ }
+ f = &obj->props[obj->len++];
+ f->name = json_string_new(name);
+ f->value = prop_val;
+ }
+ return 0;
+}
+
+JSONValue json_array_get(JSONValue val, unsigned int idx)
+{
+ JSONArray *array;
+
+ if (val.type != JSON_ARRAY)
+ return json_undefined_new();
+ array = val.u.array;
+ if (idx < array->len) {
+ return array->tab[idx];
+ } else {
+ return json_undefined_new();
+ }
+}
+
+int json_array_set(JSONValue val, unsigned int idx, JSONValue prop_val)
+{
+ JSONArray *array;
+ int new_size;
+
+ if (val.type != JSON_ARRAY)
+ return -1;
+ array = val.u.array;
+ if (idx < array->len) {
+ json_free(array->tab[idx]);
+ array->tab[idx] = prop_val;
+ } else if (idx == array->len) {
+ if (array->len >= array->size) {
+ new_size = max_int(array->len + 1, array->size * 3 / 2);
+ array->tab = realloc(array->tab, new_size * sizeof(JSONValue));
+ array->size = new_size;
+ }
+ array->tab[array->len++] = prop_val;
+ } else {
+ return -1;
+ }
+ return 0;
+}
+
+const char *json_get_str(JSONValue val)
+{
+ if (val.type != JSON_STR)
+ return NULL;
+ return val.u.str->data;
+}
+
+const char *json_get_error(JSONValue val)
+{
+ if (val.type != JSON_EXCEPTION)
+ return NULL;
+ return val.u.str->data;
+}
+
+JSONValue json_string_new2(const char *str, int len)
+{
+ JSONValue val;
+ JSONString *str1;
+
+ str1 = malloc(sizeof(JSONString) + len + 1);
+ str1->len = len;
+ memcpy(str1->data, str, len + 1);
+ val.type = JSON_STR;
+ val.u.str = str1;
+ return val;
+}
+
+JSONValue json_string_new(const char *str)
+{
+ return json_string_new2(str, strlen(str));
+}
+
+JSONValue __attribute__((format(printf, 1, 2))) json_error_new(const char *fmt, ...)
+{
+ JSONValue val;
+ va_list ap;
+ char buf[256];
+
+ va_start(ap, fmt);
+ vsnprintf(buf, sizeof(buf), fmt, ap);
+ va_end(ap);
+ val = json_string_new(buf);
+ val.type = JSON_EXCEPTION;
+ return val;
+}
+
+JSONValue json_object_new(void)
+{
+ JSONValue val;
+ JSONObject *obj;
+ obj = mallocz(sizeof(JSONObject));
+ val.type = JSON_OBJ;
+ val.u.obj = obj;
+ return val;
+}
+
+JSONValue json_array_new(void)
+{
+ JSONValue val;
+ JSONArray *array;
+ array = mallocz(sizeof(JSONArray));
+ val.type = JSON_ARRAY;
+ val.u.array = array;
+ return val;
+}
+
+void json_free(JSONValue val)
+{
+ switch(val.type) {
+ case JSON_STR:
+ case JSON_EXCEPTION:
+ free(val.u.str);
+ break;
+ case JSON_INT:
+ case JSON_BOOL:
+ case JSON_NULL:
+ case JSON_UNDEFINED:
+ break;
+ case JSON_ARRAY:
+ {
+ JSONArray *array = val.u.array;
+ int i;
+
+ for(i = 0; i < array->len; i++) {
+ json_free(array->tab[i]);
+ }
+ free(array);
+ }
+ break;
+ case JSON_OBJ:
+ {
+ JSONObject *obj = val.u.obj;
+ JSONProperty *f;
+ int i;
+
+ for(i = 0; i < obj->len; i++) {
+ f = &obj->props[i];
+ json_free(f->name);
+ json_free(f->value);
+ }
+ free(obj);
+ }
+ break;
+ default:
+ abort();
+ }
+}
+
+static void skip_spaces(const char **pp)
+{
+ const char *p;
+ p = *pp;
+ for(;;) {
+ if (isspace(*p)) {
+ p++;
+ } else if (p[0] == '/' && p[1] == '/') {
+ p += 2;
+ while (*p != '\0' && *p != '\n')
+ p++;
+ } else if (p[0] == '/' && p[1] == '*') {
+ p += 2;
+ while (*p != '\0' && (p[0] != '*' || p[1] != '/'))
+ p++;
+ if (*p != '\0')
+ p += 2;
+ } else {
+ break;
+ }
+ }
+ *pp = p;
+}
+
+static inline BOOL is_ident_first(int c)
+{
+ return (c >= 'a' && c <= 'z') ||
+ (c >= 'A' && c <= 'Z') ||
+ c == '_' || c == '$';
+}
+
+static int parse_ident(char *buf, int buf_size, const char **pp)
+{
+ char *q;
+ const char *p;
+ p = *pp;
+ q = buf;
+ *q++ = *p++; /* first char is already tested */
+ while (is_ident_first(*p) || isdigit(*p)) {
+ if ((q - buf) >= buf_size - 1)
+ return -1;
+ *q++ = *p++;
+ }
+ *pp = p;
+ *q = '\0';
+ return 0;
+}
+
+JSONValue json_parse_value2(const char **pp)
+{
+ char buf[128];
+ const char *p;
+ JSONValue val, val1, tag;
+
+ p = *pp;
+ skip_spaces(&p);
+ if (*p == '\0') {
+ return json_error_new("unexpected end of file");
+ }
+ if (isdigit(*p)) {
+ val = json_int32_new(strtol(p, (char **)&p, 0));
+ } else if (*p == '"') {
+ val = parse_string(&p);
+ } else if (*p == '{') {
+ p++;
+ val = json_object_new();
+ for(;;) {
+ skip_spaces(&p);
+ if (*p == '}') {
+ p++;
+ break;
+ }
+ if (*p == '"') {
+ tag = parse_string(&p);
+ if (json_is_error(tag))
+ return tag;
+ } else if (is_ident_first(*p)) {
+ if (parse_ident(buf, sizeof(buf), &p) < 0)
+ goto invalid_prop;
+ tag = json_string_new(buf);
+ } else {
+ goto invalid_prop;
+ }
+ // printf("property: %s\n", json_get_str(tag));
+ if (tag.u.str->len == 0) {
+ invalid_prop:
+ return json_error_new("Invalid property name");
+ }
+ skip_spaces(&p);
+ if (*p != ':') {
+ return json_error_new("':' expected");
+ }
+ p++;
+
+ val1 = json_parse_value2(&p);
+ json_object_set(val, tag.u.str->data, val1);
+
+ skip_spaces(&p);
+ if (*p == ',') {
+ p++;
+ } else if (*p != '}') {
+ return json_error_new("expecting ',' or '}'");
+ }
+ }
+ } else if (*p == '[') {
+ int idx;
+
+ p++;
+ val = json_array_new();
+ idx = 0;
+ for(;;) {
+ skip_spaces(&p);
+ if (*p == ']') {
+ p++;
+ break;
+ }
+ val1 = json_parse_value2(&p);
+ json_array_set(val, idx++, val1);
+
+ skip_spaces(&p);
+ if (*p == ',') {
+ p++;
+ } else if (*p != ']') {
+ return json_error_new("expecting ',' or ']'");
+ }
+ }
+ } else if (is_ident_first(*p)) {
+ if (parse_ident(buf, sizeof(buf), &p) < 0)
+ goto unknown_id;
+ if (!strcmp(buf, "null")) {
+ val = json_null_new();
+ } else if (!strcmp(buf, "true")) {
+ val = json_bool_new(TRUE);
+ } else if (!strcmp(buf, "false")) {
+ val = json_bool_new(FALSE);
+ } else {
+ unknown_id:
+ return json_error_new("unknown identifier: '%s'", buf);
+ }
+ } else {
+ return json_error_new("unexpected character");
+ }
+ *pp = p;
+ return val;
+}
+
+JSONValue json_parse_value(const char *p)
+{
+ JSONValue val;
+ val = json_parse_value2(&p);
+ if (json_is_error(val))
+ return val;
+ skip_spaces(&p);
+ if (*p != '\0') {
+ json_free(val);
+ return json_error_new("unexpected characters at the end");
+ }
+ return val;
+}
+
+JSONValue json_parse_value_len(const char *p, int len)
+{
+ char *str;
+ JSONValue val;
+ str = malloc(len + 1);
+ memcpy(str, p, len);
+ str[len] = '\0';
+ val = json_parse_value(str);
+ free(str);
+ return val;
+}