Return-Path: X-Original-To: notmuch@notmuchmail.org Delivered-To: notmuch@notmuchmail.org Received: from localhost (localhost [127.0.0.1]) by olra.theworths.org (Postfix) with ESMTP id 7CC12431FC7 for ; Wed, 11 Jul 2012 01:25:12 -0700 (PDT) X-Virus-Scanned: Debian amavisd-new at olra.theworths.org X-Spam-Flag: NO X-Spam-Score: 0.001 X-Spam-Level: X-Spam-Status: No, score=0.001 tagged_above=-999 required=5 tests=[FREEMAIL_FROM=0.001, RCVD_IN_DNSWL_NONE=-0.0001] autolearn=disabled Received: from olra.theworths.org ([127.0.0.1]) by localhost (olra.theworths.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id qYmoeOLsQiDk for ; Wed, 11 Jul 2012 01:25:10 -0700 (PDT) Received: from mailout-de.gmx.net (mailout-de.gmx.net [213.165.64.22]) by olra.theworths.org (Postfix) with SMTP id 50A62431FAE for ; Wed, 11 Jul 2012 01:25:10 -0700 (PDT) Received: (qmail invoked by alias); 11 Jul 2012 08:25:09 -0000 Received: from gw.arelion.cust.net.lagis.at (EHLO dodekanex.arelion.at) [83.164.197.182] by mail.gmx.net (mp032) with SMTP; 11 Jul 2012 10:25:09 +0200 X-Authenticated: #201305 X-Provags-ID: V01U2FsdGVkX1/IO9IRSDPIMxIhkl5XHIWKb7Q2PE0PO9rF1UJChC 5PJbGz768JJ1Lf Received: by dodekanex.arelion.at (Postfix, from userid 1000) id E798030313E; Wed, 11 Jul 2012 10:26:36 +0200 (CEST) From: To: notmuch@notmuchmail.org Subject: [PATCH v3 3/3] Use the JSON structure printer in notmuch-search. Date: Wed, 11 Jul 2012 10:26:35 +0200 Message-Id: <1341995195-2497-4-git-send-email-craven@gmx.net> X-Mailer: git-send-email 1.7.11.1 In-Reply-To: <1341995195-2497-1-git-send-email-craven@gmx.net> References: <20120710191331.GE7332@mit.edu> <1341995195-2497-1-git-send-email-craven@gmx.net> X-Y-GMX-Trusted: 0 X-BeenThere: notmuch@notmuchmail.org X-Mailman-Version: 2.1.13 Precedence: list List-Id: "Use and development of the notmuch mail system." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 11 Jul 2012 08:25:12 -0000 This patch uses the JSON structure printer for notmuch search. The changes necessary for switching to the structure printer are minor, a large part of this patch is concerned with keeping the normal unstructured text output. --- notmuch-search.c | 278 ++++++++++++++++++++++++++++++------------------------- 1 file changed, 150 insertions(+), 128 deletions(-) diff --git a/notmuch-search.c b/notmuch-search.c index 3be296d..84e4cbc 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,23 +319,32 @@ 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; } - + 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,13 +494,16 @@ notmuch_search_command (void *ctx, int argc, char *argv[]) switch (format_sel) { case NOTMUCH_FORMAT_TEXT: - format = &format_text; + format = unstructured_text_printer; break; case NOTMUCH_FORMAT_JSON: - format = &format_json; + format = &json_structure_printer; break; } + if(format != unstructured_text_printer) + state = format->initial_state(format, stdout); + config = notmuch_config_open (ctx, NULL, NULL); if (config == NULL) return 1; @@ -532,14 +554,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.11.1