This patch adds JSON objects and lists and methods to print them Signed-off-by: Viktor Prutyanov <viktor.prutyanov@xxxxxxxxxxxxx> --- lib/support/Makefile.in | 7 +- lib/support/json-out.c | 300 ++++++++++++++++++++++++++++++++++++++++++++++++ lib/support/json-out.h | 69 +++++++++++ 3 files changed, 374 insertions(+), 2 deletions(-) create mode 100644 lib/support/json-out.c create mode 100644 lib/support/json-out.h diff --git a/lib/support/Makefile.in b/lib/support/Makefile.in index 40206b74..42fa3324 100644 --- a/lib/support/Makefile.in +++ b/lib/support/Makefile.in @@ -22,7 +22,8 @@ OBJS= cstring.o \ quotaio.o \ quotaio_v2.o \ quotaio_tree.o \ - dict.o + dict.o \ + json-out.o SRCS= $(srcdir)/argv_parse.c \ $(srcdir)/cstring.c \ @@ -35,7 +36,8 @@ SRCS= $(srcdir)/argv_parse.c \ $(srcdir)/quotaio.c \ $(srcdir)/quotaio_tree.c \ $(srcdir)/quotaio_v2.c \ - $(srcdir)/dict.c + $(srcdir)/dict.c \ + $(srcdir)/json-out.c LIBRARY= libsupport LIBDIR= support @@ -165,3 +167,4 @@ quotaio_v2.o: $(srcdir)/quotaio_v2.c $(top_builddir)/lib/config.h \ $(srcdir)/dqblk_v2.h $(srcdir)/quotaio_tree.h dict.o: $(srcdir)/dict.c $(top_builddir)/lib/config.h \ $(top_builddir)/lib/dirpaths.h $(srcdir)/dict.h +json-out.o: $(srcdir)/json-out.c $(srcdir)/json-out.h diff --git a/lib/support/json-out.c b/lib/support/json-out.c new file mode 100644 index 00000000..a87fe92e --- /dev/null +++ b/lib/support/json-out.c @@ -0,0 +1,300 @@ +/* + * json-out.c -- JSON output + * + * Copyright (c) 2018 Virtuozzo International GmbH + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Public + * License. + * %End-Header% + */ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <stdarg.h> + +#include "json-out.h" + +static void *xmalloc(size_t size) +{ + void *p = malloc(size); + + if (!p) + exit(1); + + return p; +} + +static void *xstrdup(const char *str) +{ + size_t size = strlen(str) + 1; + char *p = xmalloc(size); + + return strcpy(p, str); +} + +struct json_list *json_list_create(enum json_val_type type) +{ + struct json_list *list = xmalloc(sizeof(struct json_list)); + + list->node = NULL; + list->type = type; + + return list; +} + +struct json_list *json_list_create_in_obj(struct json_obj *parent_obj, char *key, enum json_val_type type) +{ + struct json_list *list = json_list_create(type); + + json_obj_add_list(parent_obj, key, list); + + return list; +} + +void json_list_delete(struct json_list *list) +{ + struct json_list_node *node = list->node, *next; + + while (node) { + switch (list->type) { + case JSON_VAL_STRING: + free(node->val.str); + break; + case JSON_VAL_LIST: + json_list_delete(node->val.list); + break; + case JSON_VAL_OBJECT: + json_obj_delete(node->val.obj); + break; + default: + break; + } + next = node->next; + free(node); + node = next; + } + free(list); +} + +struct json_obj *json_obj_create(void) +{ + struct json_obj *obj = xmalloc(sizeof(struct json_obj)); + + obj->pair = NULL; + + return obj; +} + +struct json_obj *json_obj_create_in_obj(struct json_obj *parent_obj, char *key) +{ + struct json_obj *obj = json_obj_create(); + + json_obj_add_obj(parent_obj, key, obj); + + return obj; +} + +static void json_pair_delete(struct json_pair *pair) +{ + switch (pair->type) + { + case JSON_VAL_STRING: + free(pair->val.str); + break; + case JSON_VAL_LIST: + json_list_delete(pair->val.list); + break; + case JSON_VAL_OBJECT: + json_obj_delete(pair->val.obj); + break; + default: + break; + } + free(pair->key); + free(pair); +} + +void json_obj_delete(struct json_obj *obj) +{ + struct json_pair *pair = obj->pair, *next; + + while (pair) { + next = pair->next; + json_pair_delete(pair); + pair = next; + } + free(obj); +} + +void json_obj_delete_pair(struct json_obj *obj, char *key) +{ + struct json_pair *pair = obj->pair, *next, *prev = NULL; + + while (pair) { + next = pair->next; + if (!strcmp(pair->key, key)) { + json_pair_delete(pair); + if (prev) + prev->next = next; + else + obj->pair = next; + break; + } + prev = pair; + pair = next; + } +} + +static struct json_list_node *json_list_add_node(struct json_list *list) +{ + struct json_list_node *new_node = xmalloc(sizeof(struct json_list_node)); + + new_node->next = NULL; + + if (list->node) { + struct json_list_node *node; + + for (node = list->node; node && node->next; node = node->next); + node->next = new_node; + } else + list->node = new_node; + + return new_node; +} + +void json_list_add_str(struct json_list *list, const char *str) +{ + struct json_list_node *new_node = json_list_add_node(list); + + new_node->val.str = xstrdup(str); +} + +void json_list_add_obj(struct json_list *list, struct json_obj *obj) +{ + struct json_list_node *new_node = json_list_add_node(list); + + new_node->val.obj = obj; +} + +static struct json_pair *json_obj_add_pair(struct json_obj *obj, const char *key, enum json_val_type type) +{ + struct json_pair *new_pair = xmalloc(sizeof(struct json_pair)); + new_pair->key = xstrdup(key); + new_pair->next = NULL; + new_pair->type = type; + + if (obj->pair) { + struct json_pair *pair; + + for (pair = obj->pair; pair && pair->next; pair = pair->next); + pair->next = new_pair; + } else + obj->pair = new_pair; + + return new_pair; +} + +void json_obj_add_str(struct json_obj *obj, const char *key, const char *str) +{ + struct json_pair *new_pair = json_obj_add_pair(obj, key, JSON_VAL_STRING); + + new_pair->val.str = xstrdup(str); +} + +void json_obj_add_fmt_buf_str(struct json_obj *obj, const char *key, char *buf, size_t size, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + vsnprintf(buf, size, fmt, ap); + va_end(ap); + + json_obj_add_str(obj, key, buf); +} + +void json_obj_add_fmt_str(struct json_obj *obj, const char *key, size_t size, const char *fmt, ...) +{ + va_list ap; + char *buf = malloc(size); + + va_start(ap, fmt); + vsnprintf(buf, size, fmt, ap); + va_end(ap); + + json_obj_add_str(obj, key, buf); + free(buf); +} + +void json_obj_add_list(struct json_obj *obj, const char *key, struct json_list *list) +{ + struct json_pair *new_pair = json_obj_add_pair(obj, key, JSON_VAL_LIST); + + new_pair->val.list = list; +} + +void json_obj_add_obj(struct json_obj *obj, const char *key, struct json_obj *new_obj) +{ + struct json_pair *new_pair = json_obj_add_pair(obj, key, JSON_VAL_OBJECT); + + new_pair->val.obj = new_obj; +} + +static void json_pair_print_json(struct json_pair *pair); + +void json_obj_print_json(struct json_obj *obj) +{ + struct json_pair *pair; + + printf("{"); + for (pair = obj->pair; pair; pair = pair->next) { + json_pair_print_json(pair); + if (pair->next) + printf(", "); + } + printf("}"); +} + +void json_list_print_json(struct json_list *list) +{ + struct json_list_node *node; + + printf("["); + for (node = list->node; node; node = node->next) { + switch (list->type) { + case JSON_VAL_STRING: + printf("\"%s\"", node->val.str); + break; + case JSON_VAL_LIST: + json_list_print_json(node->val.list); + break; + case JSON_VAL_OBJECT: + json_obj_print_json(node->val.obj); + break; + default: + break; + } + if (node->next) + printf(", "); + } + printf("]"); +} + +static void json_pair_print_json(struct json_pair *pair) +{ + printf("\"%s\": ", pair->key); + switch (pair->type) { + case JSON_VAL_STRING: + printf("\"%s\"", pair->val.str); + break; + case JSON_VAL_LIST: + json_list_print_json(pair->val.list); + break; + case JSON_VAL_OBJECT: + json_obj_print_json(pair->val.obj); + break; + default: + break; + } +} diff --git a/lib/support/json-out.h b/lib/support/json-out.h new file mode 100644 index 00000000..ec9cab7c --- /dev/null +++ b/lib/support/json-out.h @@ -0,0 +1,69 @@ +/* + * json-out.h -- JSON output + * + * Copyright (c) 2018 Virtuozzo International GmbH + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Public + * License. + * %End-Header% + */ + +#ifndef H_JSON_OUT +#define H_JSON_OUT + +enum json_val_type { + JSON_VAL_STRING, + JSON_VAL_OBJECT, + JSON_VAL_LIST, + JSON_VAL_FLAG +}; + +struct json_obj { + struct json_pair *pair; +}; + +union json_val { + char *str; + struct json_obj *obj; + struct json_list *list; + char flag; +}; + +struct json_pair { + char *key; + enum json_val_type type; + union json_val val; + struct json_pair *next; +}; + +struct json_list { + enum json_val_type type; + struct json_list_node *node; +}; + +struct json_list_node { + union json_val val; + struct json_list_node *next; +}; + +struct json_obj *json_obj_create(void); +struct json_obj *json_obj_create_in_obj(struct json_obj *parent_obj, char *key); +void json_obj_add_str(struct json_obj *obj, const char *key, const char *str); +void json_obj_add_list(struct json_obj *obj, const char *key, struct json_list *list); +void json_obj_add_obj(struct json_obj *obj, const char *key, struct json_obj *new_obj); +void json_obj_add_flag(struct json_obj *obj, const char *key, char flag); +void json_obj_add_fmt_str(struct json_obj *obj, const char *key, size_t size, const char *fmt, ...); +void json_obj_add_fmt_buf_str(struct json_obj *obj, const char *key, char *buf, size_t size, const char *fmt, ...); +void json_obj_print_json(struct json_obj *obj); +void json_obj_delete_pair(struct json_obj *obj, char *key); +void json_obj_delete(struct json_obj *obj); + +struct json_list *json_list_create(enum json_val_type type); +struct json_list *json_list_create_in_obj(struct json_obj *parent_obj, char *key, enum json_val_type type); +void json_list_add_str(struct json_list *list, const char *str); +void json_list_add_obj(struct json_list *list, struct json_obj *obj); +void json_list_print_json(struct json_list *list); +void json_list_delete(struct json_list *list); + +#endif -- 2.14.1