(mh_msgset_reverse,mh_msgset_negate,
mh_msgset_current, mh_msgset_free): new functions. Added comments.
Showing
1 changed file
with
296 additions
and
82 deletions
... | @@ -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, ¤t_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 | ... | ... |
-
Please register or sign in to post a comment