NeoMutt  2025-09-05-7-geaa2bd
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, struct Menu *menu, 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 52 of file compile.c.

◆ MUTT_PDR_MINUS

#define MUTT_PDR_MINUS   (1 << 0)

Pattern contains a range.

Definition at line 53 of file compile.c.

◆ MUTT_PDR_PLUS

#define MUTT_PDR_PLUS   (1 << 1)

Extend the range using '+'.

Definition at line 54 of file compile.c.

◆ MUTT_PDR_WINDOW

#define MUTT_PDR_WINDOW   (1 << 2)

Extend the range in both directions using '*'.

Definition at line 55 of file compile.c.

◆ MUTT_PDR_ABSOLUTE

#define MUTT_PDR_ABSOLUTE   (1 << 3)

Absolute pattern range.

Definition at line 56 of file compile.c.

◆ MUTT_PDR_DONE

#define MUTT_PDR_DONE   (1 << 4)

Pattern parse successfully.

Definition at line 57 of file compile.c.

◆ MUTT_PDR_ERROR

#define MUTT_PDR_ERROR   (1 << 8)

Invalid pattern.

Definition at line 58 of file compile.c.

◆ MUTT_PDR_ERRORDONE

#define MUTT_PDR_ERRORDONE   (MUTT_PDR_ERROR | MUTT_PDR_DONE)

Definition at line 61 of file compile.c.

Typedef Documentation

◆ ParseDateRangeFlags

typedef uint16_t ParseDateRangeFlags

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

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

223{
224 char *ps = NULL;
225 int offset = strtol(s, &ps, 0);
226 if (((sign < 0) && (offset > 0)) || ((sign > 0) && (offset < 0)))
227 offset = -offset;
228
229 switch (*ps)
230 {
231 case 'y':
232 tm->tm_year += offset;
233 break;
234 case 'm':
235 tm->tm_mon += offset;
236 break;
237 case 'w':
238 tm->tm_mday += 7 * offset;
239 break;
240 case 'd':
241 tm->tm_mday += offset;
242 break;
243 case 'H':
244 tm->tm_hour += offset;
245 break;
246 case 'M':
247 tm->tm_min += offset;
248 break;
249 case 'S':
250 tm->tm_sec += offset;
251 break;
252 default:
253 return s;
254 }
256 return ps + 1;
257}
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 276 of file compile.c.

277{
278 char *p = NULL;
279 struct tm tm = mutt_date_localtime(mutt_date_now());
280 bool iso8601 = true;
281
282 for (int v = 0; v < 8; v++)
283 {
284 if (s[v] && (s[v] >= '0') && (s[v] <= '9'))
285 continue;
286
287 iso8601 = false;
288 break;
289 }
290
291 if (iso8601)
292 {
293 int year = 0;
294 int month = 0;
295 int mday = 0;
296 sscanf(s, "%4d%2d%2d", &year, &month, &mday);
297
298 t->tm_year = year;
299 if (t->tm_year > 1900)
300 t->tm_year -= 1900;
301 t->tm_mon = month - 1;
302 t->tm_mday = mday;
303
304 if ((t->tm_mday < 1) || (t->tm_mday > 31))
305 {
306 buf_printf(err, _("Invalid day of month: %s"), s);
307 return NULL;
308 }
309 if ((t->tm_mon < 0) || (t->tm_mon > 11))
310 {
311 buf_printf(err, _("Invalid month: %s"), s);
312 return NULL;
313 }
314
315 return (s + 8);
316 }
317
318 t->tm_mday = strtol(s, &p, 10);
319 if ((t->tm_mday < 1) || (t->tm_mday > 31))
320 {
321 buf_printf(err, _("Invalid day of month: %s"), s);
322 return NULL;
323 }
324 if (*p != '/')
325 {
326 /* fill in today's month and year */
327 t->tm_mon = tm.tm_mon;
328 t->tm_year = tm.tm_year;
329 return p;
330 }
331 p++;
332 t->tm_mon = strtol(p, &p, 10) - 1;
333 if ((t->tm_mon < 0) || (t->tm_mon > 11))
334 {
335 buf_printf(err, _("Invalid month: %s"), p);
336 return NULL;
337 }
338 if (*p != '/')
339 {
340 t->tm_year = tm.tm_year;
341 return p;
342 }
343 p++;
344 t->tm_year = strtol(p, &p, 10);
345 if (t->tm_year < 70) /* year 2000+ */
346 t->tm_year += 100;
347 else if (t->tm_year > 1900)
348 t->tm_year -= 1900;
349 return p;
350}
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 362 of file compile.c.

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

457{
458 if ((min->tm_year > max->tm_year) ||
459 ((min->tm_year == max->tm_year) && (min->tm_mon > max->tm_mon)) ||
460 ((min->tm_year == max->tm_year) && (min->tm_mon == max->tm_mon) &&
461 (min->tm_mday > max->tm_mday)))
462 {
463 int tmp;
464
465 tmp = min->tm_year;
466 min->tm_year = max->tm_year;
467 max->tm_year = tmp;
468
469 tmp = min->tm_mon;
470 min->tm_mon = max->tm_mon;
471 max->tm_mon = tmp;
472
473 tmp = min->tm_mday;
474 min->tm_mday = max->tm_mday;
475 max->tm_mday = tmp;
476
477 min->tm_hour = 0;
478 min->tm_min = 0;
479 min->tm_sec = 0;
480 max->tm_hour = 23;
481 max->tm_min = 59;
482 max->tm_sec = 59;
483 }
484}
+ 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 494 of file compile.c.

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

753{
754 int level = 1;
755
756 for (; *s; s++)
757 {
758 if (*s == '(')
759 {
760 level++;
761 }
762 else if (*s == ')')
763 {
764 level--;
765 if (level == 0)
766 break;
767 }
768 }
769 return s;
770}
+ 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 776 of file compile.c.

777{
778 if (!pat || !*pat)
779 return;
780
781 struct Pattern *np = SLIST_FIRST(*pat);
782 struct Pattern *next = NULL;
783
784 while (np)
785 {
786 next = SLIST_NEXT(np, entries);
787
788 if (np->is_multi)
789 {
791 }
792 else if (np->string_match || np->dynamic)
793 {
794 FREE(&np->p.str);
795 }
796 else if (np->group_match)
797 {
798 np->p.group = NULL;
799 }
800 else if (np->p.regex)
801 {
802 regfree(np->p.regex);
803 FREE(&np->p.regex);
804 }
805
806#ifdef USE_DEBUG_GRAPHVIZ
807 FREE(&np->raw_pattern);
808#endif
810 FREE(&np);
811
812 np = next;
813 }
814
815 FREE(pat);
816}
void mutt_pattern_free(struct PatternList **pat)
Free a Pattern.
Definition: compile.c:776
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::@1 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 822 of file compile.c.

823{
824 return MUTT_MEM_CALLOC(1, struct Pattern);
825}
#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 831 of file compile.c.

832{
833 struct PatternList *h = MUTT_MEM_CALLOC(1, struct PatternList);
834 SLIST_INIT(h);
835 struct Pattern *p = mutt_pattern_new();
836 SLIST_INSERT_HEAD(h, p, entries);
837 return h;
838}
static struct Pattern * mutt_pattern_new(void)
Create a new Pattern.
Definition: compile.c:822
#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 846 of file compile.c.

847{
848 struct Pattern *last = NULL;
849 SLIST_FOREACH(last, list, entries)
850 {
851 // TODO - or we could use a doubly-linked list
852 if (!SLIST_NEXT(last, entries))
853 {
854 SLIST_NEXT(last, entries) = leaf;
855 break;
856 }
857 }
858 return leaf;
859}
#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 868 of file compile.c.

869{
870 struct PatternList *root = mutt_pattern_list_new();
871 struct Pattern *leaf = SLIST_FIRST(root);
872 leaf->child = *curlist;
873 *curlist = root;
874 return leaf;
875}
static struct PatternList * mutt_pattern_list_new(void)
Create a new list containing a Pattern.
Definition: compile.c:831
+ 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 884 of file compile.c.

885{
886 if (*curlist)
887 {
888 return attach_leaf(*curlist, mutt_pattern_new());
889 }
890 else
891 {
892 return attach_new_root(curlist);
893 }
894}
static struct Pattern * attach_new_root(struct PatternList **curlist)
Create a new Pattern as a parent for a List.
Definition: compile.c:868
static struct Pattern * attach_leaf(struct PatternList *list, struct Pattern *leaf)
Attach a Pattern to a Pattern List.
Definition: compile.c:846
+ 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,
struct Menu menu,
const char *  s,
PatternCompFlags  flags,
struct Buffer err 
)

Create a Pattern.

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

Definition at line 905 of file compile.c.

908{
909 /* curlist when assigned will always point to a list containing at least one node
910 * with a Pattern value. */
911 struct PatternList *curlist = NULL;
912 bool pat_not = false;
913 bool all_addr = false;
914 bool pat_or = false;
915 bool implicit = true; /* used to detect logical AND operator */
916 bool is_alias = false;
917 const struct PatternFlags *entry = NULL;
918 char *p = NULL;
919 char *buf = NULL;
920 struct Mailbox *m = mv ? mv->mailbox : NULL;
921
922 if (!s || (s[0] == '\0'))
923 {
924 buf_strcpy(err, _("empty pattern"));
925 return NULL;
926 }
927
928 struct Buffer *ps = buf_pool_get();
929 buf_strcpy(ps, s);
930 buf_seek(ps, 0);
931
932 SKIPWS(ps->dptr);
933 while (*ps->dptr)
934 {
935 switch (*ps->dptr)
936 {
937 case '^':
938 ps->dptr++;
939 all_addr = !all_addr;
940 break;
941 case '!':
942 ps->dptr++;
943 pat_not = !pat_not;
944 break;
945 case '@':
946 ps->dptr++;
947 is_alias = !is_alias;
948 break;
949 case '|':
950 if (!pat_or)
951 {
952 if (!curlist)
953 {
954 buf_printf(err, _("error in pattern at: %s"), ps->dptr);
955 buf_pool_release(&ps);
956 return NULL;
957 }
958
959 struct Pattern *pat = SLIST_FIRST(curlist);
960 if (SLIST_NEXT(pat, entries))
961 {
962 /* A & B | C == (A & B) | C */
963 struct Pattern *root = attach_new_root(&curlist);
964 root->op = MUTT_PAT_AND;
965 }
966
967 pat_or = true;
968 }
969 ps->dptr++;
970 implicit = false;
971 pat_not = false;
972 all_addr = false;
973 is_alias = false;
974 break;
975 case '%':
976 case '=':
977 case '~':
978 {
979 if (ps->dptr[1] == '\0')
980 {
981 buf_printf(err, _("missing pattern: %s"), ps->dptr);
982 goto cleanup;
983 }
984 short thread_op = 0;
985 if (ps->dptr[1] == '(')
986 thread_op = MUTT_PAT_THREAD;
987 else if ((ps->dptr[1] == '<') && (ps->dptr[2] == '('))
988 thread_op = MUTT_PAT_PARENT;
989 else if ((ps->dptr[1] == '>') && (ps->dptr[2] == '('))
990 thread_op = MUTT_PAT_CHILDREN;
991 if (thread_op != 0)
992 {
993 ps->dptr++; /* skip ~ */
994 if ((thread_op == MUTT_PAT_PARENT) || (thread_op == MUTT_PAT_CHILDREN))
995 ps->dptr++;
996 p = find_matching_paren(ps->dptr + 1);
997 if (p[0] != ')')
998 {
999 buf_printf(err, _("mismatched parentheses: %s"), ps->dptr);
1000 goto cleanup;
1001 }
1002 struct Pattern *leaf = attach_new_leaf(&curlist);
1003 leaf->op = thread_op;
1004 leaf->pat_not = pat_not;
1005 leaf->all_addr = all_addr;
1006 leaf->is_alias = is_alias;
1007 pat_not = false;
1008 all_addr = false;
1009 is_alias = false;
1010 /* compile the sub-expression */
1011 buf = mutt_strn_dup(ps->dptr + 1, p - (ps->dptr + 1));
1012 leaf->child = mutt_pattern_comp(mv, menu, buf, flags, err);
1013 if (!leaf->child)
1014 {
1015 FREE(&buf);
1016 goto cleanup;
1017 }
1018 FREE(&buf);
1019 ps->dptr = p + 1; /* restore location */
1020 break;
1021 }
1022 if (implicit && pat_or)
1023 {
1024 /* A | B & C == (A | B) & C */
1025 struct Pattern *root = attach_new_root(&curlist);
1026 root->op = MUTT_PAT_OR;
1027 pat_or = false;
1028 }
1029
1030 entry = lookup_tag(ps->dptr[1]);
1031 if (!entry)
1032 {
1033 buf_printf(err, _("%c: invalid pattern modifier"), *ps->dptr);
1034 goto cleanup;
1035 }
1036 if (entry->flags && ((flags & entry->flags) == 0))
1037 {
1038 buf_printf(err, _("%c: not supported in this mode"), *ps->dptr);
1039 goto cleanup;
1040 }
1041
1042 struct Pattern *leaf = attach_new_leaf(&curlist);
1043 leaf->pat_not = pat_not;
1044 leaf->all_addr = all_addr;
1045 leaf->is_alias = is_alias;
1046 leaf->string_match = (ps->dptr[0] == '=');
1047 leaf->group_match = (ps->dptr[0] == '%');
1048 leaf->sendmode = (flags & MUTT_PC_SEND_MODE_SEARCH);
1049 leaf->op = entry->op;
1050 pat_not = false;
1051 all_addr = false;
1052 is_alias = false;
1053
1054 ps->dptr++; /* move past the ~ */
1055 ps->dptr++; /* eat the operator and any optional whitespace */
1056 SKIPWS(ps->dptr);
1057 if (entry->eat_arg)
1058 {
1059 if (ps->dptr[0] == '\0')
1060 {
1061 buf_addstr(err, _("missing parameter"));
1062 goto cleanup;
1063 }
1064 switch (entry->eat_arg)
1065 {
1066 case EAT_REGEX:
1067 if (!eat_regex(leaf, flags, ps, err))
1068 goto cleanup;
1069 break;
1070 case EAT_DATE:
1071 if (!eat_date(leaf, flags, ps, err))
1072 goto cleanup;
1073 break;
1074 case EAT_RANGE:
1075 if (!eat_range(leaf, flags, ps, err))
1076 goto cleanup;
1077 break;
1078 case EAT_MESSAGE_RANGE:
1079 if (!eat_message_range(leaf, flags, ps, err, mv))
1080 goto cleanup;
1081 break;
1082 case EAT_QUERY:
1083 if (!eat_query(leaf, flags, ps, err, m))
1084 goto cleanup;
1085 break;
1086 default:
1087 break;
1088 }
1089 }
1090 implicit = true;
1091 break;
1092 }
1093
1094 case '(':
1095 {
1096 p = find_matching_paren(ps->dptr + 1);
1097 if (p[0] != ')')
1098 {
1099 buf_printf(err, _("mismatched parentheses: %s"), ps->dptr);
1100 goto cleanup;
1101 }
1102 /* compile the sub-expression */
1103 buf = mutt_strn_dup(ps->dptr + 1, p - (ps->dptr + 1));
1104 struct PatternList *sub = mutt_pattern_comp(mv, menu, buf, flags, err);
1105 FREE(&buf);
1106 if (!sub)
1107 goto cleanup;
1108 struct Pattern *leaf = SLIST_FIRST(sub);
1109 if (curlist)
1110 {
1111 attach_leaf(curlist, leaf);
1112 FREE(&sub);
1113 }
1114 else
1115 {
1116 curlist = sub;
1117 }
1118 leaf->pat_not ^= pat_not;
1119 leaf->all_addr |= all_addr;
1120 leaf->is_alias |= is_alias;
1121 pat_not = false;
1122 all_addr = false;
1123 is_alias = false;
1124 ps->dptr = p + 1; /* restore location */
1125 break;
1126 }
1127
1128 default:
1129 buf_printf(err, _("error in pattern at: %s"), ps->dptr);
1130 goto cleanup;
1131 }
1132 SKIPWS(ps->dptr);
1133 }
1134 buf_pool_release(&ps);
1135
1136 if (!curlist)
1137 {
1138 buf_strcpy(err, _("empty pattern"));
1139 return NULL;
1140 }
1141
1142 if (SLIST_NEXT(SLIST_FIRST(curlist), entries))
1143 {
1144 struct Pattern *root = attach_new_root(&curlist);
1145 root->op = pat_or ? MUTT_PAT_OR : MUTT_PAT_AND;
1146 }
1147
1148 return curlist;
1149
1150cleanup:
1151 mutt_pattern_free(&curlist);
1152 buf_pool_release(&ps);
1153 return NULL;
1154}
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:884
static char * find_matching_paren(char *s)
Find the matching parenthesis.
Definition: compile.c:752
struct PatternList * mutt_pattern_comp(struct MailboxView *mv, struct Menu *menu, const char *s, PatternCompFlags flags, struct Buffer *err)
Create a Pattern.
Definition: compile.c:905
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:141
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:622
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:713
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:66
char * mutt_strn_dup(const char *begin, size_t len)
Duplicate a sub-string.
Definition: string.c:381
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: