Commit a14aceea a14aceea0b23e88b3e661c0e46be15abb6a47a70 by Sergey Poznyakoff

(mh_msgset_reverse,mh_msgset_negate,

 mh_msgset_current, mh_msgset_free): new functions.
Added comments.
1 parent 6da00798
......@@ -18,7 +18,10 @@
/* MH message sets. */
#include <mh.h>
#include <mailutils/argcv.h>
/* Expand a message set (msgcnt;msglist) to accomodate `inc' more
elements */
static void
_expand (size_t *msgcnt, size_t **msglist, size_t inc)
{
......@@ -34,6 +37,7 @@ _expand (size_t *msgcnt, size_t **msglist, size_t inc)
}
}
/* Fatal error handler */
static void
msgset_abort (const char *arg)
{
......@@ -41,6 +45,8 @@ msgset_abort (const char *arg)
exit (1);
}
/* Handlers for expansion of the reserved message names */
static int
msgset_first (mailbox_t mbox, size_t *pnum)
{
......@@ -135,10 +141,15 @@ static struct msgset_keyword {
{ NULL },
};
/* 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 (mailbox_t mbox, char *arg, char **rest)
{
struct msgset_keyword *p;
char *cp;
for (p = keywords; p->name; p++)
if (strncmp (arg, p->name, strlen (p->name)) == 0)
......@@ -161,16 +172,29 @@ msgset_preproc_part (mailbox_t mbox, char *arg, char **rest)
*rest = arg + strlen (p->name);
return ret;
}
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;
}
*rest = arg + strlen (arg);
return strdup (arg);
}
/* Preprocess (expand) a single message designation */
static char *
msgset_preproc (mailbox_t mbox, char *arg)
{
char *buf, *tail;
if (strcmp (arg, "all") == 0)
if (strcmp (arg, "all") == 0 || strcmp (arg, ".") == 0)
{
/* Special case */
arg = "first-last";
......@@ -207,21 +231,91 @@ comp_mesg (const void *a, const void *b)
return 0;
}
static int _mh_msgset_parse __P((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
mh_msgset_parse (mailbox_t mbox, mh_msgset_t *msgset, int argc, char **argv)
expand_user_seq (mailbox_t mbox, mh_msgset_t *msgset, char *arg)
{
int argc;
char **argv;
char *p, *listp;
int rc = 1;
int negate = 0;
p = strchr (arg, ':');
if (p)
*p++ = 0;
listp = mh_global_sequences_get (arg, NULL);
if (!listp)
{
int len;
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 (arg + len, NULL);
if (!listp)
return 1;
}
if (argcv_get (listp, "", NULL, &argc, &argv) == 0)
rc = _mh_msgset_parse (mbox, msgset, argc, argv);
argcv_free (argc, argv);
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;
}
return rc;
}
/* Parse a message specification from (argc;argv). Returned msgset is
not sorted nor optimised */
int
_mh_msgset_parse (mailbox_t mbox, mh_msgset_t *msgset, int argc, char **argv)
{
size_t msgcnt;
size_t *msglist;
char *xargv[2];
size_t i, msgno;
if (argc == 0)
{
argc = 1;
argv = xargv;
argv[0] = "cur";
argv[1] = NULL;
}
return 1;
msgcnt = argc;
msglist = calloc (msgcnt, sizeof(*msglist));
......@@ -232,6 +326,24 @@ mh_msgset_parse (mailbox_t mbox, mh_msgset_t *msgset, int argc, char **argv)
size_t msg_first, n;
long num;
char *arg = msgset_preproc (mbox, argv[i]);
if (!isdigit (arg[0]))
{
int j;
mh_msgset_t m;
if (expand_user_seq (mbox, &m, arg))
{
mh_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)
{
......@@ -301,25 +413,55 @@ mh_msgset_parse (mailbox_t mbox, mh_msgset_t *msgset, int argc, char **argv)
default:
msgset_abort (argv[i]);
}
}
free (arg);
}
msgcnt = msgno;
msgset->count = msgno;
msgset->list = msglist;
return 0;
}
/* 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 (mailbox_t mbox, mh_msgset_t *msgset,
int argc, char **argv, char *def)
{
char *xargv[2];
int rc;
if (argc == 0)
{
argc = 1;
argv = xargv;
argv[0] = def ? def : "cur";
argv[1] = NULL;
}
rc = _mh_msgset_parse (mbox, msgset, argc, argv);
if (rc == 0)
{
size_t i, msgno;
size_t msgcnt = msgset->count;
size_t *msglist = msgset->list;
/* Sort the resulting message set */
qsort (msglist, msgcnt, sizeof (*msglist), comp_mesg);
qsort (msglist, msgcnt, sizeof (*msgset->list), comp_mesg);
/* Remove duplicates. */
for (i = 0, msgno = 1; i < msgcnt; i++)
for (i = 0, msgno = 1; i < msgset->count; i++)
if (msglist[msgno-1] != msglist[i])
msglist[msgno++] = msglist[i];
msgcnt = msgno;
msgset->count = msgcnt;
msgset->list = msglist;
return 0;
msgset->count = msgno;
}
return rc;
}
/* Check if message with ordinal number `num' is contained in the
message set. */
int
mh_msgset_member (mh_msgset_t *msgset, size_t num)
{
......@@ -400,3 +542,75 @@ mh_get_message (mailbox_t mbox, size_t seqno, 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)
{
int head, tail;
for (head = 0, tail = msgset->count-1; head < tail; head++, tail--)
{
size_t val = msgset->list[head];
msgset->list[head] = msgset->list[tail];
msgset->list[tail] = val;
}
}
/* Set the current message to that contained at position `index'
in the given message set */
int
mh_msgset_current (mailbox_t mbox, mh_msgset_t *msgset, int index)
{
message_t msg = NULL;
if (mailbox_get_message (mbox, msgset->list[index], &msg))
return 1;
return mh_message_number (msg, &current_message);
}
/* 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)
{
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 (mailbox_t mbox, mh_msgset_t *msgset)
{
size_t i, total = 0, msgno;
size_t *list;
mailbox_messages_count (mbox, &total);
list = calloc (total, sizeof (list[0]));
if (!list)
{
mh_error ("not enough memory");
abort ();
}
for (i = 1, msgno = 0; i <= total; i++)
{
if (!mh_msgset_member (msgset, i))
list[msgno++] = i;
}
list = realloc (list, sizeof (list[0]) * msgno);
if (!list)
{
mh_error ("not enough memory");
abort ();
}
mh_msgset_free (msgset);
msgset->count = msgno;
msgset->list = list;
}
......