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,11 +141,16 @@ static struct msgset_keyword { ...@@ -135,11 +141,16 @@ 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;
142 152 char *cp;
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)
145 { 156 {
...@@ -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,94 +326,142 @@ mh_msgset_parse (mailbox_t mbox, mh_msgset_t *msgset, int argc, char **argv) ...@@ -232,94 +326,142 @@ 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]);
235 start = strtoul (arg, &p, 0); 329
236 switch (*p) 330 if (!isdigit (arg[0]))
237 { 331 {
238 case 0: 332 int j;
239 n = mh_get_message (mbox, start, NULL); 333 mh_msgset_t m;
240 if (!n)
241 {
242 mh_error ("message %d does not exist", start);
243 exit (1);
244 }
245 msglist[msgno++] = n;
246 break;
247 334
248 case '-': 335 if (expand_user_seq (mbox, &m, arg))
249 end = strtoul (p+1, &p, 0);
250 if (*p || end == start)
251 msgset_abort (argv[i]);
252 if (end < start)
253 { 336 {
254 size_t t = start; 337 mh_error ("message set %s does not exist", arg);
255 start = end;
256 end = t;
257 }
258 _expand (&msgcnt, &msglist, end - start);
259 msg_first = msgno;
260 for (; start <= end; start++)
261 {
262 n = mh_get_message (mbox, start, NULL);
263 if (n)
264 msglist[msgno++] = n;
265 }
266 if (msgno == msg_first)
267 {
268 mh_error ("no messages in range %s", argv[i]);
269 exit (1); 338 exit (1);
270 } 339 }
271 break; 340 _expand (&msgcnt, &msglist, m.count);
272 341 for (j = 0; j < m.count; j++)
273 case ':': 342 msglist[msgno++] = m.list[j];
274 num = strtoul (p+1, &p, 0); 343 mh_msgset_free (&m);
275 if (*p) 344 }
276 msgset_abort (argv[i]); 345 else
277 end = start + num; 346 {
278 if (end < start) 347 start = strtoul (arg, &p, 0);
279 { 348 switch (*p)
280 size_t t = start;
281 start = end + 1;
282 end = t;
283 }
284 else
285 end--;
286 _expand (&msgcnt, &msglist, end - start);
287 msg_first = msgno;
288 for (; start <= end; start++)
289 { 349 {
350 case 0:
290 n = mh_get_message (mbox, start, NULL); 351 n = mh_get_message (mbox, start, NULL);
291 if (n) 352 if (!n)
292 msglist[msgno++] = n; 353 {
293 } 354 mh_error ("message %d does not exist", start);
294 if (msgno == msg_first) 355 exit (1);
295 { 356 }
296 mh_error ("no messages in range %s", argv[i]); 357 msglist[msgno++] = n;
297 exit (1); 358 break;
359
360 case '-':
361 end = strtoul (p+1, &p, 0);
362 if (*p || end == start)
363 msgset_abort (argv[i]);
364 if (end < start)
365 {
366 size_t t = start;
367 start = end;
368 end = t;
369 }
370 _expand (&msgcnt, &msglist, end - start);
371 msg_first = msgno;
372 for (; start <= end; start++)
373 {
374 n = mh_get_message (mbox, start, NULL);
375 if (n)
376 msglist[msgno++] = n;
377 }
378 if (msgno == msg_first)
379 {
380 mh_error ("no messages in range %s", argv[i]);
381 exit (1);
382 }
383 break;
384
385 case ':':
386 num = strtoul (p+1, &p, 0);
387 if (*p)
388 msgset_abort (argv[i]);
389 end = start + num;
390 if (end < start)
391 {
392 size_t t = start;
393 start = end + 1;
394 end = t;
395 }
396 else
397 end--;
398 _expand (&msgcnt, &msglist, end - start);
399 msg_first = msgno;
400 for (; start <= end; start++)
401 {
402 n = mh_get_message (mbox, start, NULL);
403 if (n)
404 msglist[msgno++] = n;
405 }
406 if (msgno == msg_first)
407 {
408 mh_error ("no messages in range %s", argv[i]);
409 exit (1);
410 }
411 break;
412
413 default:
414 msgset_abort (argv[i]);
298 } 415 }
299 break;
300
301 default:
302 msgset_abort (argv[i]);
303 } 416 }
304 free (arg); 417 free (arg);
305 } 418 }
306 419
307 msgcnt = msgno; 420 msgset->count = msgno;
308
309 /* Sort the resulting message set */
310 qsort (msglist, msgcnt, sizeof (*msglist), comp_mesg);
311
312 /* Remove duplicates. */
313 for (i = 0, msgno = 1; i < msgcnt; i++)
314 if (msglist[msgno-1] != msglist[i])
315 msglist[msgno++] = msglist[i];
316 msgcnt = msgno;
317
318 msgset->count = msgcnt;
319 msgset->list = msglist; 421 msgset->list = msglist;
320 return 0; 422 return 0;
321 } 423 }
322 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;
450
451 /* Sort the resulting message set */
452 qsort (msglist, msgcnt, sizeof (*msgset->list), comp_mesg);
453
454 /* Remove duplicates. */
455 for (i = 0, msgno = 1; i < msgset->count; i++)
456 if (msglist[msgno-1] != msglist[i])
457 msglist[msgno++] = msglist[i];
458 msgset->count = msgno;
459 }
460 return rc;
461 }
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
......