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,68 +206,90 @@ 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)
wh_env.file = mh_expand_name (NULL, "draft", 0);
{
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;
}
switch (check_draft_disposition (&wh_env, use_draft))
{
case DISP_QUIT:
exit (0);
wh_env.draftfile = wh_env.file;
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;
mbox = mh_open_folder (mh_current_folder (), 0);
mh_msgset_parse (mbox, &msgset, argc - index, argv + index, "cur");
if (msgset.count != 1)
{
mh_msgset_t msgset;
mu_mailbox_t mbox;
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;
mbox = mh_open_folder (mh_current_folder (), 0);
mh_msgset_parse (mbox, &msgset, argc - index, argv + index, "cur");
if (msgset.count != 1)
{
mu_error (_("only one message at a time!"));
return 1;
}
copy_message (mbox, msgset.list[0], wh_env.file);
mu_mailbox_destroy (&mbox);
mh_msgset_free (&msgset);
case DISP_REPLACE:
unlink (wh_env.draftfile);
mh_comp_draft (formfile, "components", wh_env.file);
}
else
mh_comp_draft (formfile, "components", wh_env.file);
}
/* Exit immediately if --build is given */
......
......@@ -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,8 +304,8 @@ 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,
int argc, char **argv, char *def);
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);
void mh_msgset_negate (mu_mailbox_t mbox, 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
uid = msgset.list[0];
{
mh_msgset_uids (mbox, &msgset);
uid = msgset.list[0];
}
mh_msgset_free (&msgset);
}
......
......@@ -19,473 +19,184 @@
#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;
}
static int
msgset_cur (mu_mailbox_t mbox, size_t *pnum)
void
mh_msgset_add (mh_msgset_t *msgset, size_t n)
{
size_t i, count = 0;
static int cached_n = 0;
size_t cur;
mh_mailbox_get_cur (mbox, &cur);
if (cached_n)
{
*pnum = cached_n;
return 0;
}
mu_mailbox_messages_count (mbox, &count);
for (i = 1; i <= count; i++)
{
mu_message_t msg = NULL;
size_t uid = 0;
mu_mailbox_get_message (mbox, i, &msg);
mh_message_number (msg, &uid);
if (uid == cur)
{
*pnum = cached_n = i;
return 0;
}
}
mu_error (_("no cur message"));
exit (1);
mh_msgset_expand (msgset, 1);
msgset->list[msgset->count++] = n;
}
static int
msgset_prev (mu_mailbox_t mbox, size_t *pnum)
comp_mesg (const void *a, const void *b)
{
size_t cur_n = 0;
msgset_cur (mbox, &cur_n);
if (cur_n < 1)
{
mu_error (_("no prev message"));
exit (1);
}
*pnum = cur_n - 1;
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;
}
static int
msgset_next (mu_mailbox_t mbox, size_t *pnum)
void
mh_msgset_optimize (mh_msgset_t *msgset)
{
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 (_("no next message"));
exit (1);
}
*pnum = cur_n + 1;
return 0;
}
size_t i, msgno;
size_t msgcnt = msgset->count;
size_t *msglist = msgset->list;
/* Sort the resulting message set */
qsort (msglist, msgcnt, sizeof (*msgset->list), comp_mesg);
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 },
};
/* Remove duplicates. */
for (i = 0, msgno = 1; i < msgset->count; i++)
if (msglist[msgno-1] != msglist[i])
msglist[msgno++] = msglist[i];
msgset->count = msgno;
}
/* 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)
/* Check if message with ordinal number `num' is contained in the
message set. */
int
mh_msgset_member (mh_msgset_t *msgset, size_t num)
{
struct msgset_keyword *p;
char *cp;
for (p = keywords; p->name; p++)
if (strncmp (arg, p->name, strlen (p->name)) == 0)
{
int rc;
size_t uid, num;
mu_message_t msg;
if (p->handler (mbox, &num))
msgset_abort (arg);
rc = mu_mailbox_get_message (mbox, num, &msg);
if (rc)
{
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));
}
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;
}
size_t i;
*rest = arg + strlen (arg);
return strdup (arg);
for (i = 0; i < msgset->count; i++)
if (msgset->list[i] == num)
return i + 1;
return 0;
}
/* Preprocess (expand) a single message designation */
static char *
msgset_preproc (mu_mailbox_t mbox, char *arg)
/* Reverse the order of messages in the message set */
void
mh_msgset_reverse (mh_msgset_t *msgset)
{
char *buf, *tail;
if (strcmp (arg, "all") == 0 || strcmp (arg, ".") == 0)
{
/* Special case */
arg = "first-last";
}
int head, tail;
buf = msgset_preproc_part (mbox, arg, &tail);
if (tail[0] == '-')
{
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 (tail[0])
for (head = 0, tail = msgset->count-1; head < tail; head++, tail--)
{
char *p = NULL;
mu_asprintf (&p, "%s%s", buf, tail);
free (buf);
buf = p;
size_t val = msgset->list[head];
msgset->list[head] = msgset->list[tail];
msgset->list[tail] = val;
}
return buf;
}
static int
comp_mesg (const void *a, const void *b)
{
if (*(size_t*)a > *(size_t*)b)
return 1;
else if (*(size_t*)a < *(size_t*)b)
return -1;
return 0;
}
static int _mh_msgset_parse (mu_mailbox_t mbox, mh_msgset_t *msgset,
int argc, char **argv);
/* 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)
/* 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)
{
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);
if (!listp)
{
int len;
const char *neg = mh_global_profile_get ("Sequence-Negation", NULL);
if (!neg)
return 1;
len = strlen (neg);
if (strncmp (arg, neg, len))
return 1;
negate = 1;
listp = mh_global_sequences_get (mbox, arg + len, NULL);
if (!listp)
return 1;
}
if (mu_wordsplit (listp, &ws, MU_WRDSF_DEFFLAGS))
{
mu_error (_("cannot split line `%s': %s"), listp,
mu_wordsplit_strerror (&ws));
}
else
{
rc = _mh_msgset_parse (mbox, msgset, ws.ws_wordc, ws.ws_wordv);
mu_wordsplit_free (&ws);
}
mu_message_t msg = NULL;
int rc;
size_t cur;
rc = mu_mailbox_get_message (mbox, msgset->list[index], &msg);
if (rc)
return rc;
if (negate)
mh_msgset_negate (mbox, msgset);
if (p)
{
int first, num;
num = strtoul (p, &p, 0);
if (*p)
{
mh_msgset_free (msgset);
return 1;
}
if (num < 0)
{
first = num + msgset->count;
num = - num;
}
else
first = 0;
if (num > msgset->count)
{
mh_msgset_free (msgset);
return 1;
}
if (first > 0)
memmove (msgset->list, &msgset->list[first],
sizeof (msgset->list[0]) * num);
msgset->count = num;
mu_diag_funcall (MU_DIAG_ERROR, "mu_mailbox_get_message", NULL, rc);
exit (1);
}
return rc;
mh_message_number (msg, &cur);
mh_mailbox_set_cur (mbox, cur);
}
/* 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)
/* 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 msgcnt;
size_t *msglist;
size_t i, msgno;
if (argc == 0)
return 1;
msgcnt = argc;
msglist = calloc (msgcnt, sizeof(*msglist));
for (i = 0, msgno = 0; i < argc; i++)
{
char *p = NULL, *q;
size_t start, end;
size_t msg_first, n;
long num;
char *arg = msgset_preproc (mbox, argv[i]);
if (!mu_isdigit (arg[0]))
{
int j;
mh_msgset_t m;
if (expand_user_seq (mbox, &m, arg))
{
mu_error (_("message set %s does not exist"), arg);
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)
{
mu_error (_("message %lu does not exist"),
(unsigned long) start);
exit (1);
}
msglist[msgno++] = n;
break;
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)
{
mu_error (_("no messages in range %s"), argv[i]);
exit (1);
}
break;
case ':':
num = strtoul (p+1, &q, 0);
if (*q)
msgset_abort (argv[i]);
if (p[1] != '+' && p[1] != '-')
{
if (strncmp (argv[i], "last:", 5) == 0
|| strncmp (argv[i], "prev:", 5) == 0)
num = -num;
}
end = start + num;
if (end < start)
{
size_t t = start;
start = end + 1;
end = t;
}
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;
}
if (msgno == msg_first)
{
mu_error (_("no messages in range %s"), argv[i]);
exit (1);
}
break;
default:
msgset_abort (argv[i]);
}
}
free (arg);
}
msgset->count = msgno;
msgset->list = msglist;
return 0;
if (msgset->count)
free (msgset->list);
}
/* 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)
/* 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)
{
char *xargv[2];
int rc;
if (argc == 0)
size_t i, total = 0, msgno;
size_t *list;
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++)
{
argc = 1;
argv = xargv;
argv[0] = def ? def : "cur";
argv[1] = NULL;
if (!mh_msgset_member (msgset, i))
list[msgno++] = i;
}
rc = _mh_msgset_parse (mbox, msgset, argc, argv);
if (rc == 0)
list = realloc (list, sizeof (list[0]) * msgno);
if (!list)
{
size_t i, msgno;
size_t msgcnt = msgset->count;
size_t *msglist = msgset->list;
/* 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_error (_("not enough memory"));
abort ();
}
return rc;
mh_msgset_free (msgset);
msgset->count = msgno;
msgset->list = list;
}
/* Check if message with ordinal number `num' is contained in the
message set. */
int
mh_msgset_member (mh_msgset_t *msgset, size_t num)
void
mh_msgset_uids (mu_mailbox_t mbox, mh_msgset_t *msgset)
{
size_t i;
if (msgset->flags & MH_MSGSET_UID)
return;
for (i = 0; i < msgset->count; i++)
if (msgset->list[i] == num)
return i + 1;
return 0;
{
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;
}
/* Auxiliary function. Performs binary search for a message with the
given sequence number */
static size_t
......@@ -555,87 +266,457 @@ mh_get_message (mu_mailbox_t mbox, size_t seqno, mu_message_t *mesg)
return mh_search_message (mbox, 1, count, seqno, mesg);
}
/* Reverse the order of messages in the message set */
void
mh_msgset_reverse (mh_msgset_t *msgset)
struct msgset_parser
{
int head, tail;
mu_mailbox_t mbox;
mh_msgset_t *msgset;
char *curp;
int argc;
char **argv;
int sign;
size_t number;
int validuid;
};
for (head = 0, tail = msgset->count-1; head < tail; head++, tail--)
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
nextarg (struct msgset_parser *parser)
{
if (parser->argc == 0)
return 0;
parser->argc--;
parser->curp = *parser->argv++;
return 1;
}
static void msgset_parser_run (struct msgset_parser *parser);
static int
_expand_sequence (struct msgset_parser *parser, char *term)
{
struct mu_wordsplit ws;
const char *listp;
int negate = 0;
listp = mh_global_sequences_get (parser->mbox, term, NULL);
if (!listp)
{
size_t val = msgset->list[head];
msgset->list[head] = msgset->list[tail];
msgset->list[tail] = val;
int len;
const char *neg = mh_global_profile_get ("Sequence-Negation", NULL);
if (!neg)
return 1;
len = strlen (neg);
if (strncmp (term, neg, len))
return 1;
negate = 1;
listp = mh_global_sequences_get (parser->mbox, term + len, NULL);
if (!listp)
return 1;
}
if (mu_wordsplit (listp, &ws, MU_WRDSF_DEFFLAGS))
{
mu_error (_("cannot split line `%s': %s"), listp,
mu_wordsplit_strerror (&ws));
exit (1);
}
else
{
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 (negate)
mh_msgset_negate (parser->mbox, parser->msgset);
return 0;
}
/* 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)
static int
parse_count (struct msgset_parser *parser)
{
char *endp;
if (!*parser->curp && nextarg (parser) == 0)
return 0;
if (*parser->curp == '-')
{
parser->sign = 1;
parser->curp++;
}
else if (*parser->curp == '+')
{
parser->sign = 0;
parser->curp++;
}
parser->number = strtoul (parser->curp, &endp, 10);
if (*endp)
msgset_abort (parser->curp);
parser->curp = endp;
return 1;
}
static int
msgset_first (mu_mailbox_t mbox, size_t *pnum)
{
*pnum = 1;
return 0;
}
static int
msgset_last (mu_mailbox_t mbox, size_t *pnum)
{
mu_message_t msg = NULL;
int rc;
size_t cur;
rc = mu_mailbox_get_message (mbox, msgset->list[index], &msg);
rc = mu_mailbox_messages_count (mbox, pnum);
if (rc)
{
mu_diag_funcall (MU_DIAG_ERROR, "mu_mailbox_get_message", NULL, rc);
mu_error (_("cannot get last message: %s"), mu_strerror (rc));
exit (1);
}
mh_message_number (msg, &cur);
mh_mailbox_set_cur (mbox, cur);
return 0;
}
/* 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)
static int
msgset_cur (mu_mailbox_t mbox, size_t *pnum)
{
if (msgset->count)
free (msgset->list);
size_t num;
mh_mailbox_get_cur (mbox, &num);
return mh_uid_to_msgno (mbox, num, pnum);
}
/* 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)
static int
msgset_prev (mu_mailbox_t mbox, size_t *pnum)
{
size_t i, total = 0, msgno;
size_t *list;
size_t cur_n = 0;
msgset_cur (mbox, &cur_n);
if (cur_n < 1)
{
mu_error (_("no prev message"));
exit (1);
}
*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);
list = calloc (total, sizeof (list[0]));
if (!list)
mh_err_memory (1);
for (i = 1, msgno = 0; i <= total; i++)
if (cur_n + 1 > total)
{
if (!mh_msgset_member (msgset, i))
list[msgno++] = i;
mu_error (_("no next message"));
exit (1);
}
*pnum = cur_n + 1;
return 0;
}
list = realloc (list, sizeof (list[0]) * msgno);
if (!list)
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 (_("not enough memory"));
abort ();
struct msgset_keyword *p;
for (p = keywords; p->name; p++)
if (tlen == p->len && memcmp (p->name, term, tlen) == 0)
{
if (p->handler (parser->mbox, &parser->number))
msgset_abort (term);
parser->sign = p->sign;
parser->validuid = 1;
return PARSE_MORE;
}
if (*parser->curp == 0 && seq)
{
/* See if it is a user-defined sequence */
if (_expand_sequence (parser, term) == 0)
return PARSE_SUCCESS;
}
msgset_abort (term);
}
mh_msgset_free (msgset);
msgset->count = msgno;
msgset->list = list;
else if (mu_isdigit (*term))
{
char *endp;
size_t num = strtoul (term, &endp, 10);
if (endp != parser->curp)
msgset_abort (term);
if (mh_uid_to_msgno (parser->mbox, num, &parser->number))
{
parser->validuid = 0;
parser->number = num;
}
else
parser->validuid = 1;
parser->sign = 0;
}
else
msgset_abort (term);
return PARSE_MORE;
}
void
mh_msgset_uids (mu_mailbox_t mbox, mh_msgset_t *msgset)
static void
add_messages (struct msgset_parser *parser, size_t start, size_t count,
int sign)
{
size_t i;
for (i = 0; i < msgset->count; i++)
if (start == 0)
start = 1;
mh_msgset_expand (parser->msgset, count);
if (sign)
{
mu_message_t msg;
mu_mailbox_get_message (mbox, msgset->list[i], &msg);
mh_message_number (msg, &msgset->list[i]);
if (count > start)
count = start;
for (i = 0; i < count; i++, start--)
parser->msgset->list[parser->msgset->count++] = start;
}
else
{
size_t total;
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;
}
if (count == 0)
emptyrange_abort (parser->argv[-1]);
}
static void
add_message_range (struct msgset_parser *parser, size_t start, size_t end)
{
if (end == start)
emptyrange_abort (parser->argv[-1]);
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;
}
/* range: term '-' term
| term ':' count
;
count: NUMBER
| '+' NUMBER
| '-' NUMBER
;
*/
static int
parse_range (struct msgset_parser *parser)
{
size_t start;
switch (parse_term (parser, 1))
{
case PARSE_EOF:
return 0;
case PARSE_SUCCESS:
return 1;
case PARSE_MORE:
break;
}
start = parser->number;
if (*parser->curp == ':')
{
int validuid = parser->validuid;
parser->curp++;
if (parse_count (parser) == 0)
return 0;
if (!validuid)
{
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;
parser->curp++;
if (parse_term (parser, 0) == PARSE_EOF)
return 0;
if (!parser->validuid)
{
size_t total;
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)
{
if (!lastuid)
{
size_t total;
msgset_last (parser->mbox, &total);
mh_msgno_to_uid (parser->mbox, total, &lastuid);
}
if (start > lastuid && !parser->validuid)
emptyrange_abort (parser->argv[-1]);
start = 1;
}
add_message_range (parser, start, parser->number);
}
else if (!parser->validuid)
{
mu_error (_("message %s does not exist"), parser->argv[-1]);
exit (1);
}
else
mh_msgset_add (parser->msgset, start);
return 1;
}
/* Parse a message specification. The composed msgset is
not sorted nor optimised */
static void
msgset_parser_run (struct msgset_parser *parser)
{
while (parse_range (parser))
;
}
/* 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_parse (mu_mailbox_t mbox, mh_msgset_t *msgset,
int argc, char **argv, char *def)
{
struct msgset_parser parser;
char *xargv[2];
if (argc == 0)
{
argc = 1;
argv = xargv;
argv[0] = def ? def : "cur";
argv[1] = NULL;
}
if (argc == 1 &&
(strcmp (argv[0], "all") == 0 || strcmp (argv[0], ".") == 0))
{
argc = 1;
argv = xargv;
argv[0] = "first-last";
argv[1] = NULL;
}
mh_msgset_init (msgset);
msgset_parser_init (&parser, mbox, msgset, argc, argv);
msgset_parser_run (&parser);
mh_msgset_optimize (msgset);
}
......
......@@ -346,18 +346,21 @@ _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);
if (rc)
......@@ -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);
{
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])
......