From: Jeff Hostetler
Add basic routines to generate data in JSON format.
Signed-off-by: Jeff Hostetler
---
Makefile| 2 +
json-writer.c | 321 +
json-writer.h | 86 +
t/helper/test-json-writer.c | 420
t/t0019-json-writer.sh | 213 ++
5 files changed, 1042 insertions(+)
create mode 100644 json-writer.c
create mode 100644 json-writer.h
create mode 100644 t/helper/test-json-writer.c
create mode 100755 t/t0019-json-writer.sh
diff --git a/Makefile b/Makefile
index 1a9b23b..57f58e6 100644
--- a/Makefile
+++ b/Makefile
@@ -662,6 +662,7 @@ TEST_PROGRAMS_NEED_X += test-fake-ssh
TEST_PROGRAMS_NEED_X += test-genrandom
TEST_PROGRAMS_NEED_X += test-hashmap
TEST_PROGRAMS_NEED_X += test-index-version
+TEST_PROGRAMS_NEED_X += test-json-writer
TEST_PROGRAMS_NEED_X += test-lazy-init-name-hash
TEST_PROGRAMS_NEED_X += test-line-buffer
TEST_PROGRAMS_NEED_X += test-match-trees
@@ -815,6 +816,7 @@ LIB_OBJS += hashmap.o
LIB_OBJS += help.o
LIB_OBJS += hex.o
LIB_OBJS += ident.o
+LIB_OBJS += json-writer.o
LIB_OBJS += kwset.o
LIB_OBJS += levenshtein.o
LIB_OBJS += line-log.o
diff --git a/json-writer.c b/json-writer.c
new file mode 100644
index 000..1861382
--- /dev/null
+++ b/json-writer.c
@@ -0,0 +1,321 @@
+#include "cache.h"
+#include "json-writer.h"
+
+static char ch_open[2] = { '{', '[' };
+static char ch_close[2] = { '}', ']' };
+
+/*
+ * Append JSON-quoted version of the given string to 'out'.
+ */
+static void append_quoted_string(struct strbuf *out, const char *in)
+{
+ strbuf_addch(out, '"');
+ for (/**/; *in; in++) {
+ unsigned char c = (unsigned char)*in;
+ if (c == '"')
+ strbuf_add(out, "\\\"", 2);
+ else if (c == '\\')
+ strbuf_add(out, "", 2);
+ else if (c == '\n')
+ strbuf_add(out, "\\n", 2);
+ else if (c == '\r')
+ strbuf_add(out, "\\r", 2);
+ else if (c == '\t')
+ strbuf_add(out, "\\t", 2);
+ else if (c == '\f')
+ strbuf_add(out, "\\f", 2);
+ else if (c == '\b')
+ strbuf_add(out, "\\b", 2);
+ else if (c < 0x20)
+ strbuf_addf(out, "\\u%04x", c);
+ else
+ strbuf_addch(out, c);
+ }
+ strbuf_addch(out, '"');
+}
+
+
+static inline void begin(struct json_writer *jw, int is_array)
+{
+ ALLOC_GROW(jw->level, jw->nr + 1, jw->alloc);
+
+ jw->level[jw->nr].is_array = !!is_array;
+ jw->level[jw->nr].is_empty = 1;
+
+ strbuf_addch(&jw->json, ch_open[!!is_array]);
+
+ jw->nr++;
+}
+
+/*
+ * Assert that we have an open object at this level.
+ */
+static void inline assert_in_object(const struct json_writer *jw, const char
*key)
+{
+ if (!jw->nr)
+ die("json-writer: object: missing jw_object_begin(): '%s'",
key);
+ if (jw->level[jw->nr - 1].is_array)
+ die("json-writer: object: not in object: '%s'", key);
+}
+
+/*
+ * Assert that we have an open array at this level.
+ */
+static void inline assert_in_array(const struct json_writer *jw)
+{
+ if (!jw->nr)
+ die("json-writer: array: missing jw_begin()");
+ if (!jw->level[jw->nr - 1].is_array)
+ die("json-writer: array: not in array");
+}
+
+/*
+ * Add comma if we have already seen a member at this level.
+ */
+static void inline maybe_add_comma(struct json_writer *jw)
+{
+ if (jw->level[jw->nr - 1].is_empty)
+ jw->level[jw->nr - 1].is_empty = 0;
+ else
+ strbuf_addch(&jw->json, ',');
+}
+
+/*
+ * Assert that the given JSON object or JSON array has been properly
+ * terminated. (Has closing bracket.)
+ */
+static void inline assert_is_terminated(const struct json_writer *jw)
+{
+ if (jw->nr)
+ die("json-writer: object: missing jw_end(): '%s'",
jw->json.buf);
+}
+
+void jw_object_begin(struct json_writer *jw)
+{
+ begin(jw, 0);
+}
+
+void jw_object_string(struct json_writer *jw, const char *key, const char
*value)
+{
+ assert_in_object(jw, key);
+ maybe_add_comma(jw);
+
+ append_quoted_string(&jw->json, key);
+ strbuf_addch(&jw->json, ':');
+ append_quoted_string(&jw->json, value);
+}
+
+void jw_object_int(struct json_writer *jw, const char *key, int value)
+{
+ assert_in_object(jw, key);
+ maybe_add_comma(jw);
+
+ append_quoted_string(&jw->json, key);
+ strbuf_addf(&jw->json, ":%d", value);
+}
+
+void jw_object_uint64(struct json_writer *jw, const char *key, uint64_t value)
+{
+ assert_in_object(jw, key);
+ maybe_add_comma(jw);
+
+ append_quoted_string(&jw->json, key);
+ strbuf_addf(&jw->