From 6ce2bf68f53fec4302121763e588c33c7cd86a9c Mon Sep 17 00:00:00 2001 From: Scott Robinson Date: Thu, 31 Dec 2009 11:17:40 -0400 Subject: Add an "--format=(json|text)" command-line option to both notmuch-search and notmuch-show. In the case of notmuch-show, "--format=json" also implies "--entire-thread" as the thread structure is implicit in the emitted document tree. As a coincidence to the implementation, multipart message ID numbers are now incremented with each part printed. This changes the previous semantics, which were unclear and not necessary related to the actual ordering of the message parts. --- notmuch-search.c | 163 ++++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 149 insertions(+), 14 deletions(-) (limited to 'notmuch-search.c') diff --git a/notmuch-search.c b/notmuch-search.c index dc44eb66..482c6e8e 100644 --- a/notmuch-search.c +++ b/notmuch-search.c @@ -20,8 +20,120 @@ #include "notmuch-client.h" +typedef struct search_format { + const char *results_start; + const char *thread_start; + void (*thread) (const void *ctx, + const char *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 *thread_sep; + const char *thread_end; + const char *results_end; +} search_format_t; + +static void +format_thread_text (const void *ctx, + const char *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_thread_text, + " (", + "%s", " ", + ")", "", + "\n", + "", +}; + +static void +format_thread_json (const void *ctx, + const char *id, + const time_t date, + const int matched, + const int total, + const char *authors, + const char *subject); +static const search_format_t format_json = { + "[", + "{", + format_thread_json, + "\"tags\": [", + "\"%s\"", ", ", + "]", ",\n", + "}", + "]\n", +}; + +static void +format_thread_text (const void *ctx, + const char *id, + const time_t date, + const int matched, + const int total, + const char *authors, + const char *subject) +{ + printf ("thread:%s %12s [%d/%d] %s; %s", + id, + notmuch_time_relative_date (ctx, date), + matched, + total, + authors, + subject); +} + +static void +format_thread_json (const void *ctx, + const char *id, + const time_t date, + const int matched, + const int total, + const char *authors, + const char *subject) +{ + struct tm *tm; + char timestamp[40]; + void *ctx_quote = talloc_new (ctx); + + tm = gmtime (&date); + if (tm == NULL) + INTERNAL_ERROR ("gmtime failed on thread %s.", id); + + if (strftime (timestamp, sizeof (timestamp), "%s", tm) == 0) + INTERNAL_ERROR ("strftime failed on thread %s.", id); + + printf ("\"id\": %s,\n" + "\"timestamp\": %s,\n" + "\"matched\": %d,\n" + "\"total\": %d,\n" + "\"authors\": %s,\n" + "\"subject\": %s,\n", + json_quote_str (ctx_quote, id), + timestamp, + matched, + total, + json_quote_str (ctx_quote, authors), + json_quote_str (ctx_quote, subject)); + + talloc_free (ctx_quote); +} + static void do_search_threads (const void *ctx, + const search_format_t *format, notmuch_query_t *query, notmuch_sort_t sort) { @@ -29,7 +141,9 @@ do_search_threads (const void *ctx, notmuch_threads_t *threads; notmuch_tags_t *tags; time_t date; - const char *relative_date; + int first_thread = 1; + + fputs (format->results_start, stdout); for (threads = notmuch_query_search_threads (query); notmuch_threads_has_more (threads); @@ -37,6 +151,9 @@ do_search_threads (const void *ctx, { int first_tag = 1; + if (! first_thread) + fputs (format->thread_sep, stdout); + thread = notmuch_threads_get (threads); if (sort == NOTMUCH_SORT_OLDEST_FIRST) @@ -44,30 +161,37 @@ do_search_threads (const void *ctx, else date = notmuch_thread_get_newest_date (thread); - relative_date = notmuch_time_relative_date (ctx, date); + fputs (format->thread_start, stdout); + + format->thread (ctx, + 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)); - printf ("thread:%s %12s [%d/%d] %s; %s", - notmuch_thread_get_thread_id (thread), - relative_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); - printf (" ("); for (tags = notmuch_thread_get_tags (thread); notmuch_tags_has_more (tags); notmuch_tags_advance (tags)) { if (! first_tag) - printf (" "); - printf ("%s", notmuch_tags_get (tags)); + fputs (format->tag_sep, stdout); + printf (format->tag, notmuch_tags_get (tags)); first_tag = 0; } - printf (")\n"); + + fputs (format->tag_end, stdout); + fputs (format->thread_end, stdout); + + first_thread = 0; notmuch_thread_destroy (thread); } + + fputs (format->results_end, stdout); } int @@ -79,6 +203,7 @@ notmuch_search_command (void *ctx, int argc, char *argv[]) char *query_str; char *opt; notmuch_sort_t sort = NOTMUCH_SORT_NEWEST_FIRST; + const search_format_t *format = &format_text; int i; for (i = 0; i < argc && argv[i][0] == '-'; i++) { @@ -96,6 +221,16 @@ notmuch_search_command (void *ctx, int argc, char *argv[]) fprintf (stderr, "Invalid value for --sort: %s\n", opt); return 1; } + } else if (STRNCMP_LITERAL (argv[i], "--format=") == 0) { + opt = argv[i] + sizeof ("--format=") - 1; + if (strcmp (opt, "text") == 0) { + format = &format_text; + } else if (strcmp (opt, "json") == 0) { + format = &format_json; + } else { + fprintf (stderr, "Invalid value for --format: %s\n", opt); + return 1; + } } else { fprintf (stderr, "Unrecognized option: %s\n", argv[i]); return 1; @@ -132,7 +267,7 @@ notmuch_search_command (void *ctx, int argc, char *argv[]) notmuch_query_set_sort (query, sort); - do_search_threads (ctx, query, sort); + do_search_threads (ctx, format, query, sort); notmuch_query_destroy (query); notmuch_database_close (notmuch); -- cgit v1.2.3