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 @@ ...@@ -18,7 +18,10 @@
18 /* MH message sets. */ 18 /* MH message sets. */
19 19
20 #include <mh.h> 20 #include <mh.h>
21 #include <mailutils/argcv.h>
21 22
23 /* Expand a message set (msgcnt;msglist) to accomodate `inc' more
24 elements */
22 static void 25 static void
23 _expand (size_t *msgcnt, size_t **msglist, size_t inc) 26 _expand (size_t *msgcnt, size_t **msglist, size_t inc)
24 { 27 {
...@@ -34,6 +37,7 @@ _expand (size_t *msgcnt, size_t **msglist, size_t inc) ...@@ -34,6 +37,7 @@ _expand (size_t *msgcnt, size_t **msglist, size_t inc)
34 } 37 }
35 } 38 }
36 39
40 /* Fatal error handler */
37 static void 41 static void
38 msgset_abort (const char *arg) 42 msgset_abort (const char *arg)
39 { 43 {
...@@ -41,6 +45,8 @@ msgset_abort (const char *arg) ...@@ -41,6 +45,8 @@ msgset_abort (const char *arg)
41 exit (1); 45 exit (1);
42 } 46 }
43 47
48 /* Handlers for expansion of the reserved message names */
49
44 static int 50 static int
45 msgset_first (mailbox_t mbox, size_t *pnum) 51 msgset_first (mailbox_t mbox, size_t *pnum)
46 { 52 {
...@@ -135,10 +141,15 @@ static struct msgset_keyword { ...@@ -135,10 +141,15 @@ static struct msgset_keyword {
135 { NULL }, 141 { NULL },
136 }; 142 };
137 143
144 /* Preprocess a part of a complex message designation. Returns
145 a pointer to the allocated memory containing expanded part of
146 the designation. Pointer to the beginning of the not expanded
147 part (in arg) is placed into *rest */
138 static char * 148 static char *
139 msgset_preproc_part (mailbox_t mbox, char *arg, char **rest) 149 msgset_preproc_part (mailbox_t mbox, char *arg, char **rest)
140 { 150 {
141 struct msgset_keyword *p; 151 struct msgset_keyword *p;
152 char *cp;
142 153
143 for (p = keywords; p->name; p++) 154 for (p = keywords; p->name; p++)
144 if (strncmp (arg, p->name, strlen (p->name)) == 0) 155 if (strncmp (arg, p->name, strlen (p->name)) == 0)
...@@ -161,16 +172,29 @@ msgset_preproc_part (mailbox_t mbox, char *arg, char **rest) ...@@ -161,16 +172,29 @@ msgset_preproc_part (mailbox_t mbox, char *arg, char **rest)
161 *rest = arg + strlen (p->name); 172 *rest = arg + strlen (p->name);
162 return ret; 173 return ret;
163 } 174 }
175 cp = strchr (arg, '-');
176 if (cp)
177 {
178 char *ret;
179
180 *rest = cp;
181 ret = xmalloc (cp - arg + 1);
182 memcpy (ret, arg, cp - arg);
183 ret[cp - arg] = 0;
184 return ret;
185 }
186
164 *rest = arg + strlen (arg); 187 *rest = arg + strlen (arg);
165 return strdup (arg); 188 return strdup (arg);
166 } 189 }
167 190
191 /* Preprocess (expand) a single message designation */
168 static char * 192 static char *
169 msgset_preproc (mailbox_t mbox, char *arg) 193 msgset_preproc (mailbox_t mbox, char *arg)
170 { 194 {
171 char *buf, *tail; 195 char *buf, *tail;
172 196
173 if (strcmp (arg, "all") == 0) 197 if (strcmp (arg, "all") == 0 || strcmp (arg, ".") == 0)
174 { 198 {
175 /* Special case */ 199 /* Special case */
176 arg = "first-last"; 200 arg = "first-last";
...@@ -207,21 +231,91 @@ comp_mesg (const void *a, const void *b) ...@@ -207,21 +231,91 @@ comp_mesg (const void *a, const void *b)
207 return 0; 231 return 0;
208 } 232 }
209 233
234 static int _mh_msgset_parse __P((mailbox_t mbox, mh_msgset_t *msgset,
235 int argc, char **argv));
236
237 /* Treat arg as a name of user-defined sequence and attempt to
238 expand it. Return 0 if succeeded, non-zero otherwise. */
210 int 239 int
211 mh_msgset_parse (mailbox_t mbox, mh_msgset_t *msgset, int argc, char **argv) 240 expand_user_seq (mailbox_t mbox, mh_msgset_t *msgset, char *arg)
241 {
242 int argc;
243 char **argv;
244 char *p, *listp;
245 int rc = 1;
246 int negate = 0;
247
248 p = strchr (arg, ':');
249 if (p)
250 *p++ = 0;
251 listp = mh_global_sequences_get (arg, NULL);
252 if (!listp)
253 {
254 int len;
255 char *neg = mh_global_profile_get ("Sequence-Negation", NULL);
256 if (!neg)
257 return 1;
258 len = strlen (neg);
259 if (strncmp (arg, neg, len))
260 return 1;
261 negate = 1;
262 listp = mh_global_sequences_get (arg + len, NULL);
263 if (!listp)
264 return 1;
265 }
266
267 if (argcv_get (listp, "", NULL, &argc, &argv) == 0)
268 rc = _mh_msgset_parse (mbox, msgset, argc, argv);
269 argcv_free (argc, argv);
270 if (rc)
271 return rc;
272
273 if (negate)
274 mh_msgset_negate (mbox, msgset);
275
276 if (p)
277 {
278 int first, num;
279
280 num = strtoul (p, &p, 0);
281 if (*p)
282 {
283 mh_msgset_free (msgset);
284 return 1;
285 }
286 if (num < 0)
287 {
288 first = num + msgset->count;
289 num = - num;
290 }
291 else
292 first = 0;
293 if (num > msgset->count)
294 {
295 mh_msgset_free (msgset);
296 return 1;
297 }
298
299 if (first > 0)
300 memmove (msgset->list, &msgset->list[first],
301 sizeof (msgset->list[0]) * num);
302 msgset->count = num;
303 }
304
305 return rc;
306 }
307
308 /* Parse a message specification from (argc;argv). Returned msgset is
309 not sorted nor optimised */
310 int
311 _mh_msgset_parse (mailbox_t mbox, mh_msgset_t *msgset, int argc, char **argv)
212 { 312 {
213 size_t msgcnt; 313 size_t msgcnt;
214 size_t *msglist; 314 size_t *msglist;
215 char *xargv[2];
216 size_t i, msgno; 315 size_t i, msgno;
217 316
218 if (argc == 0) 317 if (argc == 0)
219 { 318 return 1;
220 argc = 1;
221 argv = xargv;
222 argv[0] = "cur";
223 argv[1] = NULL;
224 }
225 319
226 msgcnt = argc; 320 msgcnt = argc;
227 msglist = calloc (msgcnt, sizeof(*msglist)); 321 msglist = calloc (msgcnt, sizeof(*msglist));
...@@ -232,6 +326,24 @@ mh_msgset_parse (mailbox_t mbox, mh_msgset_t *msgset, int argc, char **argv) ...@@ -232,6 +326,24 @@ mh_msgset_parse (mailbox_t mbox, mh_msgset_t *msgset, int argc, char **argv)
232 size_t msg_first, n; 326 size_t msg_first, n;
233 long num; 327 long num;
234 char *arg = msgset_preproc (mbox, argv[i]); 328 char *arg = msgset_preproc (mbox, argv[i]);
329
330 if (!isdigit (arg[0]))
331 {
332 int j;
333 mh_msgset_t m;
334
335 if (expand_user_seq (mbox, &m, arg))
336 {
337 mh_error ("message set %s does not exist", arg);
338 exit (1);
339 }
340 _expand (&msgcnt, &msglist, m.count);
341 for (j = 0; j < m.count; j++)
342 msglist[msgno++] = m.list[j];
343 mh_msgset_free (&m);
344 }
345 else
346 {
235 start = strtoul (arg, &p, 0); 347 start = strtoul (arg, &p, 0);
236 switch (*p) 348 switch (*p)
237 { 349 {
...@@ -301,25 +413,55 @@ mh_msgset_parse (mailbox_t mbox, mh_msgset_t *msgset, int argc, char **argv) ...@@ -301,25 +413,55 @@ mh_msgset_parse (mailbox_t mbox, mh_msgset_t *msgset, int argc, char **argv)
301 default: 413 default:
302 msgset_abort (argv[i]); 414 msgset_abort (argv[i]);
303 } 415 }
416 }
304 free (arg); 417 free (arg);
305 } 418 }
306 419
307 msgcnt = msgno; 420 msgset->count = msgno;
421 msgset->list = msglist;
422 return 0;
423 }
424
425 /* Parse a message specification from (argc;argv). Returned msgset is
426 sorted and optimised (i.e. it does not contain duplicate message
427 numbers) */
428 int
429 mh_msgset_parse (mailbox_t mbox, mh_msgset_t *msgset,
430 int argc, char **argv, char *def)
431 {
432 char *xargv[2];
433 int rc;
434
435 if (argc == 0)
436 {
437 argc = 1;
438 argv = xargv;
439 argv[0] = def ? def : "cur";
440 argv[1] = NULL;
441 }
442
443 rc = _mh_msgset_parse (mbox, msgset, argc, argv);
444
445 if (rc == 0)
446 {
447 size_t i, msgno;
448 size_t msgcnt = msgset->count;
449 size_t *msglist = msgset->list;
308 450
309 /* Sort the resulting message set */ 451 /* Sort the resulting message set */
310 qsort (msglist, msgcnt, sizeof (*msglist), comp_mesg); 452 qsort (msglist, msgcnt, sizeof (*msgset->list), comp_mesg);
311 453
312 /* Remove duplicates. */ 454 /* Remove duplicates. */
313 for (i = 0, msgno = 1; i < msgcnt; i++) 455 for (i = 0, msgno = 1; i < msgset->count; i++)
314 if (msglist[msgno-1] != msglist[i]) 456 if (msglist[msgno-1] != msglist[i])
315 msglist[msgno++] = msglist[i]; 457 msglist[msgno++] = msglist[i];
316 msgcnt = msgno; 458 msgset->count = msgno;
317 459 }
318 msgset->count = msgcnt; 460 return rc;
319 msgset->list = msglist;
320 return 0;
321 } 461 }
322 462
463 /* Check if message with ordinal number `num' is contained in the
464 message set. */
323 int 465 int
324 mh_msgset_member (mh_msgset_t *msgset, size_t num) 466 mh_msgset_member (mh_msgset_t *msgset, size_t num)
325 { 467 {
...@@ -400,3 +542,75 @@ mh_get_message (mailbox_t mbox, size_t seqno, message_t *mesg) ...@@ -400,3 +542,75 @@ mh_get_message (mailbox_t mbox, size_t seqno, message_t *mesg)
400 return mh_search_message (mbox, 1, count, seqno, mesg); 542 return mh_search_message (mbox, 1, count, seqno, mesg);
401 } 543 }
402 544
545 /* Reverse the order of messages in the message set */
546 void
547 mh_msgset_reverse (mh_msgset_t *msgset)
548 {
549 int head, tail;
550
551 for (head = 0, tail = msgset->count-1; head < tail; head++, tail--)
552 {
553 size_t val = msgset->list[head];
554 msgset->list[head] = msgset->list[tail];
555 msgset->list[tail] = val;
556 }
557 }
558
559 /* Set the current message to that contained at position `index'
560 in the given message set */
561 int
562 mh_msgset_current (mailbox_t mbox, mh_msgset_t *msgset, int index)
563 {
564 message_t msg = NULL;
565 if (mailbox_get_message (mbox, msgset->list[index], &msg))
566 return 1;
567 return mh_message_number (msg, &current_message);
568 }
569
570 /* Free memory allocated for the message set. Note, that the msgset
571 itself is supposed to reside in the statically allocated memory and
572 therefore is not freed */
573 void
574 mh_msgset_free (mh_msgset_t *msgset)
575 {
576 if (msgset->count)
577 free (msgset->list);
578 }
579
580 /* Negate the message set: on return `msgset' consists of the messages
581 _not contained_ in the input message set. Any memory associated with
582 the input message set is freed */
583 void
584 mh_msgset_negate (mailbox_t mbox, mh_msgset_t *msgset)
585 {
586 size_t i, total = 0, msgno;
587 size_t *list;
588
589 mailbox_messages_count (mbox, &total);
590 list = calloc (total, sizeof (list[0]));
591 if (!list)
592 {
593 mh_error ("not enough memory");
594 abort ();
595 }
596
597 for (i = 1, msgno = 0; i <= total; i++)
598 {
599 if (!mh_msgset_member (msgset, i))
600 list[msgno++] = i;
601 }
602
603 list = realloc (list, sizeof (list[0]) * msgno);
604 if (!list)
605 {
606 mh_error ("not enough memory");
607 abort ();
608 }
609 mh_msgset_free (msgset);
610 msgset->count = msgno;
611 msgset->list = list;
612 }
613
614
615
616
......