NeoMutt  2025-12-11-276-g10b23b
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 "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_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 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_NO_FLAGS

#define MUTT_PDR_NO_FLAGS   0

No flags are set.

Definition at line 51 of file compile.c.

◆ MUTT_PDR_MINUS

#define MUTT_PDR_MINUS   (1 << 0)

Pattern contains a range.

Definition at line 52 of file compile.c.

◆ MUTT_PDR_PLUS

#define MUTT_PDR_PLUS   (1 << 1)

Extend the range using '+'.

Definition at line 53 of file compile.c.

◆ MUTT_PDR_WINDOW

#define MUTT_PDR_WINDOW   (1 << 2)

Extend the range in both directions using '*'.

Definition at line 54 of file compile.c.

◆ MUTT_PDR_ABSOLUTE

#define MUTT_PDR_ABSOLUTE   (1 << 3)

Absolute pattern range.

Definition at line 55 of file compile.c.

◆ MUTT_PDR_DONE

#define MUTT_PDR_DONE   (1 << 4)

Pattern parse successfully.

Definition at line 56 of file compile.c.

◆ MUTT_PDR_ERROR

#define MUTT_PDR_ERROR   (1 << 8)

Invalid pattern.

Definition at line 57 of file compile.c.

◆ MUTT_PDR_ERRORDONE

#define MUTT_PDR_ERRORDONE   (MUTT_PDR_ERROR | MUTT_PDR_DONE)

Definition at line 60 of file compile.c.

Typedef Documentation

◆ ParseDateRangeFlags

typedef uint16_t ParseDateRangeFlags

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

Definition at line 50 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 272 of file compile.c.

273{
274 char *ps = NULL;
275 int offset = strtol(s, &ps, 0);
276 if (((sign < 0) && (offset > 0)) || ((sign > 0) && (offset < 0)))
277 offset = -offset;
278
279 switch (*ps)
280 {
281 case 'y':
282 tm->tm_year += offset;
283 break;
284 case 'm':
285 tm->tm_mon += offset;
286 break;
287 case 'w':
288 tm->tm_mday += 7 * offset;
289 break;
290 case 'd':
291 tm->tm_mday += offset;
292 break;
293 case 'H':
294 tm->tm_hour += offset;
295 break;
296 case 'M':
297 tm->tm_min += offset;
298 break;
299 case 'S':
300 tm->tm_sec += offset;
301 break;
302 default:
303 return s;
304 }
306 return ps + 1;
307}
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 326 of file compile.c.

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

414{
416 while (*pc && ((flags & MUTT_PDR_DONE) == 0))
417 {
418 const char *pt = NULL;
419 char ch = *pc++;
420 SKIPWS(pc);
421 switch (ch)
422 {
423 case '-':
424 {
425 /* try a range of absolute date minus offset of Ndwmy */
426 pt = get_offset(min, pc, -1);
427 if (pc == pt)
428 {
429 if (flags == MUTT_PDR_NO_FLAGS)
430 { /* nothing yet and no offset parsed => absolute date? */
431 if (!get_date(pc, max, err))
432 {
433 flags |= (MUTT_PDR_ABSOLUTE | MUTT_PDR_ERRORDONE); /* done bad */
434 }
435 else
436 {
437 /* reestablish initial base minimum if not specified */
438 if (!have_min)
439 memcpy(min, base_min, sizeof(struct tm));
440 flags |= (MUTT_PDR_ABSOLUTE | MUTT_PDR_DONE); /* done good */
441 }
442 }
443 else
444 {
445 flags |= MUTT_PDR_ERRORDONE;
446 }
447 }
448 else
449 {
450 pc = pt;
451 if ((flags == MUTT_PDR_NO_FLAGS) && !have_min)
452 { /* the very first "-3d" without a previous absolute date */
453 max->tm_year = min->tm_year;
454 max->tm_mon = min->tm_mon;
455 max->tm_mday = min->tm_mday;
456 }
457 flags |= MUTT_PDR_MINUS;
458 }
459 break;
460 }
461 case '+':
462 { /* enlarge plus range */
463 pt = get_offset(max, pc, 1);
464 if (pc == pt)
465 {
466 flags |= MUTT_PDR_ERRORDONE;
467 }
468 else
469 {
470 pc = pt;
471 flags |= MUTT_PDR_PLUS;
472 }
473 break;
474 }
475 case '*':
476 { /* enlarge window in both directions */
477 pt = get_offset(min, pc, -1);
478 if (pc == pt)
479 {
480 flags |= MUTT_PDR_ERRORDONE;
481 }
482 else
483 {
484 pc = get_offset(max, pc, 1);
485 flags |= MUTT_PDR_WINDOW;
486 }
487 break;
488 }
489 default:
490 flags |= MUTT_PDR_ERRORDONE;
491 }
492 SKIPWS(pc);
493 }
494 if ((flags & MUTT_PDR_ERROR) && !(flags & MUTT_PDR_ABSOLUTE))
495 { /* get_date has its own error message, don't overwrite it here */
496 buf_printf(err, _("Invalid relative date: %s"), pc - 1);
497 }
498 return (flags & MUTT_PDR_ERROR) ? NULL : pc;
499}
#define MUTT_PDR_PLUS
Extend the range using '+'.
Definition compile.c:53
#define MUTT_PDR_NO_FLAGS
No flags are set.
Definition compile.c:51
uint16_t ParseDateRangeFlags
Flags for parse_date_range(), e.g. MUTT_PDR_MINUS.
Definition compile.c:50
#define MUTT_PDR_ERROR
Invalid pattern.
Definition compile.c:57
#define MUTT_PDR_ABSOLUTE
Absolute pattern range.
Definition compile.c:55
static const char * get_offset(struct tm *tm, const char *s, int sign)
Calculate a symbolic offset.
Definition compile.c:272
#define MUTT_PDR_DONE
Pattern parse successfully.
Definition compile.c:56
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:326
#define MUTT_PDR_ERRORDONE
Definition compile.c:60
#define MUTT_PDR_MINUS
Pattern contains a range.
Definition compile.c:52
#define MUTT_PDR_WINDOW
Extend the range in both directions using '*'.
Definition compile.c:54
#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 506 of file compile.c.

507{
508 if ((min->tm_year > max->tm_year) ||
509 ((min->tm_year == max->tm_year) && (min->tm_mon > max->tm_mon)) ||
510 ((min->tm_year == max->tm_year) && (min->tm_mon == max->tm_mon) &&
511 (min->tm_mday > max->tm_mday)))
512 {
513 int tmp;
514
515 tmp = min->tm_year;
516 min->tm_year = max->tm_year;
517 max->tm_year = tmp;
518
519 tmp = min->tm_mon;
520 min->tm_mon = max->tm_mon;
521 max->tm_mon = tmp;
522
523 tmp = min->tm_mday;
524 min->tm_mday = max->tm_mday;
525 max->tm_mday = tmp;
526
527 min->tm_hour = 0;
528 min->tm_min = 0;
529 min->tm_sec = 0;
530 max->tm_hour = 23;
531 max->tm_min = 59;
532 max->tm_sec = 59;
533 }
534}
+ 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 544 of file compile.c.

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

803{
804 int level = 1;
805
806 for (; *s; s++)
807 {
808 if (*s == '(')
809 {
810 level++;
811 }
812 else if (*s == ')')
813 {
814 level--;
815 if (level == 0)
816 break;
817 }
818 }
819 return s;
820}
+ 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 826 of file compile.c.

827{
828 if (!pat || !*pat)
829 return;
830
831 struct Pattern *np = SLIST_FIRST(*pat);
832 struct Pattern *next = NULL;
833
834 while (np)
835 {
836 next = SLIST_NEXT(np, entries);
837
838 if (np->is_multi)
839 {
841 }
842 else if (np->string_match || np->dynamic)
843 {
844 FREE(&np->p.str);
845 }
846 else if (np->group_match)
847 {
848 np->p.group = NULL;
849 }
850 else if (np->p.regex)
851 {
852 regfree(np->p.regex);
853 FREE(&np->p.regex);
854 }
855
856#ifdef USE_DEBUG_GRAPHVIZ
857 FREE(&np->raw_pattern);
858#endif
860 FREE(&np);
861
862 np = next;
863 }
864
865 FREE(pat);
866}
void mutt_pattern_free(struct PatternList **pat)
Free a Pattern.
Definition compile.c:826
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:78
bool group_match
Check a group of Addresses.
Definition lib.h:83
union Pattern::@006112053024257132210207314205210350156165326341 p
struct Group * group
Address group if group_match is set.
Definition lib.h:94
struct PatternList * child
Arguments to logical operation.
Definition lib.h:91
bool string_match
Check a string for a match.
Definition lib.h:82
regex_t * regex
Compiled regex, for non-pattern matching.
Definition lib.h:93
struct ListHead multi_cases
Multiple strings for ~I pattern.
Definition lib.h:96
char * str
String, if string_match is set.
Definition lib.h:95
bool dynamic
Evaluate date ranges at run time.
Definition lib.h:86
bool is_multi
Multiple case (only for ~I pattern now)
Definition lib.h:88
+ 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 872 of file compile.c.

873{
874 return MUTT_MEM_CALLOC(1, struct Pattern);
875}
#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 881 of file compile.c.

882{
883 struct PatternList *h = MUTT_MEM_CALLOC(1, struct PatternList);
884 SLIST_INIT(h);
885 struct Pattern *p = mutt_pattern_new();
886 SLIST_INSERT_HEAD(h, p, entries);
887 return h;
888}
static struct Pattern * mutt_pattern_new(void)
Create a new Pattern.
Definition compile.c:872
#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 896 of file compile.c.

897{
898 struct Pattern *last = NULL;
899 SLIST_FOREACH(last, list, entries)
900 {
901 // TODO - or we could use a doubly-linked list
902 if (!SLIST_NEXT(last, entries))
903 {
904 SLIST_NEXT(last, entries) = leaf;
905 break;
906 }
907 }
908 return leaf;
909}
#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 918 of file compile.c.

919{
920 struct PatternList *root = mutt_pattern_list_new();
921 struct Pattern *leaf = SLIST_FIRST(root);
922 leaf->child = *curlist;
923 *curlist = root;
924 return leaf;
925}
static struct PatternList * mutt_pattern_list_new(void)
Create a new list containing a Pattern.
Definition compile.c:881
+ 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 934 of file compile.c.

935{
936 if (*curlist)
937 {
938 return attach_leaf(*curlist, mutt_pattern_new());
939 }
940 else
941 {
942 return attach_new_root(curlist);
943 }
944}
static struct Pattern * attach_new_root(struct PatternList **curlist)
Create a new Pattern as a parent for a List.
Definition compile.c:918
static struct Pattern * attach_leaf(struct PatternList *list, struct Pattern *leaf)
Attach a Pattern to a Pattern List.
Definition compile.c:896
+ 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 954 of file compile.c.

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