[PATCH v3 3/3] Use the structured format printer in notmuch search.

craven at gmx.net craven at gmx.net
Tue Jul 10 11:57:23 PDT 2012


This patch uses the previously introduced structured format printer in notmuch-search.
Most of this patch is necessary to keep the text output unchanged. All tests pass, both text and JSON are printed exactly the same as they were before.
---
 notmuch-search.c |  275 +++++++++++++++++++++++++++++-------------------------
 1 file changed, 148 insertions(+), 127 deletions(-)

diff --git a/notmuch-search.c b/notmuch-search.c
index 3be296d..321b32a 100644
--- a/notmuch-search.c
+++ b/notmuch-search.c
@@ -19,6 +19,7 @@
  */
 
 #include "notmuch-client.h"
+#include "structured-output.h"
 
 typedef enum {
     OUTPUT_SUMMARY,
@@ -28,6 +29,7 @@ typedef enum {
     OUTPUT_TAGS
 } output_t;
 
+/* legacy, only needed for non-structured text output */
 typedef struct search_format {
     const char *results_start;
     const char *item_start;
@@ -64,6 +66,7 @@ format_thread_text (const void *ctx,
 		    const int total,
 		    const char *authors,
 		    const char *subject);
+
 static const search_format_t format_text = {
     "",
 	"",
@@ -78,35 +81,6 @@ static const search_format_t format_text = {
 };
 
 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)
@@ -153,50 +127,9 @@ format_thread_text (const void *ctx,
     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),
-	    matched,
-	    total,
-	    json_quote_str (ctx_quote, authors),
-	    json_quote_str (ctx_quote, subject));
-
-    talloc_free (ctx_quote);
-}
-
 static int
-do_search_threads (const search_format_t *format,
+do_search_threads (const structure_printer_t *format,
+		   void *state,
 		   notmuch_query_t *query,
 		   notmuch_sort_t sort,
 		   output_t output,
@@ -209,6 +142,8 @@ do_search_threads (const search_format_t *format,
     time_t date;
     int first_thread = 1;
     int i;
+    int outermost_level = 0;
+    int items_level = 0;
 
     if (offset < 0) {
 	offset += notmuch_query_count_threads (query);
@@ -220,7 +155,11 @@ do_search_threads (const search_format_t *format,
     if (threads == NULL)
 	return 1;
 
-    fputs (format->results_start, stdout);
+    if (format == unstructured_text_printer) {
+	fputs(format_text.results_start, stdout);
+    } else { /* structured output */
+	outermost_level = format->list(state);
+    }
 
     for (i = 0;
 	 notmuch_threads_valid (threads) && (limit < 0 || i < offset + limit);
@@ -235,43 +174,85 @@ do_search_threads (const search_format_t *format,
 	    continue;
 	}
 
-	if (! first_thread)
-	    fputs (format->item_sep, stdout);
+	if (format == unstructured_text_printer && ! first_thread)
+	    fputs (format_text.item_sep, stdout);
 
 	if (output == OUTPUT_THREADS) {
-	    format->item_id (thread, "thread:",
-			     notmuch_thread_get_thread_id (thread));
+	    if (format == unstructured_text_printer) {
+		format_text.item_id (thread, "thread:",
+				     notmuch_thread_get_thread_id (thread));
+	    } else { /* structured output */
+		format->string(state, notmuch_thread_get_thread_id (thread));
+	    }
 	} else { /* output == OUTPUT_SUMMARY */
-	    fputs (format->item_start, stdout);
+
+	    if (format == unstructured_text_printer) {
+		fputs (format_text.item_start, stdout);
+	    } else { /* structured output */
+		items_level = format->map(state);
+	    }
 
 	    if (sort == NOTMUCH_SORT_OLDEST_FIRST)
 		date = notmuch_thread_get_oldest_date (thread);
 	    else
 		date = notmuch_thread_get_newest_date (thread);
 
-	    format->thread_summary (thread,
-				    notmuch_thread_get_thread_id (thread),
-				    date,
-				    notmuch_thread_get_matched_messages (thread),
-				    notmuch_thread_get_total_messages (thread),
-				    notmuch_thread_get_authors (thread),
-				    notmuch_thread_get_subject (thread));
-
-	    fputs (format->tag_start, stdout);
+	    if (format == unstructured_text_printer) {
+		format_text.thread_summary (thread,
+					    notmuch_thread_get_thread_id (thread),
+					    date,
+					    notmuch_thread_get_matched_messages (thread),
+					    notmuch_thread_get_total_messages (thread),
+					    notmuch_thread_get_authors (thread),
+					    notmuch_thread_get_subject (thread));
+	    } else { /* structured output */
+		void *ctx = talloc_new (0);
+		format->map_key(state, "thread");
+		format->string(state, notmuch_thread_get_thread_id (thread));
+		format->map_key(state, "timestamp");
+		format->number(state, date);
+		format->map_key(state, "date_relative");
+		format->string(state, notmuch_time_relative_date(ctx, date));
+		format->map_key(state, "matched");
+		format->number(state, notmuch_thread_get_matched_messages(thread));
+		format->map_key(state, "total");
+		format->number(state, notmuch_thread_get_total_messages(thread));
+		format->map_key(state, "authors");
+		format->string(state, notmuch_thread_get_authors(thread));
+		format->map_key(state, "subject");
+		format->string(state, notmuch_thread_get_subject(thread));
+		talloc_free(ctx);
+	    };
+
+	    if (format == unstructured_text_printer) {
+		fputs (format_text.tag_start, stdout);
+	    } else { /* structured output */
+		format->map_key(state, "tags");
+		format->list(state);
+	    }
 
 	    for (tags = notmuch_thread_get_tags (thread);
 		 notmuch_tags_valid (tags);
 		 notmuch_tags_move_to_next (tags))
 	    {
-		if (! first_tag)
-		    fputs (format->tag_sep, stdout);
-		printf (format->tag, notmuch_tags_get (tags));
+		if (format == unstructured_text_printer && ! first_tag) {
+		    fputs (format_text.tag_sep, stdout);
+		}
+		
+		if(format == unstructured_text_printer) {
+		    printf (format_text.tag, notmuch_tags_get (tags));
+		} else {
+		    format->string(state, notmuch_tags_get(tags));
+		}
 		first_tag = 0;
 	    }
 
-	    fputs (format->tag_end, stdout);
-
-	    fputs (format->item_end, stdout);
+	    if(format == unstructured_text_printer) {
+		fputs (format_text.tag_end, stdout);
+		fputs (format_text.item_end, stdout);
+	    } else { /* structured output */
+		format->pop(state, items_level);
+	    }
 	}
 
 	first_thread = 0;
@@ -279,16 +260,21 @@ do_search_threads (const search_format_t *format,
 	notmuch_thread_destroy (thread);
     }
 
-    if (first_thread)
-	fputs (format->results_null, stdout);
-    else
-	fputs (format->results_end, stdout);
+    if (format == unstructured_text_printer) {
+	if (first_thread)
+	    fputs (format_text.results_null, stdout);
+	else
+	    fputs (format_text.results_end, stdout);
+    } else { /* structured output */
+	format->pop(state, outermost_level);
+    }
 
     return 0;
 }
 
 static int
-do_search_messages (const search_format_t *format,
+do_search_messages (const structure_printer_t *format,
+		    void *state,
 		    notmuch_query_t *query,
 		    output_t output,
 		    int offset,
@@ -299,6 +285,7 @@ do_search_messages (const search_format_t *format,
     notmuch_filenames_t *filenames;
     int first_message = 1;
     int i;
+    int outermost_level = 0;
 
     if (offset < 0) {
 	offset += notmuch_query_count_messages (query);
@@ -310,7 +297,11 @@ do_search_messages (const search_format_t *format,
     if (messages == NULL)
 	return 1;
 
-    fputs (format->results_start, stdout);
+    if(format == unstructured_text_printer) {
+	fputs (format_text.results_start, stdout);
+    } else { /* structured output */
+	outermost_level = format->list(state);
+    }
 
     for (i = 0;
 	 notmuch_messages_valid (messages) && (limit < 0 || i < offset + limit);
@@ -328,11 +319,15 @@ do_search_messages (const search_format_t *format,
 		 notmuch_filenames_valid (filenames);
 		 notmuch_filenames_move_to_next (filenames))
 	    {
-		if (! first_message)
-		    fputs (format->item_sep, stdout);
+		if (format == unstructured_text_printer) {
+		    if (! first_message)
+			fputs (format_text.item_sep, stdout);
 
-		format->item_id (message, "",
-				 notmuch_filenames_get (filenames));
+		    format_text.item_id (message, "",
+					 notmuch_filenames_get (filenames));
+		} else { /* structured output */
+		format->string(state, notmuch_filenames_get (filenames));
+		}
 
 		first_message = 0;
 	    }
@@ -340,11 +335,16 @@ do_search_messages (const search_format_t *format,
 	    notmuch_filenames_destroy( filenames );
 
 	} else { /* output == OUTPUT_MESSAGES */
-	    if (! first_message)
-		fputs (format->item_sep, stdout);
+	    if (format == unstructured_text_printer) {
+		if (! first_message)
+		    fputs (format_text.item_sep, stdout);
+
+		format_text.item_id (message, "id:",
+				     notmuch_message_get_message_id (message));
+	    } else { /* structured output */
+		format->string(state, notmuch_message_get_message_id (message));
+	    }
 
-	    format->item_id (message, "id:",
-			     notmuch_message_get_message_id (message));
 	    first_message = 0;
 	}
 
@@ -353,23 +353,29 @@ do_search_messages (const search_format_t *format,
 
     notmuch_messages_destroy (messages);
 
-    if (first_message)
-	fputs (format->results_null, stdout);
-    else
-	fputs (format->results_end, stdout);
+    if (format == unstructured_text_printer) {
+	if (first_message)
+	    fputs (format_text.results_null, stdout);
+	else
+	    fputs (format_text.results_end, stdout);
+    } else { /* structured output */
+	format->pop(state, outermost_level);
+    };
 
     return 0;
 }
 
 static int
 do_search_tags (notmuch_database_t *notmuch,
-		const search_format_t *format,
+		const structure_printer_t *format,
+		void *state,
 		notmuch_query_t *query)
 {
     notmuch_messages_t *messages = NULL;
     notmuch_tags_t *tags;
     const char *tag;
     int first_tag = 1;
+    int outermost_level = 0;
 
     /* should the following only special case if no excluded terms
      * specified? */
@@ -387,7 +393,11 @@ do_search_tags (notmuch_database_t *notmuch,
     if (tags == NULL)
 	return 1;
 
-    fputs (format->results_start, stdout);
+    if (format == unstructured_text_printer) {
+	fputs (format_text.results_start, stdout);
+    } else { /* structured output */
+	outermost_level = format->list(state);
+    }
 
     for (;
 	 notmuch_tags_valid (tags);
@@ -395,10 +405,14 @@ do_search_tags (notmuch_database_t *notmuch,
     {
 	tag = notmuch_tags_get (tags);
 
-	if (! first_tag)
-	    fputs (format->item_sep, stdout);
-
-	format->item_id (tags, "", tag);
+	if (format == unstructured_text_printer) {
+	    if (! first_tag) {
+		fputs (format_text.item_sep, stdout);
+	    }
+	    format_text.item_id (tags, "", tag);
+	} else { /* structured output */
+	    format->string(state, tag);
+	}
 
 	first_tag = 0;
     }
@@ -408,10 +422,14 @@ do_search_tags (notmuch_database_t *notmuch,
     if (messages)
 	notmuch_messages_destroy (messages);
 
-    if (first_tag)
-	fputs (format->results_null, stdout);
-    else
-	fputs (format->results_end, stdout);
+    if (format == unstructured_text_printer) {
+	if (first_tag)
+	    fputs (format_text.results_null, stdout);
+	else
+	    fputs (format_text.results_end, stdout);
+    } else { /* structured output */
+	format->pop(state, outermost_level);
+    };
 
     return 0;
 }
@@ -430,7 +448,8 @@ notmuch_search_command (void *ctx, int argc, char *argv[])
     notmuch_query_t *query;
     char *query_str;
     notmuch_sort_t sort = NOTMUCH_SORT_NEWEST_FIRST;
-    const search_format_t *format = &format_text;
+    const structure_printer_t *format = unstructured_text_printer;
+    void *state = NULL;
     int opt_index, ret;
     output_t output = OUTPUT_SUMMARY;
     int offset = 0;
@@ -475,10 +494,12 @@ notmuch_search_command (void *ctx, int argc, char *argv[])
 
     switch (format_sel) {
     case NOTMUCH_FORMAT_TEXT:
-	format = &format_text;
+	format = unstructured_text_printer;
+	state = 0;
 	break;
     case NOTMUCH_FORMAT_JSON:
-	format = &format_json;
+	format = &json_structure_printer;
+	state = format->initial_state(format, stdout);
 	break;
     }
 
@@ -532,14 +553,14 @@ notmuch_search_command (void *ctx, int argc, char *argv[])
     default:
     case OUTPUT_SUMMARY:
     case OUTPUT_THREADS:
-	ret = do_search_threads (format, query, sort, output, offset, limit);
+	ret = do_search_threads (format, state, query, sort, output, offset, limit);
 	break;
     case OUTPUT_MESSAGES:
     case OUTPUT_FILES:
-	ret = do_search_messages (format, query, output, offset, limit);
+	ret = do_search_messages (format, state, query, output, offset, limit);
 	break;
     case OUTPUT_TAGS:
-	ret = do_search_tags (notmuch, format, query);
+	ret = do_search_tags (notmuch, format, state, query);
 	break;
     }
 
-- 
1.7.10.4



More information about the notmuch mailing list