NeoMutt  2024-02-01-35-geee02f
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
compile.c File Reference

Compile a Pattern. More...

#include "config.h"
#include <ctype.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.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 "globals.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 53 of file compile.c.

◆ MUTT_PDR_MINUS

#define MUTT_PDR_MINUS   (1 << 0)

Pattern contains a range.

Definition at line 54 of file compile.c.

◆ MUTT_PDR_PLUS

#define MUTT_PDR_PLUS   (1 << 1)

Extend the range using '+'.

Definition at line 55 of file compile.c.

◆ MUTT_PDR_WINDOW

#define MUTT_PDR_WINDOW   (1 << 2)

Extend the range in both directions using '*'.

Definition at line 56 of file compile.c.

◆ MUTT_PDR_ABSOLUTE

#define MUTT_PDR_ABSOLUTE   (1 << 3)

Absolute pattern range.

Definition at line 57 of file compile.c.

◆ MUTT_PDR_DONE

#define MUTT_PDR_DONE   (1 << 4)

Pattern parse successfully.

Definition at line 58 of file compile.c.

◆ MUTT_PDR_ERROR

#define MUTT_PDR_ERROR   (1 << 8)

Invalid pattern.

Definition at line 59 of file compile.c.

◆ MUTT_PDR_ERRORDONE

#define MUTT_PDR_ERRORDONE   (MUTT_PDR_ERROR | MUTT_PDR_DONE)

Definition at line 62 of file compile.c.

Typedef Documentation

◆ ParseDateRangeFlags

typedef uint16_t ParseDateRangeFlags

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

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

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

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

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

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

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

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

778{
779 if (!pat || !*pat)
780 return;
781
782 struct Pattern *np = SLIST_FIRST(*pat), *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:777
void mutt_list_free(struct ListHead *h)
Free a List AND its strings.
Definition: list.c:122
#define FREE(x)
Definition: memory.h:45
#define SLIST_NEXT(elm, field)
Definition: queue.h:270
#define SLIST_FIRST(head)
Definition: queue.h:229
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, sizeof(struct Pattern));
825}
void * mutt_mem_calloc(size_t nmemb, size_t size)
Allocate zeroed memory on the heap.
Definition: memory.c:50
+ Here is the call graph for this function:
+ 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, sizeof(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:256
#define SLIST_INSERT_HEAD(head, elm, field)
Definition: queue.h:265
+ 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:231
+ 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 while (*ps->dptr)
933 {
934 SKIPWS(ps->dptr);
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 SKIPWS(ps->dptr);
1021 break;
1022 }
1023 if (implicit && pat_or)
1024 {
1025 /* A | B & C == (A | B) & C */
1026 struct Pattern *root = attach_new_root(&curlist);
1027 root->op = MUTT_PAT_OR;
1028 pat_or = false;
1029 }
1030
1031 entry = lookup_tag(ps->dptr[1]);
1032 if (!entry)
1033 {
1034 buf_printf(err, _("%c: invalid pattern modifier"), *ps->dptr);
1035 goto cleanup;
1036 }
1037 if (entry->flags && ((flags & entry->flags) == 0))
1038 {
1039 buf_printf(err, _("%c: not supported in this mode"), *ps->dptr);
1040 goto cleanup;
1041 }
1042
1043 struct Pattern *leaf = attach_new_leaf(&curlist);
1044 leaf->pat_not = pat_not;
1045 leaf->all_addr = all_addr;
1046 leaf->is_alias = is_alias;
1047 leaf->string_match = (ps->dptr[0] == '=');
1048 leaf->group_match = (ps->dptr[0] == '%');
1049 leaf->sendmode = (flags & MUTT_PC_SEND_MODE_SEARCH);
1050 leaf->op = entry->op;
1051 pat_not = false;
1052 all_addr = false;
1053 is_alias = false;
1054
1055 ps->dptr++; /* move past the ~ */
1056 ps->dptr++; /* eat the operator and any optional whitespace */
1057 SKIPWS(ps->dptr);
1058 if (entry->eat_arg)
1059 {
1060 if (ps->dptr[0] == '\0')
1061 {
1062 buf_addstr(err, _("missing parameter"));
1063 goto cleanup;
1064 }
1065 switch (entry->eat_arg)
1066 {
1067 case EAT_REGEX:
1068 if (!eat_regex(leaf, flags, ps, err))
1069 goto cleanup;
1070 break;
1071 case EAT_DATE:
1072 if (!eat_date(leaf, flags, ps, err))
1073 goto cleanup;
1074 break;
1075 case EAT_RANGE:
1076 if (!eat_range(leaf, flags, ps, err))
1077 goto cleanup;
1078 break;
1079 case EAT_MESSAGE_RANGE:
1080 if (!eat_message_range(leaf, flags, ps, err, mv))
1081 goto cleanup;
1082 break;
1083 case EAT_QUERY:
1084 if (!eat_query(leaf, flags, ps, err, m))
1085 goto cleanup;
1086 break;
1087 default:
1088 break;
1089 }
1090 }
1091 implicit = true;
1092 break;
1093 }
1094
1095 case '(':
1096 {
1097 p = find_matching_paren(ps->dptr + 1);
1098 if (p[0] != ')')
1099 {
1100 buf_printf(err, _("mismatched parentheses: %s"), ps->dptr);
1101 goto cleanup;
1102 }
1103 /* compile the sub-expression */
1104 buf = mutt_strn_dup(ps->dptr + 1, p - (ps->dptr + 1));
1105 struct PatternList *sub = mutt_pattern_comp(mv, menu, buf, flags, err);
1106 FREE(&buf);
1107 if (!sub)
1108 goto cleanup;
1109 struct Pattern *leaf = SLIST_FIRST(sub);
1110 if (curlist)
1111 {
1112 attach_leaf(curlist, leaf);
1113 FREE(&sub);
1114 }
1115 else
1116 {
1117 curlist = sub;
1118 }
1119 leaf->pat_not ^= pat_not;
1120 leaf->all_addr |= all_addr;
1121 leaf->is_alias |= is_alias;
1122 pat_not = false;
1123 all_addr = false;
1124 is_alias = false;
1125 ps->dptr = p + 1; /* restore location */
1126 SKIPWS(ps->dptr);
1127 break;
1128 }
1129
1130 default:
1131 buf_printf(err, _("error in pattern at: %s"), ps->dptr);
1132 goto cleanup;
1133 }
1134 }
1135 buf_pool_release(&ps);
1136
1137 if (!curlist)
1138 {
1139 buf_strcpy(err, _("empty pattern"));
1140 return NULL;
1141 }
1142
1143 if (SLIST_NEXT(SLIST_FIRST(curlist), entries))
1144 {
1145 struct Pattern *root = attach_new_root(&curlist);
1146 root->op = pat_or ? MUTT_PAT_OR : MUTT_PAT_AND;
1147 }
1148
1149 return curlist;
1150
1151cleanup:
1152 mutt_pattern_free(&curlist);
1153 buf_pool_release(&ps);
1154 return NULL;
1155}
void buf_seek(struct Buffer *buf, size_t offset)
Set current read/write position to offset from beginning.
Definition: buffer.c:639
size_t buf_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition: buffer.c:243
size_t buf_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:412
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:753
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:142
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:282
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:623
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:714
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:67
char * mutt_strn_dup(const char *begin, size_t len)
Duplicate a sub-string.
Definition: string.c:429
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: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:52
struct Buffer * buf_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:81
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
Definition: pool.c:94
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:63
enum PatternEat eat_arg
Type of function needed to parse flag, e.g. EAT_DATE.
Definition: private.h:68
PatternCompFlags flags
Pattern flags, e.g. MUTT_PC_FULL_MSG.
Definition: private.h:66
int op
Operation to perform, e.g. MUTT_PAT_SCORE.
Definition: private.h:65
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: