Re: [PATCH] emacs: notmuch-search: fix faces
[notmuch-archives.git] / da / dcab90dda1154c3deee50bfa1cd742e96c5f42
1 Return-Path: <bremner@pivot.cs.unb.ca>\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 26153429E32\r
6         for <notmuch@notmuchmail.org>; Wed,  7 Dec 2011 11:26:58 -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: -2.3\r
10 X-Spam-Level: \r
11 X-Spam-Status: No, score=-2.3 tagged_above=-999 required=5\r
12         tests=[RCVD_IN_DNSWL_MED=-2.3] 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 g-KeGB45L3ta for <notmuch@notmuchmail.org>;\r
16         Wed,  7 Dec 2011 11:26:56 -0800 (PST)\r
17 Received: from tempo.its.unb.ca (tempo.its.unb.ca [131.202.1.21])\r
18         (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits))\r
19         (No client certificate requested)\r
20         by olra.theworths.org (Postfix) with ESMTPS id 01C83429E3B\r
21         for <notmuch@notmuchmail.org>; Wed,  7 Dec 2011 11:26:49 -0800 (PST)\r
22 Received: from convex-new.cs.unb.ca ([131.202.13.154])\r
23         by tempo.its.unb.ca (8.13.8/8.13.8) with ESMTP id pB7JQhbj021338;\r
24         Wed, 7 Dec 2011 15:26:46 -0400\r
25 Received: from bremner by convex-new.cs.unb.ca with local (Exim 4.72)\r
26         (envelope-from <bremner@pivot.cs.unb.ca>)\r
27         id 1RYN8d-0004Pg-SY; Wed, 07 Dec 2011 15:26:43 -0400\r
28 From: David Bremner <david@tethera.net>\r
29 To: notmuch@notmuchmail.org\r
30 Subject: [PATCH v4 1/5] command-line-arguments.[ch]: new argument parsing\r
31         framework for notmuch.\r
32 Date: Wed,  7 Dec 2011 15:26:35 -0400\r
33 Message-Id: <1323285999-16870-2-git-send-email-david@tethera.net>\r
34 X-Mailer: git-send-email 1.7.5.4\r
35 In-Reply-To: <1323285999-16870-1-git-send-email-david@tethera.net>\r
36 References: <87iplso9c9.fsf@zancas.localnet>\r
37         <1323285999-16870-1-git-send-email-david@tethera.net>\r
38 Cc: David Bremner <bremner@debian.org>\r
39 X-BeenThere: notmuch@notmuchmail.org\r
40 X-Mailman-Version: 2.1.13\r
41 Precedence: list\r
42 List-Id: "Use and development of the notmuch mail system."\r
43         <notmuch.notmuchmail.org>\r
44 List-Unsubscribe: <http://notmuchmail.org/mailman/options/notmuch>,\r
45         <mailto:notmuch-request@notmuchmail.org?subject=unsubscribe>\r
46 List-Archive: <http://notmuchmail.org/pipermail/notmuch>\r
47 List-Post: <mailto:notmuch@notmuchmail.org>\r
48 List-Help: <mailto:notmuch-request@notmuchmail.org?subject=help>\r
49 List-Subscribe: <http://notmuchmail.org/mailman/listinfo/notmuch>,\r
50         <mailto:notmuch-request@notmuchmail.org?subject=subscribe>\r
51 X-List-Received-Date: Wed, 07 Dec 2011 19:26:58 -0000\r
52 \r
53 From: David Bremner <bremner@debian.org>\r
54 \r
55 As we noticed when Jani kindly converted things to getopt_long, much\r
56 of the work in argument parsing in notmuch is due to the the key-value\r
57 style arguments like --format=(raw|json|text).\r
58 \r
59 The framework here provides positional arguments, simple switches,\r
60 and --key=value style arguments that can take a value being an integer,\r
61 a string, or one of a set of keywords.\r
62 ---\r
63  Makefile.local           |    1 +\r
64  command-line-arguments.c |  155 ++++++++++++++++++++++++++++++++++++++++++++++\r
65  command-line-arguments.h |   80 ++++++++++++++++++++++++\r
66  notmuch-client.h         |    1 +\r
67  4 files changed, 237 insertions(+), 0 deletions(-)\r
68  create mode 100644 command-line-arguments.c\r
69  create mode 100644 command-line-arguments.h\r
70 \r
71 diff --git a/Makefile.local b/Makefile.local\r
72 index 15e6d88..28e371a 100644\r
73 --- a/Makefile.local\r
74 +++ b/Makefile.local\r
75 @@ -295,6 +295,7 @@ clean:\r
76  distclean: clean\r
77  \r
78  notmuch_client_srcs =          \\r
79 +       command-line-arguments.c\\r
80         debugger.c              \\r
81         gmime-filter-reply.c    \\r
82         gmime-filter-headers.c  \\r
83 diff --git a/command-line-arguments.c b/command-line-arguments.c\r
84 new file mode 100644\r
85 index 0000000..3aa87aa\r
86 --- /dev/null\r
87 +++ b/command-line-arguments.c\r
88 @@ -0,0 +1,155 @@\r
89 +#include <assert.h>\r
90 +#include <string.h>\r
91 +#include <stdio.h>\r
92 +#include "error_util.h"\r
93 +#include "command-line-arguments.h"\r
94 +\r
95 +/*\r
96 +  Search the array of keywords for a given argument, assigning the\r
97 +  output variable to the corresponding value.  Return FALSE if nothing\r
98 +  matches.\r
99 +*/\r
100 +\r
101 +static notmuch_bool_t\r
102 +_process_keyword_arg (const notmuch_opt_desc_t *arg_desc, const char *arg_str) {\r
103 +\r
104 +    notmuch_keyword_t *keywords = arg_desc->keywords;\r
105 +\r
106 +    while (keywords->name) {\r
107 +       if (strcmp (arg_str, keywords->name) == 0) {\r
108 +           if (arg_desc->output_var) {\r
109 +               *((int *)arg_desc->output_var) = keywords->value;\r
110 +           }\r
111 +           return TRUE;\r
112 +       }\r
113 +       keywords++;\r
114 +    }\r
115 +    fprintf (stderr, "unknown keyword: %s\n", arg_str);\r
116 +    return FALSE;\r
117 +}\r
118 +\r
119 +/*\r
120 +   Search for the {pos_arg_index}th position argument, return FALSE if\r
121 +   that does not exist.\r
122 +*/\r
123 +\r
124 +notmuch_bool_t\r
125 +parse_position_arg (const char *arg_str, int pos_arg_index,\r
126 +                   const notmuch_opt_desc_t *arg_desc) {\r
127 +\r
128 +    int pos_arg_counter = 0;\r
129 +    while (arg_desc->opt_type != NOTMUCH_OPT_END){\r
130 +       if (arg_desc->opt_type == NOTMUCH_OPT_POSITION) {\r
131 +           if (pos_arg_counter == pos_arg_index) {\r
132 +               if (arg_desc->output_var) {\r
133 +                   *((const char **)arg_desc->output_var) = arg_str;\r
134 +               }\r
135 +               return TRUE;\r
136 +           }\r
137 +           pos_arg_counter++;\r
138 +       }\r
139 +       arg_desc++;\r
140 +    }\r
141 +    return FALSE;\r
142 +}\r
143 +\r
144 +/*\r
145 + * Search for a non-positional (i.e. starting with --) argument matching arg,\r
146 + * parse a possible value, and assign to *output_var\r
147 + */\r
148 +\r
149 +notmuch_bool_t\r
150 +parse_option (const char *arg,\r
151 +             const notmuch_opt_desc_t *options) {\r
152 +\r
153 +    assert(arg);\r
154 +    assert(options);\r
155 +\r
156 +    arg += 2;\r
157 +\r
158 +    const notmuch_opt_desc_t *try = options;\r
159 +    while (try->opt_type != NOTMUCH_OPT_END) {\r
160 +       if (try->name && strncmp (arg, try->name, strlen (try->name)) == 0) {\r
161 +           char next = arg[strlen (try->name)];\r
162 +           const char *value= arg+strlen(try->name)+1;\r
163 +\r
164 +           char *endptr;\r
165 +\r
166 +           /* Everything but boolean arguments (switches) needs a\r
167 +            * delimiter, and a non-zero length value\r
168 +            */\r
169 +\r
170 +           if (try->opt_type != NOTMUCH_OPT_BOOLEAN) {\r
171 +               if (next != '=' && next != ':') return FALSE;\r
172 +               if (value[0] == 0) return FALSE;\r
173 +           } else {\r
174 +               if (next != 0) return FALSE;\r
175 +           }\r
176 +\r
177 +           if (try->output_var == NULL)\r
178 +               INTERNAL_ERROR ("output pointer NULL for option %s", try->name);\r
179 +\r
180 +           switch (try->opt_type) {\r
181 +           case NOTMUCH_OPT_KEYWORD:\r
182 +               return _process_keyword_arg (try, value);\r
183 +               break;\r
184 +           case NOTMUCH_OPT_BOOLEAN:\r
185 +               *((notmuch_bool_t *)try->output_var) = TRUE;\r
186 +               return TRUE;\r
187 +               break;\r
188 +           case NOTMUCH_OPT_INT:\r
189 +               *((int *)try->output_var) = strtol (value, &endptr, 10);\r
190 +               return (*endptr == 0);\r
191 +               break;\r
192 +           case NOTMUCH_OPT_STRING:\r
193 +               *((const char **)try->output_var) = value;\r
194 +               return TRUE;\r
195 +               break;\r
196 +           case NOTMUCH_OPT_POSITION:\r
197 +           case NOTMUCH_OPT_END:\r
198 +           default:\r
199 +               INTERNAL_ERROR ("unknown or unhandled option type %d", try->opt_type);\r
200 +               /*UNREACHED*/\r
201 +           }\r
202 +       }\r
203 +       try++;\r
204 +    }\r
205 +    fprintf (stderr, "Unrecognized option: --%s\n", arg);\r
206 +    return FALSE;\r
207 +}\r
208 +\r
209 +/* See command-line-arguments.h for description */\r
210 +int\r
211 +parse_arguments (int argc, char **argv,\r
212 +                const notmuch_opt_desc_t *options, int opt_index) {\r
213 +\r
214 +    int pos_arg_index = 0;\r
215 +    notmuch_bool_t more_args = TRUE;\r
216 +\r
217 +    while (more_args && opt_index < argc) {\r
218 +       if (strncmp (argv[opt_index],"--",2) != 0) {\r
219 +\r
220 +           more_args = parse_position_arg (argv[opt_index], pos_arg_index, options);\r
221 +\r
222 +           if (more_args) {\r
223 +               pos_arg_index++;\r
224 +               opt_index++;\r
225 +           }\r
226 +\r
227 +       } else {\r
228 +\r
229 +           if (strlen (argv[opt_index]) == 2)\r
230 +               return opt_index+1;\r
231 +\r
232 +           more_args = parse_option (argv[opt_index], options);\r
233 +           if (more_args) {\r
234 +               opt_index++;\r
235 +           } else {\r
236 +               opt_index = -1;\r
237 +           }\r
238 +\r
239 +       }\r
240 +    }\r
241 +\r
242 +    return opt_index;\r
243 +}\r
244 diff --git a/command-line-arguments.h b/command-line-arguments.h\r
245 new file mode 100644\r
246 index 0000000..af8b1ce\r
247 --- /dev/null\r
248 +++ b/command-line-arguments.h\r
249 @@ -0,0 +1,80 @@\r
250 +#ifndef NOTMUCH_OPTS_H\r
251 +#define NOTMUCH_OPTS_H\r
252 +\r
253 +#include "notmuch.h"\r
254 +\r
255 +enum notmuch_opt_type {\r
256 +    NOTMUCH_OPT_END = 0,\r
257 +    NOTMUCH_OPT_BOOLEAN,       /* --verbose              */\r
258 +    NOTMUCH_OPT_INT,           /* --frob=8               */\r
259 +    NOTMUCH_OPT_KEYWORD,       /* --format=raw|json|text */\r
260 +    NOTMUCH_OPT_STRING,                /* --file=/tmp/gnarf.txt  */\r
261 +    NOTMUCH_OPT_POSITION       /* notmuch dump pos_arg   */\r
262 +};\r
263 +\r
264 +/*\r
265 + * Describe one of the possibilities for a keyword option\r
266 + * 'value' will be copied to the output variable\r
267 + */\r
268 +\r
269 +typedef struct notmuch_keyword {\r
270 +    const char *name;\r
271 +    int value;\r
272 +} notmuch_keyword_t;\r
273 +\r
274 +/*\r
275 + * Describe one option.\r
276 + *\r
277 + * First two parameters are mandatory.\r
278 + *\r
279 + * name is mandatory _except_ for positional arguments.\r
280 + *\r
281 + * arg_id is currently unused, but could define short arguments.\r
282 + *\r
283 + * keywords is a (possibly NULL) pointer to an array of keywords\r
284 + */\r
285 +typedef struct notmuch_opt_desc {\r
286 +    enum notmuch_opt_type opt_type;\r
287 +    void *output_var;\r
288 +    const char *name;\r
289 +    int  arg_id;\r
290 +    struct notmuch_keyword *keywords;\r
291 +} notmuch_opt_desc_t;\r
292 +\r
293 +\r
294 +/*\r
295 +  This is the main entry point for command line argument parsing.\r
296 +\r
297 +  Parse command line arguments according to structure options,\r
298 +  starting at position opt_index.\r
299 +\r
300 +  All output of parsed values is via pointers in options.\r
301 +\r
302 +  Parsing stops at -- (consumed) or at the (k+1)st argument\r
303 +  not starting with -- (a "positional argument") if options contains\r
304 +  k positional argument descriptors.\r
305 +\r
306 +  Returns the index of first non-parsed argument, or -1 in case of error.\r
307 +\r
308 +*/\r
309 +int\r
310 +parse_arguments (int argc, char **argv, const notmuch_opt_desc_t *options, int opt_index);\r
311 +\r
312 +/*\r
313 + * If the argument parsing loop provided by parse_arguments is not\r
314 + * flexible enough, then the user might be interested in the following\r
315 + * routines, but note that the API to parse_option might have to\r
316 + * change. See command-line-arguments.c for descriptions of these\r
317 + * functions.\r
318 + */\r
319 +\r
320 +notmuch_bool_t\r
321 +parse_option (const char *arg, const notmuch_opt_desc_t* options);\r
322 +\r
323 +notmuch_bool_t\r
324 +parse_position_arg (const char *arg,\r
325 +                   int position_arg_index,\r
326 +                   const notmuch_opt_desc_t* options);\r
327 +\r
328 +\r
329 +#endif\r
330 diff --git a/notmuch-client.h b/notmuch-client.h\r
331 index b50cb38..703f856 100644\r
332 --- a/notmuch-client.h\r
333 +++ b/notmuch-client.h\r
334 @@ -238,4 +238,5 @@ notmuch_config_set_maildir_synchronize_flags (notmuch_config_t *config,\r
335  notmuch_bool_t\r
336  debugger_is_active (void);\r
337  \r
338 +#include "command-line-arguments.h"\r
339  #endif\r
340 -- \r
341 1.7.5.4\r
342 \r