database error
[notmuch-archives.git] / 32 / 5b73511190bddc69f45c29be7a51a8acd70872
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 0DC90431FD2\r
6         for <notmuch@notmuchmail.org>; Fri, 14 Dec 2012 05:34:56 -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 t48dUzQh+L8a for <notmuch@notmuchmail.org>;\r
16         Fri, 14 Dec 2012 05:34:53 -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 65EDB431FD0\r
21         for <notmuch@notmuchmail.org>; Fri, 14 Dec 2012 05:34:52 -0800 (PST)\r
22 Received: from fctnnbsc30w-142167090129.dhcp-dynamic.fibreop.nb.bellaliant.net\r
23         ([142.167.90.129] 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 1TjVPf-0004yi-6l; Fri, 14 Dec 2012 09:34:51 -0400\r
28 Received: from bremner by zancas.localnet with local (Exim 4.80)\r
29         (envelope-from <bremner@tethera.net>)\r
30         id 1TjVPZ-000221-La; Fri, 14 Dec 2012 09:34:45 -0400\r
31 From: david@tethera.net\r
32 To: notmuch@notmuchmail.org\r
33 Subject: [Patch v7 03/14] notmuch-tag.c: convert to use tag-utils\r
34 Date: Fri, 14 Dec 2012 09:34:11 -0400\r
35 Message-Id: <1355492062-7546-4-git-send-email-david@tethera.net>\r
36 X-Mailer: git-send-email 1.7.10.4\r
37 In-Reply-To: <1355492062-7546-1-git-send-email-david@tethera.net>\r
38 References: <1355492062-7546-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: Fri, 14 Dec 2012 13:34:56 -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 |  109 +++++++++++++--------------------------------------------\r
65  tag-util.c    |   51 +++++++++++++++++++++++++--\r
66  tag-util.h    |   15 ++++++++\r
67  3 files changed, 89 insertions(+), 86 deletions(-)\r
68 \r
69 diff --git a/notmuch-tag.c b/notmuch-tag.c\r
70 index 88d559b..0965ee7 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  \r
79  static volatile sig_atomic_t interrupted;\r
80  \r
81 @@ -54,14 +55,9 @@ _escape_tag (char *buf, const char *tag)\r
82      return buf;\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 @@ -73,19 +69,20 @@ _optimize_tag_query (void *ctx, const char *orig_query_string,\r
98  \r
99      char *escaped, *query_string;\r
100      const char *join = "";\r
101 -    int i;\r
102 +    size_t i;\r
103      unsigned int max_tag_len = 0;\r
104  \r
105      /* Don't optimize if there are no tag changes. */\r
106 -    if (tag_ops[0].tag == NULL)\r
107 +    if (tag_op_list_size (list) == 0)\r
108         return talloc_strdup (ctx, orig_query_string);\r
109  \r
110      /* Allocate a buffer for escaping tags.  This is large enough to\r
111       * hold a fully escaped tag with every character doubled plus\r
112       * enclosing quotes and a NUL. */\r
113 -    for (i = 0; tag_ops[i].tag; i++)\r
114 -       if (strlen (tag_ops[i].tag) > max_tag_len)\r
115 -           max_tag_len = strlen (tag_ops[i].tag);\r
116 +    for (i = 0; i < tag_op_list_size (list); i++)\r
117 +       if (strlen (tag_op_list_tag (list, i)) > max_tag_len)\r
118 +           max_tag_len = strlen (tag_op_list_tag (list, i));\r
119 +\r
120      escaped = talloc_array (ctx, char, max_tag_len * 2 + 3);\r
121      if (! escaped)\r
122         return NULL;\r
123 @@ -96,11 +93,11 @@ _optimize_tag_query (void *ctx, const char *orig_query_string,\r
124      else\r
125         query_string = talloc_asprintf (ctx, "( %s ) and (", orig_query_string);\r
126  \r
127 -    for (i = 0; tag_ops[i].tag && query_string; i++) {\r
128 +    for (i = 0; i < tag_op_list_size (list) && query_string; i++) {\r
129         query_string = talloc_asprintf_append_buffer (\r
130             query_string, "%s%stag:%s", join,\r
131 -           tag_ops[i].remove ? "" : "not ",\r
132 -           _escape_tag (escaped, tag_ops[i].tag));\r
133 +           tag_op_list_isremove (list, i) ? "" : "not ",\r
134 +           _escape_tag (escaped, tag_op_list_tag (list, i)));\r
135         join = " or ";\r
136      }\r
137  \r
138 @@ -111,17 +108,15 @@ _optimize_tag_query (void *ctx, const char *orig_query_string,\r
139      return query_string;\r
140  }\r
141  \r
142 -/* Tag messages matching 'query_string' according to 'tag_ops', which\r
143 - * must be an array of tagging operations terminated with an empty\r
144 - * element. */\r
145 +/* Tag messages matching 'query_string' according to 'tag_ops'\r
146 + */\r
147  static int\r
148  tag_query (void *ctx, notmuch_database_t *notmuch, const char *query_string,\r
149 -          tag_operation_t *tag_ops, notmuch_bool_t synchronize_flags)\r
150 +          tag_op_list_t *tag_ops, tag_op_flag_t flags)\r
151  {\r
152      notmuch_query_t *query;\r
153      notmuch_messages_t *messages;\r
154      notmuch_message_t *message;\r
155 -    int i;\r
156  \r
157      /* Optimize the query so it excludes messages that already have\r
158       * the specified set of tags. */\r
159 @@ -144,21 +139,7 @@ tag_query (void *ctx, notmuch_database_t *notmuch, const char *query_string,\r
160          notmuch_messages_valid (messages) && ! interrupted;\r
161          notmuch_messages_move_to_next (messages)) {\r
162         message = notmuch_messages_get (messages);\r
163 -\r
164 -       notmuch_message_freeze (message);\r
165 -\r
166 -       for (i = 0; tag_ops[i].tag; i++) {\r
167 -           if (tag_ops[i].remove)\r
168 -               notmuch_message_remove_tag (message, tag_ops[i].tag);\r
169 -           else\r
170 -               notmuch_message_add_tag (message, tag_ops[i].tag);\r
171 -       }\r
172 -\r
173 -       notmuch_message_thaw (message);\r
174 -\r
175 -       if (synchronize_flags)\r
176 -           notmuch_message_tags_to_maildir_flags (message);\r
177 -\r
178 +       tag_op_list_apply (message, tag_ops, flags | TAG_FLAG_PRE_OPTIMIZED);\r
179         notmuch_message_destroy (message);\r
180      }\r
181  \r
182 @@ -170,15 +151,13 @@ tag_query (void *ctx, notmuch_database_t *notmuch, const char *query_string,\r
183  int\r
184  notmuch_tag_command (void *ctx, int argc, char *argv[])\r
185  {\r
186 -    tag_operation_t *tag_ops;\r
187 -    int tag_ops_count = 0;\r
188 -    char *query_string;\r
189 +    tag_op_list_t *tag_ops = NULL;\r
190 +    char *query_string = NULL;\r
191      notmuch_config_t *config;\r
192      notmuch_database_t *notmuch;\r
193      struct sigaction action;\r
194 -    notmuch_bool_t synchronize_flags;\r
195 -    int i;\r
196 -    int ret;\r
197 +    tag_op_flag_t tag_flags = TAG_FLAG_NONE;\r
198 +    int ret = 0;\r
199  \r
200      /* Setup our handler for SIGINT */\r
201      memset (&action, 0, sizeof (struct sigaction));\r
202 @@ -187,54 +166,15 @@ notmuch_tag_command (void *ctx, int argc, char *argv[])\r
203      action.sa_flags = SA_RESTART;\r
204      sigaction (SIGINT, &action, NULL);\r
205  \r
206 -    argc--; argv++; /* skip subcommand argument */\r
207 -\r
208 -    /* Array of tagging operations (add or remove), terminated with an\r
209 -     * empty element. */\r
210 -    tag_ops = talloc_array (ctx, tag_operation_t, argc + 1);\r
211 +    tag_ops = tag_op_list_create (ctx);\r
212      if (tag_ops == NULL) {\r
213         fprintf (stderr, "Out of memory.\n");\r
214         return 1;\r
215      }\r
216  \r
217 -    for (i = 0; i < argc; i++) {\r
218 -       if (strcmp (argv[i], "--") == 0) {\r
219 -           i++;\r
220 -           break;\r
221 -       }\r
222 -       if (argv[i][0] == '+' || argv[i][0] == '-') {\r
223 -           if (argv[i][0] == '+' && argv[i][1] == '\0') {\r
224 -               fprintf (stderr, "Error: tag names cannot be empty.\n");\r
225 -               return 1;\r
226 -           }\r
227 -           if (argv[i][0] == '+' && argv[i][1] == '-') {\r
228 -               /* This disallows adding the non-removable tag "-" and\r
229 -                * enables notmuch tag to take long options in the\r
230 -                * future. */\r
231 -               fprintf (stderr, "Error: tag names must not start with '-'.\n");\r
232 -               return 1;\r
233 -           }\r
234 -           tag_ops[tag_ops_count].tag = argv[i] + 1;\r
235 -           tag_ops[tag_ops_count].remove = (argv[i][0] == '-');\r
236 -           tag_ops_count++;\r
237 -       } else {\r
238 -           break;\r
239 -       }\r
240 -    }\r
241 -\r
242 -    tag_ops[tag_ops_count].tag = NULL;\r
243 -\r
244 -    if (tag_ops_count == 0) {\r
245 -       fprintf (stderr, "Error: 'notmuch tag' requires at least one tag to add or remove.\n");\r
246 -       return 1;\r
247 -    }\r
248 -\r
249 -    query_string = query_string_from_args (ctx, argc - i, &argv[i]);\r
250 -\r
251 -    if (*query_string == '\0') {\r
252 -       fprintf (stderr, "Error: notmuch tag requires at least one search term.\n");\r
253 +    if (parse_tag_command_line (ctx, argc - 1, argv + 1,\r
254 +                               &query_string, tag_ops))\r
255         return 1;\r
256 -    }\r
257  \r
258      config = notmuch_config_open (ctx, NULL, NULL);\r
259      if (config == NULL)\r
260 @@ -244,9 +184,10 @@ notmuch_tag_command (void *ctx, int argc, char *argv[])\r
261                                NOTMUCH_DATABASE_MODE_READ_WRITE, &notmuch))\r
262         return 1;\r
263  \r
264 -    synchronize_flags = notmuch_config_get_maildir_synchronize_flags (config);\r
265 +    if (notmuch_config_get_maildir_synchronize_flags (config))\r
266 +       tag_flags |= TAG_FLAG_MAILDIR_SYNC;\r
267  \r
268 -    ret = tag_query (ctx, notmuch, query_string, tag_ops, synchronize_flags);\r
269 +    ret = tag_query (ctx, notmuch, query_string, tag_ops, tag_flags);\r
270  \r
271      notmuch_database_destroy (notmuch);\r
272  \r
273 diff --git a/tag-util.c b/tag-util.c\r
274 index 13d9035..f89669a 100644\r
275 --- a/tag-util.c\r
276 +++ b/tag-util.c\r
277 @@ -45,8 +45,9 @@ illegal_tag (const char *tag, notmuch_bool_t remove)\r
278      if (*tag == '\0' && ! remove)\r
279         return "empty tag forbidden";\r
280  \r
281 -    /* This disallows adding the non-removable tag "-" and\r
282 -     * enables notmuch tag to take long options more easily.\r
283 +    /* This disallows adding tags starting with "-", in particular the\r
284 +     * non-removable tag "-" and enables notmuch tag to take long\r
285 +     * options more easily.\r
286       */\r
287  \r
288      if (*tag == '-' && ! remove)\r
289 @@ -163,6 +164,52 @@ parse_tag_line (void *ctx, char *line,\r
290      return ret;\r
291  }\r
292  \r
293 +tag_parse_status_t\r
294 +parse_tag_command_line (void *ctx, int argc, char **argv,\r
295 +                       char **query_str, tag_op_list_t *tag_ops)\r
296 +{\r
297 +\r
298 +    int i;\r
299 +\r
300 +    tag_op_list_reset (tag_ops);\r
301 +\r
302 +    for (i = 0; i < argc; i++) {\r
303 +       if (strcmp (argv[i], "--") == 0) {\r
304 +           i++;\r
305 +           break;\r
306 +       }\r
307 +\r
308 +       if (argv[i][0] != '+' && argv[i][0] != '-')\r
309 +           break;\r
310 +\r
311 +       notmuch_bool_t is_remove = argv[i][0] == '-';\r
312 +       const char *msg;\r
313 +\r
314 +       msg = illegal_tag (argv[i] + 1, is_remove);\r
315 +       if (msg) {\r
316 +           fprintf (stderr, "Error: %s", msg);\r
317 +           return TAG_PARSE_INVALID;\r
318 +       }\r
319 +\r
320 +       tag_op_list_append (ctx, tag_ops, argv[i] + 1, is_remove);\r
321 +    }\r
322 +\r
323 +    if (tag_op_list_size (tag_ops) == 0) {\r
324 +       fprintf (stderr, "Error: 'notmuch tag' requires at least one tag to add or remove.\n");\r
325 +       return TAG_PARSE_INVALID;\r
326 +    }\r
327 +\r
328 +    *query_str = query_string_from_args (ctx, argc - i, &argv[i]);\r
329 +\r
330 +    if (*query_str == NULL || **query_str == '\0') {\r
331 +       fprintf (stderr, "Error: notmuch tag requires at least one search term.\n");\r
332 +       return TAG_PARSE_INVALID;\r
333 +    }\r
334 +\r
335 +    return TAG_PARSE_SUCCESS;\r
336 +}\r
337 +\r
338 +\r
339  static inline void\r
340  message_error (notmuch_message_t *message,\r
341                notmuch_status_t status,\r
342 diff --git a/tag-util.h b/tag-util.h\r
343 index 99b0fa0..2889736 100644\r
344 --- a/tag-util.h\r
345 +++ b/tag-util.h\r
346 @@ -72,6 +72,21 @@ parse_tag_line (void *ctx, char *line,\r
347                 tag_op_flag_t flags,\r
348                 char **query_str, tag_op_list_t *ops);\r
349  \r
350 +\r
351 +\r
352 +/* Parse a command line of the following format:\r
353 + *\r
354 + * +<tag>|-<tag> [...] [--] <search-terms>\r
355 + *\r
356 + * Output Parameters:\r
357 + *     ops     contains a list of tag operations\r
358 + *     query_str the search terms.\r
359 + */\r
360 +\r
361 +tag_parse_status_t\r
362 +parse_tag_command_line (void *ctx, int argc, char **argv,\r
363 +                       char **query_str, tag_op_list_t *ops);\r
364 +\r
365  /*\r
366   * Create an empty list of tag operations\r
367   *\r
368 -- \r
369 1.7.10.4\r
370 \r