Re: [feature request] emacs: use `notmuch insert` for FCC
[notmuch-archives.git] / ee / 2db05adf2b50449bb79e816e0074f5671bc2f4
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 53310431FAE\r
6         for <notmuch@notmuchmail.org>; Thu, 12 Jul 2012 00:42:18 -0700 (PDT)\r
7 X-Virus-Scanned: Debian amavisd-new at olra.theworths.org\r
8 X-Spam-Flag: NO\r
9 X-Spam-Score: 0.001\r
10 X-Spam-Level: \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
13         autolearn=disabled\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 SFck2vzs2WeI for <notmuch@notmuchmail.org>;\r
17         Thu, 12 Jul 2012 00:42:15 -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 79522431FC9\r
20         for <notmuch@notmuchmail.org>; Thu, 12 Jul 2012 00:42:11 -0700 (PDT)\r
21 Received: (qmail invoked by alias); 12 Jul 2012 07:42:02 -0000\r
22 Received: from gw.arelion.cust.net.lagis.at (EHLO dodekanex.arelion.at)\r
23         [83.164.197.182]\r
24         by mail.gmx.net (mp028) with SMTP; 12 Jul 2012 09:42:02 +0200\r
25 X-Authenticated: #201305\r
26 X-Provags-ID: V01U2FsdGVkX19uyYcosdlugZbxWUIO4vqOl3GmgQ8WephdZfN7M7\r
27         4ENuSjvnTyIjUi\r
28 Received: by dodekanex.arelion.at (Postfix, from userid 1000)\r
29         id 577933011C1; Thu, 12 Jul 2012 09:43:31 +0200 (CEST)\r
30 From: <craven@gmx.net>\r
31 To: notmuch@notmuchmail.org\r
32 Subject: [PATCH v4 2/3] Add structured output formatter for JSON.\r
33 Date: Thu, 12 Jul 2012 09:43:23 +0200\r
34 Message-Id: <1342079004-5300-3-git-send-email-craven@gmx.net>\r
35 X-Mailer: git-send-email 1.7.11.1\r
36 In-Reply-To: <1342079004-5300-1-git-send-email-craven@gmx.net>\r
37 References: <87d34hsdx8.fsf@awakening.csail.mit.edu>\r
38         <1342079004-5300-1-git-send-email-craven@gmx.net>\r
39 X-Y-GMX-Trusted: 0\r
40 X-BeenThere: notmuch@notmuchmail.org\r
41 X-Mailman-Version: 2.1.13\r
42 Precedence: list\r
43 List-Id: "Use and development of the notmuch mail system."\r
44         <notmuch.notmuchmail.org>\r
45 List-Unsubscribe: <http://notmuchmail.org/mailman/options/notmuch>,\r
46         <mailto:notmuch-request@notmuchmail.org?subject=unsubscribe>\r
47 List-Archive: <http://notmuchmail.org/pipermail/notmuch>\r
48 List-Post: <mailto:notmuch@notmuchmail.org>\r
49 List-Help: <mailto:notmuch-request@notmuchmail.org?subject=help>\r
50 List-Subscribe: <http://notmuchmail.org/mailman/listinfo/notmuch>,\r
51         <mailto:notmuch-request@notmuchmail.org?subject=subscribe>\r
52 X-List-Received-Date: Thu, 12 Jul 2012 07:42:18 -0000\r
53 \r
54 Using the new structured printer support in sprinter.h, implement\r
55 sprinter_json_new, which returns a new JSON structured output\r
56 formatter.\r
57 \r
58 The formatter prints output similar to the existing JSON, but with\r
59 differences in whitespace (mostly newlines).\r
60 ---\r
61  Makefile.local |   1 +\r
62  sprinter.c     | 172 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++\r
63  2 files changed, 173 insertions(+)\r
64  create mode 100644 sprinter.c\r
65 \r
66 diff --git a/Makefile.local b/Makefile.local\r
67 index a890df2..8baf0c2 100644\r
68 --- a/Makefile.local\r
69 +++ b/Makefile.local\r
70 @@ -290,6 +290,7 @@ notmuch_client_srcs =               \\r
71         notmuch-show.c          \\r
72         notmuch-tag.c           \\r
73         notmuch-time.c          \\r
74 +       sprinter.c              \\r
75         query-string.c          \\r
76         mime-node.c             \\r
77         crypto.c                \\r
78 diff --git a/sprinter.c b/sprinter.c\r
79 new file mode 100644\r
80 index 0000000..649f79a\r
81 --- /dev/null\r
82 +++ b/sprinter.c\r
83 @@ -0,0 +1,172 @@\r
84 +#include <stdbool.h>\r
85 +#include <stdio.h>\r
86 +#include <talloc.h>\r
87 +#include "sprinter.h"\r
88 +\r
89 +#define ARRAY_SIZE(arr) (sizeof (arr) / sizeof (arr[0]))\r
90 +\r
91 +struct sprinter *\r
92 +sprinter_text = NULL;\r
93 +\r
94 +/*\r
95 + * Every below here is the implementation of the JSON printer.\r
96 + */\r
97 +\r
98 +struct sprinter_json\r
99 +{\r
100 +    struct sprinter vtable;\r
101 +    FILE *stream;\r
102 +    /* Top of the state stack, or NULL if the printer is not currently\r
103 +     * inside any aggregate types. */\r
104 +    struct json_state *state;\r
105 +};\r
106 +\r
107 +struct json_state\r
108 +{\r
109 +    struct json_state *parent;\r
110 +    /* True if nothing has been printed in this aggregate yet.\r
111 +     * Suppresses the comma before a value. */\r
112 +    notmuch_bool_t first;\r
113 +    /* The character that closes the current aggregate. */\r
114 +    char close;\r
115 +};\r
116 +\r
117 +/* Helper function to set up the stream to print a value.  If this\r
118 + * value follows another value, prints a comma. */\r
119 +static struct sprinter_json *\r
120 +json_begin_value(struct sprinter *sp)\r
121 +{\r
122 +    struct sprinter_json *spj = (struct sprinter_json*)sp;\r
123 +    if (spj->state) {\r
124 +       if (!spj->state->first)\r
125 +           fputs (", ", spj->stream);\r
126 +       else\r
127 +           spj->state->first = false;\r
128 +    }\r
129 +    return spj;\r
130 +}\r
131 +\r
132 +/* Helper function to begin an aggregate type.  Prints the open\r
133 + * character and pushes a new state frame. */\r
134 +static void\r
135 +json_begin_aggregate(struct sprinter *sp, char open, char close)\r
136 +{\r
137 +    struct sprinter_json *spj = json_begin_value (sp);\r
138 +    struct json_state *state = talloc (spj, struct json_state);\r
139 +\r
140 +    fputc (open, spj->stream);\r
141 +    state->parent = spj->state;\r
142 +    state->first = true;\r
143 +    state->close = close;\r
144 +    spj->state = state;\r
145 +}\r
146 +\r
147 +static void\r
148 +json_begin_map(struct sprinter *sp)\r
149 +{\r
150 +    json_begin_aggregate (sp, '{', '}');\r
151 +}\r
152 +\r
153 +static void\r
154 +json_begin_list(struct sprinter *sp)\r
155 +{\r
156 +    json_begin_aggregate (sp, '[', ']');\r
157 +}\r
158 +\r
159 +static void\r
160 +json_end(struct sprinter *sp)\r
161 +{\r
162 +    struct sprinter_json *spj = (struct sprinter_json*)sp;\r
163 +    struct json_state *state = spj->state;\r
164 +\r
165 +    fputc (spj->state->close, spj->stream);\r
166 +    spj->state = state->parent;\r
167 +    talloc_free (state);\r
168 +    if(spj->state == NULL)\r
169 +       fputc ('\n', spj->stream);\r
170 +}\r
171 +\r
172 +static void\r
173 +json_string(struct sprinter *sp, const char *val)\r
174 +{\r
175 +    static const char * const escapes[] = {\r
176 +       ['\"'] = "\\\"", ['\\'] = "\\\\", ['\b'] = "\\b",\r
177 +       ['\f'] = "\\f",  ['\n'] = "\\n",  ['\t'] = "\\t"\r
178 +    };\r
179 +    struct sprinter_json *spj = json_begin_value (sp);\r
180 +    fputc ('"', spj->stream);\r
181 +    for (; *val; ++val) {\r
182 +       unsigned char ch = *val;\r
183 +       if (ch < ARRAY_SIZE(escapes) && escapes[ch])\r
184 +           fputs (escapes[ch], spj->stream);\r
185 +       else if (ch >= 32)\r
186 +           fputc (ch, spj->stream);\r
187 +       else\r
188 +           fprintf (spj->stream, "\\u%04x", ch);\r
189 +    }\r
190 +    fputc ('"', spj->stream);\r
191 +}\r
192 +\r
193 +static void\r
194 +json_integer(struct sprinter *sp, int val)\r
195 +{\r
196 +    struct sprinter_json *spj = json_begin_value (sp);\r
197 +    fprintf (spj->stream, "%d", val);\r
198 +}\r
199 +\r
200 +static void\r
201 +json_boolean(struct sprinter *sp, notmuch_bool_t val)\r
202 +{\r
203 +    struct sprinter_json *spj = json_begin_value (sp);\r
204 +    fputs (val ? "true" : "false", spj->stream);\r
205 +}\r
206 +\r
207 +static void\r
208 +json_null(struct sprinter *sp)\r
209 +{\r
210 +    struct sprinter_json *spj = json_begin_value (sp);\r
211 +    fputs ("null", spj->stream);\r
212 +}\r
213 +\r
214 +static void\r
215 +json_map_key(struct sprinter *sp, const char *key)\r
216 +{\r
217 +    struct sprinter_json *spj = (struct sprinter_json*)sp;\r
218 +    json_string (sp, key);\r
219 +    fputs (": ", spj->stream);\r
220 +    spj->state->first = true;\r
221 +}\r
222 +\r
223 +static void\r
224 +json_frame(struct sprinter *sp)\r
225 +{\r
226 +    struct sprinter_json *spj = (struct sprinter_json*)sp;\r
227 +    fputc ('\n', spj->stream);\r
228 +}\r
229 +\r
230 +struct sprinter *\r
231 +sprinter_json_new(const void *ctx, FILE *stream)\r
232 +{\r
233 +    static const struct sprinter_json template = {\r
234 +       .vtable = {\r
235 +           .begin_map = json_begin_map,\r
236 +           .begin_list = json_begin_list,\r
237 +           .end = json_end,\r
238 +           .string = json_string,\r
239 +           .integer = json_integer,\r
240 +           .boolean = json_boolean,\r
241 +           .null = json_null,\r
242 +           .map_key = json_map_key,\r
243 +           .frame = json_frame,\r
244 +       }\r
245 +    };\r
246 +    struct sprinter_json *res;\r
247 +\r
248 +    res = talloc (ctx, struct sprinter_json);\r
249 +    if (!res)\r
250 +       return NULL;\r
251 +\r
252 +    *res = template;\r
253 +    res->stream = stream;\r
254 +    return &res->vtable;\r
255 +}\r
256 -- \r
257 1.7.11.1\r
258 \r