Commit 256e0eb6 256e0eb62991288b84d9e852e82c2911699316b1 by Sergey Poznyakoff

Implemented

1 parent fc77c565
Showing 1 changed file with 198 additions and 14 deletions
......@@ -19,6 +19,11 @@
#include <mh.h>
#include <regex.h>
#include <pick.h>
#include <pick-gram.h>
#define obstack_chunk_alloc malloc
#define obstack_chunk_free free
#include <obstack.h>
const char *argp_program_version = "pick (" PACKAGE_STRING ")";
static char doc[] = N_("GNU MH pick\v"
......@@ -37,6 +42,8 @@ static struct argp_option options[] = {
{"pattern", ARG_PATTERN, N_("STRING"), 0,
N_("A pattern to look for"), 1},
{"search", 0, NULL, OPTION_ALIAS, NULL, 1},
{"cflags", ARG_CFLAGS, N_("STRING"), 0,
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).") },
{"cc", ARG_CC, N_("STRING"), 0,
N_("Same as --component cc --pattern STRING"), 1},
{"date", ARG_DATE, N_("STRING"), 0,
......@@ -50,11 +57,11 @@ static struct argp_option options[] = {
{N_("Date constraint operations:"), 0, NULL, OPTION_DOC, NULL, 1},
{"datefield",ARG_DATEFIELD, N_("STRING"), 0,
N_("Search in the named date header field (default is `Date:')"), 2},
N_("* Search in the named date header field (default is `Date:')"), 2},
{"after", ARG_AFTER, N_("DATE"), 0,
N_("Match messages after the given date"), 2},
N_("* Match messages after the given date"), 2},
{"before", ARG_BEFORE, N_("DATE"), 0,
N_("Match messages before the given date"), 2},
N_("* Match messages before the given date"), 2},
{N_("Logical operations and grouping:"), 0, NULL, OPTION_DOC, NULL, 2},
{"and", ARG_AND, NULL, 0,
......@@ -111,13 +118,32 @@ struct mh_option mh_option[] = {
{NULL}
};
static int list;
static int mode_public = 1;
static int mode_zero = 0;
static int list = 1;
static int seq_flags = 0; /* Create public sequences;
Do not zero the sequence before addition */
static list_t seq_list; /* List of sequence names to operate upon */
static list_t lexlist; /* List of input tokens */
static struct obstack msgno_stk; /* Stack of selected message numbers */
static size_t msgno_count; /* Number of items on the stack */
static void
add_sequence (char *name)
{
if (!seq_list && list_create (&seq_list))
{
mh_error (_("can't create sequence list"));
exit (1);
}
list_append (seq_list, name);
}
static int
opt_handler (int key, char *arg, void *unused)
opt_handler (int key, char *arg, void *unused, struct argp_state *state)
{
char *s, *p;
switch (key)
{
case '+':
......@@ -126,7 +152,8 @@ opt_handler (int key, char *arg, void *unused)
break;
case ARG_SEQUENCE:
/* add_sequence (arg); */
add_sequence (arg);
list = 0;
break;
case ARG_LIST:
......@@ -138,51 +165,208 @@ opt_handler (int key, char *arg, void *unused)
break;
case ARG_COMPONENT:
pick_add_token (&lexlist, T_COMP, arg);
break;
case ARG_PATTERN:
pick_add_token (&lexlist, T_STRING, arg);
break;
case ARG_CC:
pick_add_token (&lexlist, T_COMP, "cc");
pick_add_token (&lexlist, T_STRING, arg);
break;
case ARG_DATE:
pick_add_token (&lexlist, T_COMP, "date");
pick_add_token (&lexlist, T_STRING, arg);
break;
case ARG_FROM:
pick_add_token (&lexlist, T_COMP, "from");
pick_add_token (&lexlist, T_STRING, arg);
break;
case ARG_SUBJECT:
pick_add_token (&lexlist, T_COMP, "subject");
pick_add_token (&lexlist, T_STRING, arg);
break;
case ARG_TO:
pick_add_token (&lexlist, T_COMP, "to");
pick_add_token (&lexlist, T_STRING, arg);
break;
case ARG_DATEFIELD:
pick_add_token (&lexlist, T_DATEFIELD, arg);
break;
case ARG_AFTER:
pick_add_token (&lexlist, T_AFTER, NULL);
pick_add_token (&lexlist, T_STRING, arg);
break;
case ARG_BEFORE:
pick_add_token (&lexlist, T_BEFORE, NULL);
pick_add_token (&lexlist, T_STRING, arg);
break;
case ARG_AND:
pick_add_token (&lexlist, T_AND, NULL);
break;
case ARG_OR:
pick_add_token (&lexlist, T_OR, NULL);
break;
case ARG_NOT:
pick_add_token (&lexlist, T_NOT, NULL);
break;
case ARG_LBRACE:
pick_add_token (&lexlist, T_LBRACE, NULL);
break;
case ARG_RBRACE:
pick_add_token (&lexlist, T_RBRACE, NULL);
break;
case ARG_CFLAGS:
pick_add_token (&lexlist, T_CFLAGS, arg);
break;
case ARG_PUBLIC:
mode_public = is_true (arg);
if (is_true (arg))
seq_flags &= ~SEQ_PRIVATE;
else
seq_flags |= SEQ_PRIVATE;
break;
case ARG_NOPUBLIC:
mode_public = 0;
seq_flags |= SEQ_PRIVATE;
break;
case ARG_ZERO:
mode_zero = is_true (arg);
if (is_true (arg))
seq_flags |= SEQ_ZERO;
else
seq_flags &= ~SEQ_ZERO;
break;
case ARG_NOZERO:
mode_zero = 0;
seq_flags &= ~SEQ_ZERO;
break;
case ARGP_KEY_ERROR:
s = state->argv[state->next - 1];
if (memcmp (s, "--", 2))
{
argp_error (state, _("invalid option -- %s"), s);
exit (1);
}
p = strchr (s, '=');
if (p)
*p++ = 0;
pick_add_token (&lexlist, T_COMP, s + 2);
if (!p)
{
if (state->next == state->argc)
{
mh_error (_("invalid option -- %s"), s);
exit (1);
}
p = state->argv[state->next++];
}
pick_add_token (&lexlist, T_STRING, p);
break;
default:
return 1;
}
return 0;
}
void
pick_message (mailbox_t mbox, message_t msg, size_t num, void *data)
{
if (pick_eval (msg))
{
mh_message_number (msg, &num);
if (list)
printf ("%lu\n", (unsigned long) num);
if (seq_list)
{
obstack_grow (&msgno_stk, &num, sizeof (num));
msgno_count++;
}
}
}
static int
action_add (void *item, void *data)
{
mh_seq_add ((char *)item, (mh_msgset_t *)data, seq_flags);
return 0;
}
/* NOTICE: For the compatibility with the RAND MH we have to support
the following command line syntax:
--FIELD STRING
where `FIELD' may be any string and which is equivalent to
`--field FIELD --pattern STRING'. Obviously this is in conflict
with the usual GNU long options paradigm which requires that any
unrecognized long option produce an error. Unfortunately, mh-pick.el
relies heavily on this syntax, so it can't be simply removed.
The approach taken here allows to properly recognize such syntax,
however it has an undesirable side effect: due to the specifics of
the underlying arpg library the --help and --usage options get
disabled. To make them work as well, the following approach is
taken: the mh-compatible syntax gets enabled only if the file
descriptor of stdin is not connected to a terminal, which is true
when invoked from mh-pick.el module. Otherwise, it is disabled
and the standard GNU long option syntax is in force. */
int
main (int argc, char **argv)
{
int status;
int index;
mailbox_t mbox;
mh_msgset_t msgset;
int flags;
flags = isatty (0) ? 0 : ARGP_NO_ERRS;
mu_init_nls ();
mh_argp_parse (argc, argv, options, mh_option, args_doc, doc,
opt_handler, NULL, &index);
mh_argp_parse (argc, argv, flags, options, mh_option,
args_doc, doc, opt_handler, NULL, &index);
if (pick_parse (lexlist))
return 1;
mbox = mh_open_folder (current_folder, 0);
argc -= index;
argv += index;
if (seq_list)
obstack_init (&msgno_stk);
mh_msgset_parse (mbox, &msgset, argc, argv, "all");
status = mh_iterate (mbox, &msgset, pick_message, NULL);
if (seq_list)
{
mh_msgset_t msgset;
msgset.count = msgno_count;
msgset.list = obstack_finish (&msgno_stk);
list_do (seq_list, action_add, (void*) &msgset);
}
mh_global_save_state ();
return status;
}
......