From 890eb78fd867cac2d96e0542f3f5275d070dd216 Mon Sep 17 00:00:00 2001 From: Joris Vink Date: Tue, 22 Oct 2019 23:56:47 +0200 Subject: [PATCH] Improve our new JSON api a bit. Allow JSON to be constructed via kore_json_create_item and its handy macro family: - kore_json_create_object() - kore_json_create_array() - kore_json_create_string() - kore_json_create_number() - kore_json_create_literal(). Adds kore_json_item_tobuf() to convert a JSON item into a string representation in a kore_buf data structure. Renames the kore_json_get* family to kore_json_find* instead. Allows for quite clean code: struct kore_buf buf; struct kore_json_item *root; root = kore_json_create_object(NULL, NULL); kore_json_create_string(root, "hello", "world"); kore_json_create_number(root, "value", 2.241); kore_buf_init(&buf, 128); kore_json_item_tobuf(root, &buf); kore_json_item_free(root); kore_buf_cleanup(&buf); --- include/kore/kore.h | 41 ++++++++--- src/json.c | 172 ++++++++++++++++++++++++++++++++++++-------- 2 files changed, 171 insertions(+), 42 deletions(-) diff --git a/include/kore/kore.h b/include/kore/kore.h index c1e3e0b..ac957ae 100644 --- a/include/kore/kore.h +++ b/include/kore/kore.h @@ -490,20 +490,35 @@ struct kore_buf { #define KORE_JSON_ERR_TYPE_MISMATCH 11 #define KORE_JSON_ERR_LAST KORE_JSON_ERR_TYPE_MISMATCH -#define kore_json_object(j, p) \ - kore_json_get(j, p, KORE_JSON_TYPE_OBJECT) +#define kore_json_find_object(j, p) \ + kore_json_find(j, p, KORE_JSON_TYPE_OBJECT) -#define kore_json_array(j, p) \ - kore_json_get(j, p, KORE_JSON_TYPE_ARRAY) +#define kore_json_find_array(j, p) \ + kore_json_find(j, p, KORE_JSON_TYPE_ARRAY) -#define kore_json_string(j, p) \ - kore_json_get(j, p, KORE_JSON_TYPE_STRING) +#define kore_json_find_string(j, p) \ + kore_json_find(j, p, KORE_JSON_TYPE_STRING) -#define kore_json_number(j, p) \ - kore_json_get(j, p, KORE_JSON_TYPE_NUMBER) +#define kore_json_find_number(j, p) \ + kore_json_find(j, p, KORE_JSON_TYPE_NUMBER) -#define kore_json_literal(j, p) \ - kore_json_get(j, p, KORE_JSON_TYPE_LITERAL) +#define kore_json_find_literal(j, p) \ + kore_json_find(j, p, KORE_JSON_TYPE_LITERAL) + +#define kore_json_create_object(o, n) \ + kore_json_create_item(o, n, KORE_JSON_TYPE_OBJECT) + +#define kore_json_create_array(o, n) \ + kore_json_create_item(o, n, KORE_JSON_TYPE_ARRAY) + +#define kore_json_create_string(o, n, v) \ + kore_json_create_item(o, n, KORE_JSON_TYPE_STRING, v) + +#define kore_json_create_number(o, n, v) \ + kore_json_create_item(o, n, KORE_JSON_TYPE_NUMBER, v) + +#define kore_json_create_literal(o, n, v) \ + kore_json_create_item(o, n, KORE_JSON_TYPE_LITERAL, v) struct kore_json { const u_int8_t *data; @@ -946,10 +961,14 @@ void kore_buf_replace_string(struct kore_buf *, int kore_json_parse(struct kore_json *); void kore_json_cleanup(struct kore_json *); +void kore_json_item_free(struct kore_json_item *); void kore_json_init(struct kore_json *, const u_int8_t *, size_t); +void kore_json_item_tobuf(struct kore_json_item *, struct kore_buf *); const char *kore_json_strerror(struct kore_json *); -struct kore_json_item *kore_json_get(struct kore_json *, const char *, int); +struct kore_json_item *kore_json_find(struct kore_json *, const char *, int); +struct kore_json_item *kore_json_create_item(struct kore_json_item *, + const char *, int, ...); void kore_keymgr_run(void); void kore_keymgr_cleanup(int); diff --git a/src/json.c b/src/json.c index 431d99d..c4a45a2 100644 --- a/src/json.c +++ b/src/json.c @@ -39,7 +39,6 @@ static int json_parse_string(struct kore_json *, struct kore_json_item *); static int json_parse_number(struct kore_json *, struct kore_json_item *); static int json_parse_literal(struct kore_json *, struct kore_json_item *); -static void json_item_free(struct kore_json_item *); static struct kore_json_item *json_item_alloc(int, const char *, struct kore_json_item *); static struct kore_json_item *json_find_item(struct kore_json *, @@ -92,7 +91,7 @@ kore_json_parse(struct kore_json *json) return (KORE_RESULT_ERROR); } - json->root = json_item_alloc(type, "", NULL); + json->root = json_item_alloc(type, NULL, NULL); if (!json->root->parse(json, json->root)) { if (json->error == 0) @@ -104,7 +103,7 @@ kore_json_parse(struct kore_json *json) } struct kore_json_item * -kore_json_get(struct kore_json *json, const char *path, int type) +kore_json_find(struct kore_json *json, const char *path, int type) { struct kore_json_item *item; char *copy; @@ -131,7 +130,7 @@ void kore_json_cleanup(struct kore_json *json) { kore_buf_cleanup(&json->tmpbuf); - json_item_free(json->root); + kore_json_item_free(json->root); } const char * @@ -143,6 +142,117 @@ kore_json_strerror(struct kore_json *json) return ("unknown JSON error"); } +struct kore_json_item * +kore_json_create_item(struct kore_json_item *parent, const char *name, + int type, ...) +{ + const char *p; + va_list args; + struct kore_json_item *item; + + item = kore_calloc(1, sizeof(*item)); + item->type = type; + + va_start(args, type); + + switch (item->type) { + case KORE_JSON_TYPE_OBJECT: + TAILQ_INIT(&item->data.items); + break; + case KORE_JSON_TYPE_ARRAY: + TAILQ_INIT(&item->data.items); + break; + case KORE_JSON_TYPE_STRING: + p = va_arg(args, const char *); + item->data.string = kore_strdup(p); + break; + case KORE_JSON_TYPE_NUMBER: + item->data.number = va_arg(args, double); + break; + case KORE_JSON_TYPE_LITERAL: + item->data.literal = va_arg(args, int); + break; + default: + fatal("%s: unknown type %d", __func__, item->type); + } + + if (name) + item->name = kore_strdup(name); + + if (parent) { + if (parent->type != KORE_JSON_TYPE_OBJECT && + parent->type != KORE_JSON_TYPE_ARRAY) { + fatal("%s: invalid parent type (%d)", + __func__, parent->type); + } + + TAILQ_INSERT_TAIL(&parent->data.items, item, list); + } + + va_end(args); + + return (item); +} + +void +kore_json_item_tobuf(struct kore_json_item *item, struct kore_buf *buf) +{ + struct kore_json_item *nitem; + + if (item->name) + kore_buf_appendf(buf, "\"%s\":", item->name); + + switch (item->type) { + case KORE_JSON_TYPE_OBJECT: + kore_buf_appendf(buf, "{"); + TAILQ_FOREACH(nitem, &item->data.items, list) { + kore_json_item_tobuf(nitem, buf); + + if (TAILQ_NEXT(nitem, list)) + kore_buf_appendf(buf, ","); + } + kore_buf_appendf(buf, "}"); + break; + case KORE_JSON_TYPE_ARRAY: + kore_buf_appendf(buf, "["); + TAILQ_FOREACH(nitem, &item->data.items, list) { + kore_json_item_tobuf(nitem, buf); + + if (TAILQ_NEXT(nitem, list)) + kore_buf_appendf(buf, ","); + } + kore_buf_appendf(buf, "]"); + break; + case KORE_JSON_TYPE_STRING: + kore_buf_appendf(buf, "\"%s\"", item->data.string); + break; + case KORE_JSON_TYPE_NUMBER: + kore_buf_appendf(buf, "%f", item->data.number); + break; + case KORE_JSON_TYPE_LITERAL: + switch (item->data.literal) { + case KORE_JSON_TRUE: + kore_buf_append(buf, + json_true_literal, sizeof(json_true_literal)); + break; + case KORE_JSON_FALSE: + kore_buf_append(buf, + json_false_literal, sizeof(json_false_literal)); + break; + case KORE_JSON_NULL: + kore_buf_append(buf, + json_null_literal, sizeof(json_null_literal)); + break; + default: + fatal("%s: unknown literal %d", __func__, + item->data.literal); + } + break; + default: + fatal("%s: unknown type %d", __func__, item->type); + } +} + static struct kore_json_item * json_find_item(struct kore_json *json, struct kore_json_item *object, char **tokens, int type, int pos) @@ -218,6 +328,33 @@ json_find_item(struct kore_json *json, struct kore_json_item *object, return (item); } +void +kore_json_item_free(struct kore_json_item *item) +{ + struct kore_json_item *node; + + switch (item->type) { + case KORE_JSON_TYPE_OBJECT: + case KORE_JSON_TYPE_ARRAY: + while ((node = TAILQ_FIRST(&item->data.items)) != NULL) { + TAILQ_REMOVE(&item->data.items, node, list); + kore_json_item_free(node); + } + break; + case KORE_JSON_TYPE_STRING: + kore_free(item->data.string); + break; + case KORE_JSON_TYPE_NUMBER: + case KORE_JSON_TYPE_LITERAL: + break; + default: + fatal("%s: unknown type %d", __func__, item->type); + } + + kore_free(item->name); + kore_free(item); +} + static struct kore_json_item * json_item_alloc(int type, const char *name, struct kore_json_item *parent) { @@ -265,33 +402,6 @@ json_item_alloc(int type, const char *name, struct kore_json_item *parent) return (item); } -static void -json_item_free(struct kore_json_item *item) -{ - struct kore_json_item *node; - - switch (item->type) { - case KORE_JSON_TYPE_OBJECT: - case KORE_JSON_TYPE_ARRAY: - while ((node = TAILQ_FIRST(&item->data.items)) != NULL) { - TAILQ_REMOVE(&item->data.items, node, list); - json_item_free(node); - } - break; - case KORE_JSON_TYPE_STRING: - kore_free(item->data.string); - break; - case KORE_JSON_TYPE_NUMBER: - case KORE_JSON_TYPE_LITERAL: - break; - default: - fatal("%s: unknown type %d", __func__, item->type); - } - - kore_free(item->name); - kore_free(item); -} - static int json_peek(struct kore_json *json, u_int8_t *ch) {