diff options
author | Anna (navi) Figueiredo Gomes <navi@vlhl.dev> | 2024-01-05 22:51:33 +0100 |
---|---|---|
committer | Anna (navi) Figueiredo Gomes <navi@vlhl.dev> | 2024-01-06 18:58:13 +0100 |
commit | e079370a92766181ff5281c5d6cea03a1fce5b93 (patch) | |
tree | c05ffce648ea7cb5e3c3ebb102ac4c80ff9b4c35 /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.c | 164 |
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; +} |