Implemented
Showing
1 changed file
with
202 additions
and
18 deletions
... | @@ -19,6 +19,11 @@ | ... | @@ -19,6 +19,11 @@ |
19 | 19 | ||
20 | #include <mh.h> | 20 | #include <mh.h> |
21 | #include <regex.h> | 21 | #include <regex.h> |
22 | #include <pick.h> | ||
23 | #include <pick-gram.h> | ||
24 | #define obstack_chunk_alloc malloc | ||
25 | #define obstack_chunk_free free | ||
26 | #include <obstack.h> | ||
22 | 27 | ||
23 | const char *argp_program_version = "pick (" PACKAGE_STRING ")"; | 28 | const char *argp_program_version = "pick (" PACKAGE_STRING ")"; |
24 | static char doc[] = N_("GNU MH pick\v" | 29 | static char doc[] = N_("GNU MH pick\v" |
... | @@ -37,6 +42,8 @@ static struct argp_option options[] = { | ... | @@ -37,6 +42,8 @@ static struct argp_option options[] = { |
37 | {"pattern", ARG_PATTERN, N_("STRING"), 0, | 42 | {"pattern", ARG_PATTERN, N_("STRING"), 0, |
38 | N_("A pattern to look for"), 1}, | 43 | N_("A pattern to look for"), 1}, |
39 | {"search", 0, NULL, OPTION_ALIAS, NULL, 1}, | 44 | {"search", 0, NULL, OPTION_ALIAS, NULL, 1}, |
45 | {"cflags", ARG_CFLAGS, N_("STRING"), 0, | ||
46 | N_("Flags controlling the type of regular expressions. STRING must consist of one or more of the following letters: B=basic, E=extended, I=ignore case, C=case sensitive. Default is \"EI\". The flags remain in effect until the next occurrence of --cflags option. The option must occur right before --pattern or --component option (or its alias).") }, | ||
40 | {"cc", ARG_CC, N_("STRING"), 0, | 47 | {"cc", ARG_CC, N_("STRING"), 0, |
41 | N_("Same as --component cc --pattern STRING"), 1}, | 48 | N_("Same as --component cc --pattern STRING"), 1}, |
42 | {"date", ARG_DATE, N_("STRING"), 0, | 49 | {"date", ARG_DATE, N_("STRING"), 0, |
... | @@ -50,11 +57,11 @@ static struct argp_option options[] = { | ... | @@ -50,11 +57,11 @@ static struct argp_option options[] = { |
50 | 57 | ||
51 | {N_("Date constraint operations:"), 0, NULL, OPTION_DOC, NULL, 1}, | 58 | {N_("Date constraint operations:"), 0, NULL, OPTION_DOC, NULL, 1}, |
52 | {"datefield",ARG_DATEFIELD, N_("STRING"), 0, | 59 | {"datefield",ARG_DATEFIELD, N_("STRING"), 0, |
53 | N_("Search in the named date header field (default is `Date:')"), 2}, | 60 | N_("* Search in the named date header field (default is `Date:')"), 2}, |
54 | {"after", ARG_AFTER, N_("DATE"), 0, | 61 | {"after", ARG_AFTER, N_("DATE"), 0, |
55 | N_("Match messages after the given date"), 2}, | 62 | N_("* Match messages after the given date"), 2}, |
56 | {"before", ARG_BEFORE, N_("DATE"), 0, | 63 | {"before", ARG_BEFORE, N_("DATE"), 0, |
57 | N_("Match messages before the given date"), 2}, | 64 | N_("* Match messages before the given date"), 2}, |
58 | 65 | ||
59 | {N_("Logical operations and grouping:"), 0, NULL, OPTION_DOC, NULL, 2}, | 66 | {N_("Logical operations and grouping:"), 0, NULL, OPTION_DOC, NULL, 2}, |
60 | {"and", ARG_AND, NULL, 0, | 67 | {"and", ARG_AND, NULL, 0, |
... | @@ -111,13 +118,32 @@ struct mh_option mh_option[] = { | ... | @@ -111,13 +118,32 @@ struct mh_option mh_option[] = { |
111 | {NULL} | 118 | {NULL} |
112 | }; | 119 | }; |
113 | 120 | ||
114 | static int list; | 121 | static int list = 1; |
115 | static int mode_public = 1; | 122 | static int seq_flags = 0; /* Create public sequences; |
116 | static int mode_zero = 0; | 123 | Do not zero the sequence before addition */ |
124 | static list_t seq_list; /* List of sequence names to operate upon */ | ||
125 | |||
126 | static list_t lexlist; /* List of input tokens */ | ||
127 | |||
128 | static struct obstack msgno_stk; /* Stack of selected message numbers */ | ||
129 | static size_t msgno_count; /* Number of items on the stack */ | ||
130 | |||
131 | static void | ||
132 | add_sequence (char *name) | ||
133 | { | ||
134 | if (!seq_list && list_create (&seq_list)) | ||
135 | { | ||
136 | mh_error (_("can't create sequence list")); | ||
137 | exit (1); | ||
138 | } | ||
139 | list_append (seq_list, name); | ||
140 | } | ||
117 | 141 | ||
118 | static int | 142 | static int |
119 | opt_handler (int key, char *arg, void *unused) | 143 | opt_handler (int key, char *arg, void *unused, struct argp_state *state) |
120 | { | 144 | { |
145 | char *s, *p; | ||
146 | |||
121 | switch (key) | 147 | switch (key) |
122 | { | 148 | { |
123 | case '+': | 149 | case '+': |
... | @@ -126,7 +152,8 @@ opt_handler (int key, char *arg, void *unused) | ... | @@ -126,7 +152,8 @@ opt_handler (int key, char *arg, void *unused) |
126 | break; | 152 | break; |
127 | 153 | ||
128 | case ARG_SEQUENCE: | 154 | case ARG_SEQUENCE: |
129 | /* add_sequence (arg); */ | 155 | add_sequence (arg); |
156 | list = 0; | ||
130 | break; | 157 | break; |
131 | 158 | ||
132 | case ARG_LIST: | 159 | case ARG_LIST: |
... | @@ -137,52 +164,209 @@ opt_handler (int key, char *arg, void *unused) | ... | @@ -137,52 +164,209 @@ opt_handler (int key, char *arg, void *unused) |
137 | list = 0; | 164 | list = 0; |
138 | break; | 165 | break; |
139 | 166 | ||
140 | case ARG_COMPONENT: | 167 | case ARG_COMPONENT: |
141 | case ARG_PATTERN: | 168 | pick_add_token (&lexlist, T_COMP, arg); |
142 | case ARG_CC: | 169 | break; |
170 | |||
171 | case ARG_PATTERN: | ||
172 | pick_add_token (&lexlist, T_STRING, arg); | ||
173 | break; | ||
174 | |||
175 | case ARG_CC: | ||
176 | pick_add_token (&lexlist, T_COMP, "cc"); | ||
177 | pick_add_token (&lexlist, T_STRING, arg); | ||
178 | break; | ||
179 | |||
143 | case ARG_DATE: | 180 | case ARG_DATE: |
181 | pick_add_token (&lexlist, T_COMP, "date"); | ||
182 | pick_add_token (&lexlist, T_STRING, arg); | ||
183 | break; | ||
184 | |||
144 | case ARG_FROM: | 185 | case ARG_FROM: |
186 | pick_add_token (&lexlist, T_COMP, "from"); | ||
187 | pick_add_token (&lexlist, T_STRING, arg); | ||
188 | break; | ||
189 | |||
145 | case ARG_SUBJECT: | 190 | case ARG_SUBJECT: |
146 | case ARG_TO: | 191 | pick_add_token (&lexlist, T_COMP, "subject"); |
192 | pick_add_token (&lexlist, T_STRING, arg); | ||
193 | break; | ||
194 | |||
195 | case ARG_TO: | ||
196 | pick_add_token (&lexlist, T_COMP, "to"); | ||
197 | pick_add_token (&lexlist, T_STRING, arg); | ||
198 | break; | ||
199 | |||
147 | case ARG_DATEFIELD: | 200 | case ARG_DATEFIELD: |
201 | pick_add_token (&lexlist, T_DATEFIELD, arg); | ||
202 | break; | ||
203 | |||
148 | case ARG_AFTER: | 204 | case ARG_AFTER: |
205 | pick_add_token (&lexlist, T_AFTER, NULL); | ||
206 | pick_add_token (&lexlist, T_STRING, arg); | ||
207 | break; | ||
208 | |||
149 | case ARG_BEFORE: | 209 | case ARG_BEFORE: |
210 | pick_add_token (&lexlist, T_BEFORE, NULL); | ||
211 | pick_add_token (&lexlist, T_STRING, arg); | ||
212 | break; | ||
213 | |||
150 | case ARG_AND: | 214 | case ARG_AND: |
215 | pick_add_token (&lexlist, T_AND, NULL); | ||
216 | break; | ||
217 | |||
151 | case ARG_OR: | 218 | case ARG_OR: |
219 | pick_add_token (&lexlist, T_OR, NULL); | ||
220 | break; | ||
221 | |||
152 | case ARG_NOT: | 222 | case ARG_NOT: |
223 | pick_add_token (&lexlist, T_NOT, NULL); | ||
224 | break; | ||
225 | |||
153 | case ARG_LBRACE: | 226 | case ARG_LBRACE: |
227 | pick_add_token (&lexlist, T_LBRACE, NULL); | ||
228 | break; | ||
229 | |||
154 | case ARG_RBRACE: | 230 | case ARG_RBRACE: |
231 | pick_add_token (&lexlist, T_RBRACE, NULL); | ||
232 | break; | ||
233 | |||
234 | case ARG_CFLAGS: | ||
235 | pick_add_token (&lexlist, T_CFLAGS, arg); | ||
155 | break; | 236 | break; |
156 | 237 | ||
157 | case ARG_PUBLIC: | 238 | case ARG_PUBLIC: |
158 | mode_public = is_true (arg); | 239 | if (is_true (arg)) |
240 | seq_flags &= ~SEQ_PRIVATE; | ||
241 | else | ||
242 | seq_flags |= SEQ_PRIVATE; | ||
159 | break; | 243 | break; |
160 | 244 | ||
161 | case ARG_NOPUBLIC: | 245 | case ARG_NOPUBLIC: |
162 | mode_public = 0; | 246 | seq_flags |= SEQ_PRIVATE; |
163 | break; | 247 | break; |
164 | 248 | ||
165 | case ARG_ZERO: | 249 | case ARG_ZERO: |
166 | mode_zero = is_true (arg); | 250 | if (is_true (arg)) |
251 | seq_flags |= SEQ_ZERO; | ||
252 | else | ||
253 | seq_flags &= ~SEQ_ZERO; | ||
167 | break; | 254 | break; |
168 | 255 | ||
169 | case ARG_NOZERO: | 256 | case ARG_NOZERO: |
170 | mode_zero = 0; | 257 | seq_flags &= ~SEQ_ZERO; |
258 | break; | ||
259 | |||
260 | case ARGP_KEY_ERROR: | ||
261 | s = state->argv[state->next - 1]; | ||
262 | if (memcmp (s, "--", 2)) | ||
263 | { | ||
264 | argp_error (state, _("invalid option -- %s"), s); | ||
265 | exit (1); | ||
266 | } | ||
267 | p = strchr (s, '='); | ||
268 | if (p) | ||
269 | *p++ = 0; | ||
270 | |||
271 | pick_add_token (&lexlist, T_COMP, s + 2); | ||
272 | |||
273 | if (!p) | ||
274 | { | ||
275 | if (state->next == state->argc) | ||
276 | { | ||
277 | mh_error (_("invalid option -- %s"), s); | ||
278 | exit (1); | ||
279 | } | ||
280 | p = state->argv[state->next++]; | ||
281 | } | ||
282 | |||
283 | pick_add_token (&lexlist, T_STRING, p); | ||
171 | break; | 284 | break; |
172 | 285 | ||
173 | default: | 286 | default: |
174 | return 1; | 287 | return 1; |
175 | } | 288 | } |
289 | |||
176 | return 0; | 290 | return 0; |
177 | } | 291 | } |
178 | 292 | ||
293 | void | ||
294 | pick_message (mailbox_t mbox, message_t msg, size_t num, void *data) | ||
295 | { | ||
296 | if (pick_eval (msg)) | ||
297 | { | ||
298 | mh_message_number (msg, &num); | ||
299 | if (list) | ||
300 | printf ("%lu\n", (unsigned long) num); | ||
301 | if (seq_list) | ||
302 | { | ||
303 | obstack_grow (&msgno_stk, &num, sizeof (num)); | ||
304 | msgno_count++; | ||
305 | } | ||
306 | } | ||
307 | } | ||
308 | |||
309 | static int | ||
310 | action_add (void *item, void *data) | ||
311 | { | ||
312 | mh_seq_add ((char *)item, (mh_msgset_t *)data, seq_flags); | ||
313 | return 0; | ||
314 | } | ||
315 | |||
316 | /* NOTICE: For the compatibility with the RAND MH we have to support | ||
317 | the following command line syntax: | ||
318 | |||
319 | --FIELD STRING | ||
320 | |||
321 | where `FIELD' may be any string and which is equivalent to | ||
322 | `--field FIELD --pattern STRING'. Obviously this is in conflict | ||
323 | with the usual GNU long options paradigm which requires that any | ||
324 | unrecognized long option produce an error. Unfortunately, mh-pick.el | ||
325 | relies heavily on this syntax, so it can't be simply removed. | ||
326 | The approach taken here allows to properly recognize such syntax, | ||
327 | however it has an undesirable side effect: due to the specifics of | ||
328 | the underlying arpg library the --help and --usage options get | ||
329 | disabled. To make them work as well, the following approach is | ||
330 | taken: the mh-compatible syntax gets enabled only if the file | ||
331 | descriptor of stdin is not connected to a terminal, which is true | ||
332 | when invoked from mh-pick.el module. Otherwise, it is disabled | ||
333 | and the standard GNU long option syntax is in force. */ | ||
179 | int | 334 | int |
180 | main (int argc, char **argv) | 335 | main (int argc, char **argv) |
181 | { | 336 | { |
337 | int status; | ||
182 | int index; | 338 | int index; |
339 | mailbox_t mbox; | ||
340 | mh_msgset_t msgset; | ||
341 | int flags; | ||
183 | 342 | ||
343 | flags = isatty (0) ? 0 : ARGP_NO_ERRS; | ||
184 | mu_init_nls (); | 344 | mu_init_nls (); |
185 | mh_argp_parse (argc, argv, options, mh_option, args_doc, doc, | 345 | mh_argp_parse (argc, argv, flags, options, mh_option, |
186 | opt_handler, NULL, &index); | 346 | args_doc, doc, opt_handler, NULL, &index); |
347 | if (pick_parse (lexlist)) | ||
348 | return 1; | ||
349 | |||
350 | mbox = mh_open_folder (current_folder, 0); | ||
351 | |||
352 | argc -= index; | ||
353 | argv += index; | ||
354 | |||
355 | if (seq_list) | ||
356 | obstack_init (&msgno_stk); | ||
357 | |||
358 | mh_msgset_parse (mbox, &msgset, argc, argv, "all"); | ||
359 | status = mh_iterate (mbox, &msgset, pick_message, NULL); | ||
360 | |||
361 | if (seq_list) | ||
362 | { | ||
363 | mh_msgset_t msgset; | ||
364 | msgset.count = msgno_count; | ||
365 | msgset.list = obstack_finish (&msgno_stk); | ||
366 | list_do (seq_list, action_add, (void*) &msgset); | ||
367 | } | ||
368 | |||
369 | mh_global_save_state (); | ||
370 | return status; | ||
187 | } | 371 | } |
188 | 372 | ... | ... |
-
Please register or sign in to post a comment