From aeea41b0e1ac4e82fad61d2b6c63a550672a1f05 Mon Sep 17 00:00:00 2001 From: yukkop Date: Sat, 22 Mar 2025 04:15:58 +0000 Subject: [PATCH] fix: json eval --- package/c/chectic/chectic.c | 30 ++++++++++++++++---------- package/c/chectic/chectic.h | 7 +++---- package/c/chectic/test/02-json.c | 10 ++++----- package/c/hmpl/hmpl.c | 36 +++++++++++++++++--------------- 4 files changed, 46 insertions(+), 37 deletions(-) diff --git a/package/c/chectic/chectic.c b/package/c/chectic/chectic.c index e893416..3e2da21 100644 --- a/package/c/chectic/chectic.c +++ b/package/c/chectic/chectic.c @@ -267,19 +267,24 @@ Json *json_parse(Arena *arena, const char **s) { return json_parse_value__(s, arena); } -/* Minimal JSON printer. - For simplicity, a fixed-size buffer is used. - In production you’d dynamically size or use the arena. */ -char *json_print(Arena *arena, Json *item) { +char *json_to_string(Arena *arena, Json *item) { + return json_to_string_with_opts(arena, item, 0); +} + +/* Minimal JSON printer with raw output option. + When raw is non-zero and the item is a JSON_STRING, it is printed without quotes. +*/ +char *json_to_string_with_opts(Arena *arena, Json *item, int raw) { char *out = arena_alloc(arena, 1024); - if (!out) return NULL; + if (!out) + return NULL; char *ptr = out; if (item->type == JSON_OBJECT) { ptr += sprintf(ptr, "{"); Json *child = item->child; while (child) { ptr += sprintf(ptr, "\"%s\":", child->key ? child->key : ""); - char *child_str = json_print(arena, child); + char *child_str = json_to_string_with_opts(arena, child, raw); ptr += sprintf(ptr, "%s", child_str); if (child->next) ptr += sprintf(ptr, ","); @@ -290,7 +295,7 @@ char *json_print(Arena *arena, Json *item) { ptr += sprintf(ptr, "["); Json *child = item->child; while (child) { - char *child_str = json_print(arena, child); + char *child_str = json_to_string_with_opts(arena, child, raw); ptr += sprintf(ptr, "%s", child_str); if (child->next) ptr += sprintf(ptr, ","); @@ -298,13 +303,16 @@ char *json_print(Arena *arena, Json *item) { } sprintf(ptr, "]"); } else if (item->type == JSON_STRING) { - sprintf(out, "\"%s\"", item->string); + if (raw) + sprintf(ptr, "%s", item->string); + else + sprintf(ptr, "\"%s\"", item->string); } else if (item->type == JSON_NUMBER) { - sprintf(out, "%g", item->number); + sprintf(ptr, "%g", item->number); } else if (item->type == JSON_BOOL) { - sprintf(out, item->boolean ? "true" : "false"); + sprintf(ptr, item->boolean ? "true" : "false"); } else if (item->type == JSON_NULL) { - sprintf(out, "null"); + sprintf(ptr, "null"); } return out; } diff --git a/package/c/chectic/chectic.h b/package/c/chectic/chectic.h index dbf1f89..50ec474 100644 --- a/package/c/chectic/chectic.h +++ b/package/c/chectic/chectic.h @@ -226,10 +226,9 @@ typedef struct Json { Json *json_parse(Arena *arena, const char **s); -/* Minimal JSON printer. - For simplicity, a fixed-size buffer is used. - In production you’d dynamically size or use the arena. */ -char *json_print(Arena *arena, Json *item); +char *json_to_string(Arena *arena, Json *item); + +char *json_to_string_with_opts(Arena *arena, Json *item, int raw); /* Retrieve an object item by key (case-sensitive) */ Json *json_get_object_item(Json *object, const char *key); diff --git a/package/c/chectic/test/02-json.c b/package/c/chectic/test/02-json.c index 2c32124..3094c29 100644 --- a/package/c/chectic/test/02-json.c +++ b/package/c/chectic/test/02-json.c @@ -59,7 +59,7 @@ static void test_print_json_object(void) { Arena arena = arena_init(ARENA_SIZE); const char *json = "{\"key\":\"value\", \"num\":3.14}"; Json *root = json_parse(&arena, &json); - char *printed = json_print(&arena, root); + char *printed = json_to_string(&arena, root); assert(strstr(printed, "\"key\":") != NULL); assert(strstr(printed, "\"value\"") != NULL); assert(strstr(printed, "\"num\":") != NULL); @@ -72,7 +72,7 @@ static void test_print_json_number(void) { Arena arena = arena_init(ARENA_SIZE); const char *json = "123.456"; Json *root = json_parse(&arena, &json); - char *printed = json_print(&arena, root); + char *printed = json_to_string(&arena, root); double val = atof(printed); assert(val == 123.456); arena_free(&arena); @@ -83,7 +83,7 @@ static void test_print_json_string(void) { Arena arena = arena_init(ARENA_SIZE); const char *json = "\"test string\""; Json *root = json_parse(&arena, &json); - char *printed = json_print(&arena, root); + char *printed = json_to_string(&arena, root); assert(strcmp(printed, "\"test string\"") == 0); arena_free(&arena); } @@ -113,11 +113,11 @@ static void test_arena_reset_reuse(void) { Arena arena = arena_init(ARENA_SIZE); const char *json1 = "{\"key\":\"value\"}"; Json *root1 = json_parse(&arena, &json1); - char *printed1 = json_print(&arena, root1); + char *printed1 = json_to_string(&arena, root1); arena_reset(&arena); const char *json2 = "\"another test\""; Json *root2 = json_parse(&arena, &json2); - char *printed2 = json_print(&arena, root2); + char *printed2 = json_to_string(&arena, root2); assert(strcmp(printed2, "\"another test\"") == 0); arena_free(&arena); } diff --git a/package/c/hmpl/hmpl.c b/package/c/hmpl/hmpl.c index 2b12b04..fcb4369 100644 --- a/package/c/hmpl/hmpl.c +++ b/package/c/hmpl/hmpl.c @@ -2,26 +2,28 @@ char *eval(Arena *arena, const Json * const context, const char * const key) { if (!context || !key) return NULL; + char *key_copy = arena_strdup(arena, key); - char *token, *rest = key_copy; Json *res = context; - while ((token = strtok_r(rest, ".", &rest))) { - raise_debug("context: %s; token: %s", json_print(arena, res), key); - res = json_get_object_item(res, &token); - if (!res) - return NULL; + char *start = key_copy; + char *dot; + + // Instead of using strtok_r, manually split the string using strchr. + while ((dot = strchr(start, '.')) != NULL) { + *dot = '\0'; + raise_debug("res: %s, token: %s, key: %s", json_to_string(arena, res), start, key); + res = json_get_object_item(res, start); + if (!res) + return NULL; + start = dot + 1; } - if (res == JSON_STRING && res->string) - return arena_strdup(arena, res->string); - else if (res == JSON_NUMBER) { - char buf[64]; - snprintf(buf, sizeof(buf), "%g", res->number); - return arena_strdup(arena, buf); - } - char *temp = json_print(arena, res); - char *result = arena_strdup(arena, temp); - free(temp); - return result; + + raise_debug("res: %s, token: %s, key: %s", json_to_string(arena, res), start, key); + res = json_get_object_item(res, start); + if (!res) + return NULL; + + return json_to_string_with_opts(arena, res, 1); } /* Modified: text is passed by reference so we can update it and free old allocations */