summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mh/pick.c220
1 files changed, 202 insertions, 18 deletions
diff --git a/mh/pick.c b/mh/pick.c
index 3c060500c..a9de6e540 100644
--- a/mh/pick.c
+++ b/mh/pick.c
@@ -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:
@@ -137,52 +164,209 @@ opt_handler (int key, char *arg, void *unused)
list = 0;
break;
- case ARG_COMPONENT:
- case ARG_PATTERN:
- case ARG_CC:
+ 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:
- case ARG_TO:
+ 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;
}

Return to:

Send suggestions and report system problems to the System administrator.