NeoMutt  2024-10-02-37-gfa9146
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 <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 "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 54 of file compile.c.

◆ MUTT_PDR_MINUS

#define MUTT_PDR_MINUS   (1 << 0)

Pattern contains a range.

Definition at line 55 of file compile.c.

◆ MUTT_PDR_PLUS

#define MUTT_PDR_PLUS   (1 << 1)

Extend the range using '+'.

Definition at line 56 of file compile.c.

◆ MUTT_PDR_WINDOW

#define MUTT_PDR_WINDOW   (1 << 2)

Extend the range in both directions using '*'.

Definition at line 57 of file compile.c.

◆ MUTT_PDR_ABSOLUTE

#define MUTT_PDR_ABSOLUTE   (1 << 3)

Absolute pattern range.

Definition at line 58 of file compile.c.

◆ MUTT_PDR_DONE

#define MUTT_PDR_DONE   (1 << 4)

Pattern parse successfully.

Definition at line 59 of file compile.c.

◆ MUTT_PDR_ERROR

#define MUTT_PDR_ERROR   (1 << 8)

Invalid pattern.

Definition at line 60 of file compile.c.

◆ MUTT_PDR_ERRORDONE

#define MUTT_PDR_ERRORDONE   (MUTT_PDR_ERROR | MUTT_PDR_DONE)

Definition at line 63 of file compile.c.

Typedef Documentation

◆ ParseDateRangeFlags

typedef uint16_t ParseDateRangeFlags

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

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

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

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

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

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

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

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

779{
780 if (!pat || !*pat)
781 return;
782
783 struct Pattern *np = SLIST_FIRST(*pat), *next = NULL;
784
785 while (np)
786 {
787 next = SLIST_NEXT(np, entries);
788
789 if (np->is_multi)
790 {
792 }
793 else if (np->string_match || np->dynamic)
794 {
795 FREE(&np->p.str);
796 }
797 else if (np->group_match)
798 {
799 np->p.group = NULL;
800 }
801 else if (np->p.regex)
802 {
803 regfree(np->p.regex);
804 FREE(&np->p.regex);
805 }
806
807#ifdef USE_DEBUG_GRAPHVIZ
808 FREE(&np->raw_pattern);
809#endif
811 FREE(&np);
812
813 np = next;
814 }
815
816 FREE(pat);
817}
void mutt_pattern_free(struct PatternList **pat)
Free a Pattern.
Definition: compile.c:778
void mutt_list_free(struct ListHead *h)
Free a List AND its strings.
Definition: list.c:123
#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:76
bool group_match
Check a group of Addresses.
Definition: lib.h:81
union Pattern::@1 p
struct Group * group
Address group if group_match is set.
Definition: lib.h:92
struct PatternList * child
Arguments to logical operation.
Definition: lib.h:89
bool string_match
Check a string for a match.
Definition: lib.h:80
regex_t * regex
Compiled regex, for non-pattern matching.
Definition: lib.h:91
struct ListHead multi_cases
Multiple strings for ~I pattern.
Definition: lib.h:94
char * str
String, if string_match is set.
Definition: lib.h:93
bool dynamic
Evaluate date ranges at run time.
Definition: lib.h:84
bool is_multi
Multiple case (only for ~I pattern now)
Definition: lib.h:86
+ 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 823 of file compile.c.

824{
825 return mutt_mem_calloc(1, sizeof(struct Pattern));
826}
void * mutt_mem_calloc(size_t nmemb, size_t size)
Allocate zeroed memory on the heap.
Definition: memory.c:51
+ 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 832 of file compile.c.

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

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

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

886{
887 if (*curlist)
888 {
889 return attach_leaf(*curlist, mutt_pattern_new());
890 }
891 else
892 {
893 return attach_new_root(curlist);
894 }
895}
static struct Pattern * attach_new_root(struct PatternList **curlist)
Create a new Pattern as a parent for a List.
Definition: compile.c:869
static struct Pattern * attach_leaf(struct PatternList *list, struct Pattern *leaf)
Attach a Pattern to a Pattern List.
Definition: compile.c:847
+ 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 906 of file compile.c.

909{
910 /* curlist when assigned will always point to a list containing at least one node
911 * with a Pattern value. */
912 struct PatternList *curlist = NULL;
913 bool pat_not = false;
914 bool all_addr = false;
915 bool pat_or = false;
916 bool implicit = true; /* used to detect logical AND operator */
917 bool is_alias = false;
918 const struct PatternFlags *entry = NULL;
919 char *p = NULL;
920 char *buf = NULL;
921 struct Mailbox *m = mv ? mv->mailbox : NULL;
922
923 if (!s || (s[0] == '\0'))
924 {
925 buf_strcpy(err, _("empty pattern"));
926 return NULL;
927 }
928
929 struct Buffer *ps = buf_pool_get();
930 buf_strcpy(ps, s);
931 buf_seek(ps, 0);
932
933 SKIPWS(ps->dptr);
934 while (*ps->dptr)
935 {
936 switch (*ps->dptr)
937 {
938 case '^':
939 ps->dptr++;
940 all_addr = !all_addr;
941 break;
942 case '!':
943 ps->dptr++;
944 pat_not = !pat_not;
945 break;
946 case '@':
947 ps->dptr++;
948 is_alias = !is_alias;
949 break;
950 case '|':
951 if (!pat_or)
952 {
953 if (!curlist)
954 {
955 buf_printf(err, _("error in pattern at: %s"), ps->dptr);
956 buf_pool_release(&ps);
957 return NULL;
958 }
959
960 struct Pattern *pat = SLIST_FIRST(curlist);
961 if (SLIST_NEXT(pat, entries))
962 {
963 /* A & B | C == (A & B) | C */
964 struct Pattern *root = attach_new_root(&curlist);
965 root->op = MUTT_PAT_AND;
966 }
967
968 pat_or = true;
969 }
970 ps->dptr++;
971 implicit = false;
972 pat_not = false;
973 all_addr = false;
974 is_alias = false;
975 break;
976 case '%':
977 case '=':
978 case '~':
979 {
980 if (ps->dptr[1] == '\0')
981 {
982 buf_printf(err, _("missing pattern: %s"), ps->dptr);
983 goto cleanup;
984 }
985 short thread_op = 0;
986 if (ps->dptr[1] == '(')
987 thread_op = MUTT_PAT_THREAD;
988 else if ((ps->dptr[1] == '<') && (ps->dptr[2] == '('))
989 thread_op = MUTT_PAT_PARENT;
990 else if ((ps->dptr[1] == '>') && (ps->dptr[2] == '('))
991 thread_op = MUTT_PAT_CHILDREN;
992 if (thread_op != 0)
993 {
994 ps->dptr++; /* skip ~ */
995 if ((thread_op == MUTT_PAT_PARENT) || (thread_op == MUTT_PAT_CHILDREN))
996 ps->dptr++;
997 p = find_matching_paren(ps->dptr + 1);
998 if (p[0] != ')')
999 {
1000 buf_printf(err, _("mismatched parentheses: %s"), ps->dptr);
1001 goto cleanup;
1002 }
1003 struct Pattern *leaf = attach_new_leaf(&curlist);
1004 leaf->op = thread_op;
1005 leaf->pat_not = pat_not;
1006 leaf->all_addr = all_addr;
1007 leaf->is_alias = is_alias;
1008 pat_not = false;
1009 all_addr = false;
1010 is_alias = false;
1011 /* compile the sub-expression */
1012 buf = mutt_strn_dup(ps->dptr + 1, p - (ps->dptr + 1));
1013 leaf->child = mutt_pattern_comp(mv, menu, buf, flags, err);
1014 if (!leaf->child)
1015 {
1016 FREE(&buf);
1017 goto cleanup;
1018 }
1019 FREE(&buf);
1020 ps->dptr = p + 1; /* restore location */
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 break;
1127 }
1128
1129 default:
1130 buf_printf(err, _("error in pattern at: %s"), ps->dptr);
1131 goto cleanup;
1132 }
1133 SKIPWS(ps->dptr);
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: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:885
static char * find_matching_paren(char *s)
Find the matching parenthesis.
Definition: compile.c:754
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:906
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:143
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:624
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:715
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:68
char * mutt_strn_dup(const char *begin, size_t len)
Duplicate a sub-string.
Definition: string.c:380
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:70
@ MUTT_PAT_OR
Either pattern can match.
Definition: lib.h:137
@ MUTT_PAT_CHILDREN
Pattern matches a child email.
Definition: lib.h:140
@ MUTT_PAT_PARENT
Pattern matches parent.
Definition: lib.h:139
@ MUTT_PAT_AND
Both patterns must match.
Definition: lib.h:136
@ MUTT_PAT_THREAD
Pattern matches email thread.
Definition: lib.h:138
@ EAT_RANGE
Process a number (range)
Definition: private.h:66
@ EAT_MESSAGE_RANGE
Process a message number (range)
Definition: private.h:67
@ EAT_DATE
Process a date (range)
Definition: private.h:65
@ EAT_QUERY
Process a query string.
Definition: private.h:68
@ EAT_REGEX
Process a regex.
Definition: private.h:64
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:75
enum PatternEat eat_arg
Type of function needed to parse flag, e.g. EAT_DATE.
Definition: private.h:80
PatternCompFlags flags
Pattern flags, e.g. MUTT_PC_FULL_MSG.
Definition: private.h:78
int op
Operation to perform, e.g. MUTT_PAT_SCORE.
Definition: private.h:77
bool all_addr
All Addresses in the list must match.
Definition: lib.h:79
bool is_alias
Is there an alias for this Address?
Definition: lib.h:83
short op
Operation, e.g. MUTT_PAT_SCORE.
Definition: lib.h:77
bool sendmode
Evaluate searches in send-mode.
Definition: lib.h:85
bool pat_not
Pattern should be inverted (not)
Definition: lib.h:78
+ Here is the call graph for this function:
+ Here is the caller graph for this function: