diff options
| author | nsfisis <nsfisis@gmail.com> | 2025-08-29 21:25:03 +0900 |
|---|---|---|
| committer | nsfisis <nsfisis@gmail.com> | 2025-08-29 21:49:56 +0900 |
| commit | b678465c11517a5342b1ec5aa4fe21570f13a3ed (patch) | |
| tree | 6ef19e02b1cf18f5ac451e6104f6e20b475a6f52 /src/json.c | |
| parent | 8f352553faec69a6f29854898b93be47604aff28 (diff) | |
| download | ducc-b678465c11517a5342b1ec5aa4fe21570f13a3ed.tar.gz ducc-b678465c11517a5342b1ec5aa4fe21570f13a3ed.tar.zst ducc-b678465c11517a5342b1ec5aa4fe21570f13a3ed.zip | |
feat: add utility function to dump any internal object as JSON
Diffstat (limited to 'src/json.c')
| -rw-r--r-- | src/json.c | 107 |
1 files changed, 107 insertions, 0 deletions
diff --git a/src/json.c b/src/json.c new file mode 100644 index 0000000..8abeea7 --- /dev/null +++ b/src/json.c @@ -0,0 +1,107 @@ +#include "json.h" +#include "common.h" + +struct JsonBuilder { + StrBuilder buf; + BOOL has_output_element[256]; + int depth; +}; + +JsonBuilder* jsonbuilder_new() { + JsonBuilder* b = calloc(1, sizeof(JsonBuilder)); + strbuilder_init(&b->buf); + return b; +} + +const char* jsonbuilder_get_output(JsonBuilder* b) { + return b->buf.buf; +} + +static void emit_comma_if_needed(JsonBuilder* b) { + if (b->has_output_element[b->depth - 1]) { + strbuilder_append_char(&b->buf, ','); + } +} + +void jsonbuilder_object_start(JsonBuilder* b) { + strbuilder_append_char(&b->buf, '{'); + b->has_output_element[b->depth++] = FALSE; +} + +void jsonbuilder_object_end(JsonBuilder* b) { + b->depth--; + strbuilder_append_char(&b->buf, '}'); +} + +void jsonbuilder_object_member_start(JsonBuilder* b, const char* key) { + emit_comma_if_needed(b); + jsonbuilder_string(b, key); + strbuilder_append_char(&b->buf, ':'); +} + +void jsonbuilder_object_member_end(JsonBuilder* b) { + b->has_output_element[b->depth - 1] = TRUE; +} + +void jsonbuilder_array_start(JsonBuilder* b) { + strbuilder_append_char(&b->buf, '['); + b->has_output_element[b->depth++] = FALSE; +} + +void jsonbuilder_array_end(JsonBuilder* b) { + b->depth--; + strbuilder_append_char(&b->buf, ']'); +} + +void jsonbuilder_array_element_start(JsonBuilder* b) { + emit_comma_if_needed(b); +} + +void jsonbuilder_array_element_end(JsonBuilder* b) { + b->has_output_element[b->depth - 1] = TRUE; +} + +void jsonbuilder_null(JsonBuilder* b) { + strbuilder_append_string(&b->buf, "null"); +} + +void jsonbuilder_boolean(JsonBuilder* b, BOOL value) { + strbuilder_append_string(&b->buf, value ? "true" : "false"); +} + +void jsonbuilder_integer(JsonBuilder* b, int value) { + char buf[32]; + sprintf(buf, "%d", value); + strbuilder_append_string(&b->buf, buf); +} + +void jsonbuilder_string(JsonBuilder* b, const char* value) { + if (!value) { + jsonbuilder_null(b); + return; + } + + strbuilder_append_char(&b->buf, '"'); + + for (const char* p = value; *p; p++) { + if (*p == '"') { + strbuilder_append_string(&b->buf, "\\\""); + } else if (*p == '\\') { + strbuilder_append_string(&b->buf, "\\\\"); + } else if (*p == '\b') { + strbuilder_append_string(&b->buf, "\\b"); + } else if (*p == '\f') { + strbuilder_append_string(&b->buf, "\\f"); + } else if (*p == '\n') { + strbuilder_append_string(&b->buf, "\\n"); + } else if (*p == '\r') { + strbuilder_append_string(&b->buf, "\\r"); + } else if (*p == '\t') { + strbuilder_append_string(&b->buf, "\\t"); + } else { + strbuilder_append_char(&b->buf, *p); + } + } + + strbuilder_append_char(&b->buf, '"'); +} |
