From 52084f22fd5b700b749d7dfc6dedb6e01ef9ac22 Mon Sep 17 00:00:00 2001 From: Martin Mares Date: Wed, 8 Jul 2015 16:43:57 +0200 Subject: [PATCH] JSON: Rudimentary formatting --- ucw-json/Makefile | 2 +- ucw-json/format.c | 114 ++++++++++++++++++++++++++++++++++++++++++++++ ucw-json/json.c | 2 - ucw-json/json.h | 8 +++- ucw-json/parse.c | 15 +++--- 5 files changed, 129 insertions(+), 12 deletions(-) create mode 100644 ucw-json/format.c diff --git a/ucw-json/Makefile b/ucw-json/Makefile index 0e5bd98b..7c54ffb7 100644 --- a/ucw-json/Makefile +++ b/ucw-json/Makefile @@ -4,7 +4,7 @@ DIRS+=ucw-json PROGS+=$(o)/ucw-json/json-test -LIBJSON_MODS=json parse +LIBJSON_MODS=json parse format LIBJSON_MOD_PATHS=$(addprefix $(o)/ucw-json/,$(LIBJSON_MODS)) LIBJSON_INCLUDES=json.h LIBJSON_DEPS=$(LIBUCW) diff --git a/ucw-json/format.c b/ucw-json/format.c new file mode 100644 index 00000000..2c17ca59 --- /dev/null +++ b/ucw-json/format.c @@ -0,0 +1,114 @@ +/* + * UCW JSON Library -- Formatter + * + * (c) 2015 Martin Mares + * + * This software may be freely distributed and used according to the terms + * of the GNU Lesser General Public License. + */ + +#include +#include +#include +#include +#include +#include + +#include + +void json_set_output(struct json_context *js, struct fastbuf *fb) +{ + js->out_fb = fb; +} + +static void write_string(struct fastbuf *fb, const char *p) +{ + bputc(fb, '"'); + for (;;) + { + uint u; + p = utf8_32_get(p, &u); + if (!u) + break; + if (u == '"' || u == '\\') + { + bputc(fb, '\\'); + bputc(fb, u); + } + else if (u < 0x20) + { + // We avoid "\f" nor "\b" and use "\uXXXX" instead + switch (u) + { + case 0x09: bputs(fb, "\\t"); break; + case 0x0a: bputs(fb, "\\n"); break; + case 0x0d: bputs(fb, "\\r"); break; + default: + bprintf(fb, "\\u%04x", u); + } + } + else + bputc(fb, u); + } + bputc(fb, '"'); +} + +void json_write_value(struct json_context *js, struct json_node *n) +{ + struct fastbuf *fb = js->out_fb; + + switch (n->type) + { + case JSON_NULL: + bputs(fb, "null"); + break; + case JSON_BOOLEAN: + bputs(fb, (n->boolean ? "true" : "false")); + break; + case JSON_NUMBER: + // FIXME: Formatting of floats + bprintf(fb, "%f", n->number); + break; + case JSON_STRING: + write_string(fb, n->string); + break; + case JSON_ARRAY: + { + // FIXME: Indent + bputs(fb, "[ "); + for (size_t i=0; i < GARY_SIZE(n->elements); i++) + { + if (i) + bputs(fb, ", "); + json_write_value(js, n->elements[i]); + } + bputc(fb, ']'); + break; + } + case JSON_OBJECT: + { + bputs(fb, "{ "); + // FIXME: Indent + for (size_t i=0; i < GARY_SIZE(n->pairs); i++) + { + if (i) + bputs(fb, ", "); + struct json_pair *p = &n->pairs[i]; + write_string(fb, p->key); + bputs(fb, ": "); + json_write_value(js, p->value); + } + bputc(fb, '}'); + break; + } + default: + ASSERT(0); + } +} + +void json_write(struct json_context *js, struct fastbuf *fb, struct json_node *n) +{ + json_set_output(js, fb); + json_write_value(js, n); + bputc(fb, '\n'); +} diff --git a/ucw-json/json.c b/ucw-json/json.c index 35ee49f9..6b53d2fb 100644 --- a/ucw-json/json.c +++ b/ucw-json/json.c @@ -7,8 +7,6 @@ * of the GNU Lesser General Public License. */ -#undef LOCAL_DEBUG - #include #include #include diff --git a/ucw-json/json.h b/ucw-json/json.h index 5340a30e..ac5570d9 100644 --- a/ucw-json/json.h +++ b/ucw-json/json.h @@ -34,6 +34,8 @@ struct json_context { struct json_node *next_token; struct json_node *trivial_token; int next_char; + + struct fastbuf *out_fb; }; struct json_context *json_new(void); @@ -120,8 +122,12 @@ void json_set_input(struct json_context *js, struct fastbuf *in); struct json_node *json_peek_token(struct json_context *js); struct json_node *json_next_token(struct json_context *js); -struct json_node *json_next_object(struct json_context *js); +struct json_node *json_next_value(struct json_context *js); struct json_node *json_parse(struct json_context *js, struct fastbuf *fb); +void json_set_output(struct json_context *js, struct fastbuf *fb); +void json_write_value(struct json_context *js, struct json_node *n); +void json_write(struct json_context *js, struct fastbuf *fb, struct json_node *n); + #endif diff --git a/ucw-json/parse.c b/ucw-json/parse.c index 181c6afb..a4de28de 100644 --- a/ucw-json/parse.c +++ b/ucw-json/parse.c @@ -7,11 +7,10 @@ * of the GNU Lesser General Public License. */ -#undef LOCAL_DEBUG - #include -#include +#include #include +#include #include #include @@ -332,7 +331,7 @@ struct json_node *json_next_token(struct json_context *js) return t; } -struct json_node *json_next_object(struct json_context *js) +struct json_node *json_next_value(struct json_context *js) { struct json_node *t = json_next_token(js); @@ -356,7 +355,7 @@ struct json_node *json_next_object(struct json_context *js) json_next_token(js); else for (;;) { - struct json_node *v = json_next_object(js); + struct json_node *v = json_next_value(js); if (!v) json_parse_error(js, "Unterminated array"); json_array_append(a, v); @@ -378,7 +377,7 @@ struct json_node *json_next_object(struct json_context *js) json_next_token(js); else for (;;) { - struct json_node *k = json_next_object(js); + struct json_node *k = json_next_value(js); if (!k) json_parse_error(js, "Unterminated object"); if (k->type != JSON_STRING) @@ -388,7 +387,7 @@ struct json_node *json_next_object(struct json_context *js) if (t->type != JSON_NAME_SEP) json_parse_error(js, "Colon expected"); - struct json_node *v = json_next_object(js); + struct json_node *v = json_next_value(js); if (!v) json_parse_error(js, "Unterminated object"); if (json_object_get(o, k->string)) // FIXME: Optimize @@ -422,7 +421,7 @@ struct json_node *json_parse(struct json_context *js, struct fastbuf *fb) { json_set_input(js, fb); - struct json_node *n = json_next_object(js); + struct json_node *n = json_next_value(js); if (!n) json_parse_error(js, "Empty input"); -- 2.39.2