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);
This commit is contained in:
Joris Vink 2019-10-22 23:56:47 +02:00
parent 790d020ce9
commit 890eb78fd8
2 changed files with 171 additions and 42 deletions

View File

@ -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);

View File

@ -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, "<root>", 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)
{