Commit 548fc274 548fc2741060293377b07cac54c91e58a88bad3b by Sergey Poznyakoff

(msgset_preproc): Expand the second part

of the message spec as well (the one after dash).
(mh_msgset_parse): Fill message set with message ordinal
numbers.
(mh_search_message): Binary search for a message with the
given sequence number.
(mh_get_message): Retrieve the message with the given sequence
number.
1 parent 80959de7
...@@ -136,10 +136,10 @@ static struct msgset_keyword { ...@@ -136,10 +136,10 @@ static struct msgset_keyword {
136 }; 136 };
137 137
138 static char * 138 static char *
139 msgset_preproc (mailbox_t mbox, char *arg) 139 msgset_preproc_part (mailbox_t mbox, char *arg, char **rest)
140 { 140 {
141 struct msgset_keyword *p; 141 struct msgset_keyword *p;
142 142
143 for (p = keywords; p->name; p++) 143 for (p = keywords; p->name; p++)
144 if (strncmp (arg, p->name, strlen (p->name)) == 0) 144 if (strncmp (arg, p->name, strlen (p->name)) == 0)
145 { 145 {
...@@ -157,12 +157,46 @@ msgset_preproc (mailbox_t mbox, char *arg) ...@@ -157,12 +157,46 @@ msgset_preproc (mailbox_t mbox, char *arg)
157 exit (1); 157 exit (1);
158 } 158 }
159 message_get_uid (msg, &uid); 159 message_get_uid (msg, &uid);
160 asprintf (&ret, "%lu%s", (unsigned long) uid, arg + strlen (p->name)); 160 asprintf (&ret, "%lu", (unsigned long) uid);
161 *rest = arg + strlen (p->name);
161 return ret; 162 return ret;
162 } 163 }
164 *rest = arg + strlen (arg);
163 return strdup (arg); 165 return strdup (arg);
164 } 166 }
165 167
168 static char *
169 msgset_preproc (mailbox_t mbox, char *arg)
170 {
171 char *buf, *tail;
172
173 if (strcmp (arg, "all") == 0)
174 {
175 /* Special case */
176 arg = "first-last";
177 }
178
179 buf = msgset_preproc_part (mbox, arg, &tail);
180 if (tail[0] == '-')
181 {
182 char *rest = msgset_preproc_part (mbox, tail+1, &tail);
183 char *p = NULL;
184 asprintf (&p, "%s-%s", buf, rest);
185 free (rest);
186 free (buf);
187 buf = p;
188 }
189
190 if (tail[0])
191 {
192 char *p = NULL;
193 asprintf (&p, "%s%s", buf, tail);
194 free (buf);
195 buf = p;
196 }
197 return buf;
198 }
199
166 static int 200 static int
167 comp_mesg (const void *a, const void *b) 201 comp_mesg (const void *a, const void *b)
168 { 202 {
...@@ -195,13 +229,20 @@ mh_msgset_parse (mailbox_t mbox, mh_msgset_t *msgset, int argc, char **argv) ...@@ -195,13 +229,20 @@ mh_msgset_parse (mailbox_t mbox, mh_msgset_t *msgset, int argc, char **argv)
195 { 229 {
196 char *p = NULL; 230 char *p = NULL;
197 size_t start, end; 231 size_t start, end;
232 size_t msg_first, n;
198 long num; 233 long num;
199 char *arg = msgset_preproc (mbox, argv[i]); 234 char *arg = msgset_preproc (mbox, argv[i]);
200 start = strtoul (arg, &p, 0); 235 start = strtoul (arg, &p, 0);
201 switch (*p) 236 switch (*p)
202 { 237 {
203 case 0: 238 case 0:
204 msglist[msgno++] = start; 239 n = mh_get_message (mbox, start, NULL);
240 if (!n)
241 {
242 mh_error ("message %d does not exist", start);
243 exit (1);
244 }
245 msglist[msgno++] = n;
205 break; 246 break;
206 247
207 case '-': 248 case '-':
...@@ -215,8 +256,18 @@ mh_msgset_parse (mailbox_t mbox, mh_msgset_t *msgset, int argc, char **argv) ...@@ -215,8 +256,18 @@ mh_msgset_parse (mailbox_t mbox, mh_msgset_t *msgset, int argc, char **argv)
215 end = t; 256 end = t;
216 } 257 }
217 _expand (&msgcnt, &msglist, end - start); 258 _expand (&msgcnt, &msglist, end - start);
259 msg_first = msgno;
218 for (; start <= end; start++) 260 for (; start <= end; start++)
219 msglist[msgno++] = 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);
270 }
220 break; 271 break;
221 272
222 case ':': 273 case ':':
...@@ -227,12 +278,24 @@ mh_msgset_parse (mailbox_t mbox, mh_msgset_t *msgset, int argc, char **argv) ...@@ -227,12 +278,24 @@ mh_msgset_parse (mailbox_t mbox, mh_msgset_t *msgset, int argc, char **argv)
227 if (end < start) 278 if (end < start)
228 { 279 {
229 size_t t = start; 280 size_t t = start;
230 start = end; 281 start = end + 1;
231 end = t; 282 end = t;
232 } 283 }
284 else
285 end--;
233 _expand (&msgcnt, &msglist, end - start); 286 _expand (&msgcnt, &msglist, end - start);
287 msg_first = msgno;
234 for (; start <= end; start++) 288 for (; start <= end; start++)
235 msglist[msgno++] = start; 289 {
290 n = mh_get_message (mbox, start, NULL);
291 if (n)
292 msglist[msgno++] = n;
293 }
294 if (msgno == msg_first)
295 {
296 mh_error ("no messages in range %s", argv[i]);
297 exit (1);
298 }
236 break; 299 break;
237 300
238 default: 301 default:
...@@ -241,6 +304,8 @@ mh_msgset_parse (mailbox_t mbox, mh_msgset_t *msgset, int argc, char **argv) ...@@ -241,6 +304,8 @@ mh_msgset_parse (mailbox_t mbox, mh_msgset_t *msgset, int argc, char **argv)
241 free (arg); 304 free (arg);
242 } 305 }
243 306
307 msgcnt = msgno;
308
244 /* Sort the resulting message set */ 309 /* Sort the resulting message set */
245 qsort (msglist, msgcnt, sizeof (*msglist), comp_mesg); 310 qsort (msglist, msgcnt, sizeof (*msglist), comp_mesg);
246 311
...@@ -265,3 +330,73 @@ mh_msgset_member (mh_msgset_t *msgset, size_t num) ...@@ -265,3 +330,73 @@ mh_msgset_member (mh_msgset_t *msgset, size_t num)
265 return i + 1; 330 return i + 1;
266 return 0; 331 return 0;
267 } 332 }
333
334 /* Auxiliary function. Performs binary search for a message with the
335 given sequence number */
336 static size_t
337 mh_search_message (mailbox_t mbox, size_t start, size_t stop,
338 size_t seqno, message_t *mesg)
339 {
340 message_t mid_msg = NULL;
341 size_t num = 0, middle;
342
343 middle = (start + stop) / 2;
344 if (mailbox_get_message (mbox, middle, &mid_msg)
345 || mh_message_number (mid_msg, &num))
346 return 0;
347
348 if (num == seqno)
349 {
350 if (mesg)
351 *mesg = mid_msg;
352 return middle;
353 }
354
355 if (start >= stop)
356 return 0;
357
358 if (num > seqno)
359 return mh_search_message (mbox, start, middle-1, seqno, mesg);
360 else /*if (num < seqno)*/
361 return mh_search_message (mbox, middle+1, stop, seqno, mesg);
362 }
363
364 /* Retrieve the message with the given sequence number.
365 Returns ordinal number of the message in the mailbox if found,
366 zero otherwise. The retrieved message is stored in the location
367 pointed to by mesg, unless it is NULL. */
368
369 size_t
370 mh_get_message (mailbox_t mbox, size_t seqno, message_t *mesg)
371 {
372 size_t num, count;
373 message_t msg;
374
375 if (mailbox_get_message (mbox, 1, &msg)
376 || mh_message_number (msg, &num))
377 return 0;
378 if (seqno < num)
379 return 0;
380 else if (seqno == num)
381 {
382 if (mesg)
383 *mesg = msg;
384 return 1;
385 }
386
387 if (mailbox_messages_count (mbox, &count)
388 || mailbox_get_message (mbox, count, &msg)
389 || mh_message_number (msg, &num))
390 return 0;
391 if (seqno > num)
392 return 0;
393 else if (seqno == num)
394 {
395 if (mesg)
396 *mesg = msg;
397 return count;
398 }
399
400 return mh_search_message (mbox, 1, count, seqno, mesg);
401 }
402
......