[PATCH v3 2/3] Adding a structured formatter for JSON.
craven at gmx.net
craven at gmx.net
Wed Jul 11 01:26:34 PDT 2012
This patch adds a structured formatter that prints exactly the same JSON as the built-in JSON printer. All tests pass without change.
Notice that this formatter could be simpler by changing the whitespace
and line-breaks in the generated JSON.
---
Makefile.local | 1 +
structured-output.c | 167 ++++++++++++++++++++++++++++++++++++++++++++++++++++
structured-output.h | 59 +++++++++++++++++++
3 files changed, 227 insertions(+)
create mode 100644 structured-output.c
diff --git a/Makefile.local b/Makefile.local
index a890df2..9b989dc 100644
--- a/Makefile.local
+++ b/Makefile.local
@@ -291,6 +291,7 @@ notmuch_client_srcs = \
notmuch-tag.c \
notmuch-time.c \
query-string.c \
+ structured-output.c \
mime-node.c \
crypto.c \
json.c
diff --git a/structured-output.c b/structured-output.c
new file mode 100644
index 0000000..18a7306
--- /dev/null
+++ b/structured-output.c
@@ -0,0 +1,167 @@
+/* notmuch - Not much of an email program, (just index and search)
+ *
+ * Copyright © 2009 Carl Worth
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see http://www.gnu.org/licenses/ .
+ *
+ * Author: Carl Worth <cworth at cworth.org>
+ */
+
+#include "structured-output.h"
+#define ARRAY_SIZE(arr) (sizeof (arr) / sizeof (arr[0]))
+
+structure_printer_t *
+unstructured_text_printer = NULL;
+
+structure_printer_t
+json_structure_printer = {
+ &json_map,
+ &json_list,
+ &json_pop,
+ &json_map_key,
+ &json_number,
+ &json_string,
+ &json_bool,
+ &json_initial_state
+};
+
+static int
+enter_level (void *st, const char *marker, int type) {
+ json_state_t *state = (json_state_t*)st;
+ FILE *output = state->output;
+ json_list_t *el = talloc (st, json_list_t);
+
+ json_item_separator (state, (state->level == 1) ? "\n" : " ");
+ fputs (marker, output);
+
+ el->type = type;
+ el->first_seen = FALSE;
+ el->rest = state->stack;
+ state->stack = el;
+ return state->level++;
+}
+
+void
+json_print_escaped_string (FILE *output, const char *val)
+{
+ static const char * const escapes[] = {
+ ['\"'] = "\\\"", ['\\'] = "\\\\", ['\b'] = "\\b",
+ ['\f'] = "\\f", ['\n'] = "\\n", ['\t'] = "\\t"
+ };
+ fputc ('"', output);
+ for (; *val; ++val) {
+ unsigned char ch = *val;
+ if (ch < ARRAY_SIZE(escapes) && escapes[ch])
+ fputs (escapes[ch], output);
+ else if (ch >= 32)
+ fputc (ch, output);
+ else
+ fprintf (output, "\\u%04x", ch);
+ }
+ fputc ('"', output);
+}
+
+int
+json_map (void *st)
+{
+ return enter_level (st, "{", TYPE_JSON_MAP);
+}
+
+int
+json_list (void *st)
+{
+ return enter_level (st, "[", TYPE_JSON_ARRAY);
+}
+
+void
+json_pop (void *st, int level)
+{
+ json_state_t *state = (json_state_t*)st;
+ FILE *output = state->output;
+ while (state->level > level) {
+ json_list_t *tos = state->stack;
+ fputs (tos->type == TYPE_JSON_MAP ? "}" : "]", output);
+ state->stack = tos->rest;
+ state->level--;
+ talloc_free (tos);
+ }
+ if (state->level == 0) {
+ fputs ("\n", output);
+ }
+}
+
+void
+json_map_key (void *st, const char *key)
+{
+ json_state_t *state = (json_state_t*)st;
+ FILE *output = state->output;
+ if (state->stack != NULL && state->stack->first_seen) {
+ fputs (",\n", output);
+ }
+ json_print_escaped_string (output, key);
+ fputs (": ", output);
+}
+
+void
+json_item_separator (json_state_t *state, const char *suffix)
+{
+ FILE *output = state->output;
+ if (state->stack != NULL
+ && state->stack->type == TYPE_JSON_ARRAY
+ && state->stack->first_seen) {
+
+ fputs (",", output);
+ fputs (suffix, output);
+ }
+ if (state->stack != NULL)
+ state->stack->first_seen = TRUE;
+}
+
+void
+json_number (void *st, int val)
+{
+ json_state_t *state = (json_state_t*)st;
+ FILE *output = state->output;
+ json_item_separator (state, state->level == 1 ? "\n" : " ");
+ fprintf (output, "%d", val);
+}
+
+void
+json_string (void *st, const char *val)
+{
+ json_state_t *state = (json_state_t *)st;
+ FILE *output = state->output;
+ json_item_separator (state, state->level == 1 ? "\n" : " ");
+ json_print_escaped_string (output, val);
+}
+
+void
+json_bool (void *st, notmuch_bool_t val)
+{
+ json_state_t *state = (json_state_t*)st;
+ FILE *output = state->output;
+ json_item_separator (state, state->level == 1 ? "\n" : " ");
+ fputs (val ? "true" : "false", output);
+}
+
+void *
+json_initial_state (const struct structure_printer *sp, FILE *output)
+{
+ (void)sp;
+ json_state_t *st = talloc (0, json_state_t);
+ st->level = 0;
+ st->stack = NULL;
+ st->output = output;
+ return st;
+}
diff --git a/structured-output.h b/structured-output.h
index 73029f1..b211ac6 100644
--- a/structured-output.h
+++ b/structured-output.h
@@ -88,3 +88,62 @@ typedef struct structure_printer {
FILE *output);
} structure_printer_t;
+
+/* dummy object to differentiate plain text from structured output */
+structure_printer_t *
+unstructured_text_printer;
+
+/* JSON structure printer
+ * An implementation of the JSON structure printer that produces
+ * exactly the same output as the previous JSON printer.
+ */
+
+/* single linked list implementation for keeping track of the array/map
+ * nesting state.
+ */
+typedef enum {TYPE_JSON_MAP, TYPE_JSON_ARRAY} JSON_TYPE;
+
+typedef struct json_list {
+ int type;
+ notmuch_bool_t first_seen;
+ struct json_list *rest;
+} json_list_t;
+
+typedef struct json_state {
+ FILE *output;
+ json_list_t *stack;
+ int level;
+} json_state_t;
+
+int
+json_map(void *state);
+
+int
+json_list(void *state);
+
+void
+json_pop(void *state, int level);
+
+void
+json_map_key(void *state, const char *key);
+
+void
+json_number(void *state, int val);
+
+void
+json_string(void *state, const char *val);
+
+void
+json_bool(void *state, notmuch_bool_t val);
+
+void *
+json_initial_state(const struct structure_printer *sp, FILE *output);
+
+void
+json_print_escaped_string(FILE *output, const char *val);
+
+void
+json_item_separator(json_state_t *state, const char *suffix);
+
+structure_printer_t
+json_structure_printer;
--
1.7.11.1
More information about the notmuch
mailing list