19 |
|
|
20 |
#include <mh.h> |
#include <mh.h> |
21 |
#include <regex.h> |
#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> |
27 |
|
|
28 |
const char *argp_program_version = "pick (" PACKAGE_STRING ")"; |
const char *argp_program_version = "pick (" PACKAGE_STRING ")"; |
29 |
static char doc[] = N_("GNU MH pick\v" |
static char doc[] = N_("GNU MH pick\v" |
42 |
{"pattern", ARG_PATTERN, N_("STRING"), 0, |
{"pattern", ARG_PATTERN, N_("STRING"), 0, |
43 |
N_("A pattern to look for"), 1}, |
N_("A pattern to look for"), 1}, |
44 |
{"search", 0, NULL, OPTION_ALIAS, NULL, 1}, |
{"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).") }, |
47 |
{"cc", ARG_CC, N_("STRING"), 0, |
{"cc", ARG_CC, N_("STRING"), 0, |
48 |
N_("Same as --component cc --pattern STRING"), 1}, |
N_("Same as --component cc --pattern STRING"), 1}, |
49 |
{"date", ARG_DATE, N_("STRING"), 0, |
{"date", ARG_DATE, N_("STRING"), 0, |
57 |
|
|
58 |
{N_("Date constraint operations:"), 0, NULL, OPTION_DOC, NULL, 1}, |
{N_("Date constraint operations:"), 0, NULL, OPTION_DOC, NULL, 1}, |
59 |
{"datefield",ARG_DATEFIELD, N_("STRING"), 0, |
{"datefield",ARG_DATEFIELD, N_("STRING"), 0, |
60 |
N_("Search in the named date header field (default is `Date:')"), 2}, |
N_("* Search in the named date header field (default is `Date:')"), 2}, |
61 |
{"after", ARG_AFTER, N_("DATE"), 0, |
{"after", ARG_AFTER, N_("DATE"), 0, |
62 |
N_("Match messages after the given date"), 2}, |
N_("* Match messages after the given date"), 2}, |
63 |
{"before", ARG_BEFORE, N_("DATE"), 0, |
{"before", ARG_BEFORE, N_("DATE"), 0, |
64 |
N_("Match messages before the given date"), 2}, |
N_("* Match messages before the given date"), 2}, |
65 |
|
|
66 |
{N_("Logical operations and grouping:"), 0, NULL, OPTION_DOC, NULL, 2}, |
{N_("Logical operations and grouping:"), 0, NULL, OPTION_DOC, NULL, 2}, |
67 |
{"and", ARG_AND, NULL, 0, |
{"and", ARG_AND, NULL, 0, |
118 |
{NULL} |
{NULL} |
119 |
}; |
}; |
120 |
|
|
121 |
static int list; |
static int list = 1; |
122 |
static int mode_public = 1; |
static int seq_flags = 0; /* Create public sequences; |
123 |
static int mode_zero = 0; |
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 |
|
} |
141 |
|
|
142 |
static int |
static int |
143 |
opt_handler (int key, char *arg, void *unused) |
opt_handler (int key, char *arg, void *unused, struct argp_state *state) |
144 |
{ |
{ |
145 |
|
char *s, *p; |
146 |
|
|
147 |
switch (key) |
switch (key) |
148 |
{ |
{ |
149 |
case '+': |
case '+': |
152 |
break; |
break; |
153 |
|
|
154 |
case ARG_SEQUENCE: |
case ARG_SEQUENCE: |
155 |
/* add_sequence (arg); */ |
add_sequence (arg); |
156 |
|
list = 0; |
157 |
break; |
break; |
158 |
|
|
159 |
case ARG_LIST: |
case ARG_LIST: |
164 |
list = 0; |
list = 0; |
165 |
break; |
break; |
166 |
|
|
167 |
case ARG_COMPONENT: |
case ARG_COMPONENT: |
168 |
case ARG_PATTERN: |
pick_add_token (&lexlist, T_COMP, arg); |
169 |
case ARG_CC: |
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 |
|
|
180 |
case ARG_DATE: |
case ARG_DATE: |
181 |
|
pick_add_token (&lexlist, T_COMP, "date"); |
182 |
|
pick_add_token (&lexlist, T_STRING, arg); |
183 |
|
break; |
184 |
|
|
185 |
case ARG_FROM: |
case ARG_FROM: |
186 |
|
pick_add_token (&lexlist, T_COMP, "from"); |
187 |
|
pick_add_token (&lexlist, T_STRING, arg); |
188 |
|
break; |
189 |
|
|
190 |
case ARG_SUBJECT: |
case ARG_SUBJECT: |
191 |
case ARG_TO: |
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 |
|
|
200 |
case ARG_DATEFIELD: |
case ARG_DATEFIELD: |
201 |
|
pick_add_token (&lexlist, T_DATEFIELD, arg); |
202 |
|
break; |
203 |
|
|
204 |
case ARG_AFTER: |
case ARG_AFTER: |
205 |
|
pick_add_token (&lexlist, T_AFTER, NULL); |
206 |
|
pick_add_token (&lexlist, T_STRING, arg); |
207 |
|
break; |
208 |
|
|
209 |
case ARG_BEFORE: |
case ARG_BEFORE: |
210 |
|
pick_add_token (&lexlist, T_BEFORE, NULL); |
211 |
|
pick_add_token (&lexlist, T_STRING, arg); |
212 |
|
break; |
213 |
|
|
214 |
case ARG_AND: |
case ARG_AND: |
215 |
|
pick_add_token (&lexlist, T_AND, NULL); |
216 |
|
break; |
217 |
|
|
218 |
case ARG_OR: |
case ARG_OR: |
219 |
|
pick_add_token (&lexlist, T_OR, NULL); |
220 |
|
break; |
221 |
|
|
222 |
case ARG_NOT: |
case ARG_NOT: |
223 |
|
pick_add_token (&lexlist, T_NOT, NULL); |
224 |
|
break; |
225 |
|
|
226 |
case ARG_LBRACE: |
case ARG_LBRACE: |
227 |
|
pick_add_token (&lexlist, T_LBRACE, NULL); |
228 |
|
break; |
229 |
|
|
230 |
case ARG_RBRACE: |
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); |
236 |
break; |
break; |
237 |
|
|
238 |
case ARG_PUBLIC: |
case ARG_PUBLIC: |
239 |
mode_public = is_true (arg); |
if (is_true (arg)) |
240 |
|
seq_flags &= ~SEQ_PRIVATE; |
241 |
|
else |
242 |
|
seq_flags |= SEQ_PRIVATE; |
243 |
break; |
break; |
244 |
|
|
245 |
case ARG_NOPUBLIC: |
case ARG_NOPUBLIC: |
246 |
mode_public = 0; |
seq_flags |= SEQ_PRIVATE; |
247 |
break; |
break; |
248 |
|
|
249 |
case ARG_ZERO: |
case ARG_ZERO: |
250 |
mode_zero = is_true (arg); |
if (is_true (arg)) |
251 |
|
seq_flags |= SEQ_ZERO; |
252 |
|
else |
253 |
|
seq_flags &= ~SEQ_ZERO; |
254 |
break; |
break; |
255 |
|
|
256 |
case ARG_NOZERO: |
case ARG_NOZERO: |
257 |
mode_zero = 0; |
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); |
284 |
break; |
break; |
285 |
|
|
286 |
default: |
default: |
287 |
return 1; |
return 1; |
288 |
} |
} |
289 |
|
|
290 |
|
return 0; |
291 |
|
} |
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; |
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. */ |
334 |
int |
int |
335 |
main (int argc, char **argv) |
main (int argc, char **argv) |
336 |
{ |
{ |
337 |
|
int status; |
338 |
int index; |
int index; |
339 |
|
mailbox_t mbox; |
340 |
|
mh_msgset_t msgset; |
341 |
|
int flags; |
342 |
|
|
343 |
|
flags = isatty (0) ? 0 : ARGP_NO_ERRS; |
344 |
mu_init_nls (); |
mu_init_nls (); |
345 |
mh_argp_parse (argc, argv, options, mh_option, args_doc, doc, |
mh_argp_parse (argc, argv, flags, options, mh_option, |
346 |
opt_handler, NULL, &index); |
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; |
371 |
} |
} |
372 |
|
|