This formatter prints exactly the same structure as the existing JSON formatter, but uses the newly introduced structured formatting primitives. --- structured-output.c | 159 +++++++++++++++++++++++++++++++++++++++++++++++++++ structured-output.h | 48 ++++++++++++++++ 2 files changed, 207 insertions(+) create mode 100644 structured-output.c diff --git a/structured-output.c b/structured-output.c new file mode 100644 index 0000000..e10fba4 --- /dev/null +++ b/structured-output.c @@ -0,0 +1,159 @@ +/* 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@cworth.org> + */ + +#include "structured-output.h" + +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; + if (state->stack != NULL && state->stack->type == TYPE_JSON_ARRAY && state->stack->first_already_seen) { + fputs(",", output); + if (state->level == 1) + fputs("\n", output); + else + fputs(" ", output); + } + if (state->stack != NULL) { + state->stack->first_already_seen = TRUE; + } + fputs(marker, output); + void *ctx_json_map = talloc_new (0); + json_list_t *el = talloc(ctx_json_map, json_list_t); + el->type = type; + el->first_already_seen = FALSE; + el->rest = state->stack; + state->stack = el; + return state->level++; +} + +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) +{ + int i; + json_state_t *state = (json_state_t*)st; + FILE *output = state->output; + for (i = state->level; i > level; i--) { + json_list_t *tos = state->stack; + if (tos->type == TYPE_JSON_MAP) { + fputs("}", output); + } + if (tos->type == TYPE_JSON_ARRAY) { + fputs("]", 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_already_seen) { + fputs(",\n", output); + } + fputs("\"", output); + fputs(key, output); + fputs("\": ", output); +} + +void +json_number(void *st, int val) +{ + json_state_t *state = (json_state_t*)st; + FILE *output = state->output; + if (state->stack != NULL && state->stack->type == TYPE_JSON_ARRAY && state->stack->first_already_seen) { + fputs(", ", output); + } + state->stack->first_already_seen = TRUE; + fprintf(output, "%i", val); +} + +void +json_string(void *st, const char *val) +{ + json_state_t *state = (json_state_t*)st; + FILE *output = state->output; + void *ctx = talloc_new(0); + if (state->stack != NULL && state->stack->type == TYPE_JSON_ARRAY && state->stack->first_already_seen) { + fputs(",", output); + if (state->level == 1) + fputs("\n", output); + else + fputs(" ", output); + } + + state->stack->first_already_seen = TRUE; + fprintf(output, "%s", json_quote_str(ctx, val)); + talloc_free(ctx); +} + +void +json_bool(void *st, notmuch_bool_t val) +{ + json_state_t *state = (json_state_t*)st; + FILE *output = state->output; + if (val) + fputs("true", output); + else + fputs("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 b43afe0..cba3882 100644 --- a/structured-output.h +++ b/structured-output.h @@ -62,3 +62,51 @@ typedef struct structure_printer { } structure_printer_t; +/* JSON structure printer */ + +/* single linked list implementation for keeping track of the array/map nesting state */ + +typedef struct json_list { + int type; + int first_already_seen; + struct json_list *rest; +} json_list_t; + +#define TYPE_JSON_MAP 1 +#define TYPE_JSON_ARRAY 2 + +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); + +structure_printer_t +json_structure_printer; + +structure_printer_t * +unstructured_text_printer; -- 1.7.10.4