NeoMutt  2021-02-05-666-ge300cd
Teaching an old dog new tricks
DOXYGEN
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 "email/lib.h"
#include "core/lib.h"
#include "mutt.h"
#include "lib.h"
#include "menu/lib.h"
#include "context.h"
#include "init.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 Mailbox *m)
 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_menu_available (struct Buffer *s, regmatch_t pmatch[], int kind, struct Buffer *err, struct Menu *menu)
 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 Mailbox *m, struct Menu *menu)
 Parse a number range. More...
 
static int scan_range_slot (struct Buffer *s, regmatch_t pmatch[], int grp, int side, int kind, struct Mailbox *m, struct Menu *menu)
 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 Mailbox *m, struct Menu *menu)
 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 Mailbox *m, struct Menu *menu)
 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 Mailbox *m, struct Menu *menu, 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 };
Range requires Context, but none available.
Definition: compile.c:71
Range is valid.
Definition: compile.c:69
Range contains syntax error.
Definition: compile.c:70

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 }
regex_t * regex
Compiled regex, for non-pattern matching.
Definition: lib.h:84
bool group_match
Check a group of Addresses.
Definition: lib.h:74
#define MUTT_TOKEN_COMMENT
Don&#39;t reap comments.
Definition: mutt.h:72
union Pattern::@3 p
String manipulation buffer.
Definition: buffer.h:33
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:370
#define _(a)
Definition: message.h:28
#define REG_COMP(preg, regex, cflags)
Compile a regular expression.
Definition: regex3.h:54
int mutt_buffer_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition: buffer.c:160
bool string_match
Check a string for a match.
Definition: lib.h:73
int mutt_buffer_add_printf(struct Buffer *buf, const char *fmt,...)
Format a string appending a Buffer.
Definition: buffer.c:203
bool ign_case
Ignore case for local string_match searches.
Definition: lib.h:75
int mutt_extract_token(struct Buffer *dest, struct Buffer *tok, TokenFlags flags)
Extract one token from a string.
Definition: init.c:395
void * mutt_mem_malloc(size_t size)
Allocate memory on the heap.
Definition: memory.c:90
char * dptr
Current read/write position.
Definition: buffer.h:36
char * data
Pointer to data.
Definition: buffer.h:35
char * str
String, if string_match is set.
Definition: lib.h:86
struct Group * group
Address group if group_match is set.
Definition: lib.h:85
#define FREE(x)
Definition: memory.h:40
struct Buffer * mutt_buffer_init(struct Buffer *buf)
Initialise a new Buffer.
Definition: buffer.c:46
bool mutt_mb_is_lower(const char *s)
Does a multi-byte string contain only lowercase characters?
Definition: mbyte.c:357
#define MUTT_TOKEN_PATTERN
~%=!| are terms (for patterns)
Definition: mutt.h:71
struct Group * mutt_pattern_group(const char *pat)
Match a pattern to a Group.
Definition: group.c:65
+ 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 }
char * mutt_str_skip_whitespace(const char *p)
Find the first non-whitespace character in a string.
Definition: string.c:719
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:370
struct ListNode * mutt_list_insert_tail(struct ListHead *h, char *s)
Append a string to the end of a List.
Definition: list.c:64
void mutt_str_remove_trailing_ws(char *s)
Trim trailing whitespace from a string.
Definition: string.c:733
+ 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 Mailbox m 
)
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
mMailbox
Return values
trueThe 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 
162  const char *const c_external_search_command =
163  cs_subset_string(NeoMutt->sub, "external_search_command");
164  if (!c_external_search_command)
165  {
166  mutt_buffer_printf(err, "%s", _("No search command defined"));
167  return false;
168  }
169 
170  mutt_buffer_init(&tok_buf);
171  char *pexpr = s->dptr;
172  if ((mutt_extract_token(&tok_buf, s, MUTT_TOKEN_PATTERN | MUTT_TOKEN_COMMENT) != 0) ||
173  !tok_buf.data)
174  {
175  mutt_buffer_printf(err, _("Error in expression: %s"), pexpr);
176  return false;
177  }
178  if (*tok_buf.data == '\0')
179  {
180  mutt_buffer_printf(err, "%s", _("Empty expression"));
181  FREE(&tok_buf.data);
182  return false;
183  }
184 
185  mutt_buffer_init(&cmd_buf);
186  mutt_buffer_addstr(&cmd_buf, c_external_search_command);
187  mutt_buffer_addch(&cmd_buf, ' ');
188 
189  if (m)
190  {
191  char *escaped_folder = mutt_path_escape(mailbox_path(m));
192  mutt_debug(LL_DEBUG2, "escaped folder path: %s\n", escaped_folder);
193  mutt_buffer_addch(&cmd_buf, '\'');
194  mutt_buffer_addstr(&cmd_buf, escaped_folder);
195  mutt_buffer_addch(&cmd_buf, '\'');
196  }
197  else
198  {
199  mutt_buffer_addch(&cmd_buf, '/');
200  }
201  mutt_buffer_addch(&cmd_buf, ' ');
202  mutt_buffer_addstr(&cmd_buf, tok_buf.data);
203  FREE(&tok_buf.data);
204 
205  mutt_message(_("Running search command: %s ..."), cmd_buf.data);
206  pat->is_multi = true;
208  pid_t pid = filter_create(cmd_buf.data, NULL, &fp, NULL);
209  if (pid < 0)
210  {
211  mutt_buffer_printf(err, "unable to fork command: %s\n", cmd_buf.data);
212  FREE(&cmd_buf.data);
213  return false;
214  }
215 
217  mutt_file_fclose(&fp);
218  filter_wait(pid);
219  FREE(&cmd_buf.data);
220  return true;
221 }
static const char * mailbox_path(const struct Mailbox *m)
Get the Mailbox&#39;s path string.
Definition: mailbox.h:215
pid_t filter_create(const char *cmd, FILE **fp_in, FILE **fp_out, FILE **fp_err)
Set up filter program.
Definition: filter.c:206
#define MUTT_TOKEN_COMMENT
Don&#39;t reap comments.
Definition: mutt.h:72
union Pattern::@3 p
String manipulation buffer.
Definition: buffer.h:33
#define _(a)
Definition: message.h:28
bool is_multi
Multiple case (only for ~I pattern now)
Definition: lib.h:79
int mutt_buffer_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition: buffer.c:160
Container for Accounts, Notifications.
Definition: neomutt.h:36
Log at debug level 2.
Definition: logging.h:41
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:153
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
char * mutt_path_escape(const char *src)
Escapes single quotes in a path for a command string.
Definition: path.c:522
size_t mutt_buffer_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition: buffer.c:225
int mutt_extract_token(struct Buffer *dest, struct Buffer *tok, TokenFlags flags)
Extract one token from a string.
Definition: init.c:395
char * dptr
Current read/write position.
Definition: buffer.h:36
char * data
Pointer to data.
Definition: buffer.h:35
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:317
size_t mutt_buffer_addch(struct Buffer *buf, char c)
Add a single character to a Buffer.
Definition: buffer.c:240
#define mutt_debug(LEVEL,...)
Definition: logging.h:85
#define MUTT_RL_NO_FLAGS
No flags are set.
Definition: file.h:38
#define mutt_message(...)
Definition: logging.h:87
#define FREE(x)
Definition: memory.h:40
struct ListHead multi_cases
Multiple strings for ~I pattern.
Definition: lib.h:87
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
struct Buffer * mutt_buffer_init(struct Buffer *buf)
Initialise a new Buffer.
Definition: buffer.c:46
void mutt_list_clear(struct ListHead *h)
Free a list, but NOT its strings.
Definition: list.c:167
int filter_wait(pid_t pid)
Wait for the exit of a process and return its status.
Definition: filter.c:217
#define MUTT_TOKEN_PATTERN
~%=!| are terms (for patterns)
Definition: mutt.h:71
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:769
+ 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 235 of file compile.c.

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

290 {
291  char *p = NULL;
292  struct tm tm = mutt_date_localtime(MUTT_DATE_NOW);
293  bool iso8601 = true;
294 
295  for (int v = 0; v < 8; v++)
296  {
297  if (s[v] && (s[v] >= '0') && (s[v] <= '9'))
298  continue;
299 
300  iso8601 = false;
301  break;
302  }
303 
304  if (iso8601)
305  {
306  int year = 0;
307  int month = 0;
308  int mday = 0;
309  sscanf(s, "%4d%2d%2d", &year, &month, &mday);
310 
311  t->tm_year = year;
312  if (t->tm_year > 1900)
313  t->tm_year -= 1900;
314  t->tm_mon = month - 1;
315  t->tm_mday = mday;
316 
317  if ((t->tm_mday < 1) || (t->tm_mday > 31))
318  {
319  snprintf(err->data, err->dsize, _("Invalid day of month: %s"), s);
320  return NULL;
321  }
322  if ((t->tm_mon < 0) || (t->tm_mon > 11))
323  {
324  snprintf(err->data, err->dsize, _("Invalid month: %s"), s);
325  return NULL;
326  }
327 
328  return (s + 8);
329  }
330 
331  t->tm_mday = strtol(s, &p, 10);
332  if ((t->tm_mday < 1) || (t->tm_mday > 31))
333  {
334  mutt_buffer_printf(err, _("Invalid day of month: %s"), s);
335  return NULL;
336  }
337  if (*p != '/')
338  {
339  /* fill in today's month and year */
340  t->tm_mon = tm.tm_mon;
341  t->tm_year = tm.tm_year;
342  return p;
343  }
344  p++;
345  t->tm_mon = strtol(p, &p, 10) - 1;
346  if ((t->tm_mon < 0) || (t->tm_mon > 11))
347  {
348  mutt_buffer_printf(err, _("Invalid month: %s"), p);
349  return NULL;
350  }
351  if (*p != '/')
352  {
353  t->tm_year = tm.tm_year;
354  return p;
355  }
356  p++;
357  t->tm_year = strtol(p, &p, 10);
358  if (t->tm_year < 70) /* year 2000+ */
359  t->tm_year += 100;
360  else if (t->tm_year > 1900)
361  t->tm_year -= 1900;
362  return p;
363 }
struct tm mutt_date_localtime(time_t t)
Converts calendar time to a broken-down time structure expressed in user timezone.
Definition: date.c:654
#define _(a)
Definition: message.h:28
#define MUTT_DATE_NOW
Constant representing the &#39;current time&#39;, see: mutt_date_gmtime(), mutt_date_localtime() ...
Definition: date.h:39
int mutt_buffer_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition: buffer.c:160
size_t dsize
Length of data.
Definition: buffer.h:37
char * data
Pointer to data.
Definition: buffer.h:35
+ 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 375 of file compile.c.

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

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

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

629 {
630  char *tmp = NULL;
631  bool do_exclusive = false;
632  bool skip_quote = false;
633 
634  /* If simple_search is set to "~m %s", the range will have double quotes
635  * around it... */
636  if (*s->dptr == '"')
637  {
638  s->dptr++;
639  skip_quote = true;
640  }
641  if (*s->dptr == '<')
642  do_exclusive = true;
643  if ((*s->dptr != '-') && (*s->dptr != '<'))
644  {
645  /* range minimum */
646  if (*s->dptr == '>')
647  {
648  pat->max = MUTT_MAXRANGE;
649  pat->min = strtol(s->dptr + 1, &tmp, 0) + 1; /* exclusive range */
650  }
651  else
652  pat->min = strtol(s->dptr, &tmp, 0);
653  if (toupper((unsigned char) *tmp) == 'K') /* is there a prefix? */
654  {
655  pat->min *= 1024;
656  tmp++;
657  }
658  else if (toupper((unsigned char) *tmp) == 'M')
659  {
660  pat->min *= 1048576;
661  tmp++;
662  }
663  if (*s->dptr == '>')
664  {
665  s->dptr = tmp;
666  return true;
667  }
668  if (*tmp != '-')
669  {
670  /* exact value */
671  pat->max = pat->min;
672  s->dptr = tmp;
673  return true;
674  }
675  tmp++;
676  }
677  else
678  {
679  s->dptr++;
680  tmp = s->dptr;
681  }
682 
683  if (isdigit((unsigned char) *tmp))
684  {
685  /* range maximum */
686  pat->max = strtol(tmp, &tmp, 0);
687  if (toupper((unsigned char) *tmp) == 'K')
688  {
689  pat->max *= 1024;
690  tmp++;
691  }
692  else if (toupper((unsigned char) *tmp) == 'M')
693  {
694  pat->max *= 1048576;
695  tmp++;
696  }
697  if (do_exclusive)
698  (pat->max)--;
699  }
700  else
701  pat->max = MUTT_MAXRANGE;
702 
703  if (skip_quote && (*tmp == '"'))
704  tmp++;
705 
706  SKIPWS(tmp);
707  s->dptr = tmp;
708  return true;
709 }
#define SKIPWS(ch)
Definition: string2.h:46
int min
Minimum for range checks.
Definition: lib.h:80
char * dptr
Current read/write position.
Definition: buffer.h:36
#define MUTT_MAXRANGE
Definition: private.h:119
int max
Maximum for range checks.
Definition: lib.h:81
+ 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 718 of file compile.c.

719 {
720  size_t ds = err->dsize;
721 
722  if (regerror(regerr, preg, err->data, ds) > ds)
723  mutt_debug(LL_DEBUG2, "warning: buffer too small for regerror\n");
724  /* The return value is fixed, exists only to shorten code at callsite */
725  return RANGE_E_SYNTAX;
726 }
size_t dsize
Length of data.
Definition: buffer.h:37
Log at debug level 2.
Definition: logging.h:41
char * data
Pointer to data.
Definition: buffer.h:35
#define mutt_debug(LEVEL,...)
Definition: logging.h:85
Range contains syntax error.
Definition: compile.c:70
+ Here is the caller graph for this function:

◆ is_menu_available()

static bool is_menu_available ( struct Buffer s,
regmatch_t  pmatch[],
int  kind,
struct Buffer err,
struct Menu menu 
)
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
menuCurrent Menu
Return values
falseContext is required, but not available
trueOtherwise

Definition at line 738 of file compile.c.

740 {
741  const char *context_req_chars[] = {
742  [RANGE_K_REL] = ".0123456789",
743  [RANGE_K_ABS] = ".",
744  [RANGE_K_LT] = "",
745  [RANGE_K_GT] = "",
746  [RANGE_K_BARE] = ".",
747  };
748 
749  /* First decide if we're going to need the menu at all.
750  * Relative patterns need it if they contain a dot or a number.
751  * Absolute patterns only need it if they contain a dot. */
752  char *context_loc = strpbrk(s->dptr + pmatch[0].rm_so, context_req_chars[kind]);
753  if (!context_loc || (context_loc >= &s->dptr[pmatch[0].rm_eo]))
754  return true;
755 
756  /* We need a current message. Do we actually have one? */
757  if (menu)
758  return true;
759 
760  /* Nope. */
761  mutt_buffer_strcpy(err, _("No current message"));
762  return false;
763 }
Relative range.
Definition: private.h:76
Less-than range.
Definition: private.h:78
#define _(a)
Definition: message.h:28
Single symbol.
Definition: private.h:80
char * dptr
Current read/write position.
Definition: buffer.h:36
Greater-than range.
Definition: private.h:79
Absolute range.
Definition: private.h:77
size_t mutt_buffer_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:312
+ 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 Mailbox m,
struct Menu menu 
)
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
mMailbox
menuCurrent Menu
Return values
numParse number

Definition at line 775 of file compile.c.

777 {
778  int num = (int) strtol(&s->dptr[pmatch[group].rm_so], NULL, 0);
779  unsigned char c = (unsigned char) (s->dptr[pmatch[group].rm_eo - 1]);
780  if (toupper(c) == 'K')
781  num *= KILO;
782  else if (toupper(c) == 'M')
783  num *= MEGA;
784  switch (kind)
785  {
786  case RANGE_K_REL:
787  {
788  struct Email *e = mutt_get_virt_email(m, menu_get_index(menu));
789  return num + EMSG(e);
790  }
791  case RANGE_K_LT:
792  return num - 1;
793  case RANGE_K_GT:
794  return num + 1;
795  default:
796  return num;
797  }
798 }
Relative range.
Definition: private.h:76
The envelope/body of an email.
Definition: email.h:37
Less-than range.
Definition: private.h:78
struct Email * mutt_get_virt_email(struct Mailbox *m, int vnum)
Get a virtual Email.
Definition: context.c:412
#define EMSG(e)
Definition: private.h:117
#define MEGA
Definition: compile.c:75
char * dptr
Current read/write position.
Definition: buffer.h:36
Greater-than range.
Definition: private.h:79
#define KILO
Definition: compile.c:74
+ 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 Mailbox m,
struct Menu menu 
)
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
mMailbox
menuCurrent Menu
Return values
numIndex number for the message specified

Definition at line 811 of file compile.c.

813 {
814  /* This means the left or right subpattern was empty, e.g. ",." */
815  if ((pmatch[grp].rm_so == -1) || (pmatch[grp].rm_so == pmatch[grp].rm_eo))
816  {
817  if (side == RANGE_S_LEFT)
818  return 1;
819  if (side == RANGE_S_RIGHT)
820  return m->msg_count;
821  }
822  /* We have something, so determine what */
823  unsigned char c = (unsigned char) (s->dptr[pmatch[grp].rm_so]);
824  switch (c)
825  {
826  case RANGE_CIRCUM:
827  return 1;
828  case RANGE_DOLLAR:
829  return m->msg_count;
830  case RANGE_DOT:
831  {
832  struct Email *e = mutt_get_virt_email(m, menu_get_index(menu));
833  return EMSG(e);
834  }
835  case RANGE_LT:
836  case RANGE_GT:
837  return scan_range_num(s, pmatch, grp + 1, kind, m, menu);
838  default:
839  /* Only other possibility: a number */
840  return scan_range_num(s, pmatch, grp, kind, m, menu);
841  }
842 }
int msg_count
Total number of messages.
Definition: mailbox.h:91
The envelope/body of an email.
Definition: email.h:37
struct Email * mutt_get_virt_email(struct Mailbox *m, int vnum)
Get a virtual Email.
Definition: context.c:412
#define EMSG(e)
Definition: private.h:117
#define RANGE_LT
Definition: private.h:105
static int scan_range_num(struct Buffer *s, regmatch_t pmatch[], int group, int kind, struct Mailbox *m, struct Menu *menu)
Parse a number range.
Definition: compile.c:775
#define RANGE_DOT
Definition: private.h:102
char * dptr
Current read/write position.
Definition: buffer.h:36
#define RANGE_DOLLAR
Definition: private.h:104
#define RANGE_CIRCUM
Definition: private.h:103
Right side of range.
Definition: private.h:114
Left side of range.
Definition: private.h:113
#define RANGE_GT
Definition: private.h:106
+ 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 848 of file compile.c.

849 {
850  if (pat->min <= pat->max)
851  return;
852  int num = pat->min;
853  pat->min = pat->max;
854  pat->max = num;
855 }
int min
Minimum for range checks.
Definition: lib.h:80
int max
Maximum for range checks.
Definition: lib.h:81
+ 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 Mailbox m,
struct Menu menu 
)
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
mMailbox
menuCurrent Menu
Return values
numEatRangeError code, e.g. RANGE_E_OK

Definition at line 867 of file compile.c.

869 {
870  int regerr;
871  regmatch_t pmatch[RANGE_RX_GROUPS];
872  struct RangeRegex *pspec = &range_regexes[kind];
873 
874  /* First time through, compile the big regex */
875  if (!pspec->ready)
876  {
877  regerr = regcomp(&pspec->cooked, pspec->raw, REG_EXTENDED);
878  if (regerr != 0)
879  return report_regerror(regerr, &pspec->cooked, err);
880  pspec->ready = true;
881  }
882 
883  /* Match the pattern buffer against the compiled regex.
884  * No match means syntax error. */
885  regerr = regexec(&pspec->cooked, s->dptr, RANGE_RX_GROUPS, pmatch, 0);
886  if (regerr != 0)
887  return report_regerror(regerr, &pspec->cooked, err);
888 
889  if (!is_menu_available(s, pmatch, kind, err, menu))
890  return RANGE_E_CTX;
891 
892  /* Snarf the contents of the two sides of the range. */
893  pat->min = scan_range_slot(s, pmatch, pspec->lgrp, RANGE_S_LEFT, kind, m, menu);
894  pat->max = scan_range_slot(s, pmatch, pspec->rgrp, RANGE_S_RIGHT, kind, m, menu);
895  mutt_debug(LL_DEBUG1, "pat->min=%d pat->max=%d\n", pat->min, pat->max);
896 
897  /* Special case for a bare 0. */
898  if ((kind == RANGE_K_BARE) && (pat->min == 0) && (pat->max == 0))
899  {
900  if (!m || !menu)
901  {
902  mutt_buffer_strcpy(err, _("No current message"));
903  return RANGE_E_CTX;
904  }
905  struct Email *e = mutt_get_virt_email(m, menu_get_index(menu));
906  if (!e)
907  return RANGE_E_CTX;
908 
909  pat->max = EMSG(e);
910  pat->min = pat->max;
911  }
912 
913  /* Since we don't enforce order, we must swap bounds if they're backward */
914  order_range(pat);
915 
916  /* Slide pointer past the entire match. */
917  s->dptr += pmatch[0].rm_eo;
918  return RANGE_E_OK;
919 }
The envelope/body of an email.
Definition: email.h:37
static bool is_menu_available(struct Buffer *s, regmatch_t pmatch[], int kind, struct Buffer *err, struct Menu *menu)
Do we need a Context for this Pattern?
Definition: compile.c:738
struct Email * mutt_get_virt_email(struct Mailbox *m, int vnum)
Get a virtual Email.
Definition: context.c:412
regex_t cooked
Compiled form.
Definition: private.h:68
Range requires Context, but none available.
Definition: compile.c:71
Range is valid.
Definition: compile.c:69
#define EMSG(e)
Definition: private.h:117
#define _(a)
Definition: message.h:28
Single symbol.
Definition: private.h:80
int min
Minimum for range checks.
Definition: lib.h:80
#define RANGE_RX_GROUPS
Definition: private.h:100
Regular expression representing a range.
Definition: private.h:62
struct RangeRegex range_regexes[]
Set of Regexes for various range types.
Definition: pattern.c:66
char * dptr
Current read/write position.
Definition: buffer.h:36
static void order_range(struct Pattern *pat)
Put a range in order.
Definition: compile.c:848
const char * raw
Regex as string.
Definition: private.h:64
#define mutt_debug(LEVEL,...)
Definition: logging.h:85
size_t mutt_buffer_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:312
Right side of range.
Definition: private.h:114
Log at debug level 1.
Definition: logging.h:40
Left side of range.
Definition: private.h:113
static int report_regerror(int regerr, regex_t *preg, struct Buffer *err)
Create a regex error message.
Definition: compile.c:718
static int scan_range_slot(struct Buffer *s, regmatch_t pmatch[], int grp, int side, int kind, struct Mailbox *m, struct Menu *menu)
Parse a range of message numbers.
Definition: compile.c:811
int max
Maximum for range checks.
Definition: lib.h:81
int lgrp
Paren group matching the left side.
Definition: private.h:65
int rgrp
Paren group matching the right side.
Definition: private.h:66
bool ready
Compiled yet?
Definition: private.h:67
+ 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 Mailbox m,
struct Menu menu 
)
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
mMailbox
menuCurrent Menu
Return values
trueThe pattern was read successfully

Definition at line 931 of file compile.c.

934 {
935  if (!m || !menu)
936  {
937  // We need these for pretty much anything
938  mutt_buffer_strcpy(err, _("No Context"));
939  return false;
940  }
941 
942  bool skip_quote = false;
943 
944  /* If simple_search is set to "~m %s", the range will have double quotes
945  * around it... */
946  if (*s->dptr == '"')
947  {
948  s->dptr++;
949  skip_quote = true;
950  }
951 
952  for (int i_kind = 0; i_kind != RANGE_K_INVALID; i_kind++)
953  {
954  switch (eat_range_by_regex(pat, s, i_kind, err, m, menu))
955  {
956  case RANGE_E_CTX:
957  /* This means it matched syntactically but lacked context.
958  * No point in continuing. */
959  break;
960  case RANGE_E_SYNTAX:
961  /* Try another syntax, then */
962  continue;
963  case RANGE_E_OK:
964  if (skip_quote && (*s->dptr == '"'))
965  s->dptr++;
966  SKIPWS(s->dptr);
967  return true;
968  }
969  }
970  return false;
971 }
Range requires Context, but none available.
Definition: compile.c:71
Range is valid.
Definition: compile.c:69
#define _(a)
Definition: message.h:28
static int eat_range_by_regex(struct Pattern *pat, struct Buffer *s, int kind, struct Buffer *err, struct Mailbox *m, struct Menu *menu)
Parse a range given as a regex.
Definition: compile.c:867
Range is invalid.
Definition: private.h:82
#define SKIPWS(ch)
Definition: string2.h:46
char * dptr
Current read/write position.
Definition: buffer.h:36
size_t mutt_buffer_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:312
Range contains syntax error.
Definition: compile.c:70
+ 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 976 of file compile.c.

978 {
979  struct Buffer *tmp = mutt_buffer_pool_get();
980  bool rc = false;
981 
982  char *pexpr = s->dptr;
984  {
985  snprintf(err->data, err->dsize, _("Error in expression: %s"), pexpr);
986  goto out;
987  }
988 
989  if (mutt_buffer_is_empty(tmp))
990  {
991  snprintf(err->data, err->dsize, "%s", _("Empty expression"));
992  goto out;
993  }
994 
995  if (flags & MUTT_PC_PATTERN_DYNAMIC)
996  {
997  pat->dynamic = true;
998  pat->p.str = mutt_str_dup(tmp->data);
999  }
1000 
1001  rc = eval_date_minmax(pat, tmp->data, err);
1002 
1003 out:
1005 
1006  return rc;
1007 }
#define MUTT_PC_PATTERN_DYNAMIC
Enable runtime date range evaluation.
Definition: lib.h:62
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:101
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:112
#define MUTT_TOKEN_COMMENT
Don&#39;t reap comments.
Definition: mutt.h:72
union Pattern::@3 p
String manipulation buffer.
Definition: buffer.h:33
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:370
#define _(a)
Definition: message.h:28
size_t dsize
Length of data.
Definition: buffer.h:37
bool dynamic
Evaluate date ranges at run time.
Definition: lib.h:77
bool eval_date_minmax(struct Pattern *pat, const char *s, struct Buffer *err)
Evaluate a date-range pattern against &#39;now&#39;.
Definition: compile.c:499
int mutt_extract_token(struct Buffer *dest, struct Buffer *tok, TokenFlags flags)
Extract one token from a string.
Definition: init.c:395
char * dptr
Current read/write position.
Definition: buffer.h:36
char * data
Pointer to data.
Definition: buffer.h:35
char * str
String, if string_match is set.
Definition: lib.h:86
bool mutt_buffer_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition: buffer.c:252
#define MUTT_TOKEN_PATTERN
~%=!| are terms (for patterns)
Definition: mutt.h:71
+ 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 1016 of file compile.c.

1017 {
1018  int level = 1;
1019 
1020  for (; *s; s++)
1021  {
1022  if (*s == '(')
1023  level++;
1024  else if (*s == ')')
1025  {
1026  level--;
1027  if (level == 0)
1028  break;
1029  }
1030  }
1031  return s;
1032 }
+ 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 1038 of file compile.c.

1039 {
1040  if (!pat || !*pat)
1041  return;
1042 
1043  struct Pattern *np = SLIST_FIRST(*pat), *next = NULL;
1044 
1045  while (np)
1046  {
1047  next = SLIST_NEXT(np, entries);
1048 
1049  if (np->is_multi)
1051  else if (np->string_match || np->dynamic)
1052  FREE(&np->p.str);
1053  else if (np->group_match)
1054  np->p.group = NULL;
1055  else if (np->p.regex)
1056  {
1057  regfree(np->p.regex);
1058  FREE(&np->p.regex);
1059  }
1060 
1061  mutt_pattern_free(&np->child);
1062  FREE(&np);
1063 
1064  np = next;
1065  }
1066 
1067  FREE(pat);
1068 }
struct PatternList * child
Arguments to logical operation.
Definition: lib.h:82
regex_t * regex
Compiled regex, for non-pattern matching.
Definition: lib.h:84
bool group_match
Check a group of Addresses.
Definition: lib.h:74
union Pattern::@3 p
bool is_multi
Multiple case (only for ~I pattern now)
Definition: lib.h:79
void mutt_list_free(struct ListHead *h)
Free a List AND its strings.
Definition: list.c:122
A simple (non-regex) pattern.
Definition: lib.h:68
bool dynamic
Evaluate date ranges at run time.
Definition: lib.h:77
bool string_match
Check a string for a match.
Definition: lib.h:73
#define SLIST_NEXT(elm, field)
Definition: queue.h:270
#define SLIST_FIRST(head)
Definition: queue.h:229
char * str
String, if string_match is set.
Definition: lib.h:86
struct Group * group
Address group if group_match is set.
Definition: lib.h:85
#define FREE(x)
Definition: memory.h:40
struct ListHead multi_cases
Multiple strings for ~I pattern.
Definition: lib.h:87
void mutt_pattern_free(struct PatternList **pat)
Free a Pattern.
Definition: compile.c:1038
+ 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 1074 of file compile.c.

1075 {
1076  struct PatternList *h = mutt_mem_calloc(1, sizeof(struct PatternList));
1077  SLIST_INIT(h);
1078  struct Pattern *p = mutt_mem_calloc(1, sizeof(struct Pattern));
1079  SLIST_INSERT_HEAD(h, p, entries);
1080  return h;
1081 }
void * mutt_mem_calloc(size_t nmemb, size_t size)
Allocate zeroed memory on the heap.
Definition: memory.c:50
#define SLIST_INIT(head)
Definition: queue.h:256
union Pattern::@3 p
A simple (non-regex) pattern.
Definition: lib.h:68
#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:

◆ mutt_pattern_comp()

struct PatternList* mutt_pattern_comp ( struct Mailbox m,
struct Menu menu,
const char *  s,
PatternCompFlags  flags,
struct Buffer err 
)

Create a Pattern.

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

Definition at line 1092 of file compile.c.

1094 {
1095  /* curlist when assigned will always point to a list containing at least one node
1096  * with a Pattern value. */
1097  struct PatternList *curlist = NULL;
1098  struct PatternList *tmp = NULL, *tmp2 = NULL;
1099  struct PatternList *last = NULL;
1100  bool pat_not = false;
1101  bool all_addr = false;
1102  bool pat_or = false;
1103  bool implicit = true; /* used to detect logical AND operator */
1104  bool is_alias = false;
1105  short thread_op;
1106  const struct PatternFlags *entry = NULL;
1107  char *p = NULL;
1108  char *buf = NULL;
1109  struct Buffer ps;
1110 
1111  if (!s || !*s)
1112  {
1113  mutt_buffer_strcpy(err, _("empty pattern"));
1114  return NULL;
1115  }
1116 
1117  mutt_buffer_init(&ps);
1118  ps.dptr = (char *) s;
1119  ps.dsize = mutt_str_len(s);
1120 
1121  while (*ps.dptr)
1122  {
1123  SKIPWS(ps.dptr);
1124  switch (*ps.dptr)
1125  {
1126  case '^':
1127  ps.dptr++;
1128  all_addr = !all_addr;
1129  break;
1130  case '!':
1131  ps.dptr++;
1132  pat_not = !pat_not;
1133  break;
1134  case '@':
1135  ps.dptr++;
1136  is_alias = !is_alias;
1137  break;
1138  case '|':
1139  if (!pat_or)
1140  {
1141  if (!curlist)
1142  {
1143  mutt_buffer_printf(err, _("error in pattern at: %s"), ps.dptr);
1144  return NULL;
1145  }
1146 
1147  struct Pattern *pat = SLIST_FIRST(curlist);
1148 
1149  if (SLIST_NEXT(pat, entries))
1150  {
1151  /* A & B | C == (A & B) | C */
1152  tmp = mutt_pattern_node_new();
1153  pat = SLIST_FIRST(tmp);
1154  pat->op = MUTT_PAT_AND;
1155  pat->child = curlist;
1156 
1157  curlist = tmp;
1158  last = curlist;
1159  }
1160 
1161  pat_or = true;
1162  }
1163  ps.dptr++;
1164  implicit = false;
1165  pat_not = false;
1166  all_addr = false;
1167  is_alias = false;
1168  break;
1169  case '%':
1170  case '=':
1171  case '~':
1172  {
1173  struct Pattern *pat = NULL;
1174  if (ps.dptr[1] == '\0')
1175  {
1176  mutt_buffer_printf(err, _("missing pattern: %s"), ps.dptr);
1177  goto cleanup;
1178  }
1179  thread_op = 0;
1180  if (ps.dptr[1] == '(')
1181  thread_op = MUTT_PAT_THREAD;
1182  else if ((ps.dptr[1] == '<') && (ps.dptr[2] == '('))
1183  thread_op = MUTT_PAT_PARENT;
1184  else if ((ps.dptr[1] == '>') && (ps.dptr[2] == '('))
1185  thread_op = MUTT_PAT_CHILDREN;
1186  if (thread_op)
1187  {
1188  ps.dptr++; /* skip ~ */
1189  if ((thread_op == MUTT_PAT_PARENT) || (thread_op == MUTT_PAT_CHILDREN))
1190  ps.dptr++;
1191  p = find_matching_paren(ps.dptr + 1);
1192  if (p[0] != ')')
1193  {
1194  mutt_buffer_printf(err, _("mismatched parentheses: %s"), ps.dptr);
1195  goto cleanup;
1196  }
1197  tmp = mutt_pattern_node_new();
1198  pat = SLIST_FIRST(tmp);
1199  pat->op = thread_op;
1200  if (last)
1201  SLIST_NEXT(SLIST_FIRST(last), entries) = pat;
1202  else
1203  curlist = tmp;
1204  last = tmp;
1205  pat->pat_not ^= pat_not;
1206  pat->all_addr |= all_addr;
1207  pat->is_alias |= is_alias;
1208  pat_not = false;
1209  all_addr = false;
1210  is_alias = false;
1211  /* compile the sub-expression */
1212  buf = mutt_strn_dup(ps.dptr + 1, p - (ps.dptr + 1));
1213  tmp2 = mutt_pattern_comp(m, menu, buf, flags, err);
1214  if (!tmp2)
1215  {
1216  FREE(&buf);
1217  goto cleanup;
1218  }
1219  FREE(&buf);
1220  pat->child = tmp2;
1221  ps.dptr = p + 1; /* restore location */
1222  break;
1223  }
1224  if (implicit && pat_or)
1225  {
1226  /* A | B & C == (A | B) & C */
1227  tmp = mutt_pattern_node_new();
1228  pat = SLIST_FIRST(tmp);
1229  pat->op = MUTT_PAT_OR;
1230  pat->child = curlist;
1231  curlist = tmp;
1232  last = tmp;
1233  pat_or = false;
1234  }
1235 
1236  tmp = mutt_pattern_node_new();
1237  pat = SLIST_FIRST(tmp);
1238  pat->pat_not = pat_not;
1239  pat->all_addr = all_addr;
1240  pat->is_alias = is_alias;
1241  pat->string_match = (ps.dptr[0] == '=');
1242  pat->group_match = (ps.dptr[0] == '%');
1243  pat_not = false;
1244  all_addr = false;
1245  is_alias = false;
1246 
1247  if (last)
1248  SLIST_NEXT(SLIST_FIRST(last), entries) = pat;
1249  else
1250  curlist = tmp;
1251  if (curlist != last)
1252  FREE(&last);
1253  last = tmp;
1254 
1255  ps.dptr++; /* move past the ~ */
1256  entry = lookup_tag(*ps.dptr);
1257  if (!entry)
1258  {
1259  mutt_buffer_printf(err, _("%c: invalid pattern modifier"), *ps.dptr);
1260  goto cleanup;
1261  }
1262  if (entry->flags && ((flags & entry->flags) == 0))
1263  {
1264  mutt_buffer_printf(err, _("%c: not supported in this mode"), *ps.dptr);
1265  goto cleanup;
1266  }
1267  if (flags & MUTT_PC_SEND_MODE_SEARCH)
1268  pat->sendmode = true;
1269 
1270  pat->op = entry->op;
1271 
1272  ps.dptr++; /* eat the operator and any optional whitespace */
1273  SKIPWS(ps.dptr);
1274 
1275  if (entry->eat_arg)
1276  {
1277  if (ps.dptr[0] == '\0')
1278  {
1279  mutt_buffer_printf(err, "%s", _("missing parameter"));
1280  goto cleanup;
1281  }
1282  switch (entry->eat_arg)
1283  {
1284  case EAT_REGEX:
1285  if (!eat_regex(pat, flags, &ps, err))
1286  goto cleanup;
1287  break;
1288  case EAT_DATE:
1289  if (!eat_date(pat, flags, &ps, err))
1290  goto cleanup;
1291  break;
1292  case EAT_RANGE:
1293  if (!eat_range(pat, flags, &ps, err))
1294  goto cleanup;
1295  break;
1296  case EAT_MESSAGE_RANGE:
1297  if (!eat_message_range(pat, flags, &ps, err, m, menu))
1298  goto cleanup;
1299  break;
1300  case EAT_QUERY:
1301  if (!eat_query(pat, flags, &ps, err, m))
1302  goto cleanup;
1303  break;
1304  default:
1305  break;
1306  }
1307  }
1308  implicit = true;
1309  break;
1310  }
1311 
1312  case '(':
1313  {
1314  p = find_matching_paren(ps.dptr + 1);
1315  if (p[0] != ')')
1316  {
1317  mutt_buffer_printf(err, _("mismatched parentheses: %s"), ps.dptr);
1318  goto cleanup;
1319  }
1320  /* compile the sub-expression */
1321  buf = mutt_strn_dup(ps.dptr + 1, p - (ps.dptr + 1));
1322  tmp = mutt_pattern_comp(m, menu, buf, flags, err);
1323  FREE(&buf);
1324  if (!tmp)
1325  goto cleanup;
1326  struct Pattern *pat = SLIST_FIRST(tmp);
1327  if (last)
1328  SLIST_NEXT(SLIST_FIRST(last), entries) = pat;
1329  else
1330  curlist = tmp;
1331  last = tmp;
1332  pat = SLIST_FIRST(tmp);
1333  pat->pat_not ^= pat_not;
1334  pat->all_addr |= all_addr;
1335  pat->is_alias |= is_alias;
1336  pat_not = false;
1337  all_addr = false;
1338  is_alias = false;
1339  ps.dptr = p + 1; /* restore location */
1340  break;
1341  }
1342 
1343  default:
1344  mutt_buffer_printf(err, _("error in pattern at: %s"), ps.dptr);
1345  goto cleanup;
1346  }
1347  }
1348  if (!curlist)
1349  {
1350  mutt_buffer_strcpy(err, _("empty pattern"));
1351  return NULL;
1352  }
1353  if (curlist != tmp)
1354  FREE(&tmp);
1355  if (SLIST_NEXT(SLIST_FIRST(curlist), entries))
1356  {
1357  tmp = mutt_pattern_node_new();
1358  struct Pattern *pat = SLIST_FIRST(tmp);
1359  pat->op = pat_or ? MUTT_PAT_OR : MUTT_PAT_AND;
1360  pat->child = curlist;
1361  curlist = tmp;
1362  }
1363 
1364  return curlist;
1365 
1366 cleanup:
1367  mutt_pattern_free(&curlist);
1368  return NULL;
1369 }
struct PatternList * child
Arguments to logical operation.
Definition: lib.h:82
enum PatternEat eat_arg
Definition: private.h:55
bool group_match
Check a group of Addresses.
Definition: lib.h:74
Process a number (range)
Definition: private.h:41
static struct PatternList * mutt_pattern_node_new(void)
Create a new list containing a Pattern.
Definition: compile.c:1074
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:976
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
String manipulation buffer.
Definition: buffer.h:33
#define _(a)
Definition: message.h:28
int mutt_buffer_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition: buffer.c:160
Process a regex.
Definition: private.h:39
static char * find_matching_paren(char *s)
Find the matching parenthesis.
Definition: compile.c:1016
A simple (non-regex) pattern.
Definition: lib.h:68
bool is_alias
Is there an alias for this Address?
Definition: lib.h:76
int op
Operation to perform, e.g. MUTT_PAT_SCORE.
Definition: private.h:52
bool all_addr
All Addresses in the list must match.
Definition: lib.h:72
char * mutt_strn_dup(const char *begin, size_t len)
Duplicate a sub-string.
Definition: string.c:548
#define SKIPWS(ch)
Definition: string2.h:46
#define MUTT_PC_SEND_MODE_SEARCH
Allow send-mode body searching.
Definition: lib.h:63
bool string_match
Check a string for a match.
Definition: lib.h:73
bool pat_not
Pattern should be inverted (not)
Definition: lib.h:71
#define SLIST_NEXT(elm, field)
Definition: queue.h:270
static bool eat_message_range(struct Pattern *pat, PatternCompFlags flags, struct Buffer *s, struct Buffer *err, struct Mailbox *m, struct Menu *menu)
Parse a range of message numbers - Implements eat_arg_t.
Definition: compile.c:931
struct PatternList * mutt_pattern_comp(struct Mailbox *m, struct Menu *menu, const char *s, PatternCompFlags flags, struct Buffer *err)
Create a Pattern.
Definition: compile.c:1092
Process a message number (range)
Definition: private.h:42
#define SLIST_FIRST(head)
Definition: queue.h:229
short op
Operation, e.g. MUTT_PAT_SCORE.
Definition: lib.h:70
const struct PatternFlags * lookup_tag(char tag)
Lookup a pattern modifier.
Definition: flags.c:197
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:155
size_t mutt_buffer_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:312
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:664
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:627
Both patterns must match.
Definition: lib.h:126
Either pattern can match.
Definition: lib.h:127
bool sendmode
Evaluate searches in send-mode.
Definition: lib.h:78
Pattern matches parent.
Definition: lib.h:129
#define FREE(x)
Definition: memory.h:40
Pattern matches a child email.
Definition: lib.h:130
Mapping between user character and internal constant.
Definition: private.h:49
struct Buffer * mutt_buffer_init(struct Buffer *buf)
Initialise a new Buffer.
Definition: buffer.c:46
void mutt_pattern_free(struct PatternList **pat)
Free a Pattern.
Definition: compile.c:1038
Pattern matches email thread.
Definition: lib.h:128
PatternCompFlags flags
Pattern flags, e.g. MUTT_PC_FULL_MSG.
Definition: private.h:53
Process a date (range)
Definition: private.h:40
Process a query string.
Definition: private.h:43
+ Here is the call graph for this function:
+ Here is the caller graph for this function: