[PATCH] man: show: update man page for entire-thread and json.

2012-07-20 Thread Mark Walters
Previously in notmuch show --format=json implied --entire-thread. This
is still the default but it is now possible to disable this. Update
the manpage to reflect this.
---

I didn't update the manpage in the recent patch series. This corrects
that omission. (Less cumbersome wording gratefully received)

Best wishes

 
Markman/man1/notmuch-show.1 |   16 +---
 1 files changed, 9 insertions(+), 7 deletions(-)

diff --git a/man/man1/notmuch-show.1 b/man/man1/notmuch-show.1
index b51a54c..5fa590e 100644
--- a/man/man1/notmuch-show.1
+++ b/man/man1/notmuch-show.1
@@ -26,9 +26,9 @@ include
 .TP 4
 .B \-\-entire\-thread
 
-By default only those messages that match the search terms will be
-displayed. With this option, all messages in the same thread as any
-matched message will be displayed.
+By default (except when format=json) only those messages that match
+the search terms will be displayed. With this option, all messages in
+the same thread as any matched message will be displayed.
 .RE
 
 .RS 4
@@ -55,11 +55,13 @@ be nested.
 The output is formatted with Javascript Object Notation (JSON). This
 format is more robust than the text format for automated
 processing. The nested structure of multipart MIME messages is
-reflected in nested JSON output. JSON output always includes all
-messages in a matching thread; in effect
+reflected in nested JSON output. By default JSON output includes all
+messages in a matching thread; that is, by default,
 .B \-\-format=json
-implies
-.B \-\-entire\-thread
+sets
+.B "\-\-entire\-thread"
+The caller can disable this behaviour by setting
+.B \-\-entire\-thread=false
 
 .RE
 .RS 4
-- 
1.7.9.1

___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


[PATCH v7 3/3] Use the structured formatters in notmuch-search.c.

2012-07-20 Thread Tomi Ollila
On Fri, Jul 20 2012, craven at gmx.net wrote:

> From: 
>
> This patch switches from the current ad-hoc printer to the structured
> formatters in sprinter.h, sprinter-text.c and sprinter-json.c.
>
> The JSON tests are changed slightly in order to make them PASS for the
> new structured output formatter.
>
> The text tests pass without adaptation.
> ---
>  notmuch-search.c | 301 
> ---
>  test/json|  34 ---
>  2 files changed, 103 insertions(+), 232 deletions(-)
>
> diff --git a/notmuch-search.c b/notmuch-search.c
> index 3be296d..07211e8 100644
> --- a/notmuch-search.c
> +++ b/notmuch-search.c
> @@ -19,6 +19,7 @@
>   */
>  
>  #include "notmuch-client.h"
> +#include "sprinter.h"
>  
>  typedef enum {
>  OUTPUT_SUMMARY,
> @@ -28,92 +29,6 @@ typedef enum {
>  OUTPUT_TAGS
>  } output_t;
>  
> -typedef struct search_format {
> -const char *results_start;
> -const char *item_start;
> -void (*item_id) (const void *ctx,
> -  const char *item_type,
> -  const char *item_id);
> -void (*thread_summary) (const void *ctx,
> - const char *thread_id,
> - const time_t date,
> - const int matched,
> - const int total,
> - const char *authors,
> - const char *subject);
> -const char *tag_start;
> -const char *tag;
> -const char *tag_sep;
> -const char *tag_end;
> -const char *item_sep;
> -const char *item_end;
> -const char *results_end;
> -const char *results_null;
> -} search_format_t;
> -
> -static void
> -format_item_id_text (const void *ctx,
> -  const char *item_type,
> -  const char *item_id);
> -
> -static void
> -format_thread_text (const void *ctx,
> - const char *thread_id,
> - const time_t date,
> - const int matched,
> - const int total,
> - const char *authors,
> - const char *subject);
> -static const search_format_t format_text = {
> -"",
> - "",
> - format_item_id_text,
> - format_thread_text,
> - " (",
> - "%s", " ",
> - ")", "\n",
> - "",
> -"\n",
> -"",
> -};
> -
> -static void
> -format_item_id_json (const void *ctx,
> -  const char *item_type,
> -  const char *item_id);
> -
> -static void
> -format_thread_json (const void *ctx,
> - const char *thread_id,
> - const time_t date,
> - const int matched,
> - const int total,
> - const char *authors,
> - const char *subject);
> -
> -/* Any changes to the JSON format should be reflected in the file
> - * devel/schemata. */
> -static const search_format_t format_json = {
> -"[",
> - "{",
> - format_item_id_json,
> - format_thread_json,
> - "\"tags\": [",
> - "\"%s\"", ", ",
> - "]", ",\n",
> - "}",
> -"]\n",
> -"]\n",
> -};
> -
> -static void
> -format_item_id_text (unused (const void *ctx),
> -  const char *item_type,
> -  const char *item_id)
> -{
> -printf ("%s%s", item_type, item_id);
> -}
> -
>  static char *
>  sanitize_string (const void *ctx, const char *str)
>  {
> @@ -131,72 +46,8 @@ sanitize_string (const void *ctx, const char *str)
>  return out;
>  }
>  
> -static void
> -format_thread_text (const void *ctx,
> - const char *thread_id,
> - const time_t date,
> - const int matched,
> - const int total,
> - const char *authors,
> - const char *subject)
> -{
> -void *ctx_quote = talloc_new (ctx);
> -
> -printf ("thread:%s %12s [%d/%d] %s; %s",
> - thread_id,
> - notmuch_time_relative_date (ctx, date),
> - matched,
> - total,
> - sanitize_string (ctx_quote, authors),
> - sanitize_string (ctx_quote, subject));
> -
> -talloc_free (ctx_quote);
> -}
> -
> -static void
> -format_item_id_json (const void *ctx,
> -  unused (const char *item_type),
> -  const char *item_id)
> -{
> -void *ctx_quote = talloc_new (ctx);
> -
> -printf ("%s", json_quote_str (ctx_quote, item_id));
> -
> -talloc_free (ctx_quote);
> -
> -}
> -
> -static void
> -format_thread_json (const void *ctx,
> - const char *thread_id,
> - const time_t date,
> - const int matched,
> - const int total,
> - const char *authors,
> - const char *subject)
> -{
> -void *ctx_quote = talloc_new (ctx);
> -
> -printf ("\"thread\": %s,\n"
> - "\"timestamp\": %ld,\n"
> - "\"date_rela

[PATCH v7 1/3] Add support for structured output formatters.

2012-07-20 Thread Tomi Ollila
On Fri, Jul 20 2012, craven at gmx.net wrote:

> From: 
>
> This patch adds a new struct type sprinter_t, which is used for
> structured formatting, e.g. JSON or S-Expressions. The structure printer
> is heavily based on code from Austin Clements
> (id:87d34hsdx8.fsf at awakening.csail.mit.edu).
>
> It includes the following functions:
>
> /* Start a new map/dictionary structure. This should be followed by
>  * a sequence of alternating calls to map_key and one of the
>  * value-printing functions until the map is ended by end.
>  */
> void (*begin_map) (struct sprinter *);
>
> /* Start a new list/array structure.
>  */
> void (*begin_list) (struct sprinter *);
>
> /* End the last opened list or map structure.
>  */
> void (*end) (struct sprinter *);
>
> /* Print one string/integer/boolean/null element (possibly inside a
>  * list or map, followed or preceded by separators).
>  * For string, the char * must be UTF-8 encoded.
>  */
> void (*string) (struct sprinter *, const char *);
> void (*integer) (struct sprinter *, int);
> void (*boolean) (struct sprinter *, notmuch_bool_t);
> void (*null) (struct sprinter *);
>
> /* Print the key of a map's key/value pair. The char * must be UTF-8
>  * encoded.
>  */
> void (*map_key) (struct sprinter *, const char *);
>
> /* Insert a separator (usually extra whitespace) for improved
>  * readability without affecting the abstract syntax of the
>  * structure being printed.
>  * For JSON, this could simply be a line break.
>  */
> void (*separator) (struct sprinter *);
>
> /* Set the current string prefix. This only affects the text
>  * printer, which will print this string, followed by a colon,
>  * before any string. For other printers, this does nothing.
>  */
> void (*set_prefix) (struct sprinter *, const char *);

The above block duplicated below. Otherwise this LGTM.

I presume the patch 3/3 emails

id:"1342766173-1344-4-git-send-email-craven at gmx.net"
id:"1342772624-23329-1-git-send-email-craven at gmx.net"

have identical content ?

> To support the plain text format properly, the following additional
> function must also be implemented:
>
> /* Set the current string prefix. This only affects the text
>  * printer, which will print this string, followed by a colon,
>  * before any string. For other printers, this does nothing.
>  */
> void (*set_prefix) (struct sprinter *, const char *);
>
> The structure also contains a flag that should be set to FALSE in all
> custom printers and to TRUE in the plain text formatter.
>
> /* True if this is the special-cased plain text printer.
>  */
> notmuch_bool_t is_text_printer;
>
> The printer can (and should) use internal state to insert delimiters
> and syntax at the correct places.
>
> Example:
>
> format->begin_map(format);
> format->map_key(format, "foo");
> format->begin_list(format);
> format->integer(format, 1);
> format->integer(format, 2);
> format->integer(format, 3);
> format->end(format);
> format->map_key(format, "bar");
> format->begin_map(format);
> format->map_key(format, "baaz");
> format->string(format, "hello world");
> format->end(format);
> format->end(format);
>
> would output JSON as follows:
>
> {"foo": [1, 2, 3], "bar": { "baaz": "hello world"}}
> ---
>  sprinter.h | 58 ++
>  1 file changed, 58 insertions(+)
>  create mode 100644 sprinter.h
>
> diff --git a/sprinter.h b/sprinter.h
> new file mode 100644
> index 000..77dc26f
> --- /dev/null
> +++ b/sprinter.h
> @@ -0,0 +1,58 @@
> +#ifndef NOTMUCH_SPRINTER_H
> +#define NOTMUCH_SPRINTER_H
> +
> +/* Necessary for notmuch_bool_t */
> +#include "notmuch-client.h"
> +
> +/* Structure printer interface. This is used to create output
> + * structured as maps (with key/value pairs), lists and primitives
> + * (strings, integers and booleans).
> + */
> +typedef struct sprinter {
> +/* Start a new map/dictionary structure. This should be followed by
> + * a sequence of alternating calls to map_key and one of the
> + * value-printing functions until the map is ended by end.
> + */
> +void (*begin_map) (struct sprinter *);
> +
> +/* Start a new list/array structure.
> + */
> +void (*begin_list) (struct sprinter *);
> +
> +/* End the last opened list or map structure.
> + */
> +void (*end) (struct sprinter *);
> +
> +/* Print one string/integer/boolean/null element (possibly inside a
> + * list or map, followed or preceded by separators).
> + * For string, the char * must be UTF-8 encoded.
> + */
> +void (*string) (struct sprinter *, const char *);
> +void (*integer) (struct sprinter *, int);
> +void (*boolean) (struct sprinter *, notmuch_bool_t);
> +void (*null) (struct sprinter *);
> +
> +/* Print the key of a map's key/value pair. The char * must be UT

[PATCH v7 1/3] Add support for structured output formatters.

2012-07-20 Thread cra...@gmx.net
> I presume the patch 3/3 emails
> 
> id:"1342766173-1344-4-git-send-email-craven at gmx.net"
> id:"1342772624-23329-1-git-send-email-craven at gmx.net"
> 
> have identical content ?

Yes, they do, there was a problem with the Content-Type header having
^P^P, so I re-sent correctly, but the actual e-mail content is exactly
the same.

Greetings,
Peter


bug in parsing?

2012-07-20 Thread Austin Clements
On Fri, 15 Jun 2012, David Belohrad  wrote:
> Dear all,
>
> recently I got an email from matplotlib list, which fails to parse in
> notmuch-saved-search-unread.
> It looks like this:
>
> Yest. 21:04 [3/5]   Jesse Rosenthal, Tomi Ollila  [PATCHv2] emacs: derive 
> correct timestamp in FCC unique name (inbox notmuch)
>  Yest. 20:58 [1/1]   Allin Cottrell   mouse and update 23.4 -> 24.1 
> (emacs inbox)
>  Yest. 20:56 [3/6]   Milan Kratochv?l, Jaroslav Lukesh, David Obdrzalek, 
> Pavel Kutina  [OT:] Javascript alert jinak (hw inbox)
> Error: Unexpected output from notmuch search:
> thread:6a68  Yest. 20:39 [1/1] R. O'Gara; [Matplotlib-users] 
> (no subject) (matplotlib mightread unread)
>
>  Yest. 19:38 [1/1]   Baaba Maal - Avaaz. org  Stop the African hunger games 
> (inbox unread)
>  Yest. 19:27 [1/2]   Bob Proulx, sariatucla at Safe-mail.net   next-line 
> at window end without recenter (deleted emacs inbox unread)
>  Yest. 19:12 [1/12]  Ji?? Ku?era, hutta.j at seznam.cz, balu at home, Pavel
>  Hudecek  LCR meter - konstrukce (deleted hw inbox unread)
>
>
>
> It seems that the weird characted in sender does it. Should those
> characters be somehow escaped?

This should be fixed in master, as of 9c5ea07c.


[PATCH v7 3/3] Use the structured formatters in notmuch-search.c.

2012-07-20 Thread cra...@gmx.net
From: 

This patch switches from the current ad-hoc printer to the structured
formatters in sprinter.h, sprinter-text.c and sprinter-json.c.

The JSON tests are changed slightly in order to make them PASS for the
new structured output formatter.

The text tests pass without adaptation.
---
 notmuch-search.c | 301 ---
 test/json|  34 ---
 2 files changed, 103 insertions(+), 232 deletions(-)

diff --git a/notmuch-search.c b/notmuch-search.c
index 3be296d..07211e8 100644
--- a/notmuch-search.c
+++ b/notmuch-search.c
@@ -19,6 +19,7 @@
  */

 #include "notmuch-client.h"
+#include "sprinter.h"

 typedef enum {
 OUTPUT_SUMMARY,
@@ -28,92 +29,6 @@ typedef enum {
 OUTPUT_TAGS
 } output_t;

-typedef struct search_format {
-const char *results_start;
-const char *item_start;
-void (*item_id) (const void *ctx,
-const char *item_type,
-const char *item_id);
-void (*thread_summary) (const void *ctx,
-   const char *thread_id,
-   const time_t date,
-   const int matched,
-   const int total,
-   const char *authors,
-   const char *subject);
-const char *tag_start;
-const char *tag;
-const char *tag_sep;
-const char *tag_end;
-const char *item_sep;
-const char *item_end;
-const char *results_end;
-const char *results_null;
-} search_format_t;
-
-static void
-format_item_id_text (const void *ctx,
-const char *item_type,
-const char *item_id);
-
-static void
-format_thread_text (const void *ctx,
-   const char *thread_id,
-   const time_t date,
-   const int matched,
-   const int total,
-   const char *authors,
-   const char *subject);
-static const search_format_t format_text = {
-"",
-   "",
-   format_item_id_text,
-   format_thread_text,
-   " (",
-   "%s", " ",
-   ")", "\n",
-   "",
-"\n",
-"",
-};
-
-static void
-format_item_id_json (const void *ctx,
-const char *item_type,
-const char *item_id);
-
-static void
-format_thread_json (const void *ctx,
-   const char *thread_id,
-   const time_t date,
-   const int matched,
-   const int total,
-   const char *authors,
-   const char *subject);
-
-/* Any changes to the JSON format should be reflected in the file
- * devel/schemata. */
-static const search_format_t format_json = {
-"[",
-   "{",
-   format_item_id_json,
-   format_thread_json,
-   "\"tags\": [",
-   "\"%s\"", ", ",
-   "]", ",\n",
-   "}",
-"]\n",
-"]\n",
-};
-
-static void
-format_item_id_text (unused (const void *ctx),
-const char *item_type,
-const char *item_id)
-{
-printf ("%s%s", item_type, item_id);
-}
-
 static char *
 sanitize_string (const void *ctx, const char *str)
 {
@@ -131,72 +46,8 @@ sanitize_string (const void *ctx, const char *str)
 return out;
 }

-static void
-format_thread_text (const void *ctx,
-   const char *thread_id,
-   const time_t date,
-   const int matched,
-   const int total,
-   const char *authors,
-   const char *subject)
-{
-void *ctx_quote = talloc_new (ctx);
-
-printf ("thread:%s %12s [%d/%d] %s; %s",
-   thread_id,
-   notmuch_time_relative_date (ctx, date),
-   matched,
-   total,
-   sanitize_string (ctx_quote, authors),
-   sanitize_string (ctx_quote, subject));
-
-talloc_free (ctx_quote);
-}
-
-static void
-format_item_id_json (const void *ctx,
-unused (const char *item_type),
-const char *item_id)
-{
-void *ctx_quote = talloc_new (ctx);
-
-printf ("%s", json_quote_str (ctx_quote, item_id));
-
-talloc_free (ctx_quote);
-
-}
-
-static void
-format_thread_json (const void *ctx,
-   const char *thread_id,
-   const time_t date,
-   const int matched,
-   const int total,
-   const char *authors,
-   const char *subject)
-{
-void *ctx_quote = talloc_new (ctx);
-
-printf ("\"thread\": %s,\n"
-   "\"timestamp\": %ld,\n"
-   "\"date_relative\": \"%s\",\n"
-   "\"matched\": %d,\n"
-   "\"total\": %d,\n"
-   "\"authors\": %s,\n"
-   "\"subject\": %s,\n",
-   json_quote_str (ctx_quote, thread_id),
-   date,
-   notmuch_time_relative_date (ctx, date),

[PATCH v7 3/3] Use the structured formatters in notmuch-search.c.

2012-07-20 Thread cra...@gmx.net
From: 

This patch switches from the current ad-hoc printer to the structured
formatters in sprinter.h, sprinter-text.c and sprinter-json.c.

The JSON tests are changed slightly in order to make them PASS for the
new structured output formatter.

The text tests pass without adaptation.
---
 notmuch-search.c | 301 ---
 test/json|  34 ---
 2 files changed, 103 insertions(+), 232 deletions(-)

diff --git a/notmuch-search.c b/notmuch-search.c
index 3be296d..07211e8 100644
--- a/notmuch-search.c
+++ b/notmuch-search.c
@@ -19,6 +19,7 @@
  */

 #include "notmuch-client.h"
+#include "sprinter.h"

 typedef enum {
 OUTPUT_SUMMARY,
@@ -28,92 +29,6 @@ typedef enum {
 OUTPUT_TAGS
 } output_t;

-typedef struct search_format {
-const char *results_start;
-const char *item_start;
-void (*item_id) (const void *ctx,
-const char *item_type,
-const char *item_id);
-void (*thread_summary) (const void *ctx,
-   const char *thread_id,
-   const time_t date,
-   const int matched,
-   const int total,
-   const char *authors,
-   const char *subject);
-const char *tag_start;
-const char *tag;
-const char *tag_sep;
-const char *tag_end;
-const char *item_sep;
-const char *item_end;
-const char *results_end;
-const char *results_null;
-} search_format_t;
-
-static void
-format_item_id_text (const void *ctx,
-const char *item_type,
-const char *item_id);
-
-static void
-format_thread_text (const void *ctx,
-   const char *thread_id,
-   const time_t date,
-   const int matched,
-   const int total,
-   const char *authors,
-   const char *subject);
-static const search_format_t format_text = {
-"",
-   "",
-   format_item_id_text,
-   format_thread_text,
-   " (",
-   "%s", " ",
-   ")", "\n",
-   "",
-"\n",
-"",
-};
-
-static void
-format_item_id_json (const void *ctx,
-const char *item_type,
-const char *item_id);
-
-static void
-format_thread_json (const void *ctx,
-   const char *thread_id,
-   const time_t date,
-   const int matched,
-   const int total,
-   const char *authors,
-   const char *subject);
-
-/* Any changes to the JSON format should be reflected in the file
- * devel/schemata. */
-static const search_format_t format_json = {
-"[",
-   "{",
-   format_item_id_json,
-   format_thread_json,
-   "\"tags\": [",
-   "\"%s\"", ", ",
-   "]", ",\n",
-   "}",
-"]\n",
-"]\n",
-};
-
-static void
-format_item_id_text (unused (const void *ctx),
-const char *item_type,
-const char *item_id)
-{
-printf ("%s%s", item_type, item_id);
-}
-
 static char *
 sanitize_string (const void *ctx, const char *str)
 {
@@ -131,72 +46,8 @@ sanitize_string (const void *ctx, const char *str)
 return out;
 }

-static void
-format_thread_text (const void *ctx,
-   const char *thread_id,
-   const time_t date,
-   const int matched,
-   const int total,
-   const char *authors,
-   const char *subject)
-{
-void *ctx_quote = talloc_new (ctx);
-
-printf ("thread:%s %12s [%d/%d] %s; %s",
-   thread_id,
-   notmuch_time_relative_date (ctx, date),
-   matched,
-   total,
-   sanitize_string (ctx_quote, authors),
-   sanitize_string (ctx_quote, subject));
-
-talloc_free (ctx_quote);
-}
-
-static void
-format_item_id_json (const void *ctx,
-unused (const char *item_type),
-const char *item_id)
-{
-void *ctx_quote = talloc_new (ctx);
-
-printf ("%s", json_quote_str (ctx_quote, item_id));
-
-talloc_free (ctx_quote);
-
-}
-
-static void
-format_thread_json (const void *ctx,
-   const char *thread_id,
-   const time_t date,
-   const int matched,
-   const int total,
-   const char *authors,
-   const char *subject)
-{
-void *ctx_quote = talloc_new (ctx);
-
-printf ("\"thread\": %s,\n"
-   "\"timestamp\": %ld,\n"
-   "\"date_relative\": \"%s\",\n"
-   "\"matched\": %d,\n"
-   "\"total\": %d,\n"
-   "\"authors\": %s,\n"
-   "\"subject\": %s,\n",
-   json_quote_str (ctx_quote, thread_id),
-   date,
-   notmuch_time_relative_date (ctx, date),

[PATCH v7 2/3] Add structured output formatter for JSON and plain text (but don't use them yet).

2012-07-20 Thread cra...@gmx.net
From: 

Using the new structured printer support in sprinter.h, implement
sprinter_json_create, which returns a new JSON structured output
formatter. The formatter prints output similar to the existing JSON, but
with differences in whitespace (mostly newlines, --output=summary prints
the entire message summary on one line, not split across multiple lines).

Also implement a "structured" formatter for plain text that prints
prefixed strings, to be used with notmuch-search.c plain text output.
---
 Makefile.local  |   2 +
 sprinter-json.c | 185 
 sprinter-text.c | 126 ++
 sprinter.h  |  10 +++
 4 files changed, 323 insertions(+)
 create mode 100644 sprinter-json.c
 create mode 100644 sprinter-text.c

diff --git a/Makefile.local b/Makefile.local
index a890df2..296995d 100644
--- a/Makefile.local
+++ b/Makefile.local
@@ -290,6 +290,8 @@ notmuch_client_srcs =   \
notmuch-show.c  \
notmuch-tag.c   \
notmuch-time.c  \
+   sprinter-json.c \
+   sprinter-text.c \
query-string.c  \
mime-node.c \
crypto.c\
diff --git a/sprinter-json.c b/sprinter-json.c
new file mode 100644
index 000..32daa5a
--- /dev/null
+++ b/sprinter-json.c
@@ -0,0 +1,185 @@
+#include 
+#include 
+#include 
+#include "sprinter.h"
+
+struct sprinter_json {
+struct sprinter vtable;
+FILE *stream;
+/* Top of the state stack, or NULL if the printer is not currently
+ * inside any aggregate types. */
+struct json_state *state;
+
+/* A flag to signify that a separator should be inserted in the
+ * output as soon as possible.
+ */
+notmuch_bool_t insert_separator;
+};
+
+struct json_state {
+struct json_state *parent;
+/* True if nothing has been printed in this aggregate yet.
+ * Suppresses the comma before a value. */
+notmuch_bool_t first;
+/* The character that closes the current aggregate. */
+char close;
+};
+
+/* Helper function to set up the stream to print a value.  If this
+ * value follows another value, prints a comma. */
+static struct sprinter_json *
+json_begin_value (struct sprinter *sp)
+{
+struct sprinter_json *spj = (struct sprinter_json *) sp;
+
+if (spj->state) {
+   if (! spj->state->first) {
+   fputc (',', spj->stream);
+   if (spj->insert_separator) {
+   fputc ('\n', spj->stream);
+   spj->insert_separator = FALSE;
+   } else
+   fputc (' ', spj->stream);
+   } else
+   spj->state->first = FALSE;
+}
+return spj;
+}
+
+/* Helper function to begin an aggregate type.  Prints the open
+ * character and pushes a new state frame. */
+static void
+json_begin_aggregate (struct sprinter *sp, char open, char close)
+{
+struct sprinter_json *spj = json_begin_value (sp);
+struct json_state *state = talloc (spj, struct json_state);
+
+fputc (open, spj->stream);
+state->parent = spj->state;
+state->first = TRUE;
+state->close = close;
+spj->state = state;
+}
+
+static void
+json_begin_map (struct sprinter *sp)
+{
+json_begin_aggregate (sp, '{', '}');
+}
+
+static void
+json_begin_list (struct sprinter *sp)
+{
+json_begin_aggregate (sp, '[', ']');
+}
+
+static void
+json_end (struct sprinter *sp)
+{
+struct sprinter_json *spj = (struct sprinter_json *) sp;
+struct json_state *state = spj->state;
+
+fputc (spj->state->close, spj->stream);
+spj->state = state->parent;
+talloc_free (state);
+if (spj->state == NULL)
+   fputc ('\n', spj->stream);
+}
+
+static void
+json_string (struct sprinter *sp, const char *val)
+{
+static const char *const escapes[] = {
+   ['\"'] = "\\\"", ['\\'] = "", ['\b'] = "\\b",
+   ['\f'] = "\\f",  ['\n'] = "\\n",  ['\t'] = "\\t"
+};
+struct sprinter_json *spj = json_begin_value (sp);
+
+fputc ('"', spj->stream);
+for (; *val; ++val) {
+   unsigned char ch = *val;
+   if (ch < ARRAY_SIZE (escapes) && escapes[ch])
+   fputs (escapes[ch], spj->stream);
+   else if (ch >= 32)
+   fputc (ch, spj->stream);
+   else
+   fprintf (spj->stream, "\\u%04x", ch);
+}
+fputc ('"', spj->stream);
+}
+
+static void
+json_integer (struct sprinter *sp, int val)
+{
+struct sprinter_json *spj = json_begin_value (sp);
+
+fprintf (spj->stream, "%d", val);
+}
+
+static void
+json_boolean (struct sprinter *sp, notmuch_bool_t val)
+{
+struct sprinter_json *spj = json_begin_value (sp);
+
+fputs (val ? "true" : "false", spj->stream);
+}
+
+static void
+json_null (struct sprinter *sp)
+{
+struct sprinter_json *spj = json_begin_value (sp);
+
+fputs ("null", spj->stream);
+}
+
+static void
+json_map_key (struct sprinter *sp, const char *key)
+{
+struct sprinter_json *spj = (struct sprinter_js

[PATCH v7 1/3] Add support for structured output formatters.

2012-07-20 Thread cra...@gmx.net
From: 

This patch adds a new struct type sprinter_t, which is used for
structured formatting, e.g. JSON or S-Expressions. The structure printer
is heavily based on code from Austin Clements
(id:87d34hsdx8.fsf at awakening.csail.mit.edu).

It includes the following functions:

/* Start a new map/dictionary structure. This should be followed by
 * a sequence of alternating calls to map_key and one of the
 * value-printing functions until the map is ended by end.
 */
void (*begin_map) (struct sprinter *);

/* Start a new list/array structure.
 */
void (*begin_list) (struct sprinter *);

/* End the last opened list or map structure.
 */
void (*end) (struct sprinter *);

/* Print one string/integer/boolean/null element (possibly inside a
 * list or map, followed or preceded by separators).
 * For string, the char * must be UTF-8 encoded.
 */
void (*string) (struct sprinter *, const char *);
void (*integer) (struct sprinter *, int);
void (*boolean) (struct sprinter *, notmuch_bool_t);
void (*null) (struct sprinter *);

/* Print the key of a map's key/value pair. The char * must be UTF-8
 * encoded.
 */
void (*map_key) (struct sprinter *, const char *);

/* Insert a separator (usually extra whitespace) for improved
 * readability without affecting the abstract syntax of the
 * structure being printed.
 * For JSON, this could simply be a line break.
 */
void (*separator) (struct sprinter *);

/* Set the current string prefix. This only affects the text
 * printer, which will print this string, followed by a colon,
 * before any string. For other printers, this does nothing.
 */
void (*set_prefix) (struct sprinter *, const char *);

To support the plain text format properly, the following additional
function must also be implemented:

/* Set the current string prefix. This only affects the text
 * printer, which will print this string, followed by a colon,
 * before any string. For other printers, this does nothing.
 */
void (*set_prefix) (struct sprinter *, const char *);

The structure also contains a flag that should be set to FALSE in all
custom printers and to TRUE in the plain text formatter.

/* True if this is the special-cased plain text printer.
 */
notmuch_bool_t is_text_printer;

The printer can (and should) use internal state to insert delimiters
and syntax at the correct places.

Example:

format->begin_map(format);
format->map_key(format, "foo");
format->begin_list(format);
format->integer(format, 1);
format->integer(format, 2);
format->integer(format, 3);
format->end(format);
format->map_key(format, "bar");
format->begin_map(format);
format->map_key(format, "baaz");
format->string(format, "hello world");
format->end(format);
format->end(format);

would output JSON as follows:

{"foo": [1, 2, 3], "bar": { "baaz": "hello world"}}
---
 sprinter.h | 58 ++
 1 file changed, 58 insertions(+)
 create mode 100644 sprinter.h

diff --git a/sprinter.h b/sprinter.h
new file mode 100644
index 000..77dc26f
--- /dev/null
+++ b/sprinter.h
@@ -0,0 +1,58 @@
+#ifndef NOTMUCH_SPRINTER_H
+#define NOTMUCH_SPRINTER_H
+
+/* Necessary for notmuch_bool_t */
+#include "notmuch-client.h"
+
+/* Structure printer interface. This is used to create output
+ * structured as maps (with key/value pairs), lists and primitives
+ * (strings, integers and booleans).
+ */
+typedef struct sprinter {
+/* Start a new map/dictionary structure. This should be followed by
+ * a sequence of alternating calls to map_key and one of the
+ * value-printing functions until the map is ended by end.
+ */
+void (*begin_map) (struct sprinter *);
+
+/* Start a new list/array structure.
+ */
+void (*begin_list) (struct sprinter *);
+
+/* End the last opened list or map structure.
+ */
+void (*end) (struct sprinter *);
+
+/* Print one string/integer/boolean/null element (possibly inside a
+ * list or map, followed or preceded by separators).
+ * For string, the char * must be UTF-8 encoded.
+ */
+void (*string) (struct sprinter *, const char *);
+void (*integer) (struct sprinter *, int);
+void (*boolean) (struct sprinter *, notmuch_bool_t);
+void (*null) (struct sprinter *);
+
+/* Print the key of a map's key/value pair. The char * must be UTF-8
+ * encoded.
+ */
+void (*map_key) (struct sprinter *, const char *);
+
+/* Insert a separator (usually extra whitespace) for improved
+ * readability without affecting the abstract syntax of the
+ * structure being printed.
+ * For JSON, this could simply be a line break.
+ */
+void (*separator) (struct sprinter *);
+
+/* Set the current string prefix. This only affects the text
+ * printer, which will print this string, followed by a colon,
+ * before any string. F

notmuch-reply: Structured Formatters

2012-07-20 Thread cra...@gmx.net
Currently there is no easy way to add support for different structured
formatters (like JSON). For example, adding support for S-Expressions
would result in code duplication.

This patch series amends the situation by introducing structured
formatters, which allow different implementations of structures like
lists, maps, strings and numbers.

The new code in sprinter.h and sprinter-json.c can be used instead of
the current ad-hoc output in all parts of notmuch, a patch for
notmuch-search.c is included.

In a later patch, all other parts of notmuch should be adapted to the
structured formatters, and the creation of formatters should be
centralised (to make adding new formatters easier).

A "structured" formatter is provided for notmuch-search that prints the
current text format. This removes almost all the special-casing from
notmuch-search.c.

Overall diff --stat:

 Makefile.local   |   2 +
 notmuch-search.c | 301 +--
 sprinter-json.c  | 185 +
 sprinter-text.c  | 126 
 sprinter.h   |  68 +++
 test/json|  34 +++---
 6 files changed, 484 insertions(+), 232 deletions(-)

Changes versus v6 of this patch:
- is_text_printer is now a field, not a function.
- minor formatting
- sprinter_text_search has been renamed to sprinter_text (as it contains
  no search-specific code).
- string sanitization removed from sprinter_text, the caller should
  sanitize the strings.



Re: bug in parsing?

2012-07-20 Thread Austin Clements
On Fri, 15 Jun 2012, David Belohrad  wrote:
> Dear all,
>
> recently I got an email from matplotlib list, which fails to parse in
> notmuch-saved-search-unread.
> It looks like this:
>
> Yest. 21:04 [3/5]   Jesse Rosenthal, Tomi Ollila  [PATCHv2] emacs: derive 
> correct timestamp in FCC unique name (inbox notmuch)
>  Yest. 20:58 [1/1]   Allin Cottrell   mouse and update 23.4 -> 24.1 
> (emacs inbox)
>  Yest. 20:56 [3/6]   Milan Kratochvíl, Jaroslav Lukesh, David Obdrzalek, 
> Pavel Kutina  [OT:] Javascript alert jinak (hw inbox)
> Error: Unexpected output from notmuch search:
> thread:6a68  Yest. 20:39 [1/1] R. O'Gara; [Matplotlib-users] 
> (no subject) (matplotlib mightread unread)
>
>  Yest. 19:38 [1/1]   Baaba Maal - Avaaz. org  Stop the African hunger games 
> (inbox unread)
>  Yest. 19:27 [1/2]   Bob Proulx, sariatu...@safe-mail.net   next-line at 
> window end without recenter (deleted emacs inbox unread)
>  Yest. 19:12 [1/12]  Jiří Kučera, hutt...@seznam.cz, balu@home, Pavel
>  Hudecek  LCR meter - konstrukce (deleted hw inbox unread)
>
>
>
> It seems that the weird characted in sender does it. Should those
> characters be somehow escaped?

This should be fixed in master, as of 9c5ea07c.
___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


Re: [PATCH v7 3/3] Use the structured formatters in notmuch-search.c.

2012-07-20 Thread Tomi Ollila
On Fri, Jul 20 2012, cra...@gmx.net wrote:

> From: 
>
> This patch switches from the current ad-hoc printer to the structured
> formatters in sprinter.h, sprinter-text.c and sprinter-json.c.
>
> The JSON tests are changed slightly in order to make them PASS for the
> new structured output formatter.
>
> The text tests pass without adaptation.
> ---
>  notmuch-search.c | 301 
> ---
>  test/json|  34 ---
>  2 files changed, 103 insertions(+), 232 deletions(-)
>
> diff --git a/notmuch-search.c b/notmuch-search.c
> index 3be296d..07211e8 100644
> --- a/notmuch-search.c
> +++ b/notmuch-search.c
> @@ -19,6 +19,7 @@
>   */
>  
>  #include "notmuch-client.h"
> +#include "sprinter.h"
>  
>  typedef enum {
>  OUTPUT_SUMMARY,
> @@ -28,92 +29,6 @@ typedef enum {
>  OUTPUT_TAGS
>  } output_t;
>  
> -typedef struct search_format {
> -const char *results_start;
> -const char *item_start;
> -void (*item_id) (const void *ctx,
> -  const char *item_type,
> -  const char *item_id);
> -void (*thread_summary) (const void *ctx,
> - const char *thread_id,
> - const time_t date,
> - const int matched,
> - const int total,
> - const char *authors,
> - const char *subject);
> -const char *tag_start;
> -const char *tag;
> -const char *tag_sep;
> -const char *tag_end;
> -const char *item_sep;
> -const char *item_end;
> -const char *results_end;
> -const char *results_null;
> -} search_format_t;
> -
> -static void
> -format_item_id_text (const void *ctx,
> -  const char *item_type,
> -  const char *item_id);
> -
> -static void
> -format_thread_text (const void *ctx,
> - const char *thread_id,
> - const time_t date,
> - const int matched,
> - const int total,
> - const char *authors,
> - const char *subject);
> -static const search_format_t format_text = {
> -"",
> - "",
> - format_item_id_text,
> - format_thread_text,
> - " (",
> - "%s", " ",
> - ")", "\n",
> - "",
> -"\n",
> -"",
> -};
> -
> -static void
> -format_item_id_json (const void *ctx,
> -  const char *item_type,
> -  const char *item_id);
> -
> -static void
> -format_thread_json (const void *ctx,
> - const char *thread_id,
> - const time_t date,
> - const int matched,
> - const int total,
> - const char *authors,
> - const char *subject);
> -
> -/* Any changes to the JSON format should be reflected in the file
> - * devel/schemata. */
> -static const search_format_t format_json = {
> -"[",
> - "{",
> - format_item_id_json,
> - format_thread_json,
> - "\"tags\": [",
> - "\"%s\"", ", ",
> - "]", ",\n",
> - "}",
> -"]\n",
> -"]\n",
> -};
> -
> -static void
> -format_item_id_text (unused (const void *ctx),
> -  const char *item_type,
> -  const char *item_id)
> -{
> -printf ("%s%s", item_type, item_id);
> -}
> -
>  static char *
>  sanitize_string (const void *ctx, const char *str)
>  {
> @@ -131,72 +46,8 @@ sanitize_string (const void *ctx, const char *str)
>  return out;
>  }
>  
> -static void
> -format_thread_text (const void *ctx,
> - const char *thread_id,
> - const time_t date,
> - const int matched,
> - const int total,
> - const char *authors,
> - const char *subject)
> -{
> -void *ctx_quote = talloc_new (ctx);
> -
> -printf ("thread:%s %12s [%d/%d] %s; %s",
> - thread_id,
> - notmuch_time_relative_date (ctx, date),
> - matched,
> - total,
> - sanitize_string (ctx_quote, authors),
> - sanitize_string (ctx_quote, subject));
> -
> -talloc_free (ctx_quote);
> -}
> -
> -static void
> -format_item_id_json (const void *ctx,
> -  unused (const char *item_type),
> -  const char *item_id)
> -{
> -void *ctx_quote = talloc_new (ctx);
> -
> -printf ("%s", json_quote_str (ctx_quote, item_id));
> -
> -talloc_free (ctx_quote);
> -
> -}
> -
> -static void
> -format_thread_json (const void *ctx,
> - const char *thread_id,
> - const time_t date,
> - const int matched,
> - const int total,
> - const char *authors,
> - const char *subject)
> -{
> -void *ctx_quote = talloc_new (ctx);
> -
> -printf ("\"thread\": %s,\n"
> - "\"timestamp\": %ld,\n"
> - "\"date_relativ

Re: [PATCH v7 1/3] Add support for structured output formatters.

2012-07-20 Thread craven
> I presume the patch 3/3 emails
> 
> id:"1342766173-1344-4-git-send-email-cra...@gmx.net"
> id:"1342772624-23329-1-git-send-email-cra...@gmx.net"
> 
> have identical content ?

Yes, they do, there was a problem with the Content-Type header having
^P^P, so I re-sent correctly, but the actual e-mail content is exactly
the same.

Greetings,
Peter
___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


Re: [PATCH v7 1/3] Add support for structured output formatters.

2012-07-20 Thread Tomi Ollila
On Fri, Jul 20 2012, cra...@gmx.net wrote:

> From: 
>
> This patch adds a new struct type sprinter_t, which is used for
> structured formatting, e.g. JSON or S-Expressions. The structure printer
> is heavily based on code from Austin Clements
> (id:87d34hsdx8@awakening.csail.mit.edu).
>
> It includes the following functions:
>
> /* Start a new map/dictionary structure. This should be followed by
>  * a sequence of alternating calls to map_key and one of the
>  * value-printing functions until the map is ended by end.
>  */
> void (*begin_map) (struct sprinter *);
>
> /* Start a new list/array structure.
>  */
> void (*begin_list) (struct sprinter *);
>
> /* End the last opened list or map structure.
>  */
> void (*end) (struct sprinter *);
>
> /* Print one string/integer/boolean/null element (possibly inside a
>  * list or map, followed or preceded by separators).
>  * For string, the char * must be UTF-8 encoded.
>  */
> void (*string) (struct sprinter *, const char *);
> void (*integer) (struct sprinter *, int);
> void (*boolean) (struct sprinter *, notmuch_bool_t);
> void (*null) (struct sprinter *);
>
> /* Print the key of a map's key/value pair. The char * must be UTF-8
>  * encoded.
>  */
> void (*map_key) (struct sprinter *, const char *);
>
> /* Insert a separator (usually extra whitespace) for improved
>  * readability without affecting the abstract syntax of the
>  * structure being printed.
>  * For JSON, this could simply be a line break.
>  */
> void (*separator) (struct sprinter *);
>
> /* Set the current string prefix. This only affects the text
>  * printer, which will print this string, followed by a colon,
>  * before any string. For other printers, this does nothing.
>  */
> void (*set_prefix) (struct sprinter *, const char *);

The above block duplicated below. Otherwise this LGTM.

I presume the patch 3/3 emails

id:"1342766173-1344-4-git-send-email-cra...@gmx.net"
id:"1342772624-23329-1-git-send-email-cra...@gmx.net"

have identical content ?

> To support the plain text format properly, the following additional
> function must also be implemented:
>
> /* Set the current string prefix. This only affects the text
>  * printer, which will print this string, followed by a colon,
>  * before any string. For other printers, this does nothing.
>  */
> void (*set_prefix) (struct sprinter *, const char *);
>
> The structure also contains a flag that should be set to FALSE in all
> custom printers and to TRUE in the plain text formatter.
>
> /* True if this is the special-cased plain text printer.
>  */
> notmuch_bool_t is_text_printer;
>
> The printer can (and should) use internal state to insert delimiters
> and syntax at the correct places.
>
> Example:
>
> format->begin_map(format);
> format->map_key(format, "foo");
> format->begin_list(format);
> format->integer(format, 1);
> format->integer(format, 2);
> format->integer(format, 3);
> format->end(format);
> format->map_key(format, "bar");
> format->begin_map(format);
> format->map_key(format, "baaz");
> format->string(format, "hello world");
> format->end(format);
> format->end(format);
>
> would output JSON as follows:
>
> {"foo": [1, 2, 3], "bar": { "baaz": "hello world"}}
> ---
>  sprinter.h | 58 ++
>  1 file changed, 58 insertions(+)
>  create mode 100644 sprinter.h
>
> diff --git a/sprinter.h b/sprinter.h
> new file mode 100644
> index 000..77dc26f
> --- /dev/null
> +++ b/sprinter.h
> @@ -0,0 +1,58 @@
> +#ifndef NOTMUCH_SPRINTER_H
> +#define NOTMUCH_SPRINTER_H
> +
> +/* Necessary for notmuch_bool_t */
> +#include "notmuch-client.h"
> +
> +/* Structure printer interface. This is used to create output
> + * structured as maps (with key/value pairs), lists and primitives
> + * (strings, integers and booleans).
> + */
> +typedef struct sprinter {
> +/* Start a new map/dictionary structure. This should be followed by
> + * a sequence of alternating calls to map_key and one of the
> + * value-printing functions until the map is ended by end.
> + */
> +void (*begin_map) (struct sprinter *);
> +
> +/* Start a new list/array structure.
> + */
> +void (*begin_list) (struct sprinter *);
> +
> +/* End the last opened list or map structure.
> + */
> +void (*end) (struct sprinter *);
> +
> +/* Print one string/integer/boolean/null element (possibly inside a
> + * list or map, followed or preceded by separators).
> + * For string, the char * must be UTF-8 encoded.
> + */
> +void (*string) (struct sprinter *, const char *);
> +void (*integer) (struct sprinter *, int);
> +void (*boolean) (struct sprinter *, notmuch_bool_t);
> +void (*null) (struct sprinter *);
> +
> +/* Print the key of a map's key/value pair. The char * must be UTF-8
> + 

[PATCH v7 3/3] Use the structured formatters in notmuch-search.c.

2012-07-20 Thread craven
From: 

This patch switches from the current ad-hoc printer to the structured
formatters in sprinter.h, sprinter-text.c and sprinter-json.c.

The JSON tests are changed slightly in order to make them PASS for the
new structured output formatter.

The text tests pass without adaptation.
---
 notmuch-search.c | 301 ---
 test/json|  34 ---
 2 files changed, 103 insertions(+), 232 deletions(-)

diff --git a/notmuch-search.c b/notmuch-search.c
index 3be296d..07211e8 100644
--- a/notmuch-search.c
+++ b/notmuch-search.c
@@ -19,6 +19,7 @@
  */
 
 #include "notmuch-client.h"
+#include "sprinter.h"
 
 typedef enum {
 OUTPUT_SUMMARY,
@@ -28,92 +29,6 @@ typedef enum {
 OUTPUT_TAGS
 } output_t;
 
-typedef struct search_format {
-const char *results_start;
-const char *item_start;
-void (*item_id) (const void *ctx,
-const char *item_type,
-const char *item_id);
-void (*thread_summary) (const void *ctx,
-   const char *thread_id,
-   const time_t date,
-   const int matched,
-   const int total,
-   const char *authors,
-   const char *subject);
-const char *tag_start;
-const char *tag;
-const char *tag_sep;
-const char *tag_end;
-const char *item_sep;
-const char *item_end;
-const char *results_end;
-const char *results_null;
-} search_format_t;
-
-static void
-format_item_id_text (const void *ctx,
-const char *item_type,
-const char *item_id);
-
-static void
-format_thread_text (const void *ctx,
-   const char *thread_id,
-   const time_t date,
-   const int matched,
-   const int total,
-   const char *authors,
-   const char *subject);
-static const search_format_t format_text = {
-"",
-   "",
-   format_item_id_text,
-   format_thread_text,
-   " (",
-   "%s", " ",
-   ")", "\n",
-   "",
-"\n",
-"",
-};
-
-static void
-format_item_id_json (const void *ctx,
-const char *item_type,
-const char *item_id);
-
-static void
-format_thread_json (const void *ctx,
-   const char *thread_id,
-   const time_t date,
-   const int matched,
-   const int total,
-   const char *authors,
-   const char *subject);
-
-/* Any changes to the JSON format should be reflected in the file
- * devel/schemata. */
-static const search_format_t format_json = {
-"[",
-   "{",
-   format_item_id_json,
-   format_thread_json,
-   "\"tags\": [",
-   "\"%s\"", ", ",
-   "]", ",\n",
-   "}",
-"]\n",
-"]\n",
-};
-
-static void
-format_item_id_text (unused (const void *ctx),
-const char *item_type,
-const char *item_id)
-{
-printf ("%s%s", item_type, item_id);
-}
-
 static char *
 sanitize_string (const void *ctx, const char *str)
 {
@@ -131,72 +46,8 @@ sanitize_string (const void *ctx, const char *str)
 return out;
 }
 
-static void
-format_thread_text (const void *ctx,
-   const char *thread_id,
-   const time_t date,
-   const int matched,
-   const int total,
-   const char *authors,
-   const char *subject)
-{
-void *ctx_quote = talloc_new (ctx);
-
-printf ("thread:%s %12s [%d/%d] %s; %s",
-   thread_id,
-   notmuch_time_relative_date (ctx, date),
-   matched,
-   total,
-   sanitize_string (ctx_quote, authors),
-   sanitize_string (ctx_quote, subject));
-
-talloc_free (ctx_quote);
-}
-
-static void
-format_item_id_json (const void *ctx,
-unused (const char *item_type),
-const char *item_id)
-{
-void *ctx_quote = talloc_new (ctx);
-
-printf ("%s", json_quote_str (ctx_quote, item_id));
-
-talloc_free (ctx_quote);
-
-}
-
-static void
-format_thread_json (const void *ctx,
-   const char *thread_id,
-   const time_t date,
-   const int matched,
-   const int total,
-   const char *authors,
-   const char *subject)
-{
-void *ctx_quote = talloc_new (ctx);
-
-printf ("\"thread\": %s,\n"
-   "\"timestamp\": %ld,\n"
-   "\"date_relative\": \"%s\",\n"
-   "\"matched\": %d,\n"
-   "\"total\": %d,\n"
-   "\"authors\": %s,\n"
-   "\"subject\": %s,\n",
-   json_quote_str (ctx_quote, thread_id),
-   date,
-   notmuch_time_relative_date (ctx, da