From 018442a4459a1afdf703a680405b1c813030862d Mon Sep 17 00:00:00 2001 From: ari melody Date: Thu, 11 Jul 2024 14:41:47 +0100 Subject: [PATCH] fixed array parsing and windows support --- build.ps1 | 2 +- build.sh | 2 +- src/main.c | 26 +++++++------- src/parsers/json.c | 88 ++++++++++++++++++++++------------------------ src/parsers/json.h | 6 +--- 5 files changed, 58 insertions(+), 66 deletions(-) diff --git a/build.ps1 b/build.ps1 index 09a2837..1dfa5de 100644 --- a/build.ps1 +++ b/build.ps1 @@ -1,3 +1,3 @@ New-Item -ItemType Directory -Force -Path ./bin/ -gcc -Wall -o ./bin/compile ./src/*.c ./src/parsers/*.c +gcc -Wall -o ./bin/compile ./src/*.c ./src/parsers/*.c -lm diff --git a/build.sh b/build.sh index 0f2e841..dc327d1 100755 --- a/build.sh +++ b/build.sh @@ -1,3 +1,3 @@ mkdir -p ./bin/ -gcc -Wall -o ./bin/compile ./src/*.c ./src/parsers/*.c +gcc -Wall -o ./bin/compile ./src/*.c ./src/parsers/*.c -lm diff --git a/src/main.c b/src/main.c index 63b9f3c..78136b0 100644 --- a/src/main.c +++ b/src/main.c @@ -81,6 +81,7 @@ int main(int argc, char **argv) { fread(buf, 1, length, input_file); buf[length] = '\0'; + // parse the file size_t offset = 0; JsonObject *json = json_parse(buf, &offset); if (json == NULL) { @@ -88,20 +89,19 @@ int main(int argc, char **argv) { exit(EXIT_FAILURE); } - printf("title: %s\n", (char*)json_get(json, "title")); - printf("type: %s\n", (char*)json_get(json, "type")); - printf("year: %.0f\n", *(float*)json_get(json, "year")); - printf("artwork: %s\n", (char*)json_get(json, "artwork")); - printf("buylink: %s\n", (char*)json_get(json, "buylink")); + printf("title: %s\n", (char*)((JsonObject*)json_get(json, "title"))->value); + printf("type: %s\n", (char*)((JsonObject*)json_get(json, "type"))->value); + printf("year: %.0f\n", *(float*)((JsonObject*)json_get(json, "year"))->value); + printf("artwork: %s\n", (char*)((JsonObject*)json_get(json, "artwork"))->value); + printf("buylink: %s\n", (char*)((JsonObject*)json_get(json, "buylink"))->value); - JsonArrayItem *links = json_get(json, "links"); - size_t i = 0; - while (links != NULL) { - JsonObject *link = links->value; - printf("links.%zu.title: %s\n", i, (char*)json_get(link, "title")); - printf("links.%zu.url: %s\n", i, (char*)json_get(link, "url")); - links = links->next; - i++; + JsonObject *links = (JsonObject*)json_get(json, "links"); + for (size_t i = 0; i < links->length; i++) { + char path[256]; + sprintf(path, "links.%zu.title", i); + printf("%s: %s\n", path, (char*)((JsonObject*)json_get(json, path))->value); + sprintf(path, "links.%zu.url", i); + printf("%s: %s\n", path, (char*)((JsonObject*)json_get(json, path))->value); } return 0; diff --git a/src/parsers/json.c b/src/parsers/json.c index 46f9888..ded164e 100644 --- a/src/parsers/json.c +++ b/src/parsers/json.c @@ -7,6 +7,8 @@ #define SKIP_WHITESPACE while ((data[i] == ' ' || data[i] == '\t' || data[i] == '\n') && data[i] != '\0') i++ +void *parse_value(JsonType *type, char *data, size_t *offset); + void json_log(const char *error, char *data, size_t index) { int cur = 0; int line_num = 0; @@ -40,41 +42,33 @@ void json_log(const char *error, char *data, size_t index) { fprintf(stderr, "^\n\n"); } -JsonArrayItem *parse_array(char *data, size_t *offset); -void *parse_value(JsonType *type, char *data, size_t *offset); - -JsonArrayItem *parse_array(char *data, size_t *offset) { +JsonObject *parse_array(char *data, size_t *offset) { size_t i = *offset + 1; size_t count = 0; - JsonArrayItem *head = NULL; + JsonObject *head = NULL; + JsonObject *tail = NULL; while (data[i] != '\0' && data[i] != ']') { - void *item_value = NULL; + JsonObject *item_value = NULL; JsonType type = -1; item_value = parse_value(&type, data, &i); if (item_value == NULL) return NULL; - if (type == object) { - JsonObject *obj = item_value; - - if (obj->name != NULL) free(obj->name); - obj->name = malloc(sizeof(char) * log10(count) + 1); - sprintf(obj->name, "%zu", count); - } + item_value->name = malloc(sizeof(char) * (count < 10 ? 2 : (int)ceil(log10(count)) + 1)); + sprintf(item_value->name, "%zu", count); if (head == NULL) { - head = malloc(sizeof(JsonArrayItem)); - ((JsonArrayItem*)head)->value = item_value; + head = item_value; + tail = item_value; } else { - JsonArrayItem *last = head; - while (last->next != NULL) last = last->next; - last->next = malloc(sizeof(JsonArrayItem)); - last->next->value = item_value; + tail->next = item_value; + tail = tail->next; } SKIP_WHITESPACE; // skip comma, if there is one if (data[i] == ',') i++; + count++; } if (data[i] == '\0') { @@ -244,6 +238,14 @@ JsonObject *json_parse(char *data, size_t *offset) { obj->name = name; obj->type = type; obj->value = value; + if (type == array) { + obj->children = value; + JsonObject *child = obj->children; + while (child != NULL) { + obj->length++; + child = child->next; + } + } } // append new object to root's children @@ -274,18 +276,22 @@ void *json_get(JsonObject *obj, const char *query) { if (obj == NULL) return NULL; size_t cur = 0; - JsonType searching_type = object; + JsonType searching_type = obj->type; while (query[cur] != '\0') { - size_t attr_len = 0; - while (query[cur + attr_len] != '\0' && query[cur + attr_len] != '.') attr_len++; - char attr[attr_len]; - memcpy(attr, query + cur * sizeof(char), attr_len * sizeof(char)); + size_t attr_name_len = 0; + while (query[cur + attr_name_len] != '\0' && query[cur + attr_name_len] != '.') attr_name_len++; + char attr_name[attr_name_len]; + memcpy(attr_name, query + cur * sizeof(char), attr_name_len * sizeof(char) + 1); + attr_name[attr_name_len] = '\0'; if (searching_type == object) { obj = obj->children; + if (obj == NULL) { + fprintf(stderr, "error: attribute `%s` does not have any children\n", obj->name); + } while (obj != NULL) { - if (strcmp(obj->name, attr) == 0) { + if (strcmp(obj->name, attr_name) == 0) { break; } obj = obj->next; @@ -295,16 +301,16 @@ void *json_get(JsonObject *obj, const char *query) { if (searching_type == array) { size_t to_i = 0; size_t cur = 0; - while (cur < attr_len) { - if (attr[cur] < '0' || attr[cur] > '9') { - fprintf(stderr, "error: attempt to index array with attribute name (%s)\n", attr); + while (cur < attr_name_len) { + if (attr_name[cur] < '0' || attr_name[cur] > '9') { + fprintf(stderr, "error: attribute `%s` does not exist in array `%s`\n", attr_name, obj->name); return NULL; } - to_i = (to_i * 10) + (attr[cur] - '0'); + to_i = (to_i * 10) + (attr_name[cur] - '0'); cur++; } - JsonArrayItem *item = obj->value; + JsonObject *item = obj->children; size_t i = 0; while (item != NULL && i < to_i) { item = item->next; @@ -312,25 +318,25 @@ void *json_get(JsonObject *obj, const char *query) { } if (item == NULL) { - fprintf(stderr, "error: index %zu out of bounds for array %s\n", to_i, attr); + fprintf(stderr, "error: index %zu out of bounds for array `%s`\n", to_i, attr_name); return NULL; } - obj = item->value; + obj = item; } if (obj == NULL) { - fprintf(stderr, "error: %s does not exist in json object\n", query); + fprintf(stderr, "error: `%s` does not exist in json object\n", query); return NULL; } - cur += attr_len; + cur += attr_name_len; if (query[cur] == '.') { searching_type = obj->type; cur++; } } - return obj->value; + return obj; } void json_free(JsonObject *object) { @@ -344,17 +350,7 @@ void json_free(JsonObject *object) { } if (object->name != NULL) free(object->name); - if (object->value != NULL) { - if (object->type == array) { - while (object->value != NULL) { - JsonArrayItem *old = object->value; - json_free(old->value); - object->value = old->next; - free(old); - } - } - free(object->value); - } + if (object->value != NULL) free(object->value); free(object); } diff --git a/src/parsers/json.h b/src/parsers/json.h index 79d626c..4e9c01d 100644 --- a/src/parsers/json.h +++ b/src/parsers/json.h @@ -14,16 +14,12 @@ typedef struct JsonObject { char *name; JsonType type; void *value; + size_t length; struct JsonObject *children; struct JsonObject *next; } JsonObject; -typedef struct JsonArrayItem { - JsonObject *value; - struct JsonArrayItem *next; -} JsonArrayItem; - JsonObject *json_parse(char *data, size_t *offset); void *json_get(JsonObject *object, const char *child_name); void json_free(JsonObject *object);