NeoMutt  2025-12-11-911-gd8d604
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 "alias/lib.h"
#include "gui/lib.h"
#include "lib.h"
#include "parse/lib.h"
+ Include dependency graph for compile.c:

Go to the source code of this file.

Macros

#define MUTT_PDR_ERRORDONE   (MUTT_PDR_ERROR | MUTT_PDR_DONE)
 

Typedefs

typedef uint8_t ParseDateRangeFlags
 

Enumerations

enum  ParseDateRangeFlag {
  MUTT_PDR_NONE = 0 , MUTT_PDR_MINUS = 1U << 0 , MUTT_PDR_PLUS = 1U << 1 , MUTT_PDR_WINDOW = 1U << 2 ,
  MUTT_PDR_ABSOLUTE = 1U << 3 , MUTT_PDR_DONE = 1U << 4 , MUTT_PDR_ERROR = 1U << 5
}
 Flags for parse_date_range(), e.g. More...
 

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 eat_string (struct Pattern *pat, PatternCompFlags flags, struct Buffer *s, struct Buffer *err)
 Parse a plain string - Implements eat_arg_t -.
 
static bool eat_group (struct Pattern *pat, PatternCompFlags flags, struct Buffer *s, struct Buffer *err)
 Parse a group name - 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
  • Thomas Klausner

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_ERRORDONE

#define MUTT_PDR_ERRORDONE   (MUTT_PDR_ERROR | MUTT_PDR_DONE)

Definition at line 67 of file compile.c.

Typedef Documentation

◆ ParseDateRangeFlags

typedef uint8_t ParseDateRangeFlags

Definition at line 65 of file compile.c.

Enumeration Type Documentation

◆ ParseDateRangeFlag

Flags for parse_date_range(), e.g.

MUTT_PDR_MINUS

Enumerator
MUTT_PDR_NONE 

No flags are set.

MUTT_PDR_MINUS 

Pattern contains a range.

MUTT_PDR_PLUS 

Extend the range using '+'.

MUTT_PDR_WINDOW 

Extend the range in both directions using '*'.

MUTT_PDR_ABSOLUTE 

Absolute pattern range.

MUTT_PDR_DONE 

Pattern parse successfully.

MUTT_PDR_ERROR 

Invalid pattern.

Definition at line 53 of file compile.c.

54{
55 // clang-format off
56 MUTT_PDR_NONE = 0,
57 MUTT_PDR_MINUS = 1U << 0,
58 MUTT_PDR_PLUS = 1U << 1,
59 MUTT_PDR_WINDOW = 1U << 2,
60 MUTT_PDR_ABSOLUTE = 1U << 3,
61 MUTT_PDR_DONE = 1U << 4,
62 MUTT_PDR_ERROR = 1U << 5,
63 // clang-format on
64};
@ MUTT_PDR_MINUS
Pattern contains a range.
Definition compile.c:57
@ MUTT_PDR_NONE
No flags are set.
Definition compile.c:56
@ MUTT_PDR_WINDOW
Extend the range in both directions using '*'.
Definition compile.c:59
@ MUTT_PDR_DONE
Pattern parse successfully.
Definition compile.c:61
@ MUTT_PDR_PLUS
Extend the range using '+'.
Definition compile.c:58
@ MUTT_PDR_ERROR
Invalid pattern.
Definition compile.c:62
@ MUTT_PDR_ABSOLUTE
Absolute pattern range.
Definition compile.c:60

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 282 of file compile.c.

283{
284 char *ps = NULL;
285 int offset = strtol(s, &ps, 0);
286 if (((sign < 0) && (offset > 0)) || ((sign > 0) && (offset < 0)))
287 offset = -offset;
288
289 switch (*ps)
290 {
291 case 'y':
292 tm->tm_year += offset;
293 break;
294 case 'm':
295 tm->tm_mon += offset;
296 break;
297 case 'w':
298 tm->tm_mday += 7 * offset;
299 break;
300 case 'd':
301 tm->tm_mday += offset;
302 break;
303 case 'H':
304 tm->tm_hour += offset;
305 break;
306 case 'M':
307 tm->tm_min += offset;
308 break;
309 case 'S':
310 tm->tm_sec += offset;
311 break;
312 default:
313 return s;
314 }
316 return ps + 1;
317}
void mutt_date_normalize_time(struct tm *tm)
Fix the contents of a struct tm.
Definition date.c:311
+ 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 336 of file compile.c.

337{
338 char *p = NULL;
339 struct tm tm = mutt_date_localtime(mutt_date_now());
340 bool iso8601 = true;
341
342 for (int v = 0; v < 8; v++)
343 {
344 if (s[v] && (s[v] >= '0') && (s[v] <= '9'))
345 continue;
346
347 iso8601 = false;
348 break;
349 }
350
351 if (iso8601)
352 {
353 int year = 0;
354 int month = 0;
355 int mday = 0;
356 sscanf(s, "%4d%2d%2d", &year, &month, &mday);
357
358 t->tm_year = year;
359 if (t->tm_year > 1900)
360 t->tm_year -= 1900;
361 t->tm_mon = month - 1;
362 t->tm_mday = mday;
363
364 if ((t->tm_mday < 1) || (t->tm_mday > 31))
365 {
366 buf_printf(err, _("Invalid day of month: %s"), s);
367 return NULL;
368 }
369 if ((t->tm_mon < 0) || (t->tm_mon > 11))
370 {
371 buf_printf(err, _("Invalid month: %s"), s);
372 return NULL;
373 }
374
375 return (s + 8);
376 }
377
378 t->tm_mday = strtol(s, &p, 10);
379 if ((t->tm_mday < 1) || (t->tm_mday > 31))
380 {
381 buf_printf(err, _("Invalid day of month: %s"), s);
382 return NULL;
383 }
384 if (*p != '/')
385 {
386 /* fill in today's month and year */
387 t->tm_mon = tm.tm_mon;
388 t->tm_year = tm.tm_year;
389 return p;
390 }
391 p++;
392 t->tm_mon = strtol(p, &p, 10) - 1;
393 if ((t->tm_mon < 0) || (t->tm_mon > 11))
394 {
395 buf_printf(err, _("Invalid month: %s"), p);
396 return NULL;
397 }
398 if (*p != '/')
399 {
400 t->tm_year = tm.tm_year;
401 return p;
402 }
403 p++;
404 t->tm_year = strtol(p, &p, 10);
405 if (t->tm_year < 70) /* year 2000+ */
406 t->tm_year += 100;
407 else if (t->tm_year > 1900)
408 t->tm_year -= 1900;
409 return p;
410}
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:907
time_t mutt_date_now(void)
Return the number of seconds since the Unix epoch.
Definition date.c:457
#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 422 of file compile.c.

424{
426 while (*pc && ((flags & MUTT_PDR_DONE) == 0))
427 {
428 const char *pt = NULL;
429 char ch = *pc++;
430 SKIPWS(pc);
431 switch (ch)
432 {
433 case '-':
434 {
435 /* try a range of absolute date minus offset of Ndwmy */
436 pt = get_offset(min, pc, -1);
437 if (pc == pt)
438 {
439 if (flags == MUTT_PDR_NONE)
440 { /* nothing yet and no offset parsed => absolute date? */
441 if (!get_date(pc, max, err))
442 {
443 flags |= (MUTT_PDR_ABSOLUTE | MUTT_PDR_ERRORDONE); /* done bad */
444 }
445 else
446 {
447 /* reestablish initial base minimum if not specified */
448 if (!have_min)
449 memcpy(min, base_min, sizeof(struct tm));
450 flags |= (MUTT_PDR_ABSOLUTE | MUTT_PDR_DONE); /* done good */
451 }
452 }
453 else
454 {
455 flags |= MUTT_PDR_ERRORDONE;
456 }
457 }
458 else
459 {
460 pc = pt;
461 if ((flags == MUTT_PDR_NONE) && !have_min)
462 { /* the very first "-3d" without a previous absolute date */
463 max->tm_year = min->tm_year;
464 max->tm_mon = min->tm_mon;
465 max->tm_mday = min->tm_mday;
466 }
467 flags |= MUTT_PDR_MINUS;
468 }
469 break;
470 }
471 case '+':
472 { /* enlarge plus range */
473 pt = get_offset(max, pc, 1);
474 if (pc == pt)
475 {
476 flags |= MUTT_PDR_ERRORDONE;
477 }
478 else
479 {
480 pc = pt;
481 flags |= MUTT_PDR_PLUS;
482 }
483 break;
484 }
485 case '*':
486 { /* enlarge window in both directions */
487 pt = get_offset(min, pc, -1);
488 if (pc == pt)
489 {
490 flags |= MUTT_PDR_ERRORDONE;
491 }
492 else
493 {
494 pc = get_offset(max, pc, 1);
495 flags |= MUTT_PDR_WINDOW;
496 }
497 break;
498 }
499 default:
500 flags |= MUTT_PDR_ERRORDONE;
501 }
502 SKIPWS(pc);
503 }
504 if ((flags & MUTT_PDR_ERROR) && !(flags & MUTT_PDR_ABSOLUTE))
505 { /* get_date has its own error message, don't overwrite it here */
506 buf_printf(err, _("Invalid relative date: %s"), pc - 1);
507 }
508 return (flags & MUTT_PDR_ERROR) ? NULL : pc;
509}
uint8_t ParseDateRangeFlags
Definition compile.c:65
static const char * get_offset(struct tm *tm, const char *s, int sign)
Calculate a symbolic offset.
Definition compile.c:282
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:336
#define MUTT_PDR_ERRORDONE
Definition compile.c:67
#define SKIPWS(ch)
Definition string2.h:52
+ 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 516 of file compile.c.

517{
518 if ((min->tm_year > max->tm_year) ||
519 ((min->tm_year == max->tm_year) && (min->tm_mon > max->tm_mon)) ||
520 ((min->tm_year == max->tm_year) && (min->tm_mon == max->tm_mon) &&
521 (min->tm_mday > max->tm_mday)))
522 {
523 int tmp;
524
525 tmp = min->tm_year;
526 min->tm_year = max->tm_year;
527 max->tm_year = tmp;
528
529 tmp = min->tm_mon;
530 min->tm_mon = max->tm_mon;
531 max->tm_mon = tmp;
532
533 tmp = min->tm_mday;
534 min->tm_mday = max->tm_mday;
535 max->tm_mday = tmp;
536
537 min->tm_hour = 0;
538 min->tm_min = 0;
539 min->tm_sec = 0;
540 max->tm_hour = 23;
541 max->tm_min = 59;
542 max->tm_sec = 59;
543 }
544}
+ 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 554 of file compile.c.

555{
556 /* the '0' time is Jan 1, 1970 UTC, so in order to prevent a negative time
557 * when doing timezone conversion, we use Jan 2, 1970 UTC as the base here */
558 struct tm min = { 0 };
559 min.tm_mday = 2;
560 min.tm_year = 70;
561
562 /* Arbitrary year in the future. Don't set this too high or
563 * mutt_date_make_time() returns something larger than will fit in a time_t
564 * on some systems */
565 struct tm max = { 0 };
566 max.tm_year = 137;
567 max.tm_mon = 11;
568 max.tm_mday = 31;
569 max.tm_hour = 23;
570 max.tm_min = 59;
571 max.tm_sec = 59;
572
573 if (strchr("<>=", s[0]))
574 {
575 /* offset from current time
576 * <3d less than three days ago
577 * >3d more than three days ago
578 * =3d exactly three days ago */
579 struct tm *tm = NULL;
580 bool exact = false;
581
582 if (s[0] == '<')
583 {
585 tm = &min;
586 }
587 else
588 {
590 tm = &max;
591
592 if (s[0] == '=')
593 exact = true;
594 }
595
596 /* Reset the HMS unless we are relative matching using one of those
597 * offsets. */
598 char *offset_type = NULL;
599 strtol(s + 1, &offset_type, 0);
600 if (!(*offset_type && strchr("HMS", *offset_type)))
601 {
602 tm->tm_hour = 23;
603 tm->tm_min = 59;
604 tm->tm_sec = 59;
605 }
606
607 /* force negative offset */
608 get_offset(tm, s + 1, -1);
609
610 if (exact)
611 {
612 /* start at the beginning of the day in question */
613 memcpy(&min, &max, sizeof(max));
614 min.tm_hour = 0;
615 min.tm_sec = 0;
616 min.tm_min = 0;
617 }
618 }
619 else
620 {
621 const char *pc = s;
622
623 bool have_min = false;
624 bool until_now = false;
625 if (mutt_isdigit(*pc))
626 {
627 /* minimum date specified */
628 pc = get_date(pc, &min, err);
629 if (!pc)
630 {
631 return false;
632 }
633 have_min = true;
634 SKIPWS(pc);
635 if (*pc == '-')
636 {
637 const char *pt = pc + 1;
638 SKIPWS(pt);
639 until_now = (*pt == '\0');
640 }
641 }
642
643 if (!until_now)
644 { /* max date or relative range/window */
645
646 struct tm base_min = { 0 };
647
648 if (!have_min)
649 { /* save base minimum and set current date, e.g. for "-3d+1d" */
650 memcpy(&base_min, &min, sizeof(base_min));
652 min.tm_hour = 0;
653 min.tm_sec = 0;
654 min.tm_min = 0;
655 }
656
657 /* preset max date for relative offsets,
658 * if nothing follows we search for messages on a specific day */
659 max.tm_year = min.tm_year;
660 max.tm_mon = min.tm_mon;
661 max.tm_mday = min.tm_mday;
662
663 if (!parse_date_range(pc, &min, &max, have_min, &base_min, err))
664 { /* bail out on any parsing error */
665 return false;
666 }
667 }
668 }
669
670 /* Since we allow two dates to be specified we'll have to adjust that. */
671 adjust_date_range(&min, &max);
672
673 pat->min = mutt_date_make_time(&min, true);
674 pat->max = mutt_date_make_time(&max, true);
675
676 return true;
677}
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:422
static void adjust_date_range(struct tm *min, struct tm *max)
Put a date range in the correct order.
Definition compile.c:516
bool mutt_isdigit(int arg)
Wrapper for isdigit(3)
Definition ctype.c:66
time_t mutt_date_make_time(struct tm *t, bool local)
Convert struct tm to time_t
Definition date.c:243
long min
Minimum for range checks.
Definition lib.h:95
long max
Maximum for range checks.
Definition lib.h:96
+ 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 812 of file compile.c.

813{
814 int level = 1;
815
816 for (; *s; s++)
817 {
818 if (*s == '(')
819 {
820 level++;
821 }
822 else if (*s == ')')
823 {
824 level--;
825 if (level == 0)
826 break;
827 }
828 }
829 return s;
830}
+ 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 836 of file compile.c.

837{
838 if (!pat || !*pat)
839 return;
840
841 struct Pattern *np = SLIST_FIRST(*pat);
842 struct Pattern *next = NULL;
843
844 while (np)
845 {
846 next = SLIST_NEXT(np, entries);
847
848 if (np->is_multi)
849 {
851 }
852 else if (np->string_match || np->dynamic)
853 {
854 FREE(&np->p.str);
855 }
856 else if (np->group_match)
857 {
858 np->p.group = NULL;
859 }
860 else if (np->p.regex)
861 {
862 regfree(np->p.regex);
863 FREE(&np->p.regex);
864 }
865
866#ifdef USE_DEBUG_GRAPHVIZ
867 FREE(&np->raw_pattern);
868#endif
870 FREE(&np);
871
872 np = next;
873 }
874
875 FREE(pat);
876}
void mutt_pattern_free(struct PatternList **pat)
Free a Pattern.
Definition compile.c:836
void mutt_list_free(struct ListHead *h)
Free a List AND its strings.
Definition list.c:123
#define FREE(x)
Free memory and set the pointer to NULL.
Definition memory.h:68
#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:84
bool group_match
Check a group of Addresses.
Definition lib.h:89
union Pattern::@006112053024257132210207314205210350156165326341 p
struct Group * group
Address group if group_match is set.
Definition lib.h:100
struct PatternList * child
Arguments to logical operation.
Definition lib.h:97
bool string_match
Check a string for a match.
Definition lib.h:88
regex_t * regex
Compiled regex, for non-pattern matching.
Definition lib.h:99
struct ListHead multi_cases
Multiple strings for ~I pattern.
Definition lib.h:102
char * str
String, if string_match is set.
Definition lib.h:101
bool dynamic
Evaluate date ranges at run time.
Definition lib.h:92
bool is_multi
Multiple case (only for ~I pattern now)
Definition lib.h:94
+ 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 882 of file compile.c.

883{
884 return MUTT_MEM_CALLOC(1, struct Pattern);
885}
#define MUTT_MEM_CALLOC(n, type)
Definition memory.h:52
+ 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 891 of file compile.c.

892{
893 struct PatternList *h = MUTT_MEM_CALLOC(1, struct PatternList);
894 SLIST_INIT(h);
895 struct Pattern *p = mutt_pattern_new();
896 SLIST_INSERT_HEAD(h, p, entries);
897 return h;
898}
static struct Pattern * mutt_pattern_new(void)
Create a new Pattern.
Definition compile.c:882
#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 906 of file compile.c.

907{
908 struct Pattern *last = NULL;
909 SLIST_FOREACH(last, list, entries)
910 {
911 // TODO - or we could use a doubly-linked list
912 if (!SLIST_NEXT(last, entries))
913 {
914 SLIST_NEXT(last, entries) = leaf;
915 break;
916 }
917 }
918 return leaf;
919}
#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 928 of file compile.c.

929{
930 struct PatternList *root = mutt_pattern_list_new();
931 struct Pattern *leaf = SLIST_FIRST(root);
932 leaf->child = *curlist;
933 *curlist = root;
934 return leaf;
935}
static struct PatternList * mutt_pattern_list_new(void)
Create a new list containing a Pattern.
Definition compile.c:891
+ 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 944 of file compile.c.

945{
946 if (*curlist)
947 {
948 return attach_leaf(*curlist, mutt_pattern_new());
949 }
950 else
951 {
952 return attach_new_root(curlist);
953 }
954}
static struct Pattern * attach_new_root(struct PatternList **curlist)
Create a new Pattern as a parent for a List.
Definition compile.c:928
static struct Pattern * attach_leaf(struct PatternList *list, struct Pattern *leaf)
Attach a Pattern to a Pattern List.
Definition compile.c:906
+ 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 964 of file compile.c.

966{
967 /* curlist when assigned will always point to a list containing at least one node
968 * with a Pattern value. */
969 struct PatternList *curlist = NULL;
970 bool pat_not = false;
971 bool all_addr = false;
972 bool pat_or = false;
973 bool implicit = true; /* used to detect logical AND operator */
974 bool is_alias = false;
975 const struct PatternFlags *entry = NULL;
976 char *p = NULL;
977 char *buf = NULL;
978 struct Mailbox *m = mv ? mv->mailbox : NULL;
979
980 if (!s || (s[0] == '\0'))
981 {
982 buf_strcpy(err, _("empty pattern"));
983 return NULL;
984 }
985
986 struct Buffer *ps = buf_pool_get();
987 buf_strcpy(ps, s);
988 buf_seek(ps, 0);
989
990 SKIPWS(ps->dptr);
991 while (*ps->dptr)
992 {
993 switch (*ps->dptr)
994 {
995 case '^':
996 ps->dptr++;
997 all_addr = !all_addr;
998 break;
999 case '!':
1000 ps->dptr++;
1001 pat_not = !pat_not;
1002 break;
1003 case '@':
1004 ps->dptr++;
1005 is_alias = !is_alias;
1006 break;
1007 case '|':
1008 if (!pat_or)
1009 {
1010 if (!curlist)
1011 {
1012 buf_printf(err, _("error in pattern at: %s"), ps->dptr);
1013 buf_pool_release(&ps);
1014 return NULL;
1015 }
1016
1017 struct Pattern *pat = SLIST_FIRST(curlist);
1018 if (SLIST_NEXT(pat, entries))
1019 {
1020 /* A & B | C == (A & B) | C */
1021 struct Pattern *root = attach_new_root(&curlist);
1022 root->op = MUTT_PAT_AND;
1023 }
1024
1025 pat_or = true;
1026 }
1027 ps->dptr++;
1028 implicit = false;
1029 pat_not = false;
1030 all_addr = false;
1031 is_alias = false;
1032 break;
1033 case '%':
1034 case '=':
1035 case '~':
1036 {
1037 if (ps->dptr[1] == '\0')
1038 {
1039 buf_printf(err, _("missing pattern: %s"), ps->dptr);
1040 goto cleanup;
1041 }
1042 short thread_op = 0;
1043 if (ps->dptr[1] == '(')
1044 thread_op = MUTT_PAT_THREAD;
1045 else if ((ps->dptr[1] == '<') && (ps->dptr[2] == '('))
1046 thread_op = MUTT_PAT_PARENT;
1047 else if ((ps->dptr[1] == '>') && (ps->dptr[2] == '('))
1048 thread_op = MUTT_PAT_CHILDREN;
1049 if (thread_op != 0)
1050 {
1051 ps->dptr++; /* skip ~ */
1052 if ((thread_op == MUTT_PAT_PARENT) || (thread_op == MUTT_PAT_CHILDREN))
1053 ps->dptr++;
1054 p = find_matching_paren(ps->dptr + 1);
1055 if (p[0] != ')')
1056 {
1057 buf_printf(err, _("mismatched parentheses: %s"), ps->dptr);
1058 goto cleanup;
1059 }
1060 struct Pattern *leaf = attach_new_leaf(&curlist);
1061 leaf->op = thread_op;
1062 leaf->pat_not = pat_not;
1063 leaf->all_addr = all_addr;
1064 leaf->is_alias = is_alias;
1065 pat_not = false;
1066 all_addr = false;
1067 is_alias = false;
1068 /* compile the sub-expression */
1069 buf = mutt_strn_dup(ps->dptr + 1, p - (ps->dptr + 1));
1070 leaf->child = mutt_pattern_comp(mv, buf, flags, err);
1071 if (!leaf->child)
1072 {
1073 FREE(&buf);
1074 goto cleanup;
1075 }
1076 FREE(&buf);
1077 ps->dptr = p + 1; /* restore location */
1078 break;
1079 }
1080 if (implicit && pat_or)
1081 {
1082 /* A | B & C == (A | B) & C */
1083 struct Pattern *root = attach_new_root(&curlist);
1084 root->op = MUTT_PAT_OR;
1085 pat_or = false;
1086 }
1087
1088 char prefix = ps->dptr[0];
1089 entry = lookup_tag(prefix, ps->dptr[1]);
1090 if (!entry)
1091 {
1092 buf_printf(err, _("%c%c: invalid pattern"), prefix, ps->dptr[1]);
1093 goto cleanup;
1094 }
1095 if (entry->flags && ((flags & entry->flags) == 0))
1096 {
1097 buf_printf(err, _("%c%c: not supported in this mode"), prefix, ps->dptr[1]);
1098 goto cleanup;
1099 }
1100
1101 struct Pattern *leaf = attach_new_leaf(&curlist);
1102 leaf->pat_not = pat_not;
1103 leaf->all_addr = all_addr;
1104 leaf->is_alias = is_alias;
1105 leaf->sendmode = (flags & MUTT_PC_SEND_MODE_SEARCH);
1106 leaf->op = entry->op;
1107 pat_not = false;
1108 all_addr = false;
1109 is_alias = false;
1110
1111 // Determine the actual eat_arg to use.
1112 // If the entry was found via fallback (entry->prefix is '~' but we used '=' or '%'),
1113 // override the eat_arg to use string or group parsing respectively.
1114 enum PatternEat eat_arg = entry->eat_arg;
1115 if ((entry->prefix == '~') && (prefix == '=') && (eat_arg == EAT_REGEX))
1116 eat_arg = EAT_STRING;
1117 else if ((entry->prefix == '~') && (prefix == '%') && (eat_arg == EAT_REGEX))
1118 eat_arg = EAT_GROUP;
1119
1120 ps->dptr++; /* move past the prefix (~, %, =) */
1121 ps->dptr++; /* eat the operator and any optional whitespace */
1122 SKIPWS(ps->dptr);
1123 if (eat_arg)
1124 {
1125 if (ps->dptr[0] == '\0')
1126 {
1127 buf_addstr(err, _("missing parameter"));
1128 goto cleanup;
1129 }
1130 switch (eat_arg)
1131 {
1132 case EAT_REGEX:
1133 if (!eat_regex(leaf, flags, ps, err))
1134 goto cleanup;
1135 break;
1136 case EAT_STRING:
1137 if (!eat_string(leaf, flags, ps, err))
1138 goto cleanup;
1139 break;
1140 case EAT_GROUP:
1141 if (!eat_group(leaf, flags, ps, err))
1142 goto cleanup;
1143 break;
1144 case EAT_DATE:
1145 if (!eat_date(leaf, flags, ps, err))
1146 goto cleanup;
1147 break;
1148 case EAT_RANGE:
1149 if (!eat_range(leaf, flags, ps, err))
1150 goto cleanup;
1151 break;
1152 case EAT_MESSAGE_RANGE:
1153 if (!eat_message_range(leaf, flags, ps, err, mv))
1154 goto cleanup;
1155 break;
1156 case EAT_QUERY:
1157 if (!eat_query(leaf, flags, ps, err, m))
1158 goto cleanup;
1159 break;
1160 default:
1161 break;
1162 }
1163 }
1164 implicit = true;
1165 break;
1166 }
1167
1168 case '(':
1169 {
1170 p = find_matching_paren(ps->dptr + 1);
1171 if (p[0] != ')')
1172 {
1173 buf_printf(err, _("mismatched parentheses: %s"), ps->dptr);
1174 goto cleanup;
1175 }
1176 /* compile the sub-expression */
1177 buf = mutt_strn_dup(ps->dptr + 1, p - (ps->dptr + 1));
1178 struct PatternList *sub = mutt_pattern_comp(mv, buf, flags, err);
1179 FREE(&buf);
1180 if (!sub)
1181 goto cleanup;
1182 struct Pattern *leaf = SLIST_FIRST(sub);
1183 if (curlist)
1184 {
1185 attach_leaf(curlist, leaf);
1186 FREE(&sub);
1187 }
1188 else
1189 {
1190 curlist = sub;
1191 }
1192 leaf->pat_not ^= pat_not;
1193 leaf->all_addr |= all_addr;
1194 leaf->is_alias |= is_alias;
1195 pat_not = false;
1196 all_addr = false;
1197 is_alias = false;
1198 ps->dptr = p + 1; /* restore location */
1199 break;
1200 }
1201
1202 default:
1203 buf_printf(err, _("error in pattern at: %s"), ps->dptr);
1204 goto cleanup;
1205 }
1206 SKIPWS(ps->dptr);
1207 }
1208 buf_pool_release(&ps);
1209
1210 if (!curlist)
1211 {
1212 buf_strcpy(err, _("empty pattern"));
1213 return NULL;
1214 }
1215
1216 if (SLIST_NEXT(SLIST_FIRST(curlist), entries))
1217 {
1218 struct Pattern *root = attach_new_root(&curlist);
1219 root->op = pat_or ? MUTT_PAT_OR : MUTT_PAT_AND;
1220 }
1221
1222 return curlist;
1223
1224cleanup:
1225 mutt_pattern_free(&curlist);
1226 buf_pool_release(&ps);
1227 return NULL;
1228}
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:944
struct PatternList * mutt_pattern_comp(struct MailboxView *mv, const char *s, PatternCompFlags flags, struct Buffer *err)
Create a Pattern.
Definition compile.c:964
static char * find_matching_paren(char *s)
Find the matching parenthesis.
Definition compile.c:812
static bool eat_group(struct Pattern *pat, PatternCompFlags flags, struct Buffer *s, struct Buffer *err)
Parse a group name - Implements eat_arg_t -.
Definition compile.c:147
static bool eat_string(struct Pattern *pat, PatternCompFlags flags, struct Buffer *s, struct Buffer *err)
Parse a plain string - Implements eat_arg_t -.
Definition compile.c:115
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:202
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:283
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:682
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:773
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:72
char * mutt_strn_dup(const char *begin, size_t len)
Duplicate a sub-string.
Definition string.c:384
const struct PatternFlags * lookup_tag(char prefix, char tag)
Lookup a pattern modifier.
Definition flags.c:235
@ MUTT_PAT_OR
Either pattern can match.
Definition lib.h:151
@ MUTT_PAT_CHILDREN
Pattern matches a child email.
Definition lib.h:154
@ MUTT_PAT_PARENT
Pattern matches parent.
Definition lib.h:153
@ MUTT_PAT_AND
Both patterns must match.
Definition lib.h:150
@ MUTT_PAT_THREAD
Pattern matches email thread.
Definition lib.h:152
@ MUTT_PC_SEND_MODE_SEARCH
Allow send-mode body searching.
Definition lib.h:76
PatternEat
Function to process pattern arguments.
Definition private.h:51
@ EAT_STRING
Process a plain string.
Definition private.h:59
@ EAT_RANGE
Process a number (range)
Definition private.h:57
@ EAT_GROUP
Process a group name.
Definition private.h:54
@ EAT_MESSAGE_RANGE
Process a message number (range)
Definition private.h:55
@ EAT_DATE
Process a date (range)
Definition private.h:53
@ EAT_QUERY
Process a query string.
Definition private.h:56
@ EAT_REGEX
Process a regex.
Definition private.h:58
struct Buffer * buf_pool_get(void)
Get a Buffer from the pool.
Definition pool.c:91
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
Definition pool.c:111
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:81
Mapping between user character and internal constant.
Definition private.h:66
enum PatternEat eat_arg
Type of function needed to parse flag, e.g. EAT_DATE.
Definition private.h:72
PatternCompFlags flags
Pattern flags, e.g. MUTT_PC_FULL_MSG.
Definition private.h:70
int op
Operation to perform, e.g. MUTT_PAT_SCORE.
Definition private.h:69
char prefix
Prefix for this pattern, e.g. '~', '', or '='.
Definition private.h:67
bool all_addr
All Addresses in the list must match.
Definition lib.h:87
bool is_alias
Is there an alias for this Address?
Definition lib.h:91
short op
Operation, e.g. MUTT_PAT_SCORE.
Definition lib.h:85
bool sendmode
Evaluate searches in send-mode.
Definition lib.h:93
bool pat_not
Pattern should be inverted (not)
Definition lib.h:86
+ Here is the call graph for this function:
+ Here is the caller graph for this function: