Re: [PATCH v2] Omit User-Agent: header by default
[notmuch-archives.git] / ed / 1e104687952194e64a0c0fa2d02bc83f1ae798
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 E3B41429E26\r
6         for <notmuch@notmuchmail.org>; Wed,  7 Dec 2011 04:34: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 JefACwciO-wh for <notmuch@notmuchmail.org>;\r
16         Wed,  7 Dec 2011 04:34:57 -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 70920431FD0\r
21         for <notmuch@notmuchmail.org>; Wed,  7 Dec 2011 04:34:57 -0800 (PST)\r
22 Received: from zancas.localnet\r
23         (fctnnbsc36w-156034079193.pppoe-dynamic.High-Speed.nb.bellaliant.net\r
24         [156.34.79.193]) (authenticated bits=0)\r
25         by tempo.its.unb.ca (8.13.8/8.13.8) with ESMTP id pB7CYqZ0007119\r
26         (version=TLSv1/SSLv3 cipher=AES256-SHA bits=256 verify=NO);\r
27         Wed, 7 Dec 2011 08:34:53 -0400\r
28 Received: from bremner by zancas.localnet with local (Exim 4.77)\r
29         (envelope-from <bremner@tethera.net>)\r
30         id 1RYGi4-0007mu-HB; Wed, 07 Dec 2011 08:34:52 -0400\r
31 From: David Bremner <david@tethera.net>\r
32 To: notmuch@notmuchmail.org\r
33 Subject: [PATCH 1/4] command-line-arguments.[ch]: new argument parsing\r
34         framework for notmuch.\r
35 Date: Wed,  7 Dec 2011 08:34:37 -0400\r
36 Message-Id: <1323261280-29907-1-git-send-email-david@tethera.net>\r
37 X-Mailer: git-send-email 1.7.7.3\r
38 In-Reply-To: <87iplso9c9.fsf@zancas.localnet>\r
39 References: <87iplso9c9.fsf@zancas.localnet>\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: Wed, 07 Dec 2011 12:34:59 -0000\r
54 \r
55 From: David Bremner <bremner@debian.org>\r
56 \r
57 As we noticed when Jani kindly converted things to getopt_long, much\r
58 of the work in argument parsing in notmuch is due to the the key-value\r
59 style arguments like --format=(raw|json|text).\r
60 \r
61 The framework here provides positional arguments, simple switches,\r
62 and --key=value style arguments that can take a value being an integer,\r
63 a string, or one of a set of keywords.\r
64 ---\r
65  Makefile.local           |    1 +\r
66  command-line-arguments.c |  159 ++++++++++++++++++++++++++++++++++++++++++++++\r
67  command-line-arguments.h |   39 +++++++++++\r
68  notmuch-client.h         |    1 +\r
69  4 files changed, 200 insertions(+), 0 deletions(-)\r
70  create mode 100644 command-line-arguments.c\r
71  create mode 100644 command-line-arguments.h\r
72 \r
73 diff --git a/Makefile.local b/Makefile.local\r
74 index 15e6d88..28e371a 100644\r
75 --- a/Makefile.local\r
76 +++ b/Makefile.local\r
77 @@ -295,6 +295,7 @@ clean:\r
78  distclean: clean\r
79  \r
80  notmuch_client_srcs =          \\r
81 +       command-line-arguments.c\\r
82         debugger.c              \\r
83         gmime-filter-reply.c    \\r
84         gmime-filter-headers.c  \\r
85 diff --git a/command-line-arguments.c b/command-line-arguments.c\r
86 new file mode 100644\r
87 index 0000000..96ed9ba\r
88 --- /dev/null\r
89 +++ b/command-line-arguments.c\r
90 @@ -0,0 +1,159 @@\r
91 +#include <assert.h>\r
92 +#include <string.h>\r
93 +#include <stdio.h>\r
94 +#include "error_util.h"\r
95 +#include "command-line-arguments.h"\r
96 +\r
97 +/*\r
98 +  Search the array of keywords for a given argument, assigning the\r
99 +  output variable to the corresponding value.  Return FALSE if nothing\r
100 +  matches.\r
101 +*/\r
102 +\r
103 +static notmuch_bool_t\r
104 +_process_keyword_arg (const notmuch_opt_desc_t *arg_desc, const char *arg_str) {\r
105 +\r
106 +    notmuch_keyword_t *keywords = arg_desc->keywords;\r
107 +\r
108 +    while (keywords->name) {\r
109 +       if (strcmp (arg_str, keywords->name) == 0) {\r
110 +           if (arg_desc->output_var) {\r
111 +               *((int *)arg_desc->output_var) = keywords->value;\r
112 +           }\r
113 +           return TRUE;\r
114 +       }\r
115 +       keywords++;\r
116 +    }\r
117 +    fprintf (stderr, "unknown keyword: %s\n", arg_str);\r
118 +    return FALSE;\r
119 +}\r
120 +\r
121 +/*\r
122 +   Search for the {pos_arg_index}th position argument, return FALSE if\r
123 +   that does not exist.\r
124 +*/\r
125 +\r
126 +notmuch_bool_t\r
127 +parse_position_arg (const char *arg_str, int pos_arg_index, const notmuch_opt_desc_t *arg_desc) {\r
128 +\r
129 +    int pos_arg_counter = 0;\r
130 +    while (arg_desc->name){\r
131 +       if (arg_desc->opt_type == NOTMUCH_OPT_POSITION) {\r
132 +           if (pos_arg_counter == pos_arg_index) {\r
133 +               if (arg_desc->output_var) {\r
134 +                   *((const char **)arg_desc->output_var) = arg_str;\r
135 +               }\r
136 +               return TRUE;\r
137 +           }\r
138 +           pos_arg_counter++;\r
139 +       }\r
140 +       arg_desc++;\r
141 +    }\r
142 +    return FALSE;\r
143 +}\r
144 +\r
145 +notmuch_bool_t\r
146 +parse_option (const char *arg,\r
147 +             const notmuch_opt_desc_t *options) {\r
148 +\r
149 +    assert(arg);\r
150 +    assert(options);\r
151 +\r
152 +    arg += 2;\r
153 +\r
154 +    const notmuch_opt_desc_t *try = options;\r
155 +    while (try->name) {\r
156 +       if (strncmp (arg, try->name, strlen (try->name)) == 0) {\r
157 +           char next = arg[strlen (try->name)];\r
158 +           const char *value= arg+strlen(try->name)+1;\r
159 +\r
160 +           char *endptr;\r
161 +\r
162 +           /* Everything but boolean arguments (switches) needs a\r
163 +            * delimiter, and a non-zero length value\r
164 +            */\r
165 +\r
166 +           if (try->opt_type != NOTMUCH_OPT_BOOLEAN) {\r
167 +               if (next != '=' && next != ':') return FALSE;\r
168 +               if (value[0] == 0) return FALSE;\r
169 +           } else {\r
170 +               if (next != 0) return FALSE;\r
171 +           }\r
172 +\r
173 +           if (try->output_var == NULL)\r
174 +               INTERNAL_ERROR ("output pointer NULL for option %s", try->name);\r
175 +\r
176 +           switch (try->opt_type) {\r
177 +           case NOTMUCH_OPT_KEYWORD:\r
178 +               return _process_keyword_arg (try, value);\r
179 +               break;\r
180 +           case NOTMUCH_OPT_BOOLEAN:\r
181 +               *((notmuch_bool_t *)try->output_var) = TRUE;\r
182 +               return TRUE;\r
183 +               break;\r
184 +           case NOTMUCH_OPT_INT:\r
185 +               *((int *)try->output_var) = strtol (value, &endptr, 10);\r
186 +               return (*endptr == 0);\r
187 +               break;\r
188 +           case NOTMUCH_OPT_STRING:\r
189 +               *((const char **)try->output_var) = value;\r
190 +           case NOTMUCH_OPT_POSITION:\r
191 +           case NOTMUCH_OPT_NULL:\r
192 +           default:\r
193 +               INTERNAL_ERROR ("unknown or unhandled option type %d", try->opt_type);\r
194 +               /*UNREACHED*/\r
195 +           }\r
196 +       }\r
197 +       try++;\r
198 +    }\r
199 +    fprintf (stderr, "Unrecognized option: --%s\n", arg);\r
200 +    return FALSE;\r
201 +}\r
202 +\r
203 +/*\r
204 +   Parse command line arguments according to structure options,\r
205 +   starting at position opt_index.\r
206 +\r
207 +   All output of parsed values is via pointers in options.\r
208 +\r
209 +   Parsing stops at -- (consumed) or at the (k+1)st argument\r
210 +   not starting with -- (a "positional argument") if options contains\r
211 +   k positional argument descriptors.\r
212 +\r
213 +   Returns the index of first non-parsed argument, or -1 in case of error.\r
214 +\r
215 +  */\r
216 +int\r
217 +parse_arguments (int argc, char **argv,\r
218 +                const notmuch_opt_desc_t *options, int opt_index) {\r
219 +\r
220 +    int pos_arg_index = 0;\r
221 +    notmuch_bool_t more_args = TRUE;\r
222 +\r
223 +    while (more_args && opt_index < argc) {\r
224 +       if (strncmp (argv[opt_index],"--",2) != 0) {\r
225 +\r
226 +           more_args = parse_position_arg (argv[opt_index], pos_arg_index, options);\r
227 +\r
228 +           if (more_args) {\r
229 +               pos_arg_index++;\r
230 +               opt_index++;\r
231 +           }\r
232 +\r
233 +       } else {\r
234 +\r
235 +           if (strlen (argv[opt_index]) == 2)\r
236 +               return opt_index+1;\r
237 +\r
238 +           more_args = parse_option (argv[opt_index], options);\r
239 +           if (more_args) {\r
240 +               opt_index++;\r
241 +           } else {\r
242 +               opt_index = -1;\r
243 +           }\r
244 +\r
245 +       }\r
246 +    }\r
247 +\r
248 +    return opt_index;\r
249 +}\r
250 diff --git a/command-line-arguments.h b/command-line-arguments.h\r
251 new file mode 100644\r
252 index 0000000..caebe18\r
253 --- /dev/null\r
254 +++ b/command-line-arguments.h\r
255 @@ -0,0 +1,39 @@\r
256 +#ifndef NOTMUCH_OPTS_H\r
257 +#define NOTMUCH_OPTS_H\r
258 +\r
259 +#include "notmuch.h"\r
260 +\r
261 +enum notmuch_opt_type {\r
262 +    NOTMUCH_OPT_NULL = 0,\r
263 +    NOTMUCH_OPT_BOOLEAN,\r
264 +    NOTMUCH_OPT_INT,\r
265 +    NOTMUCH_OPT_KEYWORD,\r
266 +    NOTMUCH_OPT_STRING,\r
267 +    NOTMUCH_OPT_POSITION\r
268 +};\r
269 +\r
270 +typedef struct notmuch_keyword {\r
271 +    const char *name;\r
272 +    int value;\r
273 +} notmuch_keyword_t;\r
274 +\r
275 +typedef struct notmuch_opt_desc {\r
276 +    const char *name;\r
277 +    int  arg_id;\r
278 +    enum notmuch_opt_type opt_type;\r
279 +    struct notmuch_keyword *keywords;\r
280 +    void *output_var;\r
281 +} notmuch_opt_desc_t;\r
282 +\r
283 +notmuch_bool_t\r
284 +parse_option (const char *arg, const notmuch_opt_desc_t* options);\r
285 +\r
286 +notmuch_bool_t\r
287 +parse_position_arg (const char *arg,\r
288 +                   int position_arg_index,\r
289 +                   const notmuch_opt_desc_t* options);\r
290 +\r
291 +int\r
292 +parse_arguments(int argc, char **argv, const notmuch_opt_desc_t *options, int opt_index);\r
293 +\r
294 +#endif\r
295 diff --git a/notmuch-client.h b/notmuch-client.h\r
296 index b50cb38..703f856 100644\r
297 --- a/notmuch-client.h\r
298 +++ b/notmuch-client.h\r
299 @@ -238,4 +238,5 @@ notmuch_config_set_maildir_synchronize_flags (notmuch_config_t *config,\r
300  notmuch_bool_t\r
301  debugger_is_active (void);\r
302  \r
303 +#include "command-line-arguments.h"\r
304  #endif\r
305 -- \r
306 1.7.7.3\r
307 \r