[PATCH 0/2] emacs: wash: word-wrap bugfix and tweak
[notmuch-archives.git] / 36 / 35aa6d8b72a1af7bab5b9d71c4fe77e04a9fe4
1 Return-Path: <jani@nikula.org>\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 EF318431FBC\r
6         for <notmuch@notmuchmail.org>; Sat,  1 Dec 2012 15:28:42 -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.7\r
10 X-Spam-Level: \r
11 X-Spam-Status: No, score=-0.7 tagged_above=-999 required=5\r
12         tests=[RCVD_IN_DNSWL_LOW=-0.7] 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 TPtah5+z-5nr for <notmuch@notmuchmail.org>;\r
16         Sat,  1 Dec 2012 15:28:38 -0800 (PST)\r
17 Received: from mail-la0-f53.google.com (mail-la0-f53.google.com\r
18         [209.85.215.53]) (using TLSv1 with cipher RC4-SHA (128/128 bits))\r
19         (No client certificate requested)\r
20         by olra.theworths.org (Postfix) with ESMTPS id 0E54F431FAF\r
21         for <notmuch@notmuchmail.org>; Sat,  1 Dec 2012 15:28:37 -0800 (PST)\r
22 Received: by mail-la0-f53.google.com with SMTP id w12so1398352lag.26\r
23         for <notmuch@notmuchmail.org>; Sat, 01 Dec 2012 15:28:35 -0800 (PST)\r
24 X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;\r
25         d=google.com; s=20120113;\r
26         h=from:to:cc:subject:in-reply-to:references:user-agent:date\r
27         :message-id:mime-version:content-type:x-gm-message-state;\r
28         bh=Yy92i3dChp6APg1IDGv+L8rlbteNJ3QQ9/e7AeMZNUY=;\r
29         b=NumWk/mX624Z0d3Xrt/PueG6wzYHZ/K/KxIQAdSekWTVynw/83f9ARjiEqHNW0ZOBN\r
30         AbV5jlwaLh3jJ8+ixSBQsTLHw9EkkGPW2FTuUKgfetyhXYZdUxe/zLdhXyVexNSGqTyN\r
31         i4sBBFQjEq2ScbOIUDTw3yIw4yI92uhsjBezvzIo7HSQdx/KDKbHiPaUsDMM1LfvYD8O\r
32         Ono5DaUmjUV2O4rzWgA6ZP0/BByNT42A11euGBv0axYbyp+bebl/UcX7ko118Is1Wx/e\r
33         jxk55LdHV6X5adNkjHgAgUGwAegdSd1XHCdXvfnBM4DJSCc17jHYlOmeXDoyu0PzVtZc\r
34         56cw==\r
35 Received: by 10.112.38.103 with SMTP id f7mr2416761lbk.120.1354404513711;\r
36         Sat, 01 Dec 2012 15:28:33 -0800 (PST)\r
37 Received: from localhost (dsl-hkibrasgw4-fe51df00-27.dhcp.inet.fi.\r
38         [80.223.81.27])\r
39         by mx.google.com with ESMTPS id hu6sm3481151lab.13.2012.12.01.15.28.30\r
40         (version=SSLv3 cipher=OTHER); Sat, 01 Dec 2012 15:28:31 -0800 (PST)\r
41 From: Jani Nikula <jani@nikula.org>\r
42 To: david@tethera.net, notmuch@notmuchmail.org\r
43 Subject: Re: [Patch v2 09/17] tag-util.[ch]: New files for common tagging\r
44         routines\r
45 In-Reply-To: <1353792017-31459-10-git-send-email-david@tethera.net>\r
46 References: <1353792017-31459-1-git-send-email-david@tethera.net>\r
47         <1353792017-31459-10-git-send-email-david@tethera.net>\r
48 User-Agent: Notmuch/0.14+124~g3b17402 (http://notmuchmail.org) Emacs/23.4.1\r
49         (i686-pc-linux-gnu)\r
50 Date: Sun, 02 Dec 2012 01:28:29 +0200\r
51 Message-ID: <87wqx1qrmq.fsf@nikula.org>\r
52 MIME-Version: 1.0\r
53 Content-Type: text/plain; charset=us-ascii\r
54 X-Gm-Message-State:\r
55  ALoCoQn6nJBiegkn+aDF+X22HbuDzSG0x60OCbKyt8h1C4oiQ0Qug5suv7xTIdRn+ur2Q6U9JPzi\r
56 Cc: David Bremner <bremner@debian.org>\r
57 X-BeenThere: notmuch@notmuchmail.org\r
58 X-Mailman-Version: 2.1.13\r
59 Precedence: list\r
60 List-Id: "Use and development of the notmuch mail system."\r
61         <notmuch.notmuchmail.org>\r
62 List-Unsubscribe: <http://notmuchmail.org/mailman/options/notmuch>,\r
63         <mailto:notmuch-request@notmuchmail.org?subject=unsubscribe>\r
64 List-Archive: <http://notmuchmail.org/pipermail/notmuch>\r
65 List-Post: <mailto:notmuch@notmuchmail.org>\r
66 List-Help: <mailto:notmuch-request@notmuchmail.org?subject=help>\r
67 List-Subscribe: <http://notmuchmail.org/mailman/listinfo/notmuch>,\r
68         <mailto:notmuch-request@notmuchmail.org?subject=subscribe>\r
69 X-List-Received-Date: Sat, 01 Dec 2012 23:28:43 -0000\r
70 \r
71 On Sat, 24 Nov 2012, david@tethera.net wrote:\r
72 > From: David Bremner <bremner@debian.org>\r
73 >\r
74 > These are meant to be shared between notmuch-tag and notmuch-restore.\r
75 >\r
76 > The bulk of the routines implement a "tag operation list" abstract\r
77 > data type act as a structured representation of a set of tag\r
78 > operations (typically coming from a single tag command or line of\r
79 > input).\r
80 > ---\r
81 >  Makefile.local |    1 +\r
82 >  tag-util.c     |  264 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++\r
83 >  tag-util.h     |  120 ++++++++++++++++++++++++++\r
84 >  3 files changed, 385 insertions(+)\r
85 >  create mode 100644 tag-util.c\r
86 >  create mode 100644 tag-util.h\r
87 >\r
88 > diff --git a/Makefile.local b/Makefile.local\r
89 > index 2b91946..854867d 100644\r
90 > --- a/Makefile.local\r
91 > +++ b/Makefile.local\r
92 > @@ -274,6 +274,7 @@ notmuch_client_srcs =             \\r
93 >       query-string.c          \\r
94 >       mime-node.c             \\r
95 >       crypto.c                \\r
96 > +     tag-util.c\r
97 >  \r
98 >  notmuch_client_modules = $(notmuch_client_srcs:.c=.o)\r
99 >  \r
100 > diff --git a/tag-util.c b/tag-util.c\r
101 > new file mode 100644\r
102 > index 0000000..287cc67\r
103 > --- /dev/null\r
104 > +++ b/tag-util.c\r
105 > @@ -0,0 +1,264 @@\r
106 > +#include "string-util.h"\r
107 > +#include "tag-util.h"\r
108 > +#include "hex-escape.h"\r
109 > +\r
110 > +struct _tag_operation_t {\r
111 > +    const char *tag;\r
112 > +    notmuch_bool_t remove;\r
113 > +};\r
114 > +\r
115 > +struct _tag_op_list_t {\r
116 > +    tag_operation_t *ops;\r
117 > +    int count;\r
118 > +    int size;\r
119 > +};\r
120 > +\r
121 > +int\r
122 > +parse_tag_line (void *ctx, char *line,\r
123 > +             tag_op_flag_t flags,\r
124 > +             char **query_string,\r
125 > +             tag_op_list_t *tag_ops)\r
126 > +{\r
127 > +    char *tok = line;\r
128 > +    size_t tok_len = 0;\r
129 > +\r
130 > +    chomp_newline (line);\r
131 > +\r
132 > +    /* remove leading space */\r
133 > +    while (*tok == ' ' || *tok == '\t')\r
134 > +     tok++;\r
135 > +\r
136 > +    /* Skip empty and comment lines. */\r
137 > +    if (*tok == '\0' || *tok == '#')\r
138 > +         return 1;\r
139 > +\r
140 > +    tag_op_list_reset (tag_ops);\r
141 > +\r
142 > +    /* Parse tags. */\r
143 > +    while ((tok = strtok_len (tok + tok_len, " ", &tok_len)) != NULL) {\r
144 > +     notmuch_bool_t remove;\r
145 > +     char *tag;\r
146 > +\r
147 > +     /* Optional explicit end of tags marker. */\r
148 > +     if (strncmp (tok, "--", tok_len) == 0) {\r
149 \r
150 I think this should be\r
151 \r
152         if (tok_len == 2 && strncmp (tok, "--", tok_len) == 0) {\r
153 \r
154 to not match "--foo" as "--". At this level, "--foo" should probably be\r
155 interpreted as removal of tag "-foo", and any policy about tag contents\r
156 should be done by the caller on the returned tag ops list.\r
157 \r
158 (I'm tempted to blame the above on you, but yeah it's my mistake... ;)\r
159 \r
160 > +         tok = strtok_len (tok + tok_len, " ", &tok_len);\r
161 > +         break;\r
162 > +     }\r
163 > +\r
164 > +     /* Implicit end of tags. */\r
165 > +     if (*tok != '-' && *tok != '+')\r
166 > +         break;\r
167 > +\r
168 > +     /* If tag is terminated by NUL, there's no query string. */\r
169 > +     if (*(tok + tok_len) == '\0') {\r
170 > +         tok = NULL;\r
171 > +         break;\r
172 > +     }\r
173 > +\r
174 > +     /* Terminate, and start next token after terminator. */\r
175 > +     *(tok + tok_len++) = '\0';\r
176 > +\r
177 > +     remove = (*tok == '-');\r
178 > +     tag = tok + 1;\r
179 > +\r
180 > +     /* Maybe refuse empty tags. */\r
181 > +     if (!(flags & TAG_FLAG_BE_GENEROUS) && *tag == '\0') {\r
182 \r
183 I'm divided whether this deserves to be here, or whether it should be\r
184 checked by the caller. Maybe it's all right, since my first instinct\r
185 would be to just fail on lone + or - unconditionally, so this is a\r
186 special case.\r
187 \r
188 > +         tok = NULL;\r
189 > +         break;\r
190 > +     }\r
191 > +\r
192 > +     /* Decode tag. */\r
193 > +     if (hex_decode_inplace (tag) != HEX_SUCCESS) {\r
194 > +         tok = NULL;\r
195 > +         break;\r
196 > +     }\r
197 > +\r
198 > +     if (tag_op_list_append (ctx, tag_ops, tag, remove))\r
199 > +         return -1;\r
200 > +    }\r
201 > +\r
202 > +    if (tok == NULL || tag_ops->count == 0) {\r
203 > +     /* FIXME: line has been modified! */\r
204 \r
205 I think we should either ditch the %s as it's bound to be completely\r
206 useless like this, or make a copy of the input line.\r
207 \r
208 > +     fprintf (stderr, "Warning: Ignoring invalid input line: %s\n",\r
209 > +              line);\r
210 > +     return 1;\r
211 > +    }\r
212 > +\r
213 > +    /* tok now points to the query string */\r
214 > +    if (hex_decode_inplace (tok) != HEX_SUCCESS) {\r
215 > +     /* FIXME: line has been modified! */\r
216 \r
217 Ditto.\r
218 \r
219 > +     fprintf (stderr, "Warning: Ignoring invalid input line: %s\n",\r
220 > +              line);\r
221 > +     return 1;\r
222 > +    }\r
223 > +\r
224 > +    *query_string = tok;\r
225 > +\r
226 > +    return 0;\r
227 > +}\r
228 > +\r
229 > +static inline void\r
230 > +message_error (notmuch_message_t *message,\r
231 > +            notmuch_status_t status,\r
232 > +            const char *format, ...)\r
233 > +{\r
234 > +    va_list va_args;\r
235 > +\r
236 > +    va_start (va_args, format);\r
237 > +\r
238 > +    vfprintf (stderr, format, va_args);\r
239 > +    fprintf (stderr, "Message-ID: %s\n", notmuch_message_get_message_id (message));\r
240 > +    fprintf (stderr, "Status: %s\n", notmuch_status_to_string (status));\r
241 > +}\r
242 > +\r
243 > +notmuch_status_t\r
244 > +tag_op_list_apply (notmuch_message_t *message,\r
245 > +                tag_op_list_t *list,\r
246 > +                tag_op_flag_t flags)\r
247 > +{\r
248 > +    int i;\r
249 > +\r
250 > +    notmuch_status_t status = 0;\r
251 > +    tag_operation_t *tag_ops = list->ops;\r
252 > +\r
253 > +    status = notmuch_message_freeze (message);\r
254 > +    if (status) {\r
255 > +     message_error (message, status, "freezing message");\r
256 > +     return status;\r
257 > +    }\r
258 > +\r
259 > +    if (flags & TAG_FLAG_REMOVE_ALL) {\r
260 > +     status = notmuch_message_remove_all_tags (message);\r
261 > +     if (status) {\r
262 > +         message_error (message, status, "removing all tags" );\r
263 \r
264 Extra space before ).\r
265 \r
266 > +         return status;\r
267 > +     }\r
268 > +    }\r
269 > +\r
270 > +    for (i = 0; i < list->count; i++) {\r
271 > +     if (tag_ops[i].remove) {\r
272 > +         status = notmuch_message_remove_tag (message, tag_ops[i].tag);\r
273 > +         if (status) {\r
274 > +             message_error (message, status, "removing tag %s", tag_ops[i].tag);\r
275 > +             return status;\r
276 > +         }\r
277 > +     } else {\r
278 > +         status = notmuch_message_add_tag (message, tag_ops[i].tag);\r
279 > +         if (status) {\r
280 > +             message_error (message, status, "adding tag %s", tag_ops[i].tag);\r
281 > +             return status;\r
282 > +         }\r
283 > +\r
284 > +     }\r
285 > +    }\r
286 > +\r
287 > +    status = notmuch_message_thaw (message);\r
288 > +    if (status) {\r
289 > +     message_error (message, status, "thawing message");\r
290 > +     return status;\r
291 > +    }\r
292 > +\r
293 > +\r
294 > +    if (flags & TAG_FLAG_MAILDIR_SYNC) {\r
295 > +     status = notmuch_message_tags_to_maildir_flags (message);\r
296 > +     if (status) {\r
297 > +         message_error (message, status, "synching tags to maildir");\r
298 > +         return status;\r
299 > +     }\r
300 > +    }\r
301 > +\r
302 > +    return NOTMUCH_STATUS_SUCCESS;\r
303 > +\r
304 > +}\r
305 > +\r
306 > +\r
307 > +/* Array of tagging operations (add or remove), terminated with an\r
308 > + * empty element. Size will be increased as necessary. */\r
309 \r
310 "terminated with an empty element" is obsolete as you've added .count.\r
311 \r
312 > +\r
313 > +tag_op_list_t *\r
314 > +tag_op_list_create (void *ctx)\r
315 > +{\r
316 > +    tag_op_list_t *list;\r
317 > +\r
318 > +    list = talloc (ctx, tag_op_list_t);\r
319 > +    if (list == NULL)\r
320 > +     return NULL;\r
321 > +\r
322 > +    list->size = TAG_OP_LIST_INITIAL_SIZE;\r
323 > +    list->count = 0;\r
324 > +\r
325 > +    list->ops = talloc_array (ctx, tag_operation_t, list->size);\r
326 > +    if (list->ops == NULL)\r
327 > +     return NULL;\r
328 > +\r
329 > +    return list;\r
330 > +}\r
331 > +\r
332 > +\r
333 > +int\r
334 > +tag_op_list_append (void *ctx,\r
335 > +                 tag_op_list_t *list,\r
336 > +                 const char *tag,\r
337 > +                 notmuch_bool_t remove)\r
338 > +{\r
339 > +    /* Make room if current array is full.  This should be a fairly\r
340 > +     * rare case, considering the initial array size.\r
341 > +     */\r
342 > +\r
343 > +    if (list->count == list->size) {\r
344 > +     list->size *= 2;\r
345 > +     list->ops = talloc_realloc (ctx, list->ops, tag_operation_t,\r
346 > +                                 list->size);\r
347 > +     if (list->ops == NULL) {\r
348 > +         fprintf (stderr, "Out of memory.\n");\r
349 > +         return 1;\r
350 > +     }\r
351 > +    }\r
352 > +\r
353 > +    /* add the new operation */\r
354 > +\r
355 > +    list->ops[list->count].tag = tag;\r
356 > +    list->ops[list->count].remove = remove;\r
357 > +    list->count++;\r
358 > +    return 0;\r
359 > +}\r
360 > +\r
361 > +/*\r
362 > + *   Is the i'th tag operation a remove?\r
363 > + */\r
364 > +\r
365 > +notmuch_bool_t\r
366 > +tag_op_list_isremove (const tag_op_list_t *list, size_t i)\r
367 > +{\r
368 \r
369         assert (i < list->count); ?\r
370 \r
371 > +    return list->ops[i].remove;\r
372 > +}\r
373 > +\r
374 > +/*\r
375 > + * Reset a list to contain no operations\r
376 > + */\r
377 > +\r
378 > +void\r
379 > +tag_op_list_reset (tag_op_list_t *list)\r
380 > +{\r
381 > +    list->count = 0;\r
382 > +}\r
383 > +\r
384 > +/*\r
385 > + * Return the number of operations in a list\r
386 > + */\r
387 > +\r
388 > +size_t\r
389 > +tag_op_list_size (const tag_op_list_t *list)\r
390 > +{\r
391 > +    return list->count;\r
392 > +}\r
393 > +\r
394 > +/*\r
395 > + *   return the i'th tag in the list\r
396 > + */\r
397 > +\r
398 > +const char *\r
399 > +tag_op_list_tag (const tag_op_list_t *list, size_t i)\r
400 > +{\r
401 \r
402         assert (i < list->count); ?\r
403 \r
404 > +    return list->ops[i].tag;\r
405 > +}\r
406 > diff --git a/tag-util.h b/tag-util.h\r
407 > new file mode 100644\r
408 > index 0000000..508806f\r
409 > --- /dev/null\r
410 > +++ b/tag-util.h\r
411 > @@ -0,0 +1,120 @@\r
412 > +#ifndef _TAG_UTIL_H\r
413 > +#define _TAG_UTIL_H\r
414 > +\r
415 > +#include "notmuch-client.h"\r
416 > +\r
417 > +typedef struct _tag_operation_t tag_operation_t;\r
418 > +typedef struct _tag_op_list_t tag_op_list_t;\r
419 > +\r
420 > +#define TAG_OP_LIST_INITIAL_SIZE 10\r
421 \r
422 This is implementation details, could be in the .c file.\r
423 \r
424 > +\r
425 > +/* Use powers of 2 */\r
426 > +typedef enum  { TAG_FLAG_NONE = 0,\r
427 > +             /* Operations are synced to maildir, if possible */\r
428 > +\r
429 > +             TAG_FLAG_MAILDIR_SYNC = 1,\r
430 > +\r
431 > +             /* Remove all tags from message before applying\r
432 > +              * list */\r
433 > +\r
434 > +             TAG_FLAG_REMOVE_ALL = 2,\r
435 > +\r
436 > +             /* Don't try to avoid database operations.  Useful\r
437 > +              * when we know that message passed needs these\r
438 > +              *  operations. */\r
439 > +\r
440 > +             TAG_FLAG_PRE_OPTIMIZED = 4,\r
441 > +\r
442 > +             /* Accept strange tags that might be user error;\r
443 > +                intended for use by notmuch-restore.\r
444 > +             */\r
445 > +\r
446 > +             TAG_FLAG_BE_GENEROUS = 8} tag_op_flag_t;\r
447 > +\r
448 > +/* Parse a string of the following format:\r
449 > + *\r
450 > + * +<tag>|-<tag> [...] [--] <search-terms>\r
451 > + *\r
452 > + * Each line is interpreted similarly to "notmuch tag" command line\r
453 > + * arguments. The delimiter is one or more spaces ' '. Any characters\r
454 > + * in <tag> and <search-terms> MAY be hex encoded with %NN where NN is\r
455 > + * the hexadecimal value of the character. Any ' ' and '%' characters\r
456 > + * in <tag> and <search-terms> MUST be hex encoded (using %20 and %25,\r
457 > + * respectively). Any characters that are not part of <tag> or\r
458 > + * <search-terms> MUST NOT be hex encoded.\r
459 > + *\r
460 > + * Leading and trailing space ' ' is ignored. Empty lines and lines\r
461 > + * beginning with '#' are ignored.\r
462 > + *\r
463 > + * Returns: 0 for OK, 1 for skipped line, -1 for fatal(ish) error.\r
464 > + *\r
465 > + * Output Parameters:\r
466 > + *   ops     contains a list of tag operations\r
467 > + *   query_str the search terms.\r
468 > + */\r
469 > +int\r
470 > +parse_tag_line (void *ctx, char *line,\r
471 > +             tag_op_flag_t flags,\r
472 > +             char **query_str, tag_op_list_t *ops);\r
473 > +\r
474 > +/*\r
475 > + * Create an empty list of tag operations\r
476 > + *\r
477 > + * ctx is passed to talloc\r
478 > + */\r
479 > +\r
480 > +tag_op_list_t\r
481 > +*tag_op_list_create (void *ctx);\r
482 \r
483 The * belongs at the end of previous line.\r
484 \r
485 BR,\r
486 Jani.\r
487 \r
488 > +\r
489 > +/*\r
490 > + * Add a tag operation (delete iff remote == TRUE) to a list.\r
491 > + * The list is expanded as necessary.\r
492 > + */\r
493 > +\r
494 > +int\r
495 > +tag_op_list_append (void *ctx,\r
496 > +                 tag_op_list_t *list,\r
497 > +                 const char *tag,\r
498 > +                 notmuch_bool_t remove);\r
499 > +\r
500 > +/*\r
501 > + * Apply a list of tag operations, in order to a message.\r
502 > + *\r
503 > + * Flags can be bitwise ORed; see enum above for possibilies.\r
504 > + */\r
505 > +\r
506 > +notmuch_status_t\r
507 > +tag_op_list_apply (notmuch_message_t *message,\r
508 > +                tag_op_list_t *tag_ops,\r
509 > +                tag_op_flag_t flags);\r
510 > +\r
511 > +/*\r
512 > + * Return the number of operations in a list\r
513 > + */\r
514 > +\r
515 > +size_t\r
516 > +tag_op_list_size (const tag_op_list_t *list);\r
517 > +\r
518 > +/*\r
519 > + * Reset a list to contain no operations\r
520 > + */\r
521 > +\r
522 > +void\r
523 > +tag_op_list_reset (tag_op_list_t *list);\r
524 > +\r
525 > +\r
526 > + /*\r
527 > +  *   return the i'th tag in the list\r
528 > +  */\r
529 > +\r
530 > +const char *\r
531 > +tag_op_list_tag (const tag_op_list_t *list, size_t i);\r
532 > +\r
533 > +/*\r
534 > + *   Is the i'th tag operation a remove?\r
535 > + */\r
536 > +\r
537 > +notmuch_bool_t\r
538 > +tag_op_list_isremove (const tag_op_list_t *list, size_t i);\r
539 > +\r
540 > +#endif\r
541 > -- \r
542 > 1.7.10.4\r
543 >\r
544 > _______________________________________________\r
545 > notmuch mailing list\r
546 > notmuch@notmuchmail.org\r
547 > http://notmuchmail.org/mailman/listinfo/notmuch\r