1 Return-Path: <craven@gmx.net>
\r
2 X-Original-To: notmuch@notmuchmail.org
\r
3 Delivered-To: notmuch@notmuchmail.org
\r
4 Received: from localhost (localhost [127.0.0.1])
\r
5 by olra.theworths.org (Postfix) with ESMTP id 26710429E3C
\r
6 for <notmuch@notmuchmail.org>; Wed, 11 Jul 2012 01:25:26 -0700 (PDT)
\r
7 X-Virus-Scanned: Debian amavisd-new at olra.theworths.org
\r
11 X-Spam-Status: No, score=0.001 tagged_above=-999 required=5
\r
12 tests=[FREEMAIL_FROM=0.001, RCVD_IN_DNSWL_NONE=-0.0001]
\r
14 Received: from olra.theworths.org ([127.0.0.1])
\r
15 by localhost (olra.theworths.org [127.0.0.1]) (amavisd-new, port 10024)
\r
16 with ESMTP id 9a9F7MtAQ7EV for <notmuch@notmuchmail.org>;
\r
17 Wed, 11 Jul 2012 01:25:23 -0700 (PDT)
\r
18 Received: from mailout-de.gmx.net (mailout-de.gmx.net [213.165.64.22])
\r
19 by olra.theworths.org (Postfix) with SMTP id DDF20429E26
\r
20 for <notmuch@notmuchmail.org>; Wed, 11 Jul 2012 01:25:21 -0700 (PDT)
\r
21 Received: (qmail invoked by alias); 11 Jul 2012 08:25:14 -0000
\r
22 Received: from gw.arelion.cust.net.lagis.at (EHLO dodekanex.arelion.at)
\r
24 by mail.gmx.net (mp016) with SMTP; 11 Jul 2012 10:25:14 +0200
\r
25 X-Authenticated: #201305
\r
26 X-Provags-ID: V01U2FsdGVkX1887tYf0eI8tllIWkVJ6Mvejk7/HvwFk7Ruqa/5x2
\r
28 Received: by dodekanex.arelion.at (Postfix, from userid 1000)
\r
29 id BD7F330313C; Wed, 11 Jul 2012 10:26:36 +0200 (CEST)
\r
30 From: <craven@gmx.net>
\r
31 To: notmuch@notmuchmail.org
\r
32 Subject: [PATCH v3 2/3] Adding a structured formatter for JSON.
\r
33 Date: Wed, 11 Jul 2012 10:26:34 +0200
\r
34 Message-Id: <1341995195-2497-3-git-send-email-craven@gmx.net>
\r
35 X-Mailer: git-send-email 1.7.11.1
\r
36 In-Reply-To: <1341995195-2497-1-git-send-email-craven@gmx.net>
\r
37 References: <20120710191331.GE7332@mit.edu>
\r
38 <1341995195-2497-1-git-send-email-craven@gmx.net>
\r
40 Content-Type: text/plain; charset=UTF-8
\r
41 Content-Transfer-Encoding: 8bit
\r
43 X-BeenThere: notmuch@notmuchmail.org
\r
44 X-Mailman-Version: 2.1.13
\r
46 List-Id: "Use and development of the notmuch mail system."
\r
47 <notmuch.notmuchmail.org>
\r
48 List-Unsubscribe: <http://notmuchmail.org/mailman/options/notmuch>,
\r
49 <mailto:notmuch-request@notmuchmail.org?subject=unsubscribe>
\r
50 List-Archive: <http://notmuchmail.org/pipermail/notmuch>
\r
51 List-Post: <mailto:notmuch@notmuchmail.org>
\r
52 List-Help: <mailto:notmuch-request@notmuchmail.org?subject=help>
\r
53 List-Subscribe: <http://notmuchmail.org/mailman/listinfo/notmuch>,
\r
54 <mailto:notmuch-request@notmuchmail.org?subject=subscribe>
\r
55 X-List-Received-Date: Wed, 11 Jul 2012 08:25:26 -0000
\r
57 This patch adds a structured formatter that prints exactly the same JSON as the built-in JSON printer. All tests pass without change.
\r
59 Notice that this formatter could be simpler by changing the whitespace
\r
60 and line-breaks in the generated JSON.
\r
62 Makefile.local | 1 +
\r
63 structured-output.c | 167 ++++++++++++++++++++++++++++++++++++++++++++++++++++
\r
64 structured-output.h | 59 +++++++++++++++++++
\r
65 3 files changed, 227 insertions(+)
\r
66 create mode 100644 structured-output.c
\r
68 diff --git a/Makefile.local b/Makefile.local
\r
69 index a890df2..9b989dc 100644
\r
70 --- a/Makefile.local
\r
71 +++ b/Makefile.local
\r
72 @@ -291,6 +291,7 @@ notmuch_client_srcs = \
\r
76 + structured-output.c \
\r
80 diff --git a/structured-output.c b/structured-output.c
\r
81 new file mode 100644
\r
82 index 0000000..18a7306
\r
84 +++ b/structured-output.c
\r
86 +/* notmuch - Not much of an email program, (just index and search)
\r
88 + * Copyright © 2009 Carl Worth
\r
90 + * This program is free software: you can redistribute it and/or modify
\r
91 + * it under the terms of the GNU General Public License as published by
\r
92 + * the Free Software Foundation, either version 3 of the License, or
\r
93 + * (at your option) any later version.
\r
95 + * This program is distributed in the hope that it will be useful,
\r
96 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
97 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
\r
98 + * GNU General Public License for more details.
\r
100 + * You should have received a copy of the GNU General Public License
\r
101 + * along with this program. If not, see http://www.gnu.org/licenses/ .
\r
103 + * Author: Carl Worth <cworth@cworth.org>
\r
106 +#include "structured-output.h"
\r
107 +#define ARRAY_SIZE(arr) (sizeof (arr) / sizeof (arr[0]))
\r
109 +structure_printer_t *
\r
110 +unstructured_text_printer = NULL;
\r
112 +structure_printer_t
\r
113 +json_structure_printer = {
\r
121 + &json_initial_state
\r
125 +enter_level (void *st, const char *marker, int type) {
\r
126 + json_state_t *state = (json_state_t*)st;
\r
127 + FILE *output = state->output;
\r
128 + json_list_t *el = talloc (st, json_list_t);
\r
130 + json_item_separator (state, (state->level == 1) ? "\n" : " ");
\r
131 + fputs (marker, output);
\r
134 + el->first_seen = FALSE;
\r
135 + el->rest = state->stack;
\r
136 + state->stack = el;
\r
137 + return state->level++;
\r
141 +json_print_escaped_string (FILE *output, const char *val)
\r
143 + static const char * const escapes[] = {
\r
144 + ['\"'] = "\\\"", ['\\'] = "\\\\", ['\b'] = "\\b",
\r
145 + ['\f'] = "\\f", ['\n'] = "\\n", ['\t'] = "\\t"
\r
147 + fputc ('"', output);
\r
148 + for (; *val; ++val) {
\r
149 + unsigned char ch = *val;
\r
150 + if (ch < ARRAY_SIZE(escapes) && escapes[ch])
\r
151 + fputs (escapes[ch], output);
\r
152 + else if (ch >= 32)
\r
153 + fputc (ch, output);
\r
155 + fprintf (output, "\\u%04x", ch);
\r
157 + fputc ('"', output);
\r
161 +json_map (void *st)
\r
163 + return enter_level (st, "{", TYPE_JSON_MAP);
\r
167 +json_list (void *st)
\r
169 + return enter_level (st, "[", TYPE_JSON_ARRAY);
\r
173 +json_pop (void *st, int level)
\r
175 + json_state_t *state = (json_state_t*)st;
\r
176 + FILE *output = state->output;
\r
177 + while (state->level > level) {
\r
178 + json_list_t *tos = state->stack;
\r
179 + fputs (tos->type == TYPE_JSON_MAP ? "}" : "]", output);
\r
180 + state->stack = tos->rest;
\r
182 + talloc_free (tos);
\r
184 + if (state->level == 0) {
\r
185 + fputs ("\n", output);
\r
190 +json_map_key (void *st, const char *key)
\r
192 + json_state_t *state = (json_state_t*)st;
\r
193 + FILE *output = state->output;
\r
194 + if (state->stack != NULL && state->stack->first_seen) {
\r
195 + fputs (",\n", output);
\r
197 + json_print_escaped_string (output, key);
\r
198 + fputs (": ", output);
\r
202 +json_item_separator (json_state_t *state, const char *suffix)
\r
204 + FILE *output = state->output;
\r
205 + if (state->stack != NULL
\r
206 + && state->stack->type == TYPE_JSON_ARRAY
\r
207 + && state->stack->first_seen) {
\r
209 + fputs (",", output);
\r
210 + fputs (suffix, output);
\r
212 + if (state->stack != NULL)
\r
213 + state->stack->first_seen = TRUE;
\r
217 +json_number (void *st, int val)
\r
219 + json_state_t *state = (json_state_t*)st;
\r
220 + FILE *output = state->output;
\r
221 + json_item_separator (state, state->level == 1 ? "\n" : " ");
\r
222 + fprintf (output, "%d", val);
\r
226 +json_string (void *st, const char *val)
\r
228 + json_state_t *state = (json_state_t *)st;
\r
229 + FILE *output = state->output;
\r
230 + json_item_separator (state, state->level == 1 ? "\n" : " ");
\r
231 + json_print_escaped_string (output, val);
\r
235 +json_bool (void *st, notmuch_bool_t val)
\r
237 + json_state_t *state = (json_state_t*)st;
\r
238 + FILE *output = state->output;
\r
239 + json_item_separator (state, state->level == 1 ? "\n" : " ");
\r
240 + fputs (val ? "true" : "false", output);
\r
244 +json_initial_state (const struct structure_printer *sp, FILE *output)
\r
247 + json_state_t *st = talloc (0, json_state_t);
\r
249 + st->stack = NULL;
\r
250 + st->output = output;
\r
253 diff --git a/structured-output.h b/structured-output.h
\r
254 index 73029f1..b211ac6 100644
\r
255 --- a/structured-output.h
\r
256 +++ b/structured-output.h
\r
257 @@ -88,3 +88,62 @@ typedef struct structure_printer {
\r
260 } structure_printer_t;
\r
262 +/* dummy object to differentiate plain text from structured output */
\r
263 +structure_printer_t *
\r
264 +unstructured_text_printer;
\r
266 +/* JSON structure printer
\r
267 + * An implementation of the JSON structure printer that produces
\r
268 + * exactly the same output as the previous JSON printer.
\r
271 +/* single linked list implementation for keeping track of the array/map
\r
274 +typedef enum {TYPE_JSON_MAP, TYPE_JSON_ARRAY} JSON_TYPE;
\r
276 +typedef struct json_list {
\r
278 + notmuch_bool_t first_seen;
\r
279 + struct json_list *rest;
\r
282 +typedef struct json_state {
\r
284 + json_list_t *stack;
\r
289 +json_map(void *state);
\r
292 +json_list(void *state);
\r
295 +json_pop(void *state, int level);
\r
298 +json_map_key(void *state, const char *key);
\r
301 +json_number(void *state, int val);
\r
304 +json_string(void *state, const char *val);
\r
307 +json_bool(void *state, notmuch_bool_t val);
\r
310 +json_initial_state(const struct structure_printer *sp, FILE *output);
\r
313 +json_print_escaped_string(FILE *output, const char *val);
\r
316 +json_item_separator(json_state_t *state, const char *suffix);
\r
318 +structure_printer_t
\r
319 +json_structure_printer;
\r