NeoMutt  2021-02-05-89-gabe350
Teaching an old dog new tricks
DOXYGEN
compile.c File Reference
#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 "email/lib.h"
#include "core/lib.h"
#include "mutt.h"
#include "lib.h"
#include "context.h"
#include "init.h"
#include "mutt_globals.h"
#include "mutt_menu.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. More...
 
#define MUTT_PDR_MINUS   (1 << 0)
 Pattern contains a range. More...
 
#define MUTT_PDR_PLUS   (1 << 1)
 Extend the range using '+'. More...
 
#define MUTT_PDR_WINDOW   (1 << 2)
 Extend the range in both directions using '*'. More...
 
#define MUTT_PDR_ABSOLUTE   (1 << 3)
 Absolute pattern range. More...
 
#define MUTT_PDR_DONE   (1 << 4)
 Pattern parse successfully. More...
 
#define MUTT_PDR_ERROR   (1 << 8)
 Invalid pattern. More...
 
#define MUTT_PDR_ERRORDONE   (MUTT_PDR_ERROR | MUTT_PDR_DONE)
 
#define KILO   1024
 
#define MEGA   1048576
 

Typedefs

typedef uint16_t ParseDateRangeFlags
 Flags for parse_date_range(), e.g. MUTT_PDR_MINUS. More...
 

Enumerations

enum  EatRangeError { RANGE_E_OK, RANGE_E_SYNTAX, RANGE_E_CTX }
 Error codes for eat_range_by_regex() More...
 

Functions

static bool eat_regex (struct Pattern *pat, PatternCompFlags flags, struct Buffer *s, struct Buffer *err)
 Parse a regex - Implements eat_arg_t. More...
 
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. More...
 
static bool eat_query (struct Pattern *pat, PatternCompFlags flags, struct Buffer *s, struct Buffer *err, struct Context *ctx)
 Parse a query for an external search program - Implements eat_arg_t. More...
 
static const char * get_offset (struct tm *tm, const char *s, int sign)
 Calculate a symbolic offset. More...
 
static const char * get_date (const char *s, struct tm *t, struct Buffer *err)
 Parse a (partial) date in dd/mm/yyyy format. More...
 
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. More...
 
static void adjust_date_range (struct tm *min, struct tm *max)
 Put a date range in the correct order. More...
 
bool eval_date_minmax (struct Pattern *pat, const char *s, struct Buffer *err)
 Evaluate a date-range pattern against 'now'. More...
 
static bool eat_range (struct Pattern *pat, PatternCompFlags flags, struct Buffer *s, struct Buffer *err)
 Parse a number range - Implements eat_arg_t. More...
 
static int report_regerror (int regerr, regex_t *preg, struct Buffer *err)
 Create a regex error message. More...
 
static bool is_context_available (struct Buffer *s, regmatch_t pmatch[], int kind, struct Buffer *err, struct Context *ctx)
 Do we need a Context for this Pattern? More...
 
static int scan_range_num (struct Buffer *s, regmatch_t pmatch[], int group, int kind, struct Context *ctx)
 Parse a number range. More...
 
static int scan_range_slot (struct Buffer *s, regmatch_t pmatch[], int grp, int side, int kind, struct Context *ctx)
 Parse a range of message numbers. More...
 
static void order_range (struct Pattern *pat)
 Put a range in order. More...
 
static int eat_range_by_regex (struct Pattern *pat, struct Buffer *s, int kind, struct Buffer *err, struct Context *ctx)
 Parse a range given as a regex. More...
 
static bool eat_message_range (struct Pattern *pat, PatternCompFlags flags, struct Buffer *s, struct Buffer *err, struct Context *ctx)
 Parse a range of message numbers - Implements eat_arg_t. More...
 
static bool eat_date (struct Pattern *pat, PatternCompFlags flags, struct Buffer *s, struct Buffer *err)
 Parse a date pattern - Implements eat_arg_t. More...
 
static char * find_matching_paren (char *s)
 Find the matching parenthesis. More...
 
void mutt_pattern_free (struct PatternList **pat)
 Free a Pattern. More...
 
static struct PatternList * mutt_pattern_node_new (void)
 Create a new list containing a Pattern. More...
 
struct PatternList * mutt_pattern_comp (struct Context *ctx, const char *s, PatternCompFlags flags, struct Buffer *err)
 Create a Pattern. More...
 

Detailed Description

Compile a Pattern

Authors
  • Pietro Cerutti
  • Richard Russon
  • R Primus

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.

◆ KILO

#define KILO   1024

Definition at line 74 of file compile.c.

◆ MEGA

#define MEGA   1048576

Definition at line 75 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.

Enumeration Type Documentation

◆ EatRangeError

Error codes for eat_range_by_regex()

Enumerator
RANGE_E_OK 

Range is valid.

RANGE_E_SYNTAX 

Range contains syntax error.

RANGE_E_CTX 

Range requires Context, but none available.

Definition at line 67 of file compile.c.

68 {
69  RANGE_E_OK,
71  RANGE_E_CTX,
72 };

Function Documentation

◆ eat_regex()

static bool eat_regex ( struct Pattern pat,
PatternCompFlags  flags,
struct Buffer s,
struct Buffer err 
)
static

Parse a regex - Implements eat_arg_t.

Definition at line 80 of file compile.c.

82 {
83  struct Buffer buf;
84 
85  mutt_buffer_init(&buf);
86  char *pexpr = s->dptr;
87  if ((mutt_extract_token(&buf, s, MUTT_TOKEN_PATTERN | MUTT_TOKEN_COMMENT) != 0) || !buf.data)
88  {
89  mutt_buffer_printf(err, _("Error in expression: %s"), pexpr);
90  FREE(&buf.data);
91  return false;
92  }
93  if (buf.data[0] == '\0')
94  {
95  mutt_buffer_printf(err, "%s", _("Empty expression"));
96  FREE(&buf.data);
97  return false;
98  }
99 
100  if (pat->string_match)
101  {
102  pat->p.str = mutt_str_dup(buf.data);
103  pat->ign_case = mutt_mb_is_lower(buf.data);
104  FREE(&buf.data);
105  }
106  else if (pat->group_match)
107  {
108  pat->p.group = mutt_pattern_group(buf.data);
109  FREE(&buf.data);
110  }
111  else
112  {
113  pat->p.regex = mutt_mem_malloc(sizeof(regex_t));
114  uint16_t case_flags = mutt_mb_is_lower(buf.data) ? REG_ICASE : 0;
115  int rc = REG_COMP(pat->p.regex, buf.data, REG_NEWLINE | REG_NOSUB | case_flags);
116  if (rc != 0)
117  {
118  char errmsg[256];
119  regerror(rc, pat->p.regex, errmsg, sizeof(errmsg));
120  mutt_buffer_add_printf(err, "'%s': %s", buf.data, errmsg);
121  FREE(&buf.data);
122  FREE(&pat->p.regex);
123  return false;
124  }
125  FREE(&buf.data);
126  }
127 
128  return true;
129 }
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ add_query_msgid()

static bool add_query_msgid ( char *  line,
int  line_num,
void *  user_data 
)
static

Parse a Message-Id and add it to a list - Implements mutt_file_map_t.

Return values
trueAlways

Definition at line 135 of file compile.c.

136 {
137  struct ListHead *msgid_list = (struct ListHead *) (user_data);
138  char *nows = mutt_str_skip_whitespace(line);
139  if (*nows == '\0')
140  return true;
142  mutt_list_insert_tail(msgid_list, mutt_str_dup(nows));
143  return true;
144 }
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ eat_query()

static bool eat_query ( struct Pattern pat,
PatternCompFlags  flags,
struct Buffer s,
struct Buffer err,
struct Context ctx 
)
static

Parse a query for an external search program - Implements eat_arg_t.

Parameters
patPattern to store the results in
flagsFlags, e.g. MUTT_PC_PATTERN_DYNAMIC
sString to parse
errBuffer for error messages
ctxCurrent Mailbox
Return values
trueIf the pattern was read successfully

Definition at line 155 of file compile.c.

157 {
158  struct Buffer cmd_buf;
159  struct Buffer tok_buf;
160  FILE *fp = NULL;
161 
163  {
164  mutt_buffer_printf(err, "%s", _("No search command defined"));
165  return false;
166  }
167 
168  mutt_buffer_init(&tok_buf);
169  char *pexpr = s->dptr;
170  if ((mutt_extract_token(&tok_buf, s, MUTT_TOKEN_PATTERN | MUTT_TOKEN_COMMENT) != 0) ||
171  !tok_buf.data)
172  {
173  mutt_buffer_printf(err, _("Error in expression: %s"), pexpr);
174  return false;
175  }
176  if (*tok_buf.data == '\0')
177  {
178  mutt_buffer_printf(err, "%s", _("Empty expression"));
179  FREE(&tok_buf.data);
180  return false;
181  }
182 
183  mutt_buffer_init(&cmd_buf);
185  mutt_buffer_addch(&cmd_buf, ' ');
186 
187  struct Mailbox *m = ctx_mailbox(ctx);
188  if (!m)
189  {
190  mutt_buffer_addch(&cmd_buf, '/');
191  }
192  else
193  {
194  char *escaped_folder = mutt_path_escape(mailbox_path(m));
195  mutt_debug(LL_DEBUG2, "escaped folder path: %s\n", escaped_folder);
196  mutt_buffer_addch(&cmd_buf, '\'');
197  mutt_buffer_addstr(&cmd_buf, escaped_folder);
198  mutt_buffer_addch(&cmd_buf, '\'');
199  }
200  mutt_buffer_addch(&cmd_buf, ' ');
201  mutt_buffer_addstr(&cmd_buf, tok_buf.data);
202  FREE(&tok_buf.data);
203 
204  mutt_message(_("Running search command: %s ..."), cmd_buf.data);
205  pat->is_multi = true;
207  pid_t pid = filter_create(cmd_buf.data, NULL, &fp, NULL);
208  if (pid < 0)
209  {
210  mutt_buffer_printf(err, "unable to fork command: %s\n", cmd_buf.data);
211  FREE(&cmd_buf.data);
212  return false;
213  }
214 
216  mutt_file_fclose(&fp);
217  filter_wait(pid);
218  FREE(&cmd_buf.data);
219  return true;
220 }
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

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

235 {
236  char *ps = NULL;
237  int offset = strtol(s, &ps, 0);
238  if (((sign < 0) && (offset > 0)) || ((sign > 0) && (offset < 0)))
239  offset = -offset;
240 
241  switch (*ps)
242  {
243  case 'y':
244  tm->tm_year += offset;
245  break;
246  case 'm':
247  tm->tm_mon += offset;
248  break;
249  case 'w':
250  tm->tm_mday += 7 * offset;
251  break;
252  case 'd':
253  tm->tm_mday += offset;
254  break;
255  case 'H':
256  tm->tm_hour += offset;
257  break;
258  case 'M':
259  tm->tm_min += offset;
260  break;
261  case 'S':
262  tm->tm_sec += offset;
263  break;
264  default:
265  return s;
266  }
268  return ps + 1;
269 }
+ 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 288 of file compile.c.

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

376 {
378  while (*pc && ((flags & MUTT_PDR_DONE) == 0))
379  {
380  const char *pt = NULL;
381  char ch = *pc++;
382  SKIPWS(pc);
383  switch (ch)
384  {
385  case '-':
386  {
387  /* try a range of absolute date minus offset of Ndwmy */
388  pt = get_offset(min, pc, -1);
389  if (pc == pt)
390  {
391  if (flags == MUTT_PDR_NO_FLAGS)
392  { /* nothing yet and no offset parsed => absolute date? */
393  if (!get_date(pc, max, err))
394  flags |= (MUTT_PDR_ABSOLUTE | MUTT_PDR_ERRORDONE); /* done bad */
395  else
396  {
397  /* reestablish initial base minimum if not specified */
398  if (!have_min)
399  memcpy(min, base_min, sizeof(struct tm));
400  flags |= (MUTT_PDR_ABSOLUTE | MUTT_PDR_DONE); /* done good */
401  }
402  }
403  else
404  flags |= MUTT_PDR_ERRORDONE;
405  }
406  else
407  {
408  pc = pt;
409  if ((flags == MUTT_PDR_NO_FLAGS) && !have_min)
410  { /* the very first "-3d" without a previous absolute date */
411  max->tm_year = min->tm_year;
412  max->tm_mon = min->tm_mon;
413  max->tm_mday = min->tm_mday;
414  }
415  flags |= MUTT_PDR_MINUS;
416  }
417  break;
418  }
419  case '+':
420  { /* enlarge plus range */
421  pt = get_offset(max, pc, 1);
422  if (pc == pt)
423  flags |= MUTT_PDR_ERRORDONE;
424  else
425  {
426  pc = pt;
427  flags |= MUTT_PDR_PLUS;
428  }
429  break;
430  }
431  case '*':
432  { /* enlarge window in both directions */
433  pt = get_offset(min, pc, -1);
434  if (pc == pt)
435  flags |= MUTT_PDR_ERRORDONE;
436  else
437  {
438  pc = get_offset(max, pc, 1);
439  flags |= MUTT_PDR_WINDOW;
440  }
441  break;
442  }
443  default:
444  flags |= MUTT_PDR_ERRORDONE;
445  }
446  SKIPWS(pc);
447  }
448  if ((flags & MUTT_PDR_ERROR) && !(flags & MUTT_PDR_ABSOLUTE))
449  { /* get_date has its own error message, don't overwrite it here */
450  mutt_buffer_printf(err, _("Invalid relative date: %s"), pc - 1);
451  }
452  return (flags & MUTT_PDR_ERROR) ? NULL : pc;
453 }
+ 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 460 of file compile.c.

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

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

◆ eat_range()

static bool eat_range ( struct Pattern pat,
PatternCompFlags  flags,
struct Buffer s,
struct Buffer err 
)
static

Parse a number range - Implements eat_arg_t.

Definition at line 626 of file compile.c.

628 {
629  char *tmp = NULL;
630  bool do_exclusive = false;
631  bool skip_quote = false;
632 
633  /* If simple_search is set to "~m %s", the range will have double quotes
634  * around it... */
635  if (*s->dptr == '"')
636  {
637  s->dptr++;
638  skip_quote = true;
639  }
640  if (*s->dptr == '<')
641  do_exclusive = true;
642  if ((*s->dptr != '-') && (*s->dptr != '<'))
643  {
644  /* range minimum */
645  if (*s->dptr == '>')
646  {
647  pat->max = MUTT_MAXRANGE;
648  pat->min = strtol(s->dptr + 1, &tmp, 0) + 1; /* exclusive range */
649  }
650  else
651  pat->min = strtol(s->dptr, &tmp, 0);
652  if (toupper((unsigned char) *tmp) == 'K') /* is there a prefix? */
653  {
654  pat->min *= 1024;
655  tmp++;
656  }
657  else if (toupper((unsigned char) *tmp) == 'M')
658  {
659  pat->min *= 1048576;
660  tmp++;
661  }
662  if (*s->dptr == '>')
663  {
664  s->dptr = tmp;
665  return true;
666  }
667  if (*tmp != '-')
668  {
669  /* exact value */
670  pat->max = pat->min;
671  s->dptr = tmp;
672  return true;
673  }
674  tmp++;
675  }
676  else
677  {
678  s->dptr++;
679  tmp = s->dptr;
680  }
681 
682  if (isdigit((unsigned char) *tmp))
683  {
684  /* range maximum */
685  pat->max = strtol(tmp, &tmp, 0);
686  if (toupper((unsigned char) *tmp) == 'K')
687  {
688  pat->max *= 1024;
689  tmp++;
690  }
691  else if (toupper((unsigned char) *tmp) == 'M')
692  {
693  pat->max *= 1048576;
694  tmp++;
695  }
696  if (do_exclusive)
697  (pat->max)--;
698  }
699  else
700  pat->max = MUTT_MAXRANGE;
701 
702  if (skip_quote && (*tmp == '"'))
703  tmp++;
704 
705  SKIPWS(tmp);
706  s->dptr = tmp;
707  return true;
708 }
+ Here is the caller graph for this function:

◆ report_regerror()

static int report_regerror ( int  regerr,
regex_t *  preg,
struct Buffer err 
)
static

Create a regex error message.

Parameters
regerrRegex error code
pregRegex pattern buffer
errBuffer for error messages
Return values
RANGE_E_SYNTAXAlways

Definition at line 717 of file compile.c.

718 {
719  size_t ds = err->dsize;
720 
721  if (regerror(regerr, preg, err->data, ds) > ds)
722  mutt_debug(LL_DEBUG2, "warning: buffer too small for regerror\n");
723  /* The return value is fixed, exists only to shorten code at callsite */
724  return RANGE_E_SYNTAX;
725 }
+ Here is the caller graph for this function:

◆ is_context_available()

static bool is_context_available ( struct Buffer s,
regmatch_t  pmatch[],
int  kind,
struct Buffer err,
struct Context ctx 
)
static

Do we need a Context for this Pattern?

Parameters
sString to check
pmatchRegex matches
kindRange type, e.g. RANGE_K_REL
errBuffer for error messages
ctxCurrent Mailbox
Return values
falseIf context is required, but not available
trueOtherwise

Definition at line 737 of file compile.c.

739 {
740  const char *context_req_chars[] = {
741  [RANGE_K_REL] = ".0123456789",
742  [RANGE_K_ABS] = ".",
743  [RANGE_K_LT] = "",
744  [RANGE_K_GT] = "",
745  [RANGE_K_BARE] = ".",
746  };
747 
748  /* First decide if we're going to need the context at all.
749  * Relative patterns need it if they contain a dot or a number.
750  * Absolute patterns only need it if they contain a dot. */
751  char *context_loc = strpbrk(s->dptr + pmatch[0].rm_so, context_req_chars[kind]);
752  if (!context_loc || (context_loc >= &s->dptr[pmatch[0].rm_eo]))
753  return true;
754 
755  /* We need a current message. Do we actually have one? */
756  if (ctx && ctx->menu)
757  return true;
758 
759  /* Nope. */
760  mutt_buffer_strcpy(err, _("No current message"));
761  return false;
762 }
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ scan_range_num()

static int scan_range_num ( struct Buffer s,
regmatch_t  pmatch[],
int  group,
int  kind,
struct Context ctx 
)
static

Parse a number range.

Parameters
sString to parse
pmatchArray of regex matches
groupIndex of regex match to use
kindRange type, e.g. RANGE_K_REL
ctxCurrent Mailbox
Return values
numParse number

Definition at line 773 of file compile.c.

775 {
776  int num = (int) strtol(&s->dptr[pmatch[group].rm_so], NULL, 0);
777  unsigned char c = (unsigned char) (s->dptr[pmatch[group].rm_eo - 1]);
778  if (toupper(c) == 'K')
779  num *= KILO;
780  else if (toupper(c) == 'M')
781  num *= MEGA;
782  switch (kind)
783  {
784  case RANGE_K_REL:
785  {
786  struct Email *e = mutt_get_virt_email(ctx->mailbox, ctx->menu->current);
787  return num + EMSG(e);
788  }
789  case RANGE_K_LT:
790  return num - 1;
791  case RANGE_K_GT:
792  return num + 1;
793  default:
794  return num;
795  }
796 }
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ scan_range_slot()

static int scan_range_slot ( struct Buffer s,
regmatch_t  pmatch[],
int  grp,
int  side,
int  kind,
struct Context ctx 
)
static

Parse a range of message numbers.

Parameters
sString to parse
pmatchRegex matches
grpWhich regex match to use
sideWhich side of the range is this? RANGE_S_LEFT or RANGE_S_RIGHT
kindRange type, e.g. RANGE_K_REL
ctxCurrent Mailbox
Return values
numIndex number for the message specified

Definition at line 808 of file compile.c.

810 {
811  /* This means the left or right subpattern was empty, e.g. ",." */
812  if ((pmatch[grp].rm_so == -1) || (pmatch[grp].rm_so == pmatch[grp].rm_eo))
813  {
814  if (side == RANGE_S_LEFT)
815  return 1;
816  if (side == RANGE_S_RIGHT)
817  return ctx->mailbox->msg_count;
818  }
819  /* We have something, so determine what */
820  unsigned char c = (unsigned char) (s->dptr[pmatch[grp].rm_so]);
821  switch (c)
822  {
823  case RANGE_CIRCUM:
824  return 1;
825  case RANGE_DOLLAR:
826  return ctx->mailbox->msg_count;
827  case RANGE_DOT:
828  {
829  struct Email *e = mutt_get_virt_email(ctx->mailbox, ctx->menu->current);
830  return EMSG(e);
831  }
832  case RANGE_LT:
833  case RANGE_GT:
834  return scan_range_num(s, pmatch, grp + 1, kind, ctx);
835  default:
836  /* Only other possibility: a number */
837  return scan_range_num(s, pmatch, grp, kind, ctx);
838  }
839 }
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ order_range()

static void order_range ( struct Pattern pat)
static

Put a range in order.

Parameters
patPattern to check

Definition at line 845 of file compile.c.

846 {
847  if (pat->min <= pat->max)
848  return;
849  int num = pat->min;
850  pat->min = pat->max;
851  pat->max = num;
852 }
+ Here is the caller graph for this function:

◆ eat_range_by_regex()

static int eat_range_by_regex ( struct Pattern pat,
struct Buffer s,
int  kind,
struct Buffer err,
struct Context ctx 
)
static

Parse a range given as a regex.

Parameters
patPattern to store the range in
sString to parse
kindRange type, e.g. RANGE_K_REL
errBuffer for error messages
ctxCurrent Mailbox
Return values
numEatRangeError code, e.g. RANGE_E_OK

Definition at line 863 of file compile.c.

865 {
866  int regerr;
867  regmatch_t pmatch[RANGE_RX_GROUPS];
868  struct RangeRegex *pspec = &range_regexes[kind];
869 
870  /* First time through, compile the big regex */
871  if (!pspec->ready)
872  {
873  regerr = regcomp(&pspec->cooked, pspec->raw, REG_EXTENDED);
874  if (regerr != 0)
875  return report_regerror(regerr, &pspec->cooked, err);
876  pspec->ready = true;
877  }
878 
879  /* Match the pattern buffer against the compiled regex.
880  * No match means syntax error. */
881  regerr = regexec(&pspec->cooked, s->dptr, RANGE_RX_GROUPS, pmatch, 0);
882  if (regerr != 0)
883  return report_regerror(regerr, &pspec->cooked, err);
884 
885  if (!is_context_available(s, pmatch, kind, err, ctx))
886  return RANGE_E_CTX;
887 
888  /* Snarf the contents of the two sides of the range. */
889  pat->min = scan_range_slot(s, pmatch, pspec->lgrp, RANGE_S_LEFT, kind, ctx);
890  pat->max = scan_range_slot(s, pmatch, pspec->rgrp, RANGE_S_RIGHT, kind, ctx);
891  mutt_debug(LL_DEBUG1, "pat->min=%d pat->max=%d\n", pat->min, pat->max);
892 
893  /* Special case for a bare 0. */
894  if ((kind == RANGE_K_BARE) && (pat->min == 0) && (pat->max == 0))
895  {
896  if (!ctx->menu)
897  {
898  mutt_buffer_strcpy(err, _("No current message"));
899  return RANGE_E_CTX;
900  }
901  struct Email *e = mutt_get_virt_email(ctx->mailbox, ctx->menu->current);
902  pat->max = EMSG(e);
903  pat->min = pat->max;
904  }
905 
906  /* Since we don't enforce order, we must swap bounds if they're backward */
907  order_range(pat);
908 
909  /* Slide pointer past the entire match. */
910  s->dptr += pmatch[0].rm_eo;
911  return RANGE_E_OK;
912 }
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ eat_message_range()

static bool eat_message_range ( struct Pattern pat,
PatternCompFlags  flags,
struct Buffer s,
struct Buffer err,
struct Context ctx 
)
static

Parse a range of message numbers - Implements eat_arg_t.

Parameters
patPattern to store the results in
flagsFlags, e.g. MUTT_PC_PATTERN_DYNAMIC
sString to parse
errBuffer for error messages
ctxCurrent Mailbox
Return values
trueIf the pattern was read successfully

Definition at line 923 of file compile.c.

925 {
926  if (!ctx)
927  {
928  // We need a Context for pretty much anything
929  mutt_buffer_strcpy(err, _("No Context"));
930  return false;
931  }
932 
933  bool skip_quote = false;
934 
935  /* If simple_search is set to "~m %s", the range will have double quotes
936  * around it... */
937  if (*s->dptr == '"')
938  {
939  s->dptr++;
940  skip_quote = true;
941  }
942 
943  for (int i_kind = 0; i_kind != RANGE_K_INVALID; i_kind++)
944  {
945  switch (eat_range_by_regex(pat, s, i_kind, err, ctx))
946  {
947  case RANGE_E_CTX:
948  /* This means it matched syntactically but lacked context.
949  * No point in continuing. */
950  break;
951  case RANGE_E_SYNTAX:
952  /* Try another syntax, then */
953  continue;
954  case RANGE_E_OK:
955  if (skip_quote && (*s->dptr == '"'))
956  s->dptr++;
957  SKIPWS(s->dptr);
958  return true;
959  }
960  }
961  return false;
962 }
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ eat_date()

static bool eat_date ( struct Pattern pat,
PatternCompFlags  flags,
struct Buffer s,
struct Buffer err 
)
static

Parse a date pattern - Implements eat_arg_t.

Definition at line 967 of file compile.c.

969 {
970  struct Buffer *tmp = mutt_buffer_pool_get();
971  bool rc = false;
972 
973  char *pexpr = s->dptr;
975  {
976  snprintf(err->data, err->dsize, _("Error in expression: %s"), pexpr);
977  goto out;
978  }
979 
980  if (mutt_buffer_is_empty(tmp))
981  {
982  snprintf(err->data, err->dsize, "%s", _("Empty expression"));
983  goto out;
984  }
985 
986  if (flags & MUTT_PC_PATTERN_DYNAMIC)
987  {
988  pat->dynamic = true;
989  pat->p.str = mutt_str_dup(tmp->data);
990  }
991 
992  rc = eval_date_minmax(pat, tmp->data, err);
993 
994 out:
996 
997  return rc;
998 }
+ 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 1007 of file compile.c.

1008 {
1009  int level = 1;
1010 
1011  for (; *s; s++)
1012  {
1013  if (*s == '(')
1014  level++;
1015  else if (*s == ')')
1016  {
1017  level--;
1018  if (level == 0)
1019  break;
1020  }
1021  }
1022  return s;
1023 }
+ 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 1029 of file compile.c.

1030 {
1031  if (!pat || !*pat)
1032  return;
1033 
1034  struct Pattern *np = SLIST_FIRST(*pat), *next = NULL;
1035 
1036  while (np)
1037  {
1038  next = SLIST_NEXT(np, entries);
1039 
1040  if (np->is_multi)
1042  else if (np->string_match || np->dynamic)
1043  FREE(&np->p.str);
1044  else if (np->group_match)
1045  np->p.group = NULL;
1046  else if (np->p.regex)
1047  {
1048  regfree(np->p.regex);
1049  FREE(&np->p.regex);
1050  }
1051 
1052  mutt_pattern_free(&np->child);
1053  FREE(&np);
1054 
1055  np = next;
1056  }
1057 
1058  FREE(pat);
1059 }
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_pattern_node_new()

static struct PatternList* mutt_pattern_node_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 1065 of file compile.c.

1066 {
1067  struct PatternList *h = mutt_mem_calloc(1, sizeof(struct PatternList));
1068  SLIST_INIT(h);
1069  struct Pattern *p = mutt_mem_calloc(1, sizeof(struct Pattern));
1070  SLIST_INSERT_HEAD(h, p, entries);
1071  return h;
1072 }
+ 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 Context ctx,
const char *  s,
PatternCompFlags  flags,
struct Buffer err 
)

Create a Pattern.

Parameters
ctxCurrent Mailbox
sPattern string
flagsFlags, e.g. MUTT_PC_FULL_MSG
errBuffer for error messages
Return values
ptrNewly allocated Pattern

Definition at line 1082 of file compile.c.

1084 {
1085  /* curlist when assigned will always point to a list containing at least one node
1086  * with a Pattern value. */
1087  struct PatternList *curlist = NULL;
1088  struct PatternList *tmp = NULL, *tmp2 = NULL;
1089  struct PatternList *last = NULL;
1090  bool pat_not = false;
1091  bool all_addr = false;
1092  bool pat_or = false;
1093  bool implicit = true; /* used to detect logical AND operator */
1094  bool is_alias = false;
1095  short thread_op;
1096  const struct PatternFlags *entry = NULL;
1097  char *p = NULL;
1098  char *buf = NULL;
1099  struct Buffer ps;
1100 
1101  if (!s || !*s)
1102  {
1103  mutt_buffer_strcpy(err, _("empty pattern"));
1104  return NULL;
1105  }
1106 
1107  mutt_buffer_init(&ps);
1108  ps.dptr = (char *) s;
1109  ps.dsize = mutt_str_len(s);
1110 
1111  while (*ps.dptr)
1112  {
1113  SKIPWS(ps.dptr);
1114  switch (*ps.dptr)
1115  {
1116  case '^':
1117  ps.dptr++;
1118  all_addr = !all_addr;
1119  break;
1120  case '!':
1121  ps.dptr++;
1122  pat_not = !pat_not;
1123  break;
1124  case '@':
1125  ps.dptr++;
1126  is_alias = !is_alias;
1127  break;
1128  case '|':
1129  if (!pat_or)
1130  {
1131  if (!curlist)
1132  {
1133  mutt_buffer_printf(err, _("error in pattern at: %s"), ps.dptr);
1134  return NULL;
1135  }
1136 
1137  struct Pattern *pat = SLIST_FIRST(curlist);
1138 
1139  if (SLIST_NEXT(pat, entries))
1140  {
1141  /* A & B | C == (A & B) | C */
1142  tmp = mutt_pattern_node_new();
1143  pat = SLIST_FIRST(tmp);
1144  pat->op = MUTT_PAT_AND;
1145  pat->child = curlist;
1146 
1147  curlist = tmp;
1148  last = curlist;
1149  }
1150 
1151  pat_or = true;
1152  }
1153  ps.dptr++;
1154  implicit = false;
1155  pat_not = false;
1156  all_addr = false;
1157  is_alias = false;
1158  break;
1159  case '%':
1160  case '=':
1161  case '~':
1162  {
1163  struct Pattern *pat = NULL;
1164  if (ps.dptr[1] == '\0')
1165  {
1166  mutt_buffer_printf(err, _("missing pattern: %s"), ps.dptr);
1167  goto cleanup;
1168  }
1169  thread_op = 0;
1170  if (ps.dptr[1] == '(')
1171  thread_op = MUTT_PAT_THREAD;
1172  else if ((ps.dptr[1] == '<') && (ps.dptr[2] == '('))
1173  thread_op = MUTT_PAT_PARENT;
1174  else if ((ps.dptr[1] == '>') && (ps.dptr[2] == '('))
1175  thread_op = MUTT_PAT_CHILDREN;
1176  if (thread_op)
1177  {
1178  ps.dptr++; /* skip ~ */
1179  if ((thread_op == MUTT_PAT_PARENT) || (thread_op == MUTT_PAT_CHILDREN))
1180  ps.dptr++;
1181  p = find_matching_paren(ps.dptr + 1);
1182  if (p[0] != ')')
1183  {
1184  mutt_buffer_printf(err, _("mismatched parentheses: %s"), ps.dptr);
1185  goto cleanup;
1186  }
1187  tmp = mutt_pattern_node_new();
1188  pat = SLIST_FIRST(tmp);
1189  pat->op = thread_op;
1190  if (last)
1191  SLIST_NEXT(SLIST_FIRST(last), entries) = pat;
1192  else
1193  curlist = tmp;
1194  last = tmp;
1195  pat->pat_not ^= pat_not;
1196  pat->all_addr |= all_addr;
1197  pat->is_alias |= is_alias;
1198  pat_not = false;
1199  all_addr = false;
1200  is_alias = false;
1201  /* compile the sub-expression */
1202  buf = mutt_strn_dup(ps.dptr + 1, p - (ps.dptr + 1));
1203  tmp2 = mutt_pattern_comp(ctx, buf, flags, err);
1204  if (!tmp2)
1205  {
1206  FREE(&buf);
1207  goto cleanup;
1208  }
1209  FREE(&buf);
1210  pat->child = tmp2;
1211  ps.dptr = p + 1; /* restore location */
1212  break;
1213  }
1214  if (implicit && pat_or)
1215  {
1216  /* A | B & C == (A | B) & C */
1217  tmp = mutt_pattern_node_new();
1218  pat = SLIST_FIRST(tmp);
1219  pat->op = MUTT_PAT_OR;
1220  pat->child = curlist;
1221  curlist = tmp;
1222  last = tmp;
1223  pat_or = false;
1224  }
1225 
1226  tmp = mutt_pattern_node_new();
1227  pat = SLIST_FIRST(tmp);
1228  pat->pat_not = pat_not;
1229  pat->all_addr = all_addr;
1230  pat->is_alias = is_alias;
1231  pat->string_match = (ps.dptr[0] == '=');
1232  pat->group_match = (ps.dptr[0] == '%');
1233  pat_not = false;
1234  all_addr = false;
1235  is_alias = false;
1236 
1237  if (last)
1238  SLIST_NEXT(SLIST_FIRST(last), entries) = pat;
1239  else
1240  curlist = tmp;
1241  if (curlist != last)
1242  FREE(&last);
1243  last = tmp;
1244 
1245  ps.dptr++; /* move past the ~ */
1246  entry = lookup_tag(*ps.dptr);
1247  if (!entry)
1248  {
1249  mutt_buffer_printf(err, _("%c: invalid pattern modifier"), *ps.dptr);
1250  goto cleanup;
1251  }
1252  if (entry->flags && ((flags & entry->flags) == 0))
1253  {
1254  mutt_buffer_printf(err, _("%c: not supported in this mode"), *ps.dptr);
1255  goto cleanup;
1256  }
1257  if (flags & MUTT_PC_SEND_MODE_SEARCH)
1258  pat->sendmode = true;
1259 
1260  pat->op = entry->op;
1261 
1262  ps.dptr++; /* eat the operator and any optional whitespace */
1263  SKIPWS(ps.dptr);
1264 
1265  if (entry->eat_arg)
1266  {
1267  if (ps.dptr[0] == '\0')
1268  {
1269  mutt_buffer_printf(err, "%s", _("missing parameter"));
1270  goto cleanup;
1271  }
1272  switch (entry->eat_arg)
1273  {
1274  case EAT_REGEX:
1275  if (!eat_regex(pat, flags, &ps, err))
1276  goto cleanup;
1277  break;
1278  case EAT_DATE:
1279  if (!eat_date(pat, flags, &ps, err))
1280  goto cleanup;
1281  break;
1282  case EAT_RANGE:
1283  if (!eat_range(pat, flags, &ps, err))
1284  goto cleanup;
1285  break;
1286  case EAT_MESSAGE_RANGE:
1287  if (!eat_message_range(pat, flags, &ps, err, ctx))
1288  goto cleanup;
1289  break;
1290  case EAT_QUERY:
1291  if (!eat_query(pat, flags, &ps, err, ctx))
1292  goto cleanup;
1293  break;
1294  default:
1295  break;
1296  }
1297  }
1298  implicit = true;
1299  break;
1300  }
1301 
1302  case '(':
1303  {
1304  p = find_matching_paren(ps.dptr + 1);
1305  if (p[0] != ')')
1306  {
1307  mutt_buffer_printf(err, _("mismatched parentheses: %s"), ps.dptr);
1308  goto cleanup;
1309  }
1310  /* compile the sub-expression */
1311  buf = mutt_strn_dup(ps.dptr + 1, p - (ps.dptr + 1));
1312  tmp = mutt_pattern_comp(ctx, buf, flags, err);
1313  FREE(&buf);
1314  if (!tmp)
1315  goto cleanup;
1316  struct Pattern *pat = SLIST_FIRST(tmp);
1317  if (last)
1318  SLIST_NEXT(SLIST_FIRST(last), entries) = pat;
1319  else
1320  curlist = tmp;
1321  last = tmp;
1322  pat = SLIST_FIRST(tmp);
1323  pat->pat_not ^= pat_not;
1324  pat->all_addr |= all_addr;
1325  pat->is_alias |= is_alias;
1326  pat_not = false;
1327  all_addr = false;
1328  is_alias = false;
1329  ps.dptr = p + 1; /* restore location */
1330  break;
1331  }
1332 
1333  default:
1334  mutt_buffer_printf(err, _("error in pattern at: %s"), ps.dptr);
1335  goto cleanup;
1336  }
1337  }
1338  if (!curlist)
1339  {
1340  mutt_buffer_strcpy(err, _("empty pattern"));
1341  return NULL;
1342  }
1343  if (curlist != tmp)
1344  FREE(&tmp);
1345  if (SLIST_NEXT(SLIST_FIRST(curlist), entries))
1346  {
1347  tmp = mutt_pattern_node_new();
1348  struct Pattern *pat = SLIST_FIRST(tmp);
1349  pat->op = pat_or ? MUTT_PAT_OR : MUTT_PAT_AND;
1350  pat->child = curlist;
1351  curlist = tmp;
1352  }
1353 
1354  return curlist;
1355 
1356 cleanup:
1357  mutt_pattern_free(&curlist);
1358  return NULL;
1359 }
+ Here is the call graph for this function:
+ Here is the caller graph for this function:
RangeRegex::cooked
regex_t cooked
Compiled form.
Definition: private.h:71
MUTT_PAT_PARENT
@ MUTT_PAT_PARENT
Pattern matches parent.
Definition: lib.h:133
RangeRegex::lgrp
int lgrp
Paren group matching the left side.
Definition: private.h:68
mutt_get_virt_email
struct Email * mutt_get_virt_email(struct Mailbox *m, int vnum)
Get a virtual Email.
Definition: context.c:397
mutt_pattern_comp
struct PatternList * mutt_pattern_comp(struct Context *ctx, const char *s, PatternCompFlags flags, struct Buffer *err)
Create a Pattern.
Definition: compile.c:1082
Pattern::regex
regex_t * regex
Compiled regex, for non-pattern matching.
Definition: lib.h:88
EAT_DATE
@ EAT_DATE
Process a date (range)
Definition: private.h:43
SLIST_INIT
#define SLIST_INIT(head)
Definition: queue.h:255
scan_range_num
static int scan_range_num(struct Buffer *s, regmatch_t pmatch[], int group, int kind, struct Context *ctx)
Parse a number range.
Definition: compile.c:773
MUTT_TOKEN_PATTERN
#define MUTT_TOKEN_PATTERN
~%=!| are terms (for patterns)
Definition: mutt.h:75
mutt_mem_calloc
void * mutt_mem_calloc(size_t nmemb, size_t size)
Allocate zeroed memory on the heap.
Definition: memory.c:50
_
#define _(a)
Definition: message.h:28
Mailbox
A mailbox.
Definition: mailbox.h:81
get_offset
static const char * get_offset(struct tm *tm, const char *s, int sign)
Calculate a symbolic offset.
Definition: compile.c:234
RANGE_K_INVALID
@ RANGE_K_INVALID
Range is invalid.
Definition: private.h:85
MUTT_PDR_NO_FLAGS
#define MUTT_PDR_NO_FLAGS
No flags are set.
Definition: compile.c:53
mutt_pattern_free
void mutt_pattern_free(struct PatternList **pat)
Free a Pattern.
Definition: compile.c:1029
MUTT_PC_PATTERN_DYNAMIC
#define MUTT_PC_PATTERN_DYNAMIC
Enable runtime date range evaluation.
Definition: lib.h:66
MUTT_PDR_ERRORDONE
#define MUTT_PDR_ERRORDONE
Definition: compile.c:62
Pattern::is_multi
bool is_multi
Multiple case (only for ~I pattern now)
Definition: lib.h:83
Buffer
String manipulation buffer.
Definition: buffer.h:33
RANGE_GT
#define RANGE_GT
Definition: private.h:109
ctx_mailbox
struct Mailbox * ctx_mailbox(struct Context *ctx)
wrapper to get the mailbox in a Context, or NULL
Definition: context.c:429
ParseDateRangeFlags
uint16_t ParseDateRangeFlags
Flags for parse_date_range(), e.g. MUTT_PDR_MINUS.
Definition: compile.c:52
mutt_file_fclose
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:153
mutt_buffer_is_empty
bool mutt_buffer_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition: buffer.c:252
adjust_date_range
static void adjust_date_range(struct tm *min, struct tm *max)
Put a date range in the correct order.
Definition: compile.c:460
RANGE_LT
#define RANGE_LT
Definition: private.h:108
MUTT_PAT_OR
@ MUTT_PAT_OR
Either pattern can match.
Definition: lib.h:131
SLIST_NEXT
#define SLIST_NEXT(elm, field)
Definition: queue.h:269
RangeRegex
Regular expression representing a range.
Definition: private.h:65
mutt_buffer_add_printf
int mutt_buffer_add_printf(struct Buffer *buf, const char *fmt,...)
Format a string appending a Buffer.
Definition: buffer.c:203
mutt_buffer_init
struct Buffer * mutt_buffer_init(struct Buffer *buf)
Initialise a new Buffer.
Definition: buffer.c:46
eat_range
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:626
mutt_str_dup
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:370
LL_DEBUG1
@ LL_DEBUG1
Log at debug level 1.
Definition: logging.h:40
Pattern::dynamic
bool dynamic
Evaluate date ranges at run time.
Definition: lib.h:81
FREE
#define FREE(x)
Definition: memory.h:40
Buffer::dptr
char * dptr
Current read/write position.
Definition: buffer.h:36
Buffer::dsize
size_t dsize
Length of data.
Definition: buffer.h:37
RANGE_RX_GROUPS
#define RANGE_RX_GROUPS
Definition: private.h:103
MEGA
#define MEGA
Definition: compile.c:75
lookup_tag
const struct PatternFlags * lookup_tag(char tag)
Lookup a pattern modifier.
Definition: flags.c:197
RANGE_K_REL
@ RANGE_K_REL
Relative range.
Definition: private.h:79
mutt_buffer_pool_release
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:112
MUTT_PDR_WINDOW
#define MUTT_PDR_WINDOW
Extend the range in both directions using '*'.
Definition: compile.c:56
mutt_list_insert_tail
struct ListNode * mutt_list_insert_tail(struct ListHead *h, char *s)
Append a string to the end of a List.
Definition: list.c:64
EAT_RANGE
@ EAT_RANGE
Process a number (range)
Definition: private.h:44
SKIPWS
#define SKIPWS(ch)
Definition: string2.h:46
eat_range_by_regex
static int eat_range_by_regex(struct Pattern *pat, struct Buffer *s, int kind, struct Buffer *err, struct Context *ctx)
Parse a range given as a regex.
Definition: compile.c:863
eval_date_minmax
bool eval_date_minmax(struct Pattern *pat, const char *s, struct Buffer *err)
Evaluate a date-range pattern against 'now'.
Definition: compile.c:498
mutt_path_escape
char * mutt_path_escape(const char *src)
Escapes single quotes in a path for a command string.
Definition: path.c:522
MUTT_PDR_ERROR
#define MUTT_PDR_ERROR
Invalid pattern.
Definition: compile.c:59
order_range
static void order_range(struct Pattern *pat)
Put a range in order.
Definition: compile.c:845
MUTT_RL_NO_FLAGS
#define MUTT_RL_NO_FLAGS
No flags are set.
Definition: file.h:39
mutt_extract_token
int mutt_extract_token(struct Buffer *dest, struct Buffer *tok, TokenFlags flags)
Extract one token from a string.
Definition: init.c:393
filter_create
pid_t filter_create(const char *cmd, FILE **fp_in, FILE **fp_out, FILE **fp_err)
Set up filter program.
Definition: filter.c:206
mutt_date_make_time
time_t mutt_date_make_time(struct tm *t, bool local)
Convert struct tm to time_t
Definition: date.c:229
mutt_buffer_addch
size_t mutt_buffer_addch(struct Buffer *buf, char c)
Add a single character to a Buffer.
Definition: buffer.c:240
mutt_buffer_pool_get
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:101
RANGE_DOT
#define RANGE_DOT
Definition: private.h:105
MUTT_TOKEN_COMMENT
#define MUTT_TOKEN_COMMENT
Don't reap comments.
Definition: mutt.h:76
Pattern::min
int min
Minimum for range checks.
Definition: lib.h:84
Pattern::ign_case
bool ign_case
Ignore case for local string_match searches.
Definition: lib.h:79
MUTT_PDR_ABSOLUTE
#define MUTT_PDR_ABSOLUTE
Absolute pattern range.
Definition: compile.c:57
get_date
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:288
eat_date
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:967
Pattern::is_alias
bool is_alias
Is there an alias for this Address?
Definition: lib.h:80
RANGE_K_ABS
@ RANGE_K_ABS
Absolute range.
Definition: private.h:80
Pattern::all_addr
bool all_addr
All Addresses in the list must match.
Definition: lib.h:76
mutt_date_localtime
struct tm mutt_date_localtime(time_t t)
Converts calendar time to a broken-down time structure expressed in user timezone.
Definition: date.c:643
Mailbox::msg_count
int msg_count
Total number of messages.
Definition: mailbox.h:91
PatternFlags::eat_arg
enum PatternEat eat_arg
Definition: private.h:58
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)
Parse a date range.
Definition: compile.c:374
RANGE_E_CTX
@ RANGE_E_CTX
Range requires Context, but none available.
Definition: compile.c:71
C_ExternalSearchCommand
char * C_ExternalSearchCommand
Config: External search command.
Definition: config.c:36
MUTT_PAT_AND
@ MUTT_PAT_AND
Both patterns must match.
Definition: lib.h:130
Pattern::pat_not
bool pat_not
Pattern should be inverted (not)
Definition: lib.h:75
Pattern::string_match
bool string_match
Check a string for a match.
Definition: lib.h:77
Context::mailbox
struct Mailbox * mailbox
Definition: context.h:50
RANGE_K_BARE
@ RANGE_K_BARE
Single symbol.
Definition: private.h:83
range_regexes
struct RangeRegex range_regexes[]
Set of Regexes for various range types.
Definition: pattern.c:64
EAT_REGEX
@ EAT_REGEX
Process a regex.
Definition: private.h:42
eat_regex
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:80
mutt_debug
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
mutt_pattern_node_new
static struct PatternList * mutt_pattern_node_new(void)
Create a new list containing a Pattern.
Definition: compile.c:1065
MUTT_PAT_THREAD
@ MUTT_PAT_THREAD
Pattern matches email thread.
Definition: lib.h:132
REG_COMP
#define REG_COMP(preg, regex, cflags)
Compile a regular expression.
Definition: regex3.h:54
mutt_pattern_group
struct Group * mutt_pattern_group(const char *pat)
Match a pattern to a Group.
Definition: group.c:65
mutt_str_len
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:631
MUTT_PDR_MINUS
#define MUTT_PDR_MINUS
Pattern contains a range.
Definition: compile.c:54
MUTT_PAT_CHILDREN
@ MUTT_PAT_CHILDREN
Pattern matches a child email.
Definition: lib.h:134
RangeRegex::raw
const char * raw
Regex as string.
Definition: private.h:67
SLIST_FIRST
#define SLIST_FIRST(head)
Definition: queue.h:228
MUTT_DATE_NOW
#define MUTT_DATE_NOW
Constant representing the 'current time', see: mutt_date_gmtime(), mutt_date_localtime()
Definition: date.h:39
SLIST_INSERT_HEAD
#define SLIST_INSERT_HEAD(head, elm, field)
Definition: queue.h:264
filter_wait
int filter_wait(pid_t pid)
Wait for the exit of a process and return its status.
Definition: filter.c:217
Pattern::op
short op
Operation, e.g. MUTT_PAT_SCORE.
Definition: lib.h:74
EMSG
#define EMSG(e)
Definition: private.h:120
mutt_str_skip_whitespace
char * mutt_str_skip_whitespace(const char *p)
Find the first non-whitespace character in a string.
Definition: string.c:686
PatternFlags::op
int op
Operation to perform, e.g. MUTT_PAT_SCORE.
Definition: private.h:55
PatternFlags::flags
PatternCompFlags flags
Pattern flags, e.g. MUTT_PC_FULL_MSG.
Definition: private.h:56
Pattern::p
union Pattern::@2 p
report_regerror
static int report_regerror(int regerr, regex_t *preg, struct Buffer *err)
Create a regex error message.
Definition: compile.c:717
mutt_mem_malloc
void * mutt_mem_malloc(size_t size)
Allocate memory on the heap.
Definition: memory.c:90
RANGE_E_OK
@ RANGE_E_OK
Range is valid.
Definition: compile.c:69
eat_query
static bool eat_query(struct Pattern *pat, PatternCompFlags flags, struct Buffer *s, struct Buffer *err, struct Context *ctx)
Parse a query for an external search program - Implements eat_arg_t.
Definition: compile.c:155
mutt_list_clear
void mutt_list_clear(struct ListHead *h)
Free a list, but NOT its strings.
Definition: list.c:167
mutt_strn_dup
char * mutt_strn_dup(const char *begin, size_t len)
Duplicate a sub-string.
Definition: string.c:548
mutt_mb_is_lower
bool mutt_mb_is_lower(const char *s)
Does a multi-byte string contain only lowercase characters?
Definition: mbyte.c:358
mutt_str_remove_trailing_ws
void mutt_str_remove_trailing_ws(char *s)
Trim trailing whitespace from a string.
Definition: string.c:700
Context::menu
struct Menu * menu
Needed for pattern compilation.
Definition: context.h:46
Pattern::group
struct Group * group
Address group if group_match is set.
Definition: lib.h:89
EAT_MESSAGE_RANGE
@ EAT_MESSAGE_RANGE
Process a message number (range)
Definition: private.h:45
eat_message_range
static bool eat_message_range(struct Pattern *pat, PatternCompFlags flags, struct Buffer *s, struct Buffer *err, struct Context *ctx)
Parse a range of message numbers - Implements eat_arg_t.
Definition: compile.c:923
mutt_file_map_lines
bool mutt_file_map_lines(mutt_file_map_t func, void *user_data, FILE *fp, ReadLineFlags flags)
Process lines of text read from a file pointer.
Definition: file.c:767
EAT_QUERY
@ EAT_QUERY
Process a query string.
Definition: private.h:46
MUTT_PC_SEND_MODE_SEARCH
#define MUTT_PC_SEND_MODE_SEARCH
Allow send-mode body searching.
Definition: lib.h:67
scan_range_slot
static int scan_range_slot(struct Buffer *s, regmatch_t pmatch[], int grp, int side, int kind, struct Context *ctx)
Parse a range of message numbers.
Definition: compile.c:808
RANGE_K_LT
@ RANGE_K_LT
Less-than range.
Definition: private.h:81
mutt_buffer_addstr
size_t mutt_buffer_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition: buffer.c:225
Pattern::max
int max
Maximum for range checks.
Definition: lib.h:85
MUTT_PDR_PLUS
#define MUTT_PDR_PLUS
Extend the range using '+'.
Definition: compile.c:55
RANGE_K_GT
@ RANGE_K_GT
Greater-than range.
Definition: private.h:82
mailbox_path
static const char * mailbox_path(const struct Mailbox *m)
Get the Mailbox's path string.
Definition: mailbox.h:206
Menu::current
int current
Current entry.
Definition: mutt_menu.h:56
Pattern::multi_cases
struct ListHead multi_cases
Multiple strings for ~I pattern.
Definition: lib.h:91
is_context_available
static bool is_context_available(struct Buffer *s, regmatch_t pmatch[], int kind, struct Buffer *err, struct Context *ctx)
Do we need a Context for this Pattern?
Definition: compile.c:737
add_query_msgid
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.
Definition: compile.c:135
Pattern::str
char * str
String, if string_match is set.
Definition: lib.h:90
Buffer::data
char * data
Pointer to data.
Definition: buffer.h:35
Pattern::sendmode
bool sendmode
Evaluate searches in send-mode.
Definition: lib.h:82
Email
The envelope/body of an email.
Definition: email.h:37
MUTT_PDR_DONE
#define MUTT_PDR_DONE
Pattern parse successfully.
Definition: compile.c:58
mutt_message
#define mutt_message(...)
Definition: logging.h:83
RANGE_CIRCUM
#define RANGE_CIRCUM
Definition: private.h:106
mutt_buffer_printf
int mutt_buffer_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition: buffer.c:160
RANGE_DOLLAR
#define RANGE_DOLLAR
Definition: private.h:107
mutt_list_free
void mutt_list_free(struct ListHead *h)
Free a List AND its strings.
Definition: list.c:122
MUTT_MAXRANGE
#define MUTT_MAXRANGE
Definition: private.h:122
RangeRegex::ready
bool ready
Compiled yet?
Definition: private.h:70
KILO
#define KILO
Definition: compile.c:74
find_matching_paren
static char * find_matching_paren(char *s)
Find the matching parenthesis.
Definition: compile.c:1007
Pattern::group_match
bool group_match
Check a group of Addresses.
Definition: lib.h:78
mutt_buffer_strcpy
size_t mutt_buffer_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:312
RangeRegex::rgrp
int rgrp
Paren group matching the right side.
Definition: private.h:69
PatternFlags
Mapping between user character and internal constant.
Definition: private.h:52
LL_DEBUG2
@ LL_DEBUG2
Log at debug level 2.
Definition: logging.h:41
mutt_date_normalize_time
void mutt_date_normalize_time(struct tm *tm)
Fix the contents of a struct tm.
Definition: date.c:295
Pattern
A simple (non-regex) pattern.
Definition: lib.h:72
RANGE_E_SYNTAX
@ RANGE_E_SYNTAX
Range contains syntax error.
Definition: compile.c:70
RANGE_S_RIGHT
@ RANGE_S_RIGHT
Right side of range.
Definition: private.h:117
RANGE_S_LEFT
@ RANGE_S_LEFT
Left side of range.
Definition: private.h:116
Pattern::child
struct PatternList * child
Arguments to logical operation.
Definition: lib.h:86