NeoMutt  2025-09-05-43-g177ed6
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
compile.c File Reference

Compile a Pattern. More...

#include "config.h"
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <time.h>
#include "private.h"
#include "mutt/lib.h"
#include "address/lib.h"
#include "config/lib.h"
#include "core/lib.h"
#include "lib.h"
#include "parse/lib.h"
#include "mview.h"
+ Include dependency graph for compile.c:

Go to the source code of this file.

Macros

#define MUTT_PDR_NO_FLAGS   0
 No flags are set.
 
#define MUTT_PDR_MINUS   (1 << 0)
 Pattern contains a range.
 
#define MUTT_PDR_PLUS   (1 << 1)
 Extend the range using '+'.
 
#define MUTT_PDR_WINDOW   (1 << 2)
 Extend the range in both directions using '*'.
 
#define MUTT_PDR_ABSOLUTE   (1 << 3)
 Absolute pattern range.
 
#define MUTT_PDR_DONE   (1 << 4)
 Pattern parse successfully.
 
#define MUTT_PDR_ERROR   (1 << 8)
 Invalid pattern.
 
#define MUTT_PDR_ERRORDONE   (MUTT_PDR_ERROR | MUTT_PDR_DONE)
 

Typedefs

typedef uint16_t ParseDateRangeFlags
 Flags for parse_date_range(), e.g. MUTT_PDR_MINUS.
 

Functions

static bool eat_regex (struct Pattern *pat, PatternCompFlags flags, struct Buffer *s, struct Buffer *err)
 Parse a regex - Implements eat_arg_t -.
 
static bool add_query_msgid (char *line, int line_num, void *user_data)
 Parse a Message-Id and add it to a list - Implements mutt_file_map_t -.
 
static bool eat_query (struct Pattern *pat, PatternCompFlags flags, struct Buffer *s, struct Buffer *err, struct Mailbox *m)
 Parse a query for an external search program - Implements eat_arg_t -.
 
static const char * get_offset (struct tm *tm, const char *s, int sign)
 Calculate a symbolic offset.
 
static const char * get_date (const char *s, struct tm *t, struct Buffer *err)
 Parse a (partial) date in dd/mm/yyyy format.
 
static const char * parse_date_range (const char *pc, struct tm *min, struct tm *max, bool have_min, struct tm *base_min, struct Buffer *err)
 Parse a date range.
 
static void adjust_date_range (struct tm *min, struct tm *max)
 Put a date range in the correct order.
 
bool eval_date_minmax (struct Pattern *pat, const char *s, struct Buffer *err)
 Evaluate a date-range pattern against 'now'.
 
static bool eat_range (struct Pattern *pat, PatternCompFlags flags, struct Buffer *s, struct Buffer *err)
 Parse a number range - Implements eat_arg_t -.
 
static bool eat_date (struct Pattern *pat, PatternCompFlags flags, struct Buffer *s, struct Buffer *err)
 Parse a date pattern - Implements eat_arg_t -.
 
static char * find_matching_paren (char *s)
 Find the matching parenthesis.
 
void mutt_pattern_free (struct PatternList **pat)
 Free a Pattern.
 
static struct Patternmutt_pattern_new (void)
 Create a new Pattern.
 
static struct PatternList * mutt_pattern_list_new (void)
 Create a new list containing a Pattern.
 
static struct Patternattach_leaf (struct PatternList *list, struct Pattern *leaf)
 Attach a Pattern to a Pattern List.
 
static struct Patternattach_new_root (struct PatternList **curlist)
 Create a new Pattern as a parent for a List.
 
static struct Patternattach_new_leaf (struct PatternList **curlist)
 Attach a new Pattern to a List.
 
struct PatternList * mutt_pattern_comp (struct MailboxView *mv, const char *s, PatternCompFlags flags, struct Buffer *err)
 Create a Pattern.
 

Detailed Description

Compile a Pattern.

Authors
  • R Primus
  • Pietro Cerutti
  • Richard Russon

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program. If not, see http://www.gnu.org/licenses/.

Definition in file compile.c.

Macro Definition Documentation

◆ MUTT_PDR_NO_FLAGS

#define MUTT_PDR_NO_FLAGS   0

No flags are set.

Definition at line 50 of file compile.c.

◆ MUTT_PDR_MINUS

#define MUTT_PDR_MINUS   (1 << 0)

Pattern contains a range.

Definition at line 51 of file compile.c.

◆ MUTT_PDR_PLUS

#define MUTT_PDR_PLUS   (1 << 1)

Extend the range using '+'.

Definition at line 52 of file compile.c.

◆ MUTT_PDR_WINDOW

#define MUTT_PDR_WINDOW   (1 << 2)

Extend the range in both directions using '*'.

Definition at line 53 of file compile.c.

◆ MUTT_PDR_ABSOLUTE

#define MUTT_PDR_ABSOLUTE   (1 << 3)

Absolute pattern range.

Definition at line 54 of file compile.c.

◆ MUTT_PDR_DONE

#define MUTT_PDR_DONE   (1 << 4)

Pattern parse successfully.

Definition at line 55 of file compile.c.

◆ MUTT_PDR_ERROR

#define MUTT_PDR_ERROR   (1 << 8)

Invalid pattern.

Definition at line 56 of file compile.c.

◆ MUTT_PDR_ERRORDONE

#define MUTT_PDR_ERRORDONE   (MUTT_PDR_ERROR | MUTT_PDR_DONE)

Definition at line 59 of file compile.c.

Typedef Documentation

◆ ParseDateRangeFlags

typedef uint16_t ParseDateRangeFlags

Flags for parse_date_range(), e.g. MUTT_PDR_MINUS.

Definition at line 49 of file compile.c.

Function Documentation

◆ get_offset()

static const char * get_offset ( struct tm * tm,
const char * s,
int sign )
static

Calculate a symbolic offset.

Parameters
tmStore the time here
sstring to parse
signSign of range, 1 for positive, -1 for negative
Return values
ptrNext char after parsed offset
  • Ny years
  • Nm months
  • Nw weeks
  • Nd days

Definition at line 220 of file compile.c.

221{
222 char *ps = NULL;
223 int offset = strtol(s, &ps, 0);
224 if (((sign < 0) && (offset > 0)) || ((sign > 0) && (offset < 0)))
225 offset = -offset;
226
227 switch (*ps)
228 {
229 case 'y':
230 tm->tm_year += offset;
231 break;
232 case 'm':
233 tm->tm_mon += offset;
234 break;
235 case 'w':
236 tm->tm_mday += 7 * offset;
237 break;
238 case 'd':
239 tm->tm_mday += offset;
240 break;
241 case 'H':
242 tm->tm_hour += offset;
243 break;
244 case 'M':
245 tm->tm_min += offset;
246 break;
247 case 'S':
248 tm->tm_sec += offset;
249 break;
250 default:
251 return s;
252 }
254 return ps + 1;
255}
void mutt_date_normalize_time(struct tm *tm)
Fix the contents of a struct tm.
Definition date.c:310
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ get_date()

static const char * get_date ( const char * s,
struct tm * t,
struct Buffer * err )
static

Parse a (partial) date in dd/mm/yyyy format.

Parameters
sString to parse
tStore the time here
errBuffer for error messages
Return values
ptrFirst character after the date

This function parses a (partial) date separated by '/'. The month and year are optional and if the year is less than 70 it's assumed to be after 2000.

Examples:

  • "10" = 10 of this month, this year
  • "10/12" = 10 of December, this year
  • "10/12/04" = 10 of December, 2004
  • "10/12/2008" = 10 of December, 2008
  • "20081210" = 10 of December, 2008

Definition at line 274 of file compile.c.

275{
276 char *p = NULL;
277 struct tm tm = mutt_date_localtime(mutt_date_now());
278 bool iso8601 = true;
279
280 for (int v = 0; v < 8; v++)
281 {
282 if (s[v] && (s[v] >= '0') && (s[v] <= '9'))
283 continue;
284
285 iso8601 = false;
286 break;
287 }
288
289 if (iso8601)
290 {
291 int year = 0;
292 int month = 0;
293 int mday = 0;
294 sscanf(s, "%4d%2d%2d", &year, &month, &mday);
295
296 t->tm_year = year;
297 if (t->tm_year > 1900)
298 t->tm_year -= 1900;
299 t->tm_mon = month - 1;
300 t->tm_mday = mday;
301
302 if ((t->tm_mday < 1) || (t->tm_mday > 31))
303 {
304 buf_printf(err, _("Invalid day of month: %s"), s);
305 return NULL;
306 }
307 if ((t->tm_mon < 0) || (t->tm_mon > 11))
308 {
309 buf_printf(err, _("Invalid month: %s"), s);
310 return NULL;
311 }
312
313 return (s + 8);
314 }
315
316 t->tm_mday = strtol(s, &p, 10);
317 if ((t->tm_mday < 1) || (t->tm_mday > 31))
318 {
319 buf_printf(err, _("Invalid day of month: %s"), s);
320 return NULL;
321 }
322 if (*p != '/')
323 {
324 /* fill in today's month and year */
325 t->tm_mon = tm.tm_mon;
326 t->tm_year = tm.tm_year;
327 return p;
328 }
329 p++;
330 t->tm_mon = strtol(p, &p, 10) - 1;
331 if ((t->tm_mon < 0) || (t->tm_mon > 11))
332 {
333 buf_printf(err, _("Invalid month: %s"), p);
334 return NULL;
335 }
336 if (*p != '/')
337 {
338 t->tm_year = tm.tm_year;
339 return p;
340 }
341 p++;
342 t->tm_year = strtol(p, &p, 10);
343 if (t->tm_year < 70) /* year 2000+ */
344 t->tm_year += 100;
345 else if (t->tm_year > 1900)
346 t->tm_year -= 1900;
347 return p;
348}
int buf_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition buffer.c:161
struct tm mutt_date_localtime(time_t t)
Converts calendar time to a broken-down time structure expressed in user timezone.
Definition date.c:906
time_t mutt_date_now(void)
Return the number of seconds since the Unix epoch.
Definition date.c:456
#define _(a)
Definition message.h:28
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ parse_date_range()

static const char * parse_date_range ( const char * pc,
struct tm * min,
struct tm * max,
bool have_min,
struct tm * base_min,
struct Buffer * err )
static

Parse a date range.

Parameters
pcString to parse
minEarlier date
maxLater date
have_minDo we have a base minimum date?
base_minBase minimum date
errBuffer for error messages
Return values
ptrFirst character after the date

Definition at line 360 of file compile.c.

362{
364 while (*pc && ((flags & MUTT_PDR_DONE) == 0))
365 {
366 const char *pt = NULL;
367 char ch = *pc++;
368 SKIPWS(pc);
369 switch (ch)
370 {
371 case '-':
372 {
373 /* try a range of absolute date minus offset of Ndwmy */
374 pt = get_offset(min, pc, -1);
375 if (pc == pt)
376 {
377 if (flags == MUTT_PDR_NO_FLAGS)
378 { /* nothing yet and no offset parsed => absolute date? */
379 if (!get_date(pc, max, err))
380 {
381 flags |= (MUTT_PDR_ABSOLUTE | MUTT_PDR_ERRORDONE); /* done bad */
382 }
383 else
384 {
385 /* reestablish initial base minimum if not specified */
386 if (!have_min)
387 memcpy(min, base_min, sizeof(struct tm));
388 flags |= (MUTT_PDR_ABSOLUTE | MUTT_PDR_DONE); /* done good */
389 }
390 }
391 else
392 {
393 flags |= MUTT_PDR_ERRORDONE;
394 }
395 }
396 else
397 {
398 pc = pt;
399 if ((flags == MUTT_PDR_NO_FLAGS) && !have_min)
400 { /* the very first "-3d" without a previous absolute date */
401 max->tm_year = min->tm_year;
402 max->tm_mon = min->tm_mon;
403 max->tm_mday = min->tm_mday;
404 }
405 flags |= MUTT_PDR_MINUS;
406 }
407 break;
408 }
409 case '+':
410 { /* enlarge plus range */
411 pt = get_offset(max, pc, 1);
412 if (pc == pt)
413 {
414 flags |= MUTT_PDR_ERRORDONE;
415 }
416 else
417 {
418 pc = pt;
419 flags |= MUTT_PDR_PLUS;
420 }
421 break;
422 }
423 case '*':
424 { /* enlarge window in both directions */
425 pt = get_offset(min, pc, -1);
426 if (pc == pt)
427 {
428 flags |= MUTT_PDR_ERRORDONE;
429 }
430 else
431 {
432 pc = get_offset(max, pc, 1);
433 flags |= MUTT_PDR_WINDOW;
434 }
435 break;
436 }
437 default:
438 flags |= MUTT_PDR_ERRORDONE;
439 }
440 SKIPWS(pc);
441 }
442 if ((flags & MUTT_PDR_ERROR) && !(flags & MUTT_PDR_ABSOLUTE))
443 { /* get_date has its own error message, don't overwrite it here */
444 buf_printf(err, _("Invalid relative date: %s"), pc - 1);
445 }
446 return (flags & MUTT_PDR_ERROR) ? NULL : pc;
447}
#define MUTT_PDR_PLUS
Extend the range using '+'.
Definition compile.c:52
#define MUTT_PDR_NO_FLAGS
No flags are set.
Definition compile.c:50
uint16_t ParseDateRangeFlags
Flags for parse_date_range(), e.g. MUTT_PDR_MINUS.
Definition compile.c:49
#define MUTT_PDR_ERROR
Invalid pattern.
Definition compile.c:56
#define MUTT_PDR_ABSOLUTE
Absolute pattern range.
Definition compile.c:54
static const char * get_offset(struct tm *tm, const char *s, int sign)
Calculate a symbolic offset.
Definition compile.c:220
#define MUTT_PDR_DONE
Pattern parse successfully.
Definition compile.c:55
static const char * get_date(const char *s, struct tm *t, struct Buffer *err)
Parse a (partial) date in dd/mm/yyyy format.
Definition compile.c:274
#define MUTT_PDR_ERRORDONE
Definition compile.c:59
#define MUTT_PDR_MINUS
Pattern contains a range.
Definition compile.c:51
#define MUTT_PDR_WINDOW
Extend the range in both directions using '*'.
Definition compile.c:53
#define SKIPWS(ch)
Definition string2.h:51
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ adjust_date_range()

static void adjust_date_range ( struct tm * min,
struct tm * max )
static

Put a date range in the correct order.

Parameters
[in,out]minEarlier date
[in,out]maxLater date

Definition at line 454 of file compile.c.

455{
456 if ((min->tm_year > max->tm_year) ||
457 ((min->tm_year == max->tm_year) && (min->tm_mon > max->tm_mon)) ||
458 ((min->tm_year == max->tm_year) && (min->tm_mon == max->tm_mon) &&
459 (min->tm_mday > max->tm_mday)))
460 {
461 int tmp;
462
463 tmp = min->tm_year;
464 min->tm_year = max->tm_year;
465 max->tm_year = tmp;
466
467 tmp = min->tm_mon;
468 min->tm_mon = max->tm_mon;
469 max->tm_mon = tmp;
470
471 tmp = min->tm_mday;
472 min->tm_mday = max->tm_mday;
473 max->tm_mday = tmp;
474
475 min->tm_hour = 0;
476 min->tm_min = 0;
477 min->tm_sec = 0;
478 max->tm_hour = 23;
479 max->tm_min = 59;
480 max->tm_sec = 59;
481 }
482}
+ Here is the caller graph for this function:

◆ eval_date_minmax()

bool eval_date_minmax ( struct Pattern * pat,
const char * s,
struct Buffer * err )

Evaluate a date-range pattern against 'now'.

Parameters
patPattern to modify
sPattern string to use
errBuffer for error messages
Return values
truePattern valid and updated
falsePattern invalid

Definition at line 492 of file compile.c.

493{
494 /* the '0' time is Jan 1, 1970 UTC, so in order to prevent a negative time
495 * when doing timezone conversion, we use Jan 2, 1970 UTC as the base here */
496 struct tm min = { 0 };
497 min.tm_mday = 2;
498 min.tm_year = 70;
499
500 /* Arbitrary year in the future. Don't set this too high or
501 * mutt_date_make_time() returns something larger than will fit in a time_t
502 * on some systems */
503 struct tm max = { 0 };
504 max.tm_year = 130;
505 max.tm_mon = 11;
506 max.tm_mday = 31;
507 max.tm_hour = 23;
508 max.tm_min = 59;
509 max.tm_sec = 59;
510
511 if (strchr("<>=", s[0]))
512 {
513 /* offset from current time
514 * <3d less than three days ago
515 * >3d more than three days ago
516 * =3d exactly three days ago */
517 struct tm *tm = NULL;
518 bool exact = false;
519
520 if (s[0] == '<')
521 {
523 tm = &min;
524 }
525 else
526 {
528 tm = &max;
529
530 if (s[0] == '=')
531 exact = true;
532 }
533
534 /* Reset the HMS unless we are relative matching using one of those
535 * offsets. */
536 char *offset_type = NULL;
537 strtol(s + 1, &offset_type, 0);
538 if (!(*offset_type && strchr("HMS", *offset_type)))
539 {
540 tm->tm_hour = 23;
541 tm->tm_min = 59;
542 tm->tm_sec = 59;
543 }
544
545 /* force negative offset */
546 get_offset(tm, s + 1, -1);
547
548 if (exact)
549 {
550 /* start at the beginning of the day in question */
551 memcpy(&min, &max, sizeof(max));
552 min.tm_hour = 0;
553 min.tm_sec = 0;
554 min.tm_min = 0;
555 }
556 }
557 else
558 {
559 const char *pc = s;
560
561 bool have_min = false;
562 bool until_now = false;
563 if (mutt_isdigit(*pc))
564 {
565 /* minimum date specified */
566 pc = get_date(pc, &min, err);
567 if (!pc)
568 {
569 return false;
570 }
571 have_min = true;
572 SKIPWS(pc);
573 if (*pc == '-')
574 {
575 const char *pt = pc + 1;
576 SKIPWS(pt);
577 until_now = (*pt == '\0');
578 }
579 }
580
581 if (!until_now)
582 { /* max date or relative range/window */
583
584 struct tm base_min = { 0 };
585
586 if (!have_min)
587 { /* save base minimum and set current date, e.g. for "-3d+1d" */
588 memcpy(&base_min, &min, sizeof(base_min));
590 min.tm_hour = 0;
591 min.tm_sec = 0;
592 min.tm_min = 0;
593 }
594
595 /* preset max date for relative offsets,
596 * if nothing follows we search for messages on a specific day */
597 max.tm_year = min.tm_year;
598 max.tm_mon = min.tm_mon;
599 max.tm_mday = min.tm_mday;
600
601 if (!parse_date_range(pc, &min, &max, have_min, &base_min, err))
602 { /* bail out on any parsing error */
603 return false;
604 }
605 }
606 }
607
608 /* Since we allow two dates to be specified we'll have to adjust that. */
609 adjust_date_range(&min, &max);
610
611 pat->min = mutt_date_make_time(&min, true);
612 pat->max = mutt_date_make_time(&max, true);
613
614 return true;
615}
static const char * parse_date_range(const char *pc, struct tm *min, struct tm *max, bool have_min, struct tm *base_min, struct Buffer *err)
Parse a date range.
Definition compile.c:360
static void adjust_date_range(struct tm *min, struct tm *max)
Put a date range in the correct order.
Definition compile.c:454
bool mutt_isdigit(int arg)
Wrapper for isdigit(3)
Definition ctype.c:65
time_t mutt_date_make_time(struct tm *t, bool local)
Convert struct tm to time_t
Definition date.c:242
long min
Minimum for range checks.
Definition lib.h:88
long max
Maximum for range checks.
Definition lib.h:89
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ find_matching_paren()

static char * find_matching_paren ( char * s)
static

Find the matching parenthesis.

Parameters
sstring to search
Return values
ptr
  • Matching close parenthesis
  • End of string NUL, if not found

Definition at line 750 of file compile.c.

751{
752 int level = 1;
753
754 for (; *s; s++)
755 {
756 if (*s == '(')
757 {
758 level++;
759 }
760 else if (*s == ')')
761 {
762 level--;
763 if (level == 0)
764 break;
765 }
766 }
767 return s;
768}
+ Here is the caller graph for this function:

◆ mutt_pattern_free()

void mutt_pattern_free ( struct PatternList ** pat)

Free a Pattern.

Parameters
[out]patPattern to free

Definition at line 774 of file compile.c.

775{
776 if (!pat || !*pat)
777 return;
778
779 struct Pattern *np = SLIST_FIRST(*pat);
780 struct Pattern *next = NULL;
781
782 while (np)
783 {
784 next = SLIST_NEXT(np, entries);
785
786 if (np->is_multi)
787 {
789 }
790 else if (np->string_match || np->dynamic)
791 {
792 FREE(&np->p.str);
793 }
794 else if (np->group_match)
795 {
796 np->p.group = NULL;
797 }
798 else if (np->p.regex)
799 {
800 regfree(np->p.regex);
801 FREE(&np->p.regex);
802 }
803
804#ifdef USE_DEBUG_GRAPHVIZ
805 FREE(&np->raw_pattern);
806#endif
808 FREE(&np);
809
810 np = next;
811 }
812
813 FREE(pat);
814}
void mutt_pattern_free(struct PatternList **pat)
Free a Pattern.
Definition compile.c:774
void mutt_list_free(struct ListHead *h)
Free a List AND its strings.
Definition list.c:123
#define FREE(x)
Definition memory.h:62
#define SLIST_NEXT(elm, field)
Definition queue.h:268
#define SLIST_FIRST(head)
Definition queue.h:227
A simple (non-regex) pattern.
Definition lib.h:77
bool group_match
Check a group of Addresses.
Definition lib.h:82
union Pattern::@006112053024257132210207314205210350156165326341 p
struct Group * group
Address group if group_match is set.
Definition lib.h:93
struct PatternList * child
Arguments to logical operation.
Definition lib.h:90
bool string_match
Check a string for a match.
Definition lib.h:81
regex_t * regex
Compiled regex, for non-pattern matching.
Definition lib.h:92
struct ListHead multi_cases
Multiple strings for ~I pattern.
Definition lib.h:95
char * str
String, if string_match is set.
Definition lib.h:94
bool dynamic
Evaluate date ranges at run time.
Definition lib.h:85
bool is_multi
Multiple case (only for ~I pattern now)
Definition lib.h:87
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_pattern_new()

static struct Pattern * mutt_pattern_new ( void )
static

Create a new Pattern.

Return values
ptrNewly created Pattern

Definition at line 820 of file compile.c.

821{
822 return MUTT_MEM_CALLOC(1, struct Pattern);
823}
#define MUTT_MEM_CALLOC(n, type)
Definition memory.h:47
+ Here is the caller graph for this function:

◆ mutt_pattern_list_new()

static struct PatternList * mutt_pattern_list_new ( void )
static

Create a new list containing a Pattern.

Return values
ptrNewly created list containing a single node with a Pattern

Definition at line 829 of file compile.c.

830{
831 struct PatternList *h = MUTT_MEM_CALLOC(1, struct PatternList);
832 SLIST_INIT(h);
833 struct Pattern *p = mutt_pattern_new();
834 SLIST_INSERT_HEAD(h, p, entries);
835 return h;
836}
static struct Pattern * mutt_pattern_new(void)
Create a new Pattern.
Definition compile.c:820
#define SLIST_INIT(head)
Definition queue.h:254
#define SLIST_INSERT_HEAD(head, elm, field)
Definition queue.h:263
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ attach_leaf()

static struct Pattern * attach_leaf ( struct PatternList * list,
struct Pattern * leaf )
static

Attach a Pattern to a Pattern List.

Parameters
listPattern List to attach to
leafPattern to attach
Return values
ptrAttached leaf

Definition at line 844 of file compile.c.

845{
846 struct Pattern *last = NULL;
847 SLIST_FOREACH(last, list, entries)
848 {
849 // TODO - or we could use a doubly-linked list
850 if (!SLIST_NEXT(last, entries))
851 {
852 SLIST_NEXT(last, entries) = leaf;
853 break;
854 }
855 }
856 return leaf;
857}
#define SLIST_FOREACH(var, head, field)
Definition queue.h:229
+ Here is the caller graph for this function:

◆ attach_new_root()

static struct Pattern * attach_new_root ( struct PatternList ** curlist)
static

Create a new Pattern as a parent for a List.

Parameters
curlistPattern List
Return values
ptrFirst Pattern in the original List
Note
curlist will be altered to the new root Pattern

Definition at line 866 of file compile.c.

867{
868 struct PatternList *root = mutt_pattern_list_new();
869 struct Pattern *leaf = SLIST_FIRST(root);
870 leaf->child = *curlist;
871 *curlist = root;
872 return leaf;
873}
static struct PatternList * mutt_pattern_list_new(void)
Create a new list containing a Pattern.
Definition compile.c:829
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ attach_new_leaf()

static struct Pattern * attach_new_leaf ( struct PatternList ** curlist)
static

Attach a new Pattern to a List.

Parameters
curlistPattern List
Return values
ptrNew Pattern in the original List
Note
curlist may be altered

Definition at line 882 of file compile.c.

883{
884 if (*curlist)
885 {
886 return attach_leaf(*curlist, mutt_pattern_new());
887 }
888 else
889 {
890 return attach_new_root(curlist);
891 }
892}
static struct Pattern * attach_new_root(struct PatternList **curlist)
Create a new Pattern as a parent for a List.
Definition compile.c:866
static struct Pattern * attach_leaf(struct PatternList *list, struct Pattern *leaf)
Attach a Pattern to a Pattern List.
Definition compile.c:844
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_pattern_comp()

struct PatternList * mutt_pattern_comp ( struct MailboxView * mv,
const char * s,
PatternCompFlags flags,
struct Buffer * err )

Create a Pattern.

Parameters
mvMailbox view
sPattern string
flagsFlags, e.g. MUTT_PC_FULL_MSG
errBuffer for error messages
Return values
ptrNewly allocated Pattern

Definition at line 902 of file compile.c.

904{
905 /* curlist when assigned will always point to a list containing at least one node
906 * with a Pattern value. */
907 struct PatternList *curlist = NULL;
908 bool pat_not = false;
909 bool all_addr = false;
910 bool pat_or = false;
911 bool implicit = true; /* used to detect logical AND operator */
912 bool is_alias = false;
913 const struct PatternFlags *entry = NULL;
914 char *p = NULL;
915 char *buf = NULL;
916 struct Mailbox *m = mv ? mv->mailbox : NULL;
917
918 if (!s || (s[0] == '\0'))
919 {
920 buf_strcpy(err, _("empty pattern"));
921 return NULL;
922 }
923
924 struct Buffer *ps = buf_pool_get();
925 buf_strcpy(ps, s);
926 buf_seek(ps, 0);
927
928 SKIPWS(ps->dptr);
929 while (*ps->dptr)
930 {
931 switch (*ps->dptr)
932 {
933 case '^':
934 ps->dptr++;
935 all_addr = !all_addr;
936 break;
937 case '!':
938 ps->dptr++;
939 pat_not = !pat_not;
940 break;
941 case '@':
942 ps->dptr++;
943 is_alias = !is_alias;
944 break;
945 case '|':
946 if (!pat_or)
947 {
948 if (!curlist)
949 {
950 buf_printf(err, _("error in pattern at: %s"), ps->dptr);
951 buf_pool_release(&ps);
952 return NULL;
953 }
954
955 struct Pattern *pat = SLIST_FIRST(curlist);
956 if (SLIST_NEXT(pat, entries))
957 {
958 /* A & B | C == (A & B) | C */
959 struct Pattern *root = attach_new_root(&curlist);
960 root->op = MUTT_PAT_AND;
961 }
962
963 pat_or = true;
964 }
965 ps->dptr++;
966 implicit = false;
967 pat_not = false;
968 all_addr = false;
969 is_alias = false;
970 break;
971 case '%':
972 case '=':
973 case '~':
974 {
975 if (ps->dptr[1] == '\0')
976 {
977 buf_printf(err, _("missing pattern: %s"), ps->dptr);
978 goto cleanup;
979 }
980 short thread_op = 0;
981 if (ps->dptr[1] == '(')
982 thread_op = MUTT_PAT_THREAD;
983 else if ((ps->dptr[1] == '<') && (ps->dptr[2] == '('))
984 thread_op = MUTT_PAT_PARENT;
985 else if ((ps->dptr[1] == '>') && (ps->dptr[2] == '('))
986 thread_op = MUTT_PAT_CHILDREN;
987 if (thread_op != 0)
988 {
989 ps->dptr++; /* skip ~ */
990 if ((thread_op == MUTT_PAT_PARENT) || (thread_op == MUTT_PAT_CHILDREN))
991 ps->dptr++;
992 p = find_matching_paren(ps->dptr + 1);
993 if (p[0] != ')')
994 {
995 buf_printf(err, _("mismatched parentheses: %s"), ps->dptr);
996 goto cleanup;
997 }
998 struct Pattern *leaf = attach_new_leaf(&curlist);
999 leaf->op = thread_op;
1000 leaf->pat_not = pat_not;
1001 leaf->all_addr = all_addr;
1002 leaf->is_alias = is_alias;
1003 pat_not = false;
1004 all_addr = false;
1005 is_alias = false;
1006 /* compile the sub-expression */
1007 buf = mutt_strn_dup(ps->dptr + 1, p - (ps->dptr + 1));
1008 leaf->child = mutt_pattern_comp(mv, buf, flags, err);
1009 if (!leaf->child)
1010 {
1011 FREE(&buf);
1012 goto cleanup;
1013 }
1014 FREE(&buf);
1015 ps->dptr = p + 1; /* restore location */
1016 break;
1017 }
1018 if (implicit && pat_or)
1019 {
1020 /* A | B & C == (A | B) & C */
1021 struct Pattern *root = attach_new_root(&curlist);
1022 root->op = MUTT_PAT_OR;
1023 pat_or = false;
1024 }
1025
1026 entry = lookup_tag(ps->dptr[1]);
1027 if (!entry)
1028 {
1029 buf_printf(err, _("%c: invalid pattern modifier"), *ps->dptr);
1030 goto cleanup;
1031 }
1032 if (entry->flags && ((flags & entry->flags) == 0))
1033 {
1034 buf_printf(err, _("%c: not supported in this mode"), *ps->dptr);
1035 goto cleanup;
1036 }
1037
1038 struct Pattern *leaf = attach_new_leaf(&curlist);
1039 leaf->pat_not = pat_not;
1040 leaf->all_addr = all_addr;
1041 leaf->is_alias = is_alias;
1042 leaf->string_match = (ps->dptr[0] == '=');
1043 leaf->group_match = (ps->dptr[0] == '%');
1044 leaf->sendmode = (flags & MUTT_PC_SEND_MODE_SEARCH);
1045 leaf->op = entry->op;
1046 pat_not = false;
1047 all_addr = false;
1048 is_alias = false;
1049
1050 ps->dptr++; /* move past the ~ */
1051 ps->dptr++; /* eat the operator and any optional whitespace */
1052 SKIPWS(ps->dptr);
1053 if (entry->eat_arg)
1054 {
1055 if (ps->dptr[0] == '\0')
1056 {
1057 buf_addstr(err, _("missing parameter"));
1058 goto cleanup;
1059 }
1060 switch (entry->eat_arg)
1061 {
1062 case EAT_REGEX:
1063 if (!eat_regex(leaf, flags, ps, err))
1064 goto cleanup;
1065 break;
1066 case EAT_DATE:
1067 if (!eat_date(leaf, flags, ps, err))
1068 goto cleanup;
1069 break;
1070 case EAT_RANGE:
1071 if (!eat_range(leaf, flags, ps, err))
1072 goto cleanup;
1073 break;
1074 case EAT_MESSAGE_RANGE:
1075 if (!eat_message_range(leaf, flags, ps, err, mv))
1076 goto cleanup;
1077 break;
1078 case EAT_QUERY:
1079 if (!eat_query(leaf, flags, ps, err, m))
1080 goto cleanup;
1081 break;
1082 default:
1083 break;
1084 }
1085 }
1086 implicit = true;
1087 break;
1088 }
1089
1090 case '(':
1091 {
1092 p = find_matching_paren(ps->dptr + 1);
1093 if (p[0] != ')')
1094 {
1095 buf_printf(err, _("mismatched parentheses: %s"), ps->dptr);
1096 goto cleanup;
1097 }
1098 /* compile the sub-expression */
1099 buf = mutt_strn_dup(ps->dptr + 1, p - (ps->dptr + 1));
1100 struct PatternList *sub = mutt_pattern_comp(mv, buf, flags, err);
1101 FREE(&buf);
1102 if (!sub)
1103 goto cleanup;
1104 struct Pattern *leaf = SLIST_FIRST(sub);
1105 if (curlist)
1106 {
1107 attach_leaf(curlist, leaf);
1108 FREE(&sub);
1109 }
1110 else
1111 {
1112 curlist = sub;
1113 }
1114 leaf->pat_not ^= pat_not;
1115 leaf->all_addr |= all_addr;
1116 leaf->is_alias |= is_alias;
1117 pat_not = false;
1118 all_addr = false;
1119 is_alias = false;
1120 ps->dptr = p + 1; /* restore location */
1121 break;
1122 }
1123
1124 default:
1125 buf_printf(err, _("error in pattern at: %s"), ps->dptr);
1126 goto cleanup;
1127 }
1128 SKIPWS(ps->dptr);
1129 }
1130 buf_pool_release(&ps);
1131
1132 if (!curlist)
1133 {
1134 buf_strcpy(err, _("empty pattern"));
1135 return NULL;
1136 }
1137
1138 if (SLIST_NEXT(SLIST_FIRST(curlist), entries))
1139 {
1140 struct Pattern *root = attach_new_root(&curlist);
1141 root->op = pat_or ? MUTT_PAT_OR : MUTT_PAT_AND;
1142 }
1143
1144 return curlist;
1145
1146cleanup:
1147 mutt_pattern_free(&curlist);
1148 buf_pool_release(&ps);
1149 return NULL;
1150}
void buf_seek(struct Buffer *buf, size_t offset)
Set current read/write position to offset from beginning.
Definition buffer.c:622
size_t buf_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition buffer.c:226
size_t buf_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition buffer.c:395
static struct Pattern * attach_new_leaf(struct PatternList **curlist)
Attach a new Pattern to a List.
Definition compile.c:882
struct PatternList * mutt_pattern_comp(struct MailboxView *mv, const char *s, PatternCompFlags flags, struct Buffer *err)
Create a Pattern.
Definition compile.c:902
static char * find_matching_paren(char *s)
Find the matching parenthesis.
Definition compile.c:750
static bool eat_query(struct Pattern *pat, PatternCompFlags flags, struct Buffer *s, struct Buffer *err, struct Mailbox *m)
Parse a query for an external search program - Implements eat_arg_t -.
Definition compile.c:139
bool eat_message_range(struct Pattern *pat, PatternCompFlags flags, struct Buffer *s, struct Buffer *err, struct MailboxView *mv)
Parse a range of message numbers - Implements eat_arg_t -.
Definition message.c:281
static bool eat_range(struct Pattern *pat, PatternCompFlags flags, struct Buffer *s, struct Buffer *err)
Parse a number range - Implements eat_arg_t -.
Definition compile.c:620
static bool eat_date(struct Pattern *pat, PatternCompFlags flags, struct Buffer *s, struct Buffer *err)
Parse a date pattern - Implements eat_arg_t -.
Definition compile.c:711
static bool eat_regex(struct Pattern *pat, PatternCompFlags flags, struct Buffer *s, struct Buffer *err)
Parse a regex - Implements eat_arg_t -.
Definition compile.c:64
char * mutt_strn_dup(const char *begin, size_t len)
Duplicate a sub-string.
Definition string.c:382
const struct PatternFlags * lookup_tag(char tag)
Lookup a pattern modifier.
Definition flags.c:198
#define MUTT_PC_SEND_MODE_SEARCH
Allow send-mode body searching.
Definition lib.h:71
@ MUTT_PAT_OR
Either pattern can match.
Definition lib.h:138
@ MUTT_PAT_CHILDREN
Pattern matches a child email.
Definition lib.h:141
@ MUTT_PAT_PARENT
Pattern matches parent.
Definition lib.h:140
@ MUTT_PAT_AND
Both patterns must match.
Definition lib.h:137
@ MUTT_PAT_THREAD
Pattern matches email thread.
Definition lib.h:139
@ EAT_RANGE
Process a number (range)
Definition private.h:55
@ EAT_MESSAGE_RANGE
Process a message number (range)
Definition private.h:56
@ EAT_DATE
Process a date (range)
Definition private.h:54
@ EAT_QUERY
Process a query string.
Definition private.h:57
@ EAT_REGEX
Process a regex.
Definition private.h:53
struct Buffer * buf_pool_get(void)
Get a Buffer from the pool.
Definition pool.c:82
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
Definition pool.c:96
String manipulation buffer.
Definition buffer.h:36
char * dptr
Current read/write position.
Definition buffer.h:38
struct Mailbox * mailbox
Current Mailbox.
Definition mview.h:51
A mailbox.
Definition mailbox.h:79
Mapping between user character and internal constant.
Definition private.h:64
enum PatternEat eat_arg
Type of function needed to parse flag, e.g. EAT_DATE.
Definition private.h:69
PatternCompFlags flags
Pattern flags, e.g. MUTT_PC_FULL_MSG.
Definition private.h:67
int op
Operation to perform, e.g. MUTT_PAT_SCORE.
Definition private.h:66
bool all_addr
All Addresses in the list must match.
Definition lib.h:80
bool is_alias
Is there an alias for this Address?
Definition lib.h:84
short op
Operation, e.g. MUTT_PAT_SCORE.
Definition lib.h:78
bool sendmode
Evaluate searches in send-mode.
Definition lib.h:86
bool pat_not
Pattern should be inverted (not)
Definition lib.h:79
+ Here is the call graph for this function:
+ Here is the caller graph for this function: