summaryrefslogtreecommitdiff
path: root/src/json.c
diff options
context:
space:
mode:
authorAnna (navi) Figueiredo Gomes <navi@vlhl.dev>2024-01-05 22:51:33 +0100
committerAnna (navi) Figueiredo Gomes <navi@vlhl.dev>2024-01-06 18:58:13 +0100
commite079370a92766181ff5281c5d6cea03a1fce5b93 (patch)
treec05ffce648ea7cb5e3c3ebb102ac4c80ff9b4c35 /src/json.c
initial release
Signed-off-by: Anna (navi) Figueiredo Gomes <navi@vlhl.dev>
Diffstat (limited to 'src/json.c')
-rw-r--r--src/json.c164
1 files changed, 164 insertions, 0 deletions
diff --git a/src/json.c b/src/json.c
new file mode 100644
index 0000000..2e86eaf
--- /dev/null
+++ b/src/json.c
@@ -0,0 +1,164 @@
+#include <assert.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <json.h>
+#include "internal.h"
+
+#include <stdio.h>
+#include <time.h>
+#include <signal.h>
+
+
+struct json *json_parse(const char *str) {
+ return json_parse_len(str, strlen(str));
+}
+
+struct json *json_new(void) {
+ struct json *json = calloc(1, sizeof(*json));
+ if (!json)
+ return NULL;
+ json->type = JSON_INVALID;
+ return json;
+}
+
+void json_detach(struct json *json) {
+ if (!json || !json->parent) return;
+
+ struct json_children *siblings = json->parent->children;
+ if (json->index != --siblings->nitems) {
+ struct json *tmp;
+ for (size_t i = json->index; i < siblings->nitems; i++) {
+ tmp = siblings->items[i] = siblings->items[i + 1];
+ tmp->index = i;
+ tmp->prev = i > 0 ? siblings->items[tmp->index - 1] : NULL;
+ tmp->next = i < siblings->nitems ? siblings->items[tmp->index + 1] : NULL;
+ }
+ }
+
+ json->parent = NULL;
+}
+
+void json_delete(struct json *json) {
+ if (!json)
+ return;
+ json_detach(json);
+ json_clear(json);
+ free(json);
+}
+
+void json_clear(struct json *json) {
+ if (!json) return;
+ switch (json->type) {
+ case JSON_OBJECT:
+ case JSON_ARRAY:
+ for (size_t i = 0; i < json->children->nitems; i++) {
+ json_clear(json->children->items[i]);
+ free(json->children->items[i]);
+ }
+ free(json->children);
+ break;
+ case JSON_STRING:
+ free(json->string);
+ break;
+ default:
+ break;
+ }
+ free(json->key);
+ json->type = JSON_INVALID;
+}
+
+struct json *json_new_array(void) {
+ struct json *json = json_new();
+ if (!json)
+ return NULL;
+ json->type = JSON_ARRAY;
+ init_children(json);
+ return json;
+}
+
+struct json *json_new_bool(bool boolean) {
+ struct json *json = json_new();
+ if (!json)
+ return NULL;
+ json->type = boolean ? JSON_TRUE : JSON_FALSE;
+ return json;
+}
+
+struct json *json_new_null(void) {
+ struct json *json = json_new();
+ if (!json)
+ return NULL;
+ json->type = JSON_NULL;
+ return json;
+}
+
+struct json *json_new_number(double num) {
+ struct json *json = json_new();
+ if (!json)
+ return NULL;
+ json->type = JSON_NUMBER;
+ json->num = num;
+ return json;
+}
+
+struct json *json_new_string(void) {
+ struct json *json = json_new();
+ if (!json)
+ return NULL;
+ json->type = JSON_STRING;
+ json->string = NULL;
+ return json;
+}
+
+struct json *json_new_string_copy(const char *string) {
+ struct json *json = json_new();
+ if (!json)
+ return NULL;
+ json->type = JSON_STRING;
+ json->string = strdup(string);
+ return json;
+}
+
+enum json_parse_result parse_value(struct json **json_out, struct raw_json *raw, size_t depth) {
+ skip_ws(raw);
+ struct json *json = NULL;
+ enum json_parse_result ret = JSON_PARSE_OK;
+ switch (raw->data[raw->index]) {
+ case '"':
+ ret = parse_string(&json, raw);
+ break;
+ case '{':
+ ret = parse_object(&json, raw, depth);
+ break;
+ case '[':
+ ret = parse_array(&json, raw, depth);
+ break;
+ default:
+ ret = parse_literal(&json, raw);
+ break;
+ }
+ *json_out = json;
+ return ret;
+}
+
+struct json *json_parse_len(const char *str, size_t size) {
+ if (!str || size == 0)
+ return NULL;
+ struct json *json = NULL;
+ struct raw_json raw = {
+ .index = 0,
+ .data = str,
+ .size = size
+ };
+ if (parse_value(&json, &raw, 1) != JSON_PARSE_OK) {
+ return NULL;
+ };
+ skip_ws(&raw);
+ if (raw.index != raw.size) {
+ json_delete(json);
+ return NULL;
+ }
+ return json;
+}