Commit e34d8c16 e34d8c168f9031dbfc2441006e0eb24182ef4389 by Sergey Poznyakoff

mh: fix msgset parser and some more comp compatibility issues; provide testsuite for comp.

* mh/Makefile.am (bin_PROGRAMS): Add mhseq.
* mh/comp.c (main): Rewrite to fix compatibility issues.
* mh/mh.h (MH_MSGSET_UID): New define.
(mh_msgset_t) <flags,size>: New members.
* mh/mh_init.c (mh_draft_message): Bugfix: convert msgset to UIDs.
* mh/mh_msgset.c: Rewrite from scratch.

* mh/tests/comp.at: New file.
* mh/tests/mhseq.at: New file.
* mh/tests/Makefile.am (TESTSUITE_AT): Add comp.at, mhseq.at.
* mh/tests/testsuite.at: Include comp.at and mhseq.at.

* libmailutils/property/mhprop.c (_mh_prop_read_stream): Minor fix.
Do remove empty lines.
* mh/mh_whatnow.c (_whatnow): Detect EOF.
(call_send): Quit after successful send.
1 parent e6927c46
......@@ -113,7 +113,7 @@ _mh_prop_read_stream (mu_header_t *phdr, mu_stream_t stream)
argv[1] = "#";
argv[2] = "-r";
argv[3] = NULL;
rc = mu_filter_create_args (&flt, stream, argv[0], 2, argv,
rc = mu_filter_create_args (&flt, stream, argv[0], 3, argv,
MU_FILTER_DECODE, MU_STREAM_READ);
if (rc)
{
......
......@@ -23,6 +23,7 @@ mh_alias_lex.c
mh_fmtgram.c
mhl
mhn
mhseq
mhparam
mhpath
pick
......
......@@ -33,6 +33,7 @@ bin_PROGRAMS = \
mhn\
mhparam\
mhpath\
mhseq\
pick\
prompter\
refile\
......
......@@ -80,6 +80,7 @@ static int build_only = 0; /* --build flag */
static int use_draft = 0; /* --use flag */
static char *draftmessage = "new";
static const char *draftfolder = NULL;
static int folder_set; /* Folder is set on the command line */
static error_t
opt_handler (int key, char *arg, struct argp_state *state)
......@@ -87,8 +88,7 @@ opt_handler (int key, char *arg, struct argp_state *state)
switch (key)
{
case ARGP_KEY_INIT:
draftfolder = mh_global_profile_get ("Draft-Folder",
mu_folder_directory ());
draftfolder = mh_global_profile_get ("Draft-Folder", NULL);
whatnowproc = mh_global_profile_get ("whatnowproc", NULL);
break;
......@@ -106,6 +106,7 @@ opt_handler (int key, char *arg, struct argp_state *state)
case ARG_FOLDER:
mh_set_current_folder (arg);
folder_set = 1;
break;
case ARG_FORM:
......@@ -126,7 +127,7 @@ opt_handler (int key, char *arg, struct argp_state *state)
break;
case ARG_FILE:
wh_env.draftfile = mh_expand_name (NULL, arg, 0);
wh_env.file = mh_expand_name (NULL, arg, 0);
break;
case ARG_NODRAFTFOLDER:
......@@ -197,7 +198,7 @@ main (int argc, char **argv)
mh_argp_parse (&argc, &argv, 0, options, mh_option, args_doc, doc,
opt_handler, NULL, &index);
if (wh_env.draftfile)
if (wh_env.file)
{
if (build_only)
{
......@@ -205,51 +206,60 @@ main (int argc, char **argv)
exit (1);
}
}
else if (folder_set)
{
wh_env.file = mh_expand_name (NULL, "draft", 0);
}
else
{
if (build_only || !draftfolder)
{
switch (argc - index)
{
case 0:
wh_env.file = mh_expand_name (NULL, "draft", 0);
break;
case 1:
wh_env.file = mh_expand_name (NULL, argv[index], 0);
break;
default:
mu_error (_("only one message at a time!"));
return 1;
}
}
else if (draftfolder)
{
/* Comp accepts a `file', and it will, if given
`-draftfolder +folder' treat this arguments as `msg'. */
if (index < argc)
if (use_draft || index < argc)
{
mh_msgset_t msgset;
mu_mailbox_t mbox;
mbox = mh_open_folder (draftfolder, 1);
mh_msgset_parse (mbox, &msgset, argc - index, argv + index,
"new");
mh_msgset_parse (mbox, &msgset,
argc - index, argv + index,
use_draft ? "cur" : "new");
mu_mailbox_destroy (&mbox);
if (msgset.count != 1)
{
mu_error (_("only one message at a time!"));
return 1;
}
mh_msgset_uids (mbox, &msgset);
draftmessage = mu_umaxtostr (0, msgset.list[0]);
mh_msgset_free (&msgset);
index = argc;
}
if (mh_draft_message (draftfolder, draftmessage,
&wh_env.file))
return 1;
}
wh_env.draftfile = wh_env.file;
}
wh_env.draftfile = wh_env.file;
switch (check_draft_disposition (&wh_env, use_draft))
{
case DISP_QUIT:
exit (0);
case DISP_USE:
break;
case DISP_REPLACE:
unlink (wh_env.draftfile);
if (index < argc)
if (folder_set && index < argc)
{
mh_msgset_t msgset;
mu_mailbox_t mbox;
......@@ -261,13 +271,26 @@ main (int argc, char **argv)
mu_error (_("only one message at a time!"));
return 1;
}
unlink (wh_env.file);
copy_message (mbox, msgset.list[0], wh_env.file);
mu_mailbox_destroy (&mbox);
mh_msgset_free (&msgset);
}
else
{
switch (check_draft_disposition (&wh_env, use_draft))
{
case DISP_QUIT:
exit (0);
case DISP_USE:
break;
case DISP_REPLACE:
unlink (wh_env.draftfile);
mh_comp_draft (formfile, "components", wh_env.file);
}
}
/* Exit immediately if --build is given */
if (build_only)
......
......@@ -195,10 +195,14 @@ typedef struct
mu_header_t header;
} mh_context_t;
#define MH_MSGSET_UID 0x01
typedef struct
{
size_t count;
int flags;
size_t *list;
size_t count;
size_t size;
} mh_msgset_t;
typedef void (*mh_iterator_fp) (mu_mailbox_t mbox, mu_message_t msg,
......@@ -300,7 +304,7 @@ int mh_message_number (mu_message_t msg, size_t *pnum);
mu_mailbox_t mh_open_folder (const char *folder, int create);
int mh_msgset_parse (mu_mailbox_t mbox, mh_msgset_t *msgset,
void mh_msgset_parse (mu_mailbox_t mbox, mh_msgset_t *msgset,
int argc, char **argv, char *def);
int mh_msgset_member (mh_msgset_t *msgset, size_t num);
void mh_msgset_reverse (mh_msgset_t *msgset);
......
......@@ -998,14 +998,14 @@ mh_draft_message (const char *name, const char *msgspec, char **pname)
argv[0] = (char*) msgspec;
argv[1] = NULL;
rc = mh_msgset_parse (mbox, &msgset, 1, argv, "cur");
if (rc)
mu_error (_("invalid message number: %s"), msgspec);
else if (msgset.count > 1)
mh_msgset_parse (mbox, &msgset, 1, argv, "cur");
if (msgset.count > 1)
mu_error (_("only one message at a time!"));
else
{
mh_msgset_uids (mbox, &msgset);
uid = msgset.list[0];
}
mh_msgset_free (&msgset);
}
......
......@@ -19,234 +19,316 @@
#include <mh.h>
/* Expand a message set (msgcnt;msglist) to accomodate `inc' more
elements */
static void
_expand (size_t *msgcnt, size_t **msglist, size_t inc)
int
mh_uid_to_msgno (mu_mailbox_t mbox, size_t uid, size_t *msgno)
{
if (!inc)
return;
*msgcnt += inc;
*msglist = realloc (*msglist, (*msgcnt)*sizeof(**msglist));
if (!*msglist)
mh_err_memory (1);
size_t num = mh_get_message (mbox, uid, NULL);
if (num == 0)
return MU_ERR_NOENT;
*msgno = num;
return 0;
}
/* Fatal error handler */
static void
msgset_abort (const char *arg)
int
mh_msgno_to_uid (mu_mailbox_t mbox, size_t msgno, size_t *uid)
{
mu_error (_("bad message list `%s'"), arg);
exit (1);
mu_message_t msg;
int rc = mu_mailbox_get_message (mbox, msgno, &msg);
if (rc)
return rc;
return mu_message_get_uid (msg, uid);
}
/* Handlers for expansion of the reserved message names */
static int
msgset_first (mu_mailbox_t mbox, size_t *pnum)
void
mh_msgset_init (mh_msgset_t *msgset)
{
*pnum = 1;
return 0;
memset (msgset, 0, sizeof (*msgset));
}
static int
msgset_last (mu_mailbox_t mbox, size_t *pnum)
void
mh_msgset_expand (mh_msgset_t *msgset, size_t count)
{
int rc;
size_t count = 0;
size_t rest = msgset->size - msgset->count;
rc = mu_mailbox_messages_count (mbox, &count);
if (rc)
if (rest < count)
{
mu_error (_("cannot get last message: %s"), mu_strerror (rc));
exit (1);
msgset->size += count;
msgset->list = xrealloc (msgset->list,
msgset->size * sizeof (msgset->list[0]));
}
*pnum = count;
return 0;
}
void
mh_msgset_add (mh_msgset_t *msgset, size_t n)
{
mh_msgset_expand (msgset, 1);
msgset->list[msgset->count++] = n;
}
static int
msgset_cur (mu_mailbox_t mbox, size_t *pnum)
comp_mesg (const void *a, const void *b)
{
size_t i, count = 0;
static int cached_n = 0;
size_t cur;
size_t an = *(size_t*)a;
size_t bn = *(size_t*)b;
if (an > bn)
return 1;
else if (an < bn)
return -1;
return 0;
}
void
mh_msgset_optimize (mh_msgset_t *msgset)
{
size_t i, msgno;
size_t msgcnt = msgset->count;
size_t *msglist = msgset->list;
mh_mailbox_get_cur (mbox, &cur);
/* Sort the resulting message set */
qsort (msglist, msgcnt, sizeof (*msgset->list), comp_mesg);
if (cached_n)
{
*pnum = cached_n;
/* Remove duplicates. */
for (i = 0, msgno = 1; i < msgset->count; i++)
if (msglist[msgno-1] != msglist[i])
msglist[msgno++] = msglist[i];
msgset->count = msgno;
}
/* Check if message with ordinal number `num' is contained in the
message set. */
int
mh_msgset_member (mh_msgset_t *msgset, size_t num)
{
size_t i;
for (i = 0; i < msgset->count; i++)
if (msgset->list[i] == num)
return i + 1;
return 0;
}
}
mu_mailbox_messages_count (mbox, &count);
for (i = 1; i <= count; i++)
{
mu_message_t msg = NULL;
size_t uid = 0;
/* Reverse the order of messages in the message set */
void
mh_msgset_reverse (mh_msgset_t *msgset)
{
int head, tail;
mu_mailbox_get_message (mbox, i, &msg);
mh_message_number (msg, &uid);
if (uid == cur)
for (head = 0, tail = msgset->count-1; head < tail; head++, tail--)
{
*pnum = cached_n = i;
return 0;
}
size_t val = msgset->list[head];
msgset->list[head] = msgset->list[tail];
msgset->list[tail] = val;
}
mu_error (_("no cur message"));
exit (1);
}
static int
msgset_prev (mu_mailbox_t mbox, size_t *pnum)
/* Set the current message to that contained at position `index'
in the given message set */
void
mh_msgset_current (mu_mailbox_t mbox, mh_msgset_t *msgset, int index)
{
size_t cur_n = 0;
msgset_cur (mbox, &cur_n);
if (cur_n < 1)
mu_message_t msg = NULL;
int rc;
size_t cur;
rc = mu_mailbox_get_message (mbox, msgset->list[index], &msg);
if (rc)
{
mu_error (_("no prev message"));
mu_diag_funcall (MU_DIAG_ERROR, "mu_mailbox_get_message", NULL, rc);
exit (1);
}
*pnum = cur_n - 1;
return 0;
mh_message_number (msg, &cur);
mh_mailbox_set_cur (mbox, cur);
}
static int
msgset_next (mu_mailbox_t mbox, size_t *pnum)
/* Free memory allocated for the message set. Note, that the msgset
itself is supposed to reside in the statically allocated memory and
therefore is not freed */
void
mh_msgset_free (mh_msgset_t *msgset)
{
size_t cur_n = 0, total = 0;
msgset_cur (mbox, &cur_n);
if (msgset->count)
free (msgset->list);
}
/* Negate the message set: on return `msgset' consists of the messages
_not contained_ in the input message set. Any memory associated with
the input message set is freed */
void
mh_msgset_negate (mu_mailbox_t mbox, mh_msgset_t *msgset)
{
size_t i, total = 0, msgno;
size_t *list;
mu_mailbox_messages_count (mbox, &total);
if (cur_n + 1 > total)
list = calloc (total, sizeof (list[0]));
if (!list)
mh_err_memory (1);
for (i = 1, msgno = 0; i <= total; i++)
{
mu_error (_("no next message"));
exit (1);
if (!mh_msgset_member (msgset, i))
list[msgno++] = i;
}
*pnum = cur_n + 1;
return 0;
}
static struct msgset_keyword {
char *name;
int (*handler) (mu_mailbox_t mbox, size_t *pnum);
} keywords[] = {
{ "first", msgset_first },
{ "last", msgset_last },
{ "prev", msgset_prev },
{ "next", msgset_next },
{ "cur", msgset_cur },
{ NULL },
};
list = realloc (list, sizeof (list[0]) * msgno);
if (!list)
{
mu_error (_("not enough memory"));
abort ();
}
mh_msgset_free (msgset);
msgset->count = msgno;
msgset->list = list;
}
/* Preprocess a part of a complex message designation. Returns
a pointer to the allocated memory containing expanded part of
the designation. Pointer to the beginning of the not expanded
part (in arg) is placed into *rest */
static char *
msgset_preproc_part (mu_mailbox_t mbox, char *arg, char **rest)
void
mh_msgset_uids (mu_mailbox_t mbox, mh_msgset_t *msgset)
{
struct msgset_keyword *p;
char *cp;
size_t i;
for (p = keywords; p->name; p++)
if (strncmp (arg, p->name, strlen (p->name)) == 0)
if (msgset->flags & MH_MSGSET_UID)
return;
for (i = 0; i < msgset->count; i++)
{
int rc;
size_t uid, num;
mu_message_t msg;
mu_mailbox_get_message (mbox, msgset->list[i], &msg);
mh_message_number (msg, &msgset->list[i]);
}
msgset->flags |= MH_MSGSET_UID;
}
if (p->handler (mbox, &num))
msgset_abort (arg);
rc = mu_mailbox_get_message (mbox, num, &msg);
if (rc)
/* Auxiliary function. Performs binary search for a message with the
given sequence number */
static size_t
mh_search_message (mu_mailbox_t mbox, size_t start, size_t stop,
size_t seqno, mu_message_t *mesg)
{
mu_message_t mid_msg = NULL;
size_t num = 0, middle;
middle = (start + stop) / 2;
if (mu_mailbox_get_message (mbox, middle, &mid_msg)
|| mh_message_number (mid_msg, &num))
return 0;
if (num == seqno)
{
mu_error (_("cannot get message %lu: %s"),
(unsigned long) num, mu_strerror (rc));
exit (1);
}
*rest = arg + strlen (p->name);
mu_message_get_uid (msg, &uid);
return xstrdup (mu_umaxtostr (0, uid));
if (mesg)
*mesg = mid_msg;
return middle;
}
cp = strchr (arg, '-');
if (cp)
{
char *ret;
*rest = cp;
ret = xmalloc (cp - arg + 1);
memcpy (ret, arg, cp - arg);
ret[cp - arg] = 0;
return ret;
}
if (start >= stop)
return 0;
*rest = arg + strlen (arg);
return strdup (arg);
if (num > seqno)
return mh_search_message (mbox, start, middle-1, seqno, mesg);
else /*if (num < seqno)*/
return mh_search_message (mbox, middle+1, stop, seqno, mesg);
}
/* Preprocess (expand) a single message designation */
static char *
msgset_preproc (mu_mailbox_t mbox, char *arg)
/* Retrieve the message with the given sequence number.
Returns ordinal number of the message in the mailbox if found,
zero otherwise. The retrieved message is stored in the location
pointed to by mesg, unless it is NULL. */
size_t
mh_get_message (mu_mailbox_t mbox, size_t seqno, mu_message_t *mesg)
{
char *buf, *tail;
size_t num, count;
mu_message_t msg;
if (strcmp (arg, "all") == 0 || strcmp (arg, ".") == 0)
if (mu_mailbox_get_message (mbox, 1, &msg)
|| mh_message_number (msg, &num))
return 0;
if (seqno < num)
return 0;
else if (seqno == num)
{
/* Special case */
arg = "first-last";
if (mesg)
*mesg = msg;
return 1;
}
buf = msgset_preproc_part (mbox, arg, &tail);
if (tail[0] == '-')
if (mu_mailbox_messages_count (mbox, &count)
|| mu_mailbox_get_message (mbox, count, &msg)
|| mh_message_number (msg, &num))
return 0;
if (seqno > num)
return 0;
else if (seqno == num)
{
char *rest = msgset_preproc_part (mbox, tail+1, &tail);
char *p = NULL;
mu_asprintf (&p, "%s-%s", buf, rest);
free (rest);
free (buf);
buf = p;
if (mesg)
*mesg = msg;
return count;
}
if (tail[0])
{
char *p = NULL;
mu_asprintf (&p, "%s%s", buf, tail);
free (buf);
buf = p;
}
return buf;
return mh_search_message (mbox, 1, count, seqno, mesg);
}
struct msgset_parser
{
mu_mailbox_t mbox;
mh_msgset_t *msgset;
char *curp;
int argc;
char **argv;
int sign;
size_t number;
int validuid;
};
static void
msgset_parser_init (struct msgset_parser *parser, mu_mailbox_t mbox,
mh_msgset_t *msgset, int argc, char **argv)
{
parser->mbox = mbox;
parser->msgset = msgset;
parser->argc = argc;
parser->argv = argv;
parser->curp = "";
parser->sign = 0;
parser->number = 0;
}
static void
msgset_abort (const char *arg)
{
mu_error (_("bad message list `%s'"), arg);
exit (1);
}
static void
emptyrange_abort (const char *range)
{
mu_error (_("no messages in range %s"), range);
exit (1);
}
/* Advance parser to the next argument */
static int
comp_mesg (const void *a, const void *b)
nextarg (struct msgset_parser *parser)
{
if (*(size_t*)a > *(size_t*)b)
return 1;
else if (*(size_t*)a < *(size_t*)b)
return -1;
if (parser->argc == 0)
return 0;
parser->argc--;
parser->curp = *parser->argv++;
return 1;
}
static int _mh_msgset_parse (mu_mailbox_t mbox, mh_msgset_t *msgset,
int argc, char **argv);
static void msgset_parser_run (struct msgset_parser *parser);
/* Treat arg as a name of user-defined sequence and attempt to
expand it. Return 0 if succeeded, non-zero otherwise. */
int
expand_user_seq (mu_mailbox_t mbox, mh_msgset_t *msgset, char *arg)
static int
_expand_sequence (struct msgset_parser *parser, char *term)
{
struct mu_wordsplit ws;
char *p;
const char *listp;
int rc = 1;
int negate = 0;
p = strchr (arg, ':');
if (p)
*p++ = 0;
listp = mh_global_sequences_get (mbox, arg, NULL);
listp = mh_global_sequences_get (parser->mbox, term, NULL);
if (!listp)
{
int len;
......@@ -254,10 +336,10 @@ expand_user_seq (mu_mailbox_t mbox, mh_msgset_t *msgset, char *arg)
if (!neg)
return 1;
len = strlen (neg);
if (strncmp (arg, neg, len))
if (strncmp (term, neg, len))
return 1;
negate = 1;
listp = mh_global_sequences_get (mbox, arg + len, NULL);
listp = mh_global_sequences_get (parser->mbox, term + len, NULL);
if (!listp)
return 1;
}
......@@ -266,376 +348,375 @@ expand_user_seq (mu_mailbox_t mbox, mh_msgset_t *msgset, char *arg)
{
mu_error (_("cannot split line `%s': %s"), listp,
mu_wordsplit_strerror (&ws));
exit (1);
}
else
{
rc = _mh_msgset_parse (mbox, msgset, ws.ws_wordc, ws.ws_wordv);
struct msgset_parser clone;
msgset_parser_init (&clone, parser->mbox, parser->msgset,
ws.ws_wordc, ws.ws_wordv);
msgset_parser_run (&clone);
mu_wordsplit_free (&ws);
}
if (rc)
return rc;
if (negate)
mh_msgset_negate (mbox, msgset);
mh_msgset_negate (parser->mbox, parser->msgset);
return 0;
}
if (p)
static int
parse_count (struct msgset_parser *parser)
{
char *endp;
if (!*parser->curp && nextarg (parser) == 0)
return 0;
if (*parser->curp == '-')
{
int first, num;
num = strtoul (p, &p, 0);
if (*p)
{
mh_msgset_free (msgset);
return 1;
parser->sign = 1;
parser->curp++;
}
if (num < 0)
else if (*parser->curp == '+')
{
first = num + msgset->count;
num = - num;
parser->sign = 0;
parser->curp++;
}
else
first = 0;
if (num > msgset->count)
{
mh_msgset_free (msgset);
parser->number = strtoul (parser->curp, &endp, 10);
if (*endp)
msgset_abort (parser->curp);
parser->curp = endp;
return 1;
}
}
if (first > 0)
memmove (msgset->list, &msgset->list[first],
sizeof (msgset->list[0]) * num);
msgset->count = num;
}
return rc;
static int
msgset_first (mu_mailbox_t mbox, size_t *pnum)
{
*pnum = 1;
return 0;
}
/* Parse a message specification from (argc;argv). Returned msgset is
not sorted nor optimised */
int
_mh_msgset_parse (mu_mailbox_t mbox, mh_msgset_t *msgset, int argc, char **argv)
static int
msgset_last (mu_mailbox_t mbox, size_t *pnum)
{
size_t msgcnt;
size_t *msglist;
size_t i, msgno;
if (argc == 0)
return 1;
int rc;
msgcnt = argc;
msglist = calloc (msgcnt, sizeof(*msglist));
for (i = 0, msgno = 0; i < argc; i++)
rc = mu_mailbox_messages_count (mbox, pnum);
if (rc)
{
char *p = NULL, *q;
size_t start, end;
size_t msg_first, n;
long num;
char *arg = msgset_preproc (mbox, argv[i]);
mu_error (_("cannot get last message: %s"), mu_strerror (rc));
exit (1);
}
return 0;
}
if (!mu_isdigit (arg[0]))
{
int j;
mh_msgset_t m;
static int
msgset_cur (mu_mailbox_t mbox, size_t *pnum)
{
size_t num;
mh_mailbox_get_cur (mbox, &num);
return mh_uid_to_msgno (mbox, num, pnum);
}
if (expand_user_seq (mbox, &m, arg))
static int
msgset_prev (mu_mailbox_t mbox, size_t *pnum)
{
size_t cur_n = 0;
msgset_cur (mbox, &cur_n);
if (cur_n < 1)
{
mu_error (_("message set %s does not exist"), arg);
mu_error (_("no prev message"));
exit (1);
}
_expand (&msgcnt, &msglist, m.count);
for (j = 0; j < m.count; j++)
msglist[msgno++] = m.list[j];
mh_msgset_free (&m);
}
else
{
start = strtoul (arg, &p, 0);
switch (*p)
{
case 0:
n = mh_get_message (mbox, start, NULL);
if (!n)
*pnum = cur_n - 1;
return 0;
}
static int
msgset_next (mu_mailbox_t mbox, size_t *pnum)
{
size_t cur_n = 0, total = 0;
msgset_cur (mbox, &cur_n);
mu_mailbox_messages_count (mbox, &total);
if (cur_n + 1 > total)
{
mu_error (_("message %lu does not exist"),
(unsigned long) start);
mu_error (_("no next message"));
exit (1);
}
msglist[msgno++] = n;
break;
*pnum = cur_n + 1;
return 0;
}
case '-':
end = strtoul (p+1, &p, 0);
if (*p)
msgset_abort (argv[i]);
if (end < start)
{
size_t t = start;
start = end;
end = t;
}
_expand (&msgcnt, &msglist, end - start);
msg_first = msgno;
for (; start <= end; start++)
{
n = mh_get_message (mbox, start, NULL);
if (n)
msglist[msgno++] = n;
}
if (msgno == msg_first)
struct msgset_keyword
{
char *name;
size_t len;
int (*handler) (mu_mailbox_t mbox, size_t *pnum);
int sign;
};
static struct msgset_keyword keywords[] = {
#define S(s) #s, sizeof (#s) - 1
{ S(first), msgset_first, 0 },
{ S(last), msgset_last, 1 },
{ S(prev), msgset_prev, 1 },
{ S(next), msgset_next, 0 },
{ S(cur), msgset_cur, 0 },
{ NULL }
};
#define PARSE_EOF 0
#define PARSE_MORE 1
#define PARSE_SUCCESS 2
/* term : NUMBER
| "first"
| "last"
| "cur"
| "prev"
| "next"
;
*/
static int
parse_term (struct msgset_parser *parser, int seq)
{
size_t tlen;
char *term;
if (!*parser->curp && nextarg (parser) == 0)
return PARSE_EOF;
term = parser->curp;
parser->curp = mu_str_skip_class (term, MU_CTYPE_ALPHA|MU_CTYPE_DIGIT);
tlen = parser->curp - term;
if (mu_isalpha (*term))
{
mu_error (_("no messages in range %s"), argv[i]);
exit (1);
}
break;
struct msgset_keyword *p;
case ':':
num = strtoul (p+1, &q, 0);
if (*q)
msgset_abort (argv[i]);
if (p[1] != '+' && p[1] != '-')
for (p = keywords; p->name; p++)
if (tlen == p->len && memcmp (p->name, term, tlen) == 0)
{
if (strncmp (argv[i], "last:", 5) == 0
|| strncmp (argv[i], "prev:", 5) == 0)
num = -num;
if (p->handler (parser->mbox, &parser->number))
msgset_abort (term);
parser->sign = p->sign;
parser->validuid = 1;
return PARSE_MORE;
}
end = start + num;
if (end < start)
if (*parser->curp == 0 && seq)
{
size_t t = start;
start = end + 1;
end = t;
/* See if it is a user-defined sequence */
if (_expand_sequence (parser, term) == 0)
return PARSE_SUCCESS;
}
else
end--;
_expand (&msgcnt, &msglist, end - start);
msg_first = msgno;
for (; start <= end; start++)
{
n = mh_get_message (mbox, start, NULL);
if (n)
msglist[msgno++] = n;
msgset_abort (term);
}
if (msgno == msg_first)
else if (mu_isdigit (*term))
{
mu_error (_("no messages in range %s"), argv[i]);
exit (1);
}
break;
char *endp;
size_t num = strtoul (term, &endp, 10);
if (endp != parser->curp)
msgset_abort (term);
default:
msgset_abort (argv[i]);
}
if (mh_uid_to_msgno (parser->mbox, num, &parser->number))
{
parser->validuid = 0;
parser->number = num;
}
free (arg);
else
parser->validuid = 1;
parser->sign = 0;
}
msgset->count = msgno;
msgset->list = msglist;
return 0;
else
msgset_abort (term);
return PARSE_MORE;
}
/* Parse a message specification from (argc;argv). Returned msgset is
sorted and optimised (i.e. it does not contain duplicate message
numbers) */
int
mh_msgset_parse (mu_mailbox_t mbox, mh_msgset_t *msgset,
int argc, char **argv, char *def)
static void
add_messages (struct msgset_parser *parser, size_t start, size_t count,
int sign)
{
char *xargv[2];
int rc;
size_t i;
if (argc == 0)
if (start == 0)
start = 1;
mh_msgset_expand (parser->msgset, count);
if (sign)
{
argc = 1;
argv = xargv;
argv[0] = def ? def : "cur";
argv[1] = NULL;
if (count > start)
count = start;
for (i = 0; i < count; i++, start--)
parser->msgset->list[parser->msgset->count++] = start;
}
rc = _mh_msgset_parse (mbox, msgset, argc, argv);
if (rc == 0)
else
{
size_t i, msgno;
size_t msgcnt = msgset->count;
size_t *msglist = msgset->list;
size_t total;
/* Sort the resulting message set */
qsort (msglist, msgcnt, sizeof (*msgset->list), comp_mesg);
/* Remove duplicates. */
for (i = 0, msgno = 1; i < msgset->count; i++)
if (msglist[msgno-1] != msglist[i])
msglist[msgno++] = msglist[i];
msgset->count = msgno;
mu_mailbox_messages_count (parser->mbox, &total);
if (start + count > total)
count = total - start + 1;
for (i = 0; i < count; i++, start++)
parser->msgset->list[parser->msgset->count++] = start;
}
return rc;
if (count == 0)
emptyrange_abort (parser->argv[-1]);
}
/* Check if message with ordinal number `num' is contained in the
message set. */
int
mh_msgset_member (mh_msgset_t *msgset, size_t num)
static void
add_message_range (struct msgset_parser *parser, size_t start, size_t end)
{
size_t i;
if (end == start)
emptyrange_abort (parser->argv[-1]);
for (i = 0; i < msgset->count; i++)
if (msgset->list[i] == num)
return i + 1;
return 0;
if (end < start)
{
size_t t = start;
start = end;
end = t;
}
mh_msgset_expand (parser->msgset, end - start + 1);
for (; start <= end; start++)
parser->msgset->list[parser->msgset->count++] = start;
}
/* Auxiliary function. Performs binary search for a message with the
given sequence number */
static size_t
mh_search_message (mu_mailbox_t mbox, size_t start, size_t stop,
size_t seqno, mu_message_t *mesg)
/* range: term '-' term
| term ':' count
;
count: NUMBER
| '+' NUMBER
| '-' NUMBER
;
*/
static int
parse_range (struct msgset_parser *parser)
{
mu_message_t mid_msg = NULL;
size_t num = 0, middle;
middle = (start + stop) / 2;
if (mu_mailbox_get_message (mbox, middle, &mid_msg)
|| mh_message_number (mid_msg, &num))
return 0;
size_t start;
if (num == seqno)
switch (parse_term (parser, 1))
{
if (mesg)
*mesg = mid_msg;
return middle;
}
if (start >= stop)
case PARSE_EOF:
return 0;
if (num > seqno)
return mh_search_message (mbox, start, middle-1, seqno, mesg);
else /*if (num < seqno)*/
return mh_search_message (mbox, middle+1, stop, seqno, mesg);
}
case PARSE_SUCCESS:
return 1;
/* Retrieve the message with the given sequence number.
Returns ordinal number of the message in the mailbox if found,
zero otherwise. The retrieved message is stored in the location
pointed to by mesg, unless it is NULL. */
case PARSE_MORE:
break;
}
size_t
mh_get_message (mu_mailbox_t mbox, size_t seqno, mu_message_t *mesg)
{
size_t num, count;
mu_message_t msg;
start = parser->number;
if (mu_mailbox_get_message (mbox, 1, &msg)
|| mh_message_number (msg, &num))
return 0;
if (seqno < num)
if (*parser->curp == ':')
{
int validuid = parser->validuid;
parser->curp++;
if (parse_count (parser) == 0)
return 0;
else if (seqno == num)
if (!validuid)
{
if (mesg)
*mesg = msg;
size_t total, lastuid;
msgset_last (parser->mbox, &total);
mh_msgno_to_uid (parser->mbox, total, &lastuid);
if (start > lastuid)
{
if (!parser->sign)
emptyrange_abort (parser->argv[-1]);
start = total;
}
else
{
if (parser->sign)
emptyrange_abort (parser->argv[-1]);
start = 1;
}
}
add_messages (parser, start, parser->number, parser->sign);
return 1;
}
else if (*parser->curp == '-')
{
size_t lastuid = 0;
int validuid = parser->validuid;
if (mu_mailbox_messages_count (mbox, &count)
|| mu_mailbox_get_message (mbox, count, &msg)
|| mh_message_number (msg, &num))
return 0;
if (seqno > num)
parser->curp++;
if (parse_term (parser, 0) == PARSE_EOF)
return 0;
else if (seqno == num)
if (!parser->validuid)
{
if (mesg)
*mesg = msg;
return count;
}
return mh_search_message (mbox, 1, count, seqno, mesg);
}
size_t total;
/* Reverse the order of messages in the message set */
void
mh_msgset_reverse (mh_msgset_t *msgset)
{
int head, tail;
for (head = 0, tail = msgset->count-1; head < tail; head++, tail--)
msgset_last (parser->mbox, &total);
mh_msgno_to_uid (parser->mbox, total, &lastuid);
if (parser->number > lastuid)
parser->number = total;
else if (!validuid)
emptyrange_abort (parser->argv[-1]);
}
if (!validuid)
{
size_t val = msgset->list[head];
msgset->list[head] = msgset->list[tail];
msgset->list[tail] = val;
if (!lastuid)
{
size_t total;
msgset_last (parser->mbox, &total);
mh_msgno_to_uid (parser->mbox, total, &lastuid);
}
}
/* Set the current message to that contained at position `index'
in the given message set */
void
mh_msgset_current (mu_mailbox_t mbox, mh_msgset_t *msgset, int index)
{
mu_message_t msg = NULL;
int rc;
size_t cur;
rc = mu_mailbox_get_message (mbox, msgset->list[index], &msg);
if (rc)
if (start > lastuid && !parser->validuid)
emptyrange_abort (parser->argv[-1]);
start = 1;
}
add_message_range (parser, start, parser->number);
}
else if (!parser->validuid)
{
mu_diag_funcall (MU_DIAG_ERROR, "mu_mailbox_get_message", NULL, rc);
mu_error (_("message %s does not exist"), parser->argv[-1]);
exit (1);
}
mh_message_number (msg, &cur);
mh_mailbox_set_cur (mbox, cur);
else
mh_msgset_add (parser->msgset, start);
return 1;
}
/* Free memory allocated for the message set. Note, that the msgset
itself is supposed to reside in the statically allocated memory and
therefore is not freed */
void
mh_msgset_free (mh_msgset_t *msgset)
/* Parse a message specification. The composed msgset is
not sorted nor optimised */
static void
msgset_parser_run (struct msgset_parser *parser)
{
if (msgset->count)
free (msgset->list);
while (parse_range (parser))
;
}
/* Negate the message set: on return `msgset' consists of the messages
_not contained_ in the input message set. Any memory associated with
the input message set is freed */
/* Parse a message specification from (argc;argv). Returned msgset is
sorted and optimised (i.e. it does not contain duplicate message
numbers) */
void
mh_msgset_negate (mu_mailbox_t mbox, mh_msgset_t *msgset)
mh_msgset_parse (mu_mailbox_t mbox, mh_msgset_t *msgset,
int argc, char **argv, char *def)
{
size_t i, total = 0, msgno;
size_t *list;
struct msgset_parser parser;
char *xargv[2];
mu_mailbox_messages_count (mbox, &total);
list = calloc (total, sizeof (list[0]));
if (!list)
mh_err_memory (1);
for (i = 1, msgno = 0; i <= total; i++)
if (argc == 0)
{
if (!mh_msgset_member (msgset, i))
list[msgno++] = i;
argc = 1;
argv = xargv;
argv[0] = def ? def : "cur";
argv[1] = NULL;
}
list = realloc (list, sizeof (list[0]) * msgno);
if (!list)
if (argc == 1 &&
(strcmp (argv[0], "all") == 0 || strcmp (argv[0], ".") == 0))
{
mu_error (_("not enough memory"));
abort ();
argc = 1;
argv = xargv;
argv[0] = "first-last";
argv[1] = NULL;
}
mh_msgset_free (msgset);
msgset->count = msgno;
msgset->list = list;
}
void
mh_msgset_uids (mu_mailbox_t mbox, mh_msgset_t *msgset)
{
size_t i;
for (i = 0; i < msgset->count; i++)
{
mu_message_t msg;
mu_mailbox_get_message (mbox, msgset->list[i], &msg);
mh_message_number (msg, &msgset->list[i]);
}
mh_msgset_init (msgset);
msgset_parser_init (&parser, mbox, msgset, argc, argv);
msgset_parser_run (&parser);
mh_msgset_optimize (msgset);
}
......
......@@ -346,17 +346,20 @@ _whatnow (struct mh_whatnow_env *wh, struct action_tab *tab)
do
{
size_t n;
handler_fp fun;
printf ("%s ", wh->prompt);
fflush (stdout);
rc = mu_stream_getline (in, &line, &size, NULL);
rc = mu_stream_getline (in, &line, &size, &n);
if (rc)
{
mu_error (_("cannot read input stream: %s"), mu_strerror (rc));
status = 1;
break;
}
if (n == 0)
break;
ws.ws_comment = "#";
rc = mu_wordsplit (line, &ws, wsflags);
......@@ -462,7 +465,10 @@ static int
call_send (struct mh_whatnow_env *wh, int argc, char **argv, int *status)
{
if (invoke ("sendproc", MHBINDIR "/send", argc, argv, wh->file, NULL) == 0)
{
annotate (wh);
return 1;
}
return 0;
}
......
/* GNU Mailutils -- a suite of utilities for electronic mail
Copyright (C) 2010 Free Software Foundation, Inc.
GNU Mailutils is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
GNU Mailutils is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. */
/* MH mhparam command */
#include <mh.h>
static char doc[] = N_("GNU MH mhseq")"\v"
N_("Use -help to obtain the list of traditional MH options.");
static char args_doc[] = N_("[SEQUENCE]");
static struct argp_option options[] = {
{"folder", ARG_FOLDER, N_("FOLDER"), 0,
N_("specify the folder to use")},
{ "uids", 'u', NULL, 0,
N_("show message UIDs (default)")},
{ "numbers", 'n', NULL, 0,
N_("show message numbers") },
{ NULL }
};
/* Traditional MH options */
struct mh_option mh_option[] = {
{ "uid" },
{ NULL }
};
static int uid_option = 1;
static error_t
opt_handler (int key, char *arg, struct argp_state *state)
{
switch (key)
{
case ARG_FOLDER:
mh_set_current_folder (arg);
break;
case 'n':
uid_option = 0;
break;
case 'u':
uid_option = 1;
break;
default:
return ARGP_ERR_UNKNOWN;
}
return 0;
}
int
main (int argc, char **argv)
{
int index;
mu_mailbox_t mbox;
mh_msgset_t msgset;
size_t i;
/* Native Language Support */
MU_APP_INIT_NLS ();
mh_argp_init ();
mh_argp_parse (&argc, &argv, 0, options, mh_option, args_doc, doc,
opt_handler, NULL, &index);
argc -= index;
argv += index;
mbox = mh_open_folder (mh_current_folder (), 0);
mh_msgset_parse (mbox, &msgset, argc, argv, "cur");
if (uid_option)
mh_msgset_uids (mbox, &msgset);
for (i = 0; i < msgset.count; i++)
printf ("%lu\n", (unsigned long) msgset.list[i]);
return 0;
}
......@@ -42,6 +42,7 @@ TESTSUITE_AT = \
ali.at\
anno.at\
burst.at\
comp.at\
folder.at\
inc.at\
install-mh.at\
......@@ -49,6 +50,7 @@ TESTSUITE_AT = \
mhl.at\
mhparam.at\
mhpath.at\
mhseq.at\
pick.at\
scan.at\
refile.at\
......
# This file is part of GNU Mailutils. -*- Autotest -*-
# Copyright (C) 2010 Free Software Foundation, Inc.
#
# GNU Mailutils is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
# published by the Free Software Foundation; either version 3, or (at
# your option) any later version.
#
# GNU Mailutils is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>.
m4_pushdef([MH_KEYWORDS],[comp])
m4_pushdef([compcmd],[comp dnl
-form $abs_top_srcdir/mh/components dnl
-editor $abs_top_srcdir/mh/tests/mhed])
MH_CHECK([comp -file],[comp00 comp-file],[
dir=`pwd`
echo quit | compcmd -file ./infile | sed "s|$dir/*||;s| *$||"
cat infile
],
[0],
[-- Editor invocation: ./infile
-- Input file:
To:
cc:
Subject:
--------
-- Input file end
What now? draft left on "./infile".
To:
cc:
Subject:
--------
Seen by mhed
])
MH_CHECK([comp -file (del)],[comp01 comp-file_del],[
dir=`pwd`
echo 'quit -delete' | compcmd -file ./infile | sed "s|$dir/*||;s| *$||"
],
[0],
[-- Editor invocation: ./infile
-- Input file:
To:
cc:
Subject:
--------
-- Input file end
What now?])
MH_CHECK([comp file],[comp02 comp_file],[
echo 'quit' | compcmd file | sed "s|$dir/*||;s| *$||"
cat Mail/file
],
[0],
[-- Editor invocation: Mail/file
-- Input file:
To:
cc:
Subject:
--------
-- Input file end
What now? draft left on "Mail/file".
To:
cc:
Subject:
--------
Seen by mhed
])
MH_CHECK([comp -use file],[comp03 comp-use_file],[
AT_DATA([Mail/file],[From: gray
To: root
Subject: test input
message body
])
echo 'quit' | compcmd -use file | sed "s|$dir/*||;s| *$||"
cat Mail/file
],
[0],
[-- Editor invocation: Mail/file
-- Input file:
From: gray
To: root
Subject: test input
message body
-- Input file end
What now? draft left on "Mail/file".
From: gray
To: root
Subject: test input
message body
Seen by mhed
])
MH_CHECK([comp +folder msg],[comp04 comp+folder_msg],[
mkdir Mail/inbox
AT_DATA([Mail/inbox/1],[From: gray
To: root
Subject: test input
message body
])
echo 'quit' | compcmd +inbox 1 | sed "s|$dir/*||;s| *$||"
echo Mail/draft
cat Mail/draft
echo Message
cat Mail/inbox/1
],
[0],
[-- Editor invocation: Mail/draft
-- Input file:
From: gray
To: root
Subject: test input
message body
-- Input file end
What now? draft left on "Mail/draft".
Mail/draft
From: gray
To: root
Subject: test input
message body
Seen by mhed
Message
From: gray
To: root
Subject: test input
message body
])
m4_popdef([compcmd])
m4_popdef([MH_KEYWORDS])
#! /bin/sh
echo "-- Editor invocation:" $*
echo "-- Input file: "
cat $1
echo "-- Input file end"
echo "Seen by mhed" >> $1
exit 0
# This file is part of GNU Mailutils. -*- Autotest -*-
# Copyright (C) 2010 Free Software Foundation, Inc.
#
# GNU Mailutils is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
# published by the Free Software Foundation; either version 3, or (at
# your option) any later version.
#
# GNU Mailutils is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>.
m4_pushdef([MH_KEYWORDS],[mhseq mh-sequences])
dnl ---------------------------------------------------------------
MH_CHECK([mhseq: existing message number],[mhseq00],[
MUT_MBCOPY($abs_top_srcdir/testsuite/mh/mbox1,[Mail/inbox])
mhseq 1
],
[0],
[1
])
MH_CHECK([mhseq: not existing message number],[mhseq01],[
MUT_MBCOPY($abs_top_srcdir/testsuite/mh/mbox1,[Mail/inbox])
mhseq 100
],
[1],
[],
dnl FIXME: See FIXME 3 in mhpath.at
[mhseq: message 100 does not exist
])
MH_CHECK([mhseq: contiguous message range],[mhseq02],[
MUT_MBCOPY($abs_top_srcdir/testsuite/mh/mbox1,[Mail/inbox])
mhseq 2-5
],
[0],
[2
3
4
5
])
MH_CHECK([mhseq: reversed contiguous message range],[mhseq03],[
MUT_MBCOPY($abs_top_srcdir/testsuite/mh/mbox1,[Mail/inbox])
mhseq 5-2
],
[0],
[2
3
4
5
])
MH_CHECK([mhseq: reversed non-contiguous message range],[mhseq04],[
MUT_MBCOPY($abs_top_srcdir/testsuite/mh/mbox1,[Mail/inbox])
rm Mail/inbox/3 Mail/inbox/4
mhseq 5-2
],
[0],
[2
5
])
MH_CHECK([mhseq: message range (left fixup)],[mhseq05],[
MUT_MBCOPY($abs_top_srcdir/testsuite/mh/mbox1,[Mail/inbox])
rm Mail/inbox/1 Mail/inbox/2
mhseq 1-5
],
[0],
[3
4
5
])
MH_CHECK([mhseq: message range (right fixup)],[mhseq06],[
MUT_MBCOPY($abs_top_srcdir/testsuite/mh/mbox1,[Mail/inbox])
rm Mail/inbox/4 Mail/inbox/5
mhseq 1-5
],
[0],
[1
2
3
])
MH_CHECK([mhseq: message range (both fixups)],[mhseq07],[
MUT_MBCOPY($abs_top_srcdir/testsuite/mh/mbox1,[Mail/inbox])
rm Mail/inbox/1 Mail/inbox/5
mhseq 1-5
],
[0],
[2
3
4
])
MH_CHECK([mhseq: non-existent message range (left)],[mhseq08],[
MUT_MBCOPY($abs_top_srcdir/testsuite/mh/mbox1,[Mail/inbox])
rm Mail/inbox/1 Mail/inbox/2 Mail/inbox/3
mhseq 1-2
],
[1],
[],
[mhseq: no messages in range 1-2
])
MH_CHECK([mhseq: non-existent message range (right)],[mhseq09],[
MUT_MBCOPY($abs_top_srcdir/testsuite/mh/mbox1,[Mail/inbox])
mhseq 6-10
],
[1],
[],
[mhseq: no messages in range 6-10
])
MH_CHECK([mhseq: message set addition],[mhseq10],[
MUT_MBCOPY($abs_top_srcdir/testsuite/mh/teaparty,[Mail/inbox])
mhseq 5 8-10 15-20
],
[0],
[5
8
9
10
15
16
17
18
19
20
])
MH_CHECK([mhseq: message set optimization],[mhseq11],[
MUT_MBCOPY($abs_top_srcdir/testsuite/mh/teaparty,[Mail/inbox])
rm Mail/inbox/17 Mail/inbox/19
mhseq 5 1-10 15-20
],
[0],
[1
2
3
4
5
6
7
8
9
10
15
16
18
20
])
MH_CHECK([mhseq: counted range (positive)],[mhseq12],[
MUT_MBCOPY($abs_top_srcdir/testsuite/mh/teaparty,[Mail/inbox])
mhseq 10:4
],
[0],
[10
11
12
13
])
MH_CHECK([mhseq: non-contiguous counted range (positive)],[mhseq13],[
MUT_MBCOPY($abs_top_srcdir/testsuite/mh/teaparty,[Mail/inbox])
rm Mail/inbox/12 Mail/inbox/14
mhseq 10:4
],
[0],
[10
11
13
15
])
MH_CHECK([mhseq: counted range (positive, left fixup)],[mhseq14],[
MUT_MBCOPY($abs_top_srcdir/testsuite/mh/mbox1,[Mail/inbox])
rm Mail/inbox/1 Mail/inbox/2
mhseq 1:3
],
[0],
[3
4
5
])
MH_CHECK([mhseq: counted range (positive, right fixup)],[mhseq15],[
MUT_MBCOPY($abs_top_srcdir/testsuite/mh/mbox1,[Mail/inbox])
mhseq 2:10
],
[0],
[2
3
4
5
])
MH_CHECK([mhseq: invalid counted range (negative)],[mhseq16],[
MUT_MBCOPY($abs_top_srcdir/testsuite/mh/mbox1,[Mail/inbox])
rm Mail/inbox/1 Mail/inbox/2
mhseq 10:2
],
[1],
[],
[mhseq: no messages in range 10:2
])
MH_CHECK([mhseq: counted range (negative)],[mhseq17],[
MUT_MBCOPY($abs_top_srcdir/testsuite/mh/teaparty,[Mail/inbox])
mhseq 10:-4
],
[0],
[7
8
9
10
])
MH_CHECK([mhseq: non-contiguous counted range (negative)],[mhseq18],[
MUT_MBCOPY($abs_top_srcdir/testsuite/mh/teaparty,[Mail/inbox])
rm Mail/inbox/8 Mail/inbox/6
mhseq 10:-4
],
[0],
[5
7
9
10
])
MH_CHECK([mhseq: counted range (negative, left fixup)],[mhseq19],[
MUT_MBCOPY($abs_top_srcdir/testsuite/mh/mbox1,[Mail/inbox])
rm Mail/inbox/1 Mail/inbox/2
mhseq 4:-30
],
[0],
[3
4
])
MH_CHECK([mhseq: counted range (negative, right fixup)],[mhseq20],[
MUT_MBCOPY($abs_top_srcdir/testsuite/mh/mbox1,[Mail/inbox])
rm Mail/inbox/1 Mail/inbox/2
mhseq 4:30
],
[0],
[4
5
])
MH_CHECK([mhseq: invalid counted range (negative)],[mhseq21],[
MUT_MBCOPY($abs_top_srcdir/testsuite/mh/mbox1,[Mail/inbox])
rm Mail/inbox/1 Mail/inbox/2
mhseq 1:-30
],
[1],
[],
[mhseq: no messages in range 1:-30
])
MH_CHECK([mhseq: cur],[mhseq22 cur],[
MUT_MBCOPY($abs_top_srcdir/testsuite/mh/mbox1,[Mail/inbox])
echo "cur: 3" > Mail/inbox/.mh_sequences
mhseq cur
],
[0],
[3
])
MH_CHECK([mhseq: cur:n -- default direction],[mhseq23 cur:n],[
MUT_MBCOPY($abs_top_srcdir/testsuite/mh/mbox1,[Mail/inbox])
echo "cur: 3" > Mail/inbox/.mh_sequences
mhseq cur:2
],
[0],
[3
4
])
MH_CHECK([mhseq: cur:n -- explicit dir (negative)],[mhseq24 cur:n cur:n-],[
MUT_MBCOPY($abs_top_srcdir/testsuite/mh/mbox1,[Mail/inbox])
echo "cur: 3" > Mail/inbox/.mh_sequences
mhseq cur:-2
],
[0],
[2
3
])
MH_CHECK([mhseq: cur:n -- explicit dir (positive)],[mhseq25 cur:n cur:n+],[
MUT_MBCOPY($abs_top_srcdir/testsuite/mh/mbox1,[Mail/inbox])
echo "cur: 3" > Mail/inbox/.mh_sequences
mhseq cur:+2
],
[0],
[3
4
])
MH_CHECK([mhseq: next],[mhseq26 next],[
MUT_MBCOPY($abs_top_srcdir/testsuite/mh/mbox1,[Mail/inbox])
echo "cur: 3" > Mail/inbox/.mh_sequences
rm Mail/inbox/4
mhseq next
],
[0],
[5
])
MH_CHECK([mhseq: next:n -- default direction],[mhseq27 next:n],[
MUT_MBCOPY($abs_top_srcdir/testsuite/mh/mbox1,[Mail/inbox])
echo "cur: 3" > Mail/inbox/.mh_sequences
mhseq next:2
],
[0],
[4
5
])
MH_CHECK([mhseq: prev],[mhseq28 prev],[
MUT_MBCOPY($abs_top_srcdir/testsuite/mh/mbox1,[Mail/inbox])
echo "cur: 3" > Mail/inbox/.mh_sequences
rm Mail/inbox/2
mhseq prev
],
[0],
[1
])
MH_CHECK([mhseq: prev:n -- default direction],[mhseq29 prev:n],[
MUT_MBCOPY($abs_top_srcdir/testsuite/mh/mbox1,[Mail/inbox])
echo "cur: 3" > Mail/inbox/.mh_sequences
mhseq prev:2
],
[0],
[1
2
])
MH_CHECK([mhseq: first],[mhseq30 first],[
MUT_MBCOPY($abs_top_srcdir/testsuite/mh/mbox1,[Mail/inbox])
rm Mail/inbox/1
mhseq first
],
[0],
[2
])
MH_CHECK([mhseq: first:n -- default direction],[mhseq31 first:n],[
MUT_MBCOPY($abs_top_srcdir/testsuite/mh/mbox1,[Mail/inbox])
rm Mail/inbox/1
mhseq first:2
],
[0],
[2
3
])
MH_CHECK([mhseq: last],[mhseq32 last],[
MUT_MBCOPY($abs_top_srcdir/testsuite/mh/mbox1,[Mail/inbox])
mhseq last
],
[0],
[5
])
MH_CHECK([mhseq: last:n -- default direction],[mhseq33 last:n],[
MUT_MBCOPY($abs_top_srcdir/testsuite/mh/mbox1,[Mail/inbox])
mhseq last:2
],
[0],
[4
5
])
m4_popdef([MH_KEYWORDS])
# End of mhseq.at
\ No newline at end of file
......@@ -42,6 +42,7 @@ AT_CLEANUP
AT_INIT
m4_include([install-mh.at])
m4_include([mhseq.at])
m4_include([ali.at])
m4_include([folder.at])
m4_include([inc.at])
......@@ -56,3 +57,4 @@ m4_include([mhl.at])
m4_include([anno.at])
m4_include([pick.at])
m4_include([burst.at])
m4_include([comp.at])
......