[PATCH] configure: add --without-api-docs option
[notmuch-archives.git] / 47 / aa36dbbb243bf000c32a84ea2913b3392a15bb
1 Return-Path: <amdragon@mit.edu>\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 10578431FAF\r
6         for <notmuch@notmuchmail.org>; Wed, 18 Jul 2012 12:48:24 -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.7\r
10 X-Spam-Level: \r
11 X-Spam-Status: No, score=-0.7 tagged_above=-999 required=5\r
12         tests=[RCVD_IN_DNSWL_LOW=-0.7] autolearn=disabled\r
13 Received: from olra.theworths.org ([127.0.0.1])\r
14         by localhost (olra.theworths.org [127.0.0.1]) (amavisd-new, port 10024)\r
15         with ESMTP id usmcuWkLXBqJ for <notmuch@notmuchmail.org>;\r
16         Wed, 18 Jul 2012 12:48:22 -0700 (PDT)\r
17 Received: from dmz-mailsec-scanner-4.mit.edu (DMZ-MAILSEC-SCANNER-4.MIT.EDU\r
18         [18.9.25.15])\r
19         by olra.theworths.org (Postfix) with ESMTP id 941E0431FAE\r
20         for <notmuch@notmuchmail.org>; Wed, 18 Jul 2012 12:48:22 -0700 (PDT)\r
21 X-AuditID: 1209190f-b7f306d0000008b4-bf-500713062470\r
22 Received: from mailhub-auth-4.mit.edu ( [18.7.62.39])\r
23         by dmz-mailsec-scanner-4.mit.edu (Symantec Messaging Gateway) with SMTP\r
24         id 56.47.02228.60317005; Wed, 18 Jul 2012 15:48:22 -0400 (EDT)\r
25 Received: from outgoing.mit.edu (OUTGOING-AUTH.MIT.EDU [18.7.22.103])\r
26         by mailhub-auth-4.mit.edu (8.13.8/8.9.2) with ESMTP id q6IJmLAM022316; \r
27         Wed, 18 Jul 2012 15:48:21 -0400\r
28 Received: from awakening.csail.mit.edu (awakening.csail.mit.edu [18.26.4.91])\r
29         (authenticated bits=0)\r
30         (User authenticated as amdragon@ATHENA.MIT.EDU)\r
31         by outgoing.mit.edu (8.13.6/8.12.4) with ESMTP id q6IJmKL5008295\r
32         (version=TLSv1/SSLv3 cipher=AES256-SHA bits=256 verify=NOT);\r
33         Wed, 18 Jul 2012 15:48:20 -0400 (EDT)\r
34 Received: from amthrax by awakening.csail.mit.edu with local (Exim 4.77)\r
35         (envelope-from <amdragon@mit.edu>)\r
36         id 1SraEN-00014k-TM; Wed, 18 Jul 2012 15:48:19 -0400\r
37 Date: Wed, 18 Jul 2012 15:48:19 -0400\r
38 From: Austin Clements <amdragon@MIT.EDU>\r
39 To: craven@gmx.net\r
40 Subject: Re: [PATCH v6 2/3] Add structured output formatter for JSON and\r
41         plain text.\r
42 Message-ID: <20120718194819.GP31670@mit.edu>\r
43 References: <20120714020954.GD31670@mit.edu>\r
44         <1342427702-23316-1-git-send-email-craven@gmx.net>\r
45         <1342427702-23316-3-git-send-email-craven@gmx.net>\r
46 MIME-Version: 1.0\r
47 Content-Type: text/plain; charset=us-ascii\r
48 Content-Disposition: inline\r
49 In-Reply-To: <1342427702-23316-3-git-send-email-craven@gmx.net>\r
50 User-Agent: Mutt/1.5.21 (2010-09-15)\r
51 X-Brightmail-Tracker:\r
52  H4sIAAAAAAAAA+NgFprAKsWRmVeSWpSXmKPExsUixG6nrssmzB5g8Hwxl8XehnZGi+s3ZzI7\r
53         MHks3rSfzePZqlvMAUxRXDYpqTmZZalF+nYJXBnP965hKrgVV3Fj/nWWBsZ+jy5GTg4JAROJ\r
54         VR+mskPYYhIX7q1n62Lk4hAS2Mco8e3OJ0aQhJDABkaJQ08CIRInmSTWHm9mgXCWMEo8vdEJ\r
55         VsUioCqx//d5FhCbTUBDYtv+5WBxEQEhiUlfXoHFmQWkJb79bmYCsYUFwiRObXrNBmLzCuhI\r
56         XJu9khli6DRGiaZFZ6ASghInZz6BataSuPHvJVAzB9ig5f84QMKcAvYSF5/OBZspKqAiMeXk\r
57         NrYJjEKzkHTPQtI9C6F7ASPzKkbZlNwq3dzEzJzi1GTd4uTEvLzUIl0TvdzMEr3UlNJNjKDA\r
58         5pTk38H47aDSIUYBDkYlHt4Hu1gDhFgTy4orcw8xSnIwKYnyqguwBwjxJeWnVGYkFmfEF5Xm\r
59         pBYfYpTgYFYS4X0gCJTjTUmsrEotyodJSXOwKInzXk256S8kkJ5YkpqdmlqQWgSTleHgUJLg\r
60         5RQCahQsSk1PrUjLzClBSDNxcIIM5wEa/g9seHFBYm5xZjpE/hSjLse1h7duMQqx5OXnpUqJ\r
61         88qCDBIAKcoozYObA0tIrxjFgd4ShhjFA0xmcJNeAS1hAlrCXcwGsqQkESEl1cAo8Cdt3Q6F\r
62         V1b/nrtce8ufG1j8pFLc+oibfK2qlegSPoWYE35akrc5Pu25c/iaocIbvzPfgy9fP8wQ+W3L\r
63         C87+JWv+JPB+YHjywnLtIubAeV13Fzq/PZX7Y9fM3MAbOv/vinqelf60faEcc8fbWbfr+W9/\r
64         O6Dxb+unKZeq30dE5VYc2nI1+5bVISWW4oxEQy3mouJEAMwu6NUjAwAA\r
65 Cc: notmuch@notmuchmail.org\r
66 X-BeenThere: notmuch@notmuchmail.org\r
67 X-Mailman-Version: 2.1.13\r
68 Precedence: list\r
69 List-Id: "Use and development of the notmuch mail system."\r
70         <notmuch.notmuchmail.org>\r
71 List-Unsubscribe: <http://notmuchmail.org/mailman/options/notmuch>,\r
72         <mailto:notmuch-request@notmuchmail.org?subject=unsubscribe>\r
73 List-Archive: <http://notmuchmail.org/pipermail/notmuch>\r
74 List-Post: <mailto:notmuch@notmuchmail.org>\r
75 List-Help: <mailto:notmuch-request@notmuchmail.org?subject=help>\r
76 List-Subscribe: <http://notmuchmail.org/mailman/listinfo/notmuch>,\r
77         <mailto:notmuch-request@notmuchmail.org?subject=subscribe>\r
78 X-List-Received-Date: Wed, 18 Jul 2012 19:48:24 -0000\r
79 \r
80 Quoth craven@gmx.net on Jul 16 at 10:35 am:\r
81 > Using the new structured printer support in sprinter.h, implement\r
82 > sprinter_json_create, which returns a new JSON structured output\r
83 > formatter. The formatter prints output similar to the existing JSON, but\r
84 > with differences in whitespace (mostly newlines, --output=summary prints\r
85 > the entire message summary on one line, not split across multiple lines).\r
86\r
87 > Also implement a "structured" formatter for plain text that prints\r
88 > prefixed strings, to be used with notmuch-search.c plain text output.\r
89 > ---\r
90 >  Makefile.local         |   2 +\r
91 >  sprinter-json.c        | 191 +++++++++++++++++++++++++++++++++++++++++++++++++\r
92 >  sprinter-text-search.c | 146 +++++++++++++++++++++++++++++++++++++\r
93 >  sprinter.h             |   9 +++\r
94 >  4 files changed, 348 insertions(+)\r
95 >  create mode 100644 sprinter-json.c\r
96 >  create mode 100644 sprinter-text-search.c\r
97\r
98 > diff --git a/Makefile.local b/Makefile.local\r
99 > index a890df2..4f534f1 100644\r
100 > --- a/Makefile.local\r
101 > +++ b/Makefile.local\r
102 > @@ -290,6 +290,8 @@ notmuch_client_srcs =             \\r
103 >       notmuch-show.c          \\r
104 >       notmuch-tag.c           \\r
105 >       notmuch-time.c          \\r
106 > +     sprinter-text-search.c  \\r
107 > +     sprinter-json.c         \\r
108 >       query-string.c          \\r
109 >       mime-node.c             \\r
110 >       crypto.c                \\r
111 > diff --git a/sprinter-json.c b/sprinter-json.c\r
112 > new file mode 100644\r
113 > index 0000000..a93a390\r
114 > --- /dev/null\r
115 > +++ b/sprinter-json.c\r
116 > @@ -0,0 +1,191 @@\r
117 > +#include <stdbool.h>\r
118 > +#include <stdio.h>\r
119 > +#include <talloc.h>\r
120 > +#include "sprinter.h"\r
121 > +\r
122 > +struct sprinter_json {\r
123 > +    struct sprinter vtable;\r
124 > +    FILE *stream;\r
125 > +    /* Top of the state stack, or NULL if the printer is not currently\r
126 > +     * inside any aggregate types. */\r
127 > +    struct json_state *state;\r
128 > +\r
129 > +    /* A flag to signify that a separator should be inserted in the\r
130 > +     * output as soon as possible.\r
131 > +     */\r
132 > +    notmuch_bool_t insert_separator;\r
133 > +};\r
134 > +\r
135 > +struct json_state {\r
136 > +    struct json_state *parent;\r
137 > +    /* True if nothing has been printed in this aggregate yet.\r
138 > +     * Suppresses the comma before a value. */\r
139 > +    notmuch_bool_t first;\r
140 > +    /* The character that closes the current aggregate. */\r
141 > +    char close;\r
142 > +};\r
143 > +\r
144 > +/* Helper function to set up the stream to print a value.  If this\r
145 > + * value follows another value, prints a comma. */\r
146 > +static struct sprinter_json *\r
147 > +json_begin_value (struct sprinter *sp)\r
148 > +{\r
149 > +    struct sprinter_json *spj = (struct sprinter_json *) sp;\r
150 > +\r
151 > +    if (spj->state) {\r
152 > +     if (! spj->state->first) {\r
153 > +         fputc (',', spj->stream);\r
154 > +         if (spj->insert_separator) {\r
155 > +             fputc ('\n', spj->stream);\r
156 > +             spj->insert_separator = FALSE;\r
157 > +         } else\r
158 > +             fputc (' ', spj->stream);\r
159 > +     } else\r
160 > +         spj->state->first = FALSE;\r
161 > +    }\r
162 > +    return spj;\r
163 > +}\r
164 > +\r
165 > +/* Helper function to begin an aggregate type.  Prints the open\r
166 > + * character and pushes a new state frame. */\r
167 > +static void\r
168 > +json_begin_aggregate (struct sprinter *sp, char open, char close)\r
169 > +{\r
170 > +    struct sprinter_json *spj = json_begin_value (sp);\r
171 > +    struct json_state *state = talloc (spj, struct json_state);\r
172 > +\r
173 > +    fputc (open, spj->stream);\r
174 > +    state->parent = spj->state;\r
175 > +    state->first = TRUE;\r
176 > +    state->close = close;\r
177 > +    spj->state = state;\r
178 > +}\r
179 > +\r
180 > +static void\r
181 > +json_begin_map (struct sprinter *sp)\r
182 > +{\r
183 > +    json_begin_aggregate (sp, '{', '}');\r
184 > +}\r
185 > +\r
186 > +static void\r
187 > +json_begin_list (struct sprinter *sp)\r
188 > +{\r
189 > +    json_begin_aggregate (sp, '[', ']');\r
190 > +}\r
191 > +\r
192 > +static void\r
193 > +json_end (struct sprinter *sp)\r
194 > +{\r
195 > +    struct sprinter_json *spj = (struct sprinter_json *) sp;\r
196 > +    struct json_state *state = spj->state;\r
197 > +\r
198 > +    fputc (spj->state->close, spj->stream);\r
199 > +    spj->state = state->parent;\r
200 > +    talloc_free (state);\r
201 > +    if (spj->state == NULL)\r
202 > +     fputc ('\n', spj->stream);\r
203 > +}\r
204 > +\r
205 > +static void\r
206 > +json_string (struct sprinter *sp, const char *val)\r
207 > +{\r
208 > +    static const char *const escapes[] = {\r
209 > +     ['\"'] = "\\\"", ['\\'] = "\\\\", ['\b'] = "\\b",\r
210 > +     ['\f'] = "\\f",  ['\n'] = "\\n",  ['\t'] = "\\t"\r
211 > +    };\r
212 > +    struct sprinter_json *spj = json_begin_value (sp);\r
213 > +\r
214 > +    fputc ('"', spj->stream);\r
215 > +    for (; *val; ++val) {\r
216 > +     unsigned char ch = *val;\r
217 > +     if (ch < ARRAY_SIZE (escapes) && escapes[ch])\r
218 > +         fputs (escapes[ch], spj->stream);\r
219 > +     else if (ch >= 32)\r
220 > +         fputc (ch, spj->stream);\r
221 > +     else\r
222 > +         fprintf (spj->stream, "\\u%04x", ch);\r
223 > +    }\r
224 > +    fputc ('"', spj->stream);\r
225 > +}\r
226 > +\r
227 > +static void\r
228 > +json_integer (struct sprinter *sp, int val)\r
229 > +{\r
230 > +    struct sprinter_json *spj = json_begin_value (sp);\r
231 > +\r
232 > +    fprintf (spj->stream, "%d", val);\r
233 > +}\r
234 > +\r
235 > +static void\r
236 > +json_boolean (struct sprinter *sp, notmuch_bool_t val)\r
237 > +{\r
238 > +    struct sprinter_json *spj = json_begin_value (sp);\r
239 > +\r
240 > +    fputs (val ? "true" : "false", spj->stream);\r
241 > +}\r
242 > +\r
243 > +static void\r
244 > +json_null (struct sprinter *sp)\r
245 > +{\r
246 > +    struct sprinter_json *spj = json_begin_value (sp);\r
247 > +\r
248 > +    fputs ("null", spj->stream);\r
249 > +}\r
250 > +\r
251 > +static void\r
252 > +json_map_key (struct sprinter *sp, const char *key)\r
253 > +{\r
254 > +    struct sprinter_json *spj = (struct sprinter_json *) sp;\r
255 > +\r
256 > +    json_string (sp, key);\r
257 > +    fputs (": ", spj->stream);\r
258 > +    spj->state->first = TRUE;\r
259 > +}\r
260 > +\r
261 > +static void\r
262 > +json_set_prefix (unused (struct sprinter *sp), unused (const char *name))\r
263 > +{\r
264 > +}\r
265 > +\r
266 > +static void\r
267 > +json_separator (struct sprinter *sp)\r
268 > +{\r
269 > +    struct sprinter_json *spj = (struct sprinter_json *) sp;\r
270 > +\r
271 > +    spj->insert_separator = TRUE;\r
272 > +}\r
273 > +\r
274 > +static notmuch_bool_t\r
275 > +json_is_text_printer (unused (struct sprinter *sp))\r
276 > +{\r
277 > +    return FALSE;\r
278 > +}\r
279 \r
280 Seems like overkill to have a method for this.  Why not just use some\r
281 flag in notmuch-search.c?  Or, if you really want it to be part of the\r
282 sprinter abstraction, why not just put a flag in struct sprinter?\r
283 This isn't going to change dynamically.\r
284 \r
285 > +\r
286 > +struct sprinter *\r
287 > +sprinter_json_create (const void *ctx, FILE *stream)\r
288 > +{\r
289 > +    static const struct sprinter_json template = {\r
290 > +     .vtable = {\r
291 > +         .begin_map = json_begin_map,\r
292 > +         .begin_list = json_begin_list,\r
293 > +         .end = json_end,\r
294 > +         .string = json_string,\r
295 > +         .integer = json_integer,\r
296 > +         .boolean = json_boolean,\r
297 > +         .null = json_null,\r
298 > +         .map_key = json_map_key,\r
299 > +         .separator = json_separator,\r
300 > +         .set_prefix = json_set_prefix,\r
301 > +         .is_text_printer = json_is_text_printer,\r
302 > +     }\r
303 > +    };\r
304 > +    struct sprinter_json *res;\r
305 > +\r
306 > +    res = talloc (ctx, struct sprinter_json);\r
307 > +    if (! res)\r
308 > +     return NULL;\r
309 > +\r
310 > +    *res = template;\r
311 > +    res->stream = stream;\r
312 > +    return &res->vtable;\r
313 > +}\r
314 > diff --git a/sprinter-text-search.c b/sprinter-text-search.c\r
315 > new file mode 100644\r
316 > index 0000000..b115722\r
317 > --- /dev/null\r
318 > +++ b/sprinter-text-search.c\r
319 > @@ -0,0 +1,146 @@\r
320 > +#include <stdbool.h>\r
321 > +#include <stdio.h>\r
322 > +#include <talloc.h>\r
323 > +#include "sprinter.h"\r
324 > +\r
325 > +/* "Structured printer" interface for unstructured text printing.\r
326 > + * Note that --output=summary is dispatched and formatted in\r
327 > + * notmuch-search.c, the code in this file is only used for all other\r
328 > + * output types.\r
329 > + */\r
330 > +\r
331 > +struct sprinter_text_search {\r
332 \r
333 Why is this sprinter_text_search rather than just sprinter_text?\r
334 \r
335 > +    struct sprinter vtable;\r
336 > +    FILE *stream;\r
337 > +\r
338 > +    /* The current prefix to be printed with string/integer/boolean\r
339 > +     * data.\r
340 > +     */\r
341 > +    const char *current_prefix;\r
342 > +\r
343 > +    /* A flag to indicate if this is the first tag. Used in list of tags\r
344 > +     * for summary.\r
345 > +     */\r
346 > +    notmuch_bool_t first_tag;\r
347 > +};\r
348 > +\r
349 > +static void\r
350 > +print_sanitized_string (FILE *stream, const char *str)\r
351 > +{\r
352 > +    if (NULL == str)\r
353 > +     return;\r
354 > +\r
355 > +    for (; *str; str++) {\r
356 > +     if ((unsigned char) (*str) < 32)\r
357 > +         fputc ('?', stream);\r
358 > +     else\r
359 > +         fputc (*str, stream);\r
360 > +    }\r
361 > +}\r
362 \r
363 Either the text sprinter should be responsible for sanitization or the\r
364 caller should be.  Currently you have a text sanitizer in both.  I\r
365 think you should leave sanitization to the caller and output the\r
366 string directly in text_search_string.  For example, search\r
367 --output=files should output file names untouched, but doing\r
368 sanitization here means unusual (but legal) characters in file names\r
369 will get sanitized.\r
370 \r
371 > +\r
372 > +static void\r
373 > +text_search_string (struct sprinter *sp, const char *val)\r
374 > +{\r
375 > +    struct sprinter_text_search *sptxt = (struct sprinter_text_search *) sp;\r
376 > +\r
377 > +    if (sptxt->current_prefix != NULL)\r
378 > +     fprintf (sptxt->stream, "%s:", sptxt->current_prefix);\r
379 > +\r
380 > +    print_sanitized_string (sptxt->stream, val);\r
381 > +}\r
382 > +\r
383 > +static void\r
384 > +text_search_integer (struct sprinter *sp, int val)\r
385 > +{\r
386 > +    struct sprinter_text_search *sptxt = (struct sprinter_text_search *) sp;\r
387 > +\r
388 > +    fprintf (sptxt->stream, "%d", val);\r
389 > +}\r
390 > +\r
391 > +static void\r
392 > +text_search_boolean (struct sprinter *sp, notmuch_bool_t val)\r
393 > +{\r
394 > +    struct sprinter_text_search *sptxt = (struct sprinter_text_search *) sp;\r
395 > +\r
396 > +    fputs (val ? "true" : "false", sptxt->stream);\r
397 > +}\r
398 > +\r
399 > +static void\r
400 > +text_search_separator (struct sprinter *sp)\r
401 > +{\r
402 > +    struct sprinter_text_search *sptxt = (struct sprinter_text_search *) sp;\r
403 > +\r
404 > +    fputc ('\n', sptxt->stream);\r
405 > +}\r
406 > +\r
407 > +static void\r
408 > +text_search_set_prefix (struct sprinter *sp, const char *prefix)\r
409 > +{\r
410 > +    struct sprinter_text_search *sptxt = (struct sprinter_text_search *) sp;\r
411 > +\r
412 > +    sptxt->current_prefix = prefix;\r
413 > +}\r
414 > +\r
415 > +static notmuch_bool_t\r
416 > +text_search_is_text_printer (unused (struct sprinter *sp))\r
417 > +{\r
418 > +    return TRUE;\r
419 > +}\r
420 > +\r
421 > +/* The structure functions begin_map, begin_list, end and map_key\r
422 > + * don't do anything in the text formatter.\r
423 > + */\r
424 > +\r
425 > +static void\r
426 > +text_search_begin_map (unused (struct sprinter *sp))\r
427 > +{\r
428 > +}\r
429 > +\r
430 > +static void\r
431 > +text_search_begin_list (unused (struct sprinter *sp))\r
432 > +{\r
433 > +}\r
434 > +\r
435 > +static void\r
436 > +text_search_end (unused (struct sprinter *sp))\r
437 > +{\r
438 > +}\r
439 > +\r
440 > +static void\r
441 > +text_search_null (unused (struct sprinter *sp))\r
442 > +{\r
443 > +}\r
444 > +\r
445 > +static void\r
446 > +text_search_map_key (unused (struct sprinter *sp), unused (const char *key))\r
447 > +{\r
448 > +}\r
449 > +\r
450 > +struct sprinter *\r
451 > +sprinter_text_search_create (const void *ctx, FILE *stream)\r
452 > +{\r
453 > +    static const struct sprinter_text_search template = {\r
454 > +     .vtable = {\r
455 > +         .begin_map = text_search_begin_map,\r
456 > +         .begin_list = text_search_begin_list,\r
457 > +         .end = text_search_end,\r
458 > +         .string = text_search_string,\r
459 > +         .integer = text_search_integer,\r
460 > +         .boolean = text_search_boolean,\r
461 > +         .null = text_search_null,\r
462 > +         .map_key = text_search_map_key,\r
463 > +         .separator = text_search_separator,\r
464 > +         .set_prefix = text_search_set_prefix,\r
465 > +         .is_text_printer = text_search_is_text_printer,\r
466 > +     }\r
467 > +    };\r
468 > +    struct sprinter_text_search *res;\r
469 > +\r
470 > +    res = talloc (ctx, struct sprinter_text_search);\r
471 > +    if (! res)\r
472 > +     return NULL;\r
473 > +\r
474 > +    *res = template;\r
475 > +    res->stream = stream;\r
476 > +    return &res->vtable;\r
477 > +}\r
478 > diff --git a/sprinter.h b/sprinter.h\r
479 > index dc09a15..7ec6344 100644\r
480 > --- a/sprinter.h\r
481 > +++ b/sprinter.h\r
482 > @@ -57,4 +57,13 @@ typedef struct sprinter {\r
483 >      notmuch_bool_t (*is_text_printer) (struct sprinter *);\r
484 >  } sprinter_t;\r
485 >  \r
486 > +/* Create a new unstructured printer that emits the default text format\r
487 > + * for "notmuch search". */\r
488 > +struct sprinter *\r
489 > +sprinter_text_search_create (const void *ctx, FILE *stream);\r
490 > +\r
491 > +/* Create a new structure printer that emits JSON. */\r
492 > +struct sprinter *\r
493 > +sprinter_json_create (const void *ctx, FILE *stream);\r
494 > +\r
495 >  #endif // NOTMUCH_SPRINTER_H\r