Re: [PATCH 3/5] nmbug-status: Add an nmbug-status(5) man page
[notmuch-archives.git] / 4e / 56cf385a0281a852253a8d6f7c1ed29eaf4d7c
1 Return-Path: <bremner@tethera.net>\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 5427B431FAE\r
6         for <notmuch@notmuchmail.org>; Tue, 25 Dec 2012 11:43:20 -0800 (PST)\r
7 X-Virus-Scanned: Debian amavisd-new at olra.theworths.org\r
8 X-Spam-Flag: NO\r
9 X-Spam-Score: 0\r
10 X-Spam-Level: \r
11 X-Spam-Status: No, score=0 tagged_above=-999 required=5 tests=[none]\r
12         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 0jx+LYCCdcd8 for <notmuch@notmuchmail.org>;\r
16         Tue, 25 Dec 2012 11:43:19 -0800 (PST)\r
17 Received: from tesseract.cs.unb.ca (tesseract.cs.unb.ca [131.202.240.238])\r
18         (using TLSv1 with cipher AES256-SHA (256/256 bits))\r
19         (No client certificate requested)\r
20         by olra.theworths.org (Postfix) with ESMTPS id 23E65431FC0\r
21         for <notmuch@notmuchmail.org>; Tue, 25 Dec 2012 11:43:11 -0800 (PST)\r
22 Received: from fctnnbsc30w-156034082078.dhcp-dynamic.fibreop.nb.bellaliant.net\r
23         ([156.34.82.78] helo=zancas.localnet)\r
24         by tesseract.cs.unb.ca with esmtpsa\r
25         (TLS1.0:DHE_RSA_AES_128_CBC_SHA1:16) (Exim 4.72)\r
26         (envelope-from <bremner@tethera.net>)\r
27         id 1TnaP7-0001iF-SS; Tue, 25 Dec 2012 15:43:10 -0400\r
28 Received: from bremner by zancas.localnet with local (Exim 4.80)\r
29         (envelope-from <bremner@tethera.net>)\r
30         id 1TnaP2-0005n8-Bd; Tue, 25 Dec 2012 15:43:04 -0400\r
31 From: david@tethera.net\r
32 To: notmuch@notmuchmail.org\r
33 Subject: [PATCH 03/11] notmuch-tag.c: convert to use tag-utils\r
34 Date: Tue, 25 Dec 2012 15:42:39 -0400\r
35 Message-Id: <1356464567-21779-4-git-send-email-david@tethera.net>\r
36 X-Mailer: git-send-email 1.7.10.4\r
37 In-Reply-To: <1356464567-21779-1-git-send-email-david@tethera.net>\r
38 References: <1356464567-21779-1-git-send-email-david@tethera.net>\r
39 X-Spam_bar: -\r
40 Cc: David Bremner <bremner@debian.org>\r
41 X-BeenThere: notmuch@notmuchmail.org\r
42 X-Mailman-Version: 2.1.13\r
43 Precedence: list\r
44 List-Id: "Use and development of the notmuch mail system."\r
45         <notmuch.notmuchmail.org>\r
46 List-Unsubscribe: <http://notmuchmail.org/mailman/options/notmuch>,\r
47         <mailto:notmuch-request@notmuchmail.org?subject=unsubscribe>\r
48 List-Archive: <http://notmuchmail.org/pipermail/notmuch>\r
49 List-Post: <mailto:notmuch@notmuchmail.org>\r
50 List-Help: <mailto:notmuch-request@notmuchmail.org?subject=help>\r
51 List-Subscribe: <http://notmuchmail.org/mailman/listinfo/notmuch>,\r
52         <mailto:notmuch-request@notmuchmail.org?subject=subscribe>\r
53 X-List-Received-Date: Tue, 25 Dec 2012 19:43:20 -0000\r
54 \r
55 From: David Bremner <bremner@debian.org>\r
56 \r
57 Command line parsing is factored out into a function\r
58 parse_tag_command_line in tag-utils.c.\r
59 \r
60 There is some duplicated code eliminated in tag_query, and a bunch of\r
61 translation from using the bare tag_op structs to using that tag-utils\r
62 API.\r
63 ---\r
64  notmuch-tag.c |   99 ++++++++++++---------------------------------------------\r
65  tag-util.c    |   51 +++++++++++++++++++++++++++--\r
66  tag-util.h    |   15 +++++++++\r
67  3 files changed, 84 insertions(+), 81 deletions(-)\r
68 \r
69 diff --git a/notmuch-tag.c b/notmuch-tag.c\r
70 index fc9d43a..8129912 100644\r
71 --- a/notmuch-tag.c\r
72 +++ b/notmuch-tag.c\r
73 @@ -19,6 +19,7 @@\r
74   */\r
75  \r
76  #include "notmuch-client.h"\r
77 +#include "tag-util.h"\r
78  #include "string-util.h"\r
79  \r
80  static volatile sig_atomic_t interrupted;\r
81 @@ -36,14 +37,10 @@ handle_sigint (unused (int sig))\r
82      interrupted = 1;\r
83  }\r
84  \r
85 -typedef struct {\r
86 -    const char *tag;\r
87 -    notmuch_bool_t remove;\r
88 -} tag_operation_t;\r
89  \r
90  static char *\r
91  _optimize_tag_query (void *ctx, const char *orig_query_string,\r
92 -                    const tag_operation_t *tag_ops)\r
93 +                    const tag_op_list_t *list)\r
94  {\r
95      /* This is subtler than it looks.  Xapian ignores the '-' operator\r
96       * at the beginning both queries and parenthesized groups and,\r
97 @@ -60,7 +57,7 @@ _optimize_tag_query (void *ctx, const char *orig_query_string,\r
98      size_t i;\r
99  \r
100      /* Don't optimize if there are no tag changes. */\r
101 -    if (tag_ops[0].tag == NULL)\r
102 +    if (tag_op_list_size (list) == 0)\r
103         return talloc_strdup (ctx, orig_query_string);\r
104  \r
105      /* Build the new query string */\r
106 @@ -69,17 +66,17 @@ _optimize_tag_query (void *ctx, const char *orig_query_string,\r
107      else\r
108         query_string = talloc_asprintf (ctx, "( %s ) and (", orig_query_string);\r
109  \r
110 -    for (i = 0; tag_ops[i].tag && query_string; i++) {\r
111 +    for (i = 0; i < tag_op_list_size (list) && query_string; i++) {\r
112         /* XXX in case of OOM, query_string will be deallocated when\r
113          * ctx is, which might be at shutdown */\r
114         if (make_boolean_term (ctx,\r
115 -                              "tag", tag_ops[i].tag,\r
116 +                              "tag", tag_op_list_tag (list, i),\r
117                                &escaped, &escaped_len))\r
118             return NULL;\r
119  \r
120         query_string = talloc_asprintf_append_buffer (\r
121             query_string, "%s%s%s", join,\r
122 -           tag_ops[i].remove ? "" : "not ",\r
123 +           tag_op_list_isremove (list, i) ? "" : "not ",\r
124             escaped);\r
125         join = " or ";\r
126      }\r
127 @@ -91,17 +88,15 @@ _optimize_tag_query (void *ctx, const char *orig_query_string,\r
128      return query_string;\r
129  }\r
130  \r
131 -/* Tag messages matching 'query_string' according to 'tag_ops', which\r
132 - * must be an array of tagging operations terminated with an empty\r
133 - * element. */\r
134 +/* Tag messages matching 'query_string' according to 'tag_ops'\r
135 + */\r
136  static int\r
137  tag_query (void *ctx, notmuch_database_t *notmuch, const char *query_string,\r
138 -          tag_operation_t *tag_ops, notmuch_bool_t synchronize_flags)\r
139 +          tag_op_list_t *tag_ops, tag_op_flag_t flags)\r
140  {\r
141      notmuch_query_t *query;\r
142      notmuch_messages_t *messages;\r
143      notmuch_message_t *message;\r
144 -    int i;\r
145  \r
146      /* Optimize the query so it excludes messages that already have\r
147       * the specified set of tags. */\r
148 @@ -124,21 +119,7 @@ tag_query (void *ctx, notmuch_database_t *notmuch, const char *query_string,\r
149          notmuch_messages_valid (messages) && ! interrupted;\r
150          notmuch_messages_move_to_next (messages)) {\r
151         message = notmuch_messages_get (messages);\r
152 -\r
153 -       notmuch_message_freeze (message);\r
154 -\r
155 -       for (i = 0; tag_ops[i].tag; i++) {\r
156 -           if (tag_ops[i].remove)\r
157 -               notmuch_message_remove_tag (message, tag_ops[i].tag);\r
158 -           else\r
159 -               notmuch_message_add_tag (message, tag_ops[i].tag);\r
160 -       }\r
161 -\r
162 -       notmuch_message_thaw (message);\r
163 -\r
164 -       if (synchronize_flags)\r
165 -           notmuch_message_tags_to_maildir_flags (message);\r
166 -\r
167 +       tag_op_list_apply (message, tag_ops, flags | TAG_FLAG_PRE_OPTIMIZED);\r
168         notmuch_message_destroy (message);\r
169      }\r
170  \r
171 @@ -150,15 +131,13 @@ tag_query (void *ctx, notmuch_database_t *notmuch, const char *query_string,\r
172  int\r
173  notmuch_tag_command (void *ctx, int argc, char *argv[])\r
174  {\r
175 -    tag_operation_t *tag_ops;\r
176 -    int tag_ops_count = 0;\r
177 -    char *query_string;\r
178 +    tag_op_list_t *tag_ops = NULL;\r
179 +    char *query_string = NULL;\r
180      notmuch_config_t *config;\r
181      notmuch_database_t *notmuch;\r
182      struct sigaction action;\r
183 -    notmuch_bool_t synchronize_flags;\r
184 -    int i;\r
185 -    int ret;\r
186 +    tag_op_flag_t tag_flags = TAG_FLAG_NONE;\r
187 +    int ret = 0;\r
188  \r
189      /* Setup our handler for SIGINT */\r
190      memset (&action, 0, sizeof (struct sigaction));\r
191 @@ -167,54 +146,15 @@ notmuch_tag_command (void *ctx, int argc, char *argv[])\r
192      action.sa_flags = SA_RESTART;\r
193      sigaction (SIGINT, &action, NULL);\r
194  \r
195 -    argc--; argv++; /* skip subcommand argument */\r
196 -\r
197 -    /* Array of tagging operations (add or remove), terminated with an\r
198 -     * empty element. */\r
199 -    tag_ops = talloc_array (ctx, tag_operation_t, argc + 1);\r
200 +    tag_ops = tag_op_list_create (ctx);\r
201      if (tag_ops == NULL) {\r
202         fprintf (stderr, "Out of memory.\n");\r
203         return 1;\r
204      }\r
205  \r
206 -    for (i = 0; i < argc; i++) {\r
207 -       if (strcmp (argv[i], "--") == 0) {\r
208 -           i++;\r
209 -           break;\r
210 -       }\r
211 -       if (argv[i][0] == '+' || argv[i][0] == '-') {\r
212 -           if (argv[i][0] == '+' && argv[i][1] == '\0') {\r
213 -               fprintf (stderr, "Error: tag names cannot be empty.\n");\r
214 -               return 1;\r
215 -           }\r
216 -           if (argv[i][0] == '+' && argv[i][1] == '-') {\r
217 -               /* This disallows adding the non-removable tag "-" and\r
218 -                * enables notmuch tag to take long options in the\r
219 -                * future. */\r
220 -               fprintf (stderr, "Error: tag names must not start with '-'.\n");\r
221 -               return 1;\r
222 -           }\r
223 -           tag_ops[tag_ops_count].tag = argv[i] + 1;\r
224 -           tag_ops[tag_ops_count].remove = (argv[i][0] == '-');\r
225 -           tag_ops_count++;\r
226 -       } else {\r
227 -           break;\r
228 -       }\r
229 -    }\r
230 -\r
231 -    tag_ops[tag_ops_count].tag = NULL;\r
232 -\r
233 -    if (tag_ops_count == 0) {\r
234 -       fprintf (stderr, "Error: 'notmuch tag' requires at least one tag to add or remove.\n");\r
235 -       return 1;\r
236 -    }\r
237 -\r
238 -    query_string = query_string_from_args (ctx, argc - i, &argv[i]);\r
239 -\r
240 -    if (*query_string == '\0') {\r
241 -       fprintf (stderr, "Error: notmuch tag requires at least one search term.\n");\r
242 +    if (parse_tag_command_line (ctx, argc - 1, argv + 1,\r
243 +                               &query_string, tag_ops))\r
244         return 1;\r
245 -    }\r
246  \r
247      config = notmuch_config_open (ctx, NULL, NULL);\r
248      if (config == NULL)\r
249 @@ -224,9 +164,10 @@ notmuch_tag_command (void *ctx, int argc, char *argv[])\r
250                                NOTMUCH_DATABASE_MODE_READ_WRITE, &notmuch))\r
251         return 1;\r
252  \r
253 -    synchronize_flags = notmuch_config_get_maildir_synchronize_flags (config);\r
254 +    if (notmuch_config_get_maildir_synchronize_flags (config))\r
255 +       tag_flags |= TAG_FLAG_MAILDIR_SYNC;\r
256  \r
257 -    ret = tag_query (ctx, notmuch, query_string, tag_ops, synchronize_flags);\r
258 +    ret = tag_query (ctx, notmuch, query_string, tag_ops, tag_flags);\r
259  \r
260      notmuch_database_destroy (notmuch);\r
261  \r
262 diff --git a/tag-util.c b/tag-util.c\r
263 index 0a4fe78..701d329 100644\r
264 --- a/tag-util.c\r
265 +++ b/tag-util.c\r
266 @@ -45,8 +45,9 @@ illegal_tag (const char *tag, notmuch_bool_t remove)\r
267      if (*tag == '\0' && ! remove)\r
268         return "empty tag forbidden";\r
269  \r
270 -    /* This disallows adding the non-removable tag "-" and\r
271 -     * enables notmuch tag to take long options more easily.\r
272 +    /* This disallows adding tags starting with "-", in particular the\r
273 +     * non-removable tag "-" and enables notmuch tag to take long\r
274 +     * options more easily.\r
275       */\r
276  \r
277      if (*tag == '-' && ! remove)\r
278 @@ -157,6 +158,52 @@ parse_tag_line (void *ctx, char *line,\r
279      return ret;\r
280  }\r
281  \r
282 +tag_parse_status_t\r
283 +parse_tag_command_line (void *ctx, int argc, char **argv,\r
284 +                       char **query_str, tag_op_list_t *tag_ops)\r
285 +{\r
286 +\r
287 +    int i;\r
288 +\r
289 +    tag_op_list_reset (tag_ops);\r
290 +\r
291 +    for (i = 0; i < argc; i++) {\r
292 +       if (strcmp (argv[i], "--") == 0) {\r
293 +           i++;\r
294 +           break;\r
295 +       }\r
296 +\r
297 +       if (argv[i][0] != '+' && argv[i][0] != '-')\r
298 +           break;\r
299 +\r
300 +       notmuch_bool_t is_remove = argv[i][0] == '-';\r
301 +       const char *msg;\r
302 +\r
303 +       msg = illegal_tag (argv[i] + 1, is_remove);\r
304 +       if (msg) {\r
305 +           fprintf (stderr, "Error: %s", msg);\r
306 +           return TAG_PARSE_INVALID;\r
307 +       }\r
308 +\r
309 +       tag_op_list_append (tag_ops, argv[i] + 1, is_remove);\r
310 +    }\r
311 +\r
312 +    if (tag_op_list_size (tag_ops) == 0) {\r
313 +       fprintf (stderr, "Error: 'notmuch tag' requires at least one tag to add or remove.\n");\r
314 +       return TAG_PARSE_INVALID;\r
315 +    }\r
316 +\r
317 +    *query_str = query_string_from_args (ctx, argc - i, &argv[i]);\r
318 +\r
319 +    if (*query_str == NULL || **query_str == '\0') {\r
320 +       fprintf (stderr, "Error: notmuch tag requires at least one search term.\n");\r
321 +       return TAG_PARSE_INVALID;\r
322 +    }\r
323 +\r
324 +    return TAG_PARSE_SUCCESS;\r
325 +}\r
326 +\r
327 +\r
328  static inline void\r
329  message_error (notmuch_message_t *message,\r
330                notmuch_status_t status,\r
331 diff --git a/tag-util.h b/tag-util.h\r
332 index c07bfde..246de85 100644\r
333 --- a/tag-util.h\r
334 +++ b/tag-util.h\r
335 @@ -72,6 +72,21 @@ parse_tag_line (void *ctx, char *line,\r
336                 tag_op_flag_t flags,\r
337                 char **query_str, tag_op_list_t *ops);\r
338  \r
339 +\r
340 +\r
341 +/* Parse a command line of the following format:\r
342 + *\r
343 + * +<tag>|-<tag> [...] [--] <search-terms>\r
344 + *\r
345 + * Output Parameters:\r
346 + *     ops     contains a list of tag operations\r
347 + *     query_str the search terms.\r
348 + */\r
349 +\r
350 +tag_parse_status_t\r
351 +parse_tag_command_line (void *ctx, int argc, char **argv,\r
352 +                       char **query_str, tag_op_list_t *ops);\r
353 +\r
354  /*\r
355   * Create an empty list of tag operations\r
356   *\r
357 -- \r
358 1.7.10.4\r
359 \r