From 931e3c094bf6750f29b7e9d42b5491ffa451e402 Mon Sep 17 00:00:00 2001 From: Edouard Tisserant Date: Wed, 25 Sep 2024 15:39:58 +0200 Subject: [PATCH 1/2] Support fixed size arrays in json_scanf format. Example of format : {a:[%d, %d], b:[{c: %d}, {c: %d}]} --- README.md | 16 ++++++++++++++++ frozen.c | 18 ++++++++++++++++-- unit_test.c | 16 ++++++++++++++-- 3 files changed, 46 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 160a529..b31f8b1 100644 --- a/README.md +++ b/README.md @@ -62,6 +62,22 @@ Scans the JSON string `str`, performing scanf-like conversions according to `fmt Returns the number of elements successfully scanned & converted. Negative number means scan error. +Example - parse fixed size array of objects: + +```c + // str has the following JSON string (notice keys are out of order): + // { "a": 123, "d": true, "b": [1, 2], "c": "hi", + // "e": [ {"b": 123}, {"b": 345} ] } + // This example shows how to iterate over fixed size array, and parse each object. + + int a = 0, d = 0; + char *c = NULL; + void *my_data = NULL; + json_scanf(str, strlen(str), "{ a:%d, b:[%B, %B], c:%Q, d:%B, e:[{b: %d},{b: %d}]}", + &a, scan_array, my_data, &c, &d); + } +``` + Example - scan arbitrary JSON string: ```c diff --git a/frozen.c b/frozen.c index 55f6d04..9dde32f 100644 --- a/frozen.c +++ b/frozen.c @@ -1079,6 +1079,22 @@ int json_vscanf(const char *s, int len, const char *fmt, va_list ap) { } else if (fmt[i] == '}') { if ((p = strrchr(path, '.')) != NULL) *p = '\0'; i++; + } else if (fmt[i] == '[') { + strcat(path, "[0]"); + i++; + } else if (fmt[i] == ',' && path[strlen(path)-1] == ']' ) { + int idx; + p = strrchr(path, '['); + if(p != NULL){ + path[strlen(path)-1] = '\0'; + *p = '\0'; + idx = atoi(p+1); + snprintf(p, sizeof(path)-(p - path), "[%d]", idx+1); + } + i++; + } else if (fmt[i] == ']') { + if ((p = strrchr(path, '[')) != NULL) *p = '\0'; + i++; } else if (fmt[i] == '%') { info.target = va_arg(ap, void *); info.type = fmt[i + 1]; @@ -1099,8 +1115,6 @@ int json_vscanf(const char *s, int len, const char *fmt, va_list ap) { memcpy(fmtbuf, fmt + i, conv_len); fmtbuf[conv_len] = '\0'; i += conv_len; - if (fmt[i] != '}') - i += strspn(fmt + i, delims); break; } } diff --git a/unit_test.c b/unit_test.c index ad63a11..08b4a2b 100644 --- a/unit_test.c +++ b/unit_test.c @@ -501,12 +501,12 @@ static void scan_array(const char *str, int len, void *user_data) { static const char *test_scanf(void) { char buf[100] = ""; - int a = 0, b = 0; + int a = 0, b = 0, e = 0, f = 0, g = 0; char *d = NULL; const char *str = "{ a: 1234, b : true, \"c\": {x: [17, 78, -20]}, d: \"hi%20there\" }"; - ASSERT(json_scanf(str, strlen(str), "{a: %d, b: %B, c: [%M], d: %Q}", &a, &b, + ASSERT(json_scanf(str, strlen(str), "{a: %d, b: %B, c: %M, d: %Q}", &a, &b, &scan_array, buf, &d) == 4); ASSERT(a == 1234); ASSERT(b == 1); @@ -515,6 +515,18 @@ static const char *test_scanf(void) { ASSERT(strcmp(d, "hi%20there") == 0); free(d); + ASSERT(json_scanf(str, strlen(str), "{a: %d, b: %B, c:{ x: [%d, %d, %d]}, d: %Q}", &a, &b, + &e, &f, &g, &d) == 6); + ASSERT(a == 1234); + ASSERT(b == 1); + ASSERT(e == 17); + ASSERT(f == 78); + ASSERT(g == -20); + ASSERT(d != NULL); + ASSERT(strcmp(d, "hi%20there") == 0); + free(d); + + { const char* str = "{a:{b:4},c:5}"; int b = 0, c=0; From cfff12e9d3f20e9ea670ced1beb27be141fa3254 Mon Sep 17 00:00:00 2001 From: Edouard Tisserant Date: Wed, 25 Sep 2024 15:47:26 +0200 Subject: [PATCH 2/2] Fix documentation bug --- README.md | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index b31f8b1..4145040 100644 --- a/README.md +++ b/README.md @@ -67,15 +67,18 @@ Example - parse fixed size array of objects: ```c // str has the following JSON string (notice keys are out of order): // { "a": 123, "d": true, "b": [1, 2], "c": "hi", - // "e": [ {"b": 123}, {"b": 345} ] } + // "e": [ {"k": 123}, {"k": 345} ] } // This example shows how to iterate over fixed size array, and parse each object. - int a = 0, d = 0; + int a = 0, b1 = 0, b2 = 0, d = 0, k1 = 0, k2 = 0; char *c = NULL; void *my_data = NULL; - json_scanf(str, strlen(str), "{ a:%d, b:[%B, %B], c:%Q, d:%B, e:[{b: %d},{b: %d}]}", - &a, scan_array, my_data, &c, &d); + json_scanf(str, strlen(str), "{ a:%d, b:[%B, %B], c:%Q, d:%B, e:[{k: %d},{k: %d}]}", + &a, &b1, &b2, &c, &d, &k1, &k2); } + + // Free string allocated by %Q format specifier + free(c) ``` Example - scan arbitrary JSON string: