NeoMutt  2022-04-29-247-gc6aae8
Teaching an old dog new tricks
DOXYGEN
Parse a pattern

Prototype for a function to parse a pattern. 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 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 bool eat_range (struct Pattern *pat, PatternCompFlags flags, struct Buffer *s, struct Buffer *err)
 Parse a number range - Implements eat_arg_t -. 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...
 

Detailed Description

Prototype for a function to parse a pattern.

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

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 = mutt_buffer_pool_get();
84 bool rc = false;
85 char *pexpr = s->dptr;
86 if ((mutt_extract_token(buf, s, MUTT_TOKEN_PATTERN | MUTT_TOKEN_COMMENT) != 0) || !buf->data)
87 {
88 mutt_buffer_printf(err, _("Error in expression: %s"), pexpr);
89 goto out;
90 }
91 if (buf->data[0] == '\0')
92 {
93 mutt_buffer_printf(err, "%s", _("Empty expression"));
94 goto out;
95 }
96
97 if (pat->string_match)
98 {
99 pat->p.str = mutt_str_dup(buf->data);
100 pat->ign_case = mutt_mb_is_lower(buf->data);
101 }
102 else if (pat->group_match)
103 {
104 pat->p.group = mutt_pattern_group(buf->data);
105 }
106 else
107 {
108 pat->p.regex = mutt_mem_calloc(1, sizeof(regex_t));
109#ifdef USE_DEBUG_GRAPHVIZ
110 pat->raw_pattern = mutt_str_dup(buf->data);
111#endif
112 uint16_t case_flags = mutt_mb_is_lower(buf->data) ? REG_ICASE : 0;
113 int rc2 = REG_COMP(pat->p.regex, buf->data, REG_NEWLINE | REG_NOSUB | case_flags);
114 if (rc2 != 0)
115 {
116 char errmsg[256] = { 0 };
117 regerror(rc2, pat->p.regex, errmsg, sizeof(errmsg));
118 mutt_buffer_printf(err, "'%s': %s", buf->data, errmsg);
119 FREE(&pat->p.regex);
120 goto out;
121 }
122 }
123
124 rc = true;
125
126out:
128 return rc;
129}
int mutt_buffer_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition: buffer.c:168
struct Group * mutt_pattern_group(const char *pat)
Match a pattern to a Group.
Definition: group.c:112
int mutt_extract_token(struct Buffer *dest, struct Buffer *tok, TokenFlags flags)
Extract one token from a string.
Definition: init.c:273
bool mutt_mb_is_lower(const char *s)
Does a multi-byte string contain only lowercase characters?
Definition: mbyte.c:355
void * mutt_mem_calloc(size_t nmemb, size_t size)
Allocate zeroed memory on the heap.
Definition: memory.c:50
#define FREE(x)
Definition: memory.h:43
#define _(a)
Definition: message.h:28
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:250
#define MUTT_TOKEN_COMMENT
Don't reap comments.
Definition: mutt.h:73
#define MUTT_TOKEN_PATTERN
~%=!| are terms (for patterns)
Definition: mutt.h:72
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:112
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:101
#define REG_COMP(preg, regex, cflags)
Compile a regular expression.
Definition: regex3.h:53
String manipulation buffer.
Definition: buffer.h:34
char * dptr
Current read/write position.
Definition: buffer.h:36
char * data
Pointer to data.
Definition: buffer.h:35
bool group_match
Check a group of Addresses.
Definition: lib.h:75
union Pattern::@1 p
struct Group * group
Address group if group_match is set.
Definition: lib.h:86
bool string_match
Check a string for a match.
Definition: lib.h:74
regex_t * regex
Compiled regex, for non-pattern matching.
Definition: lib.h:85
char * str
String, if string_match is set.
Definition: lib.h:87
bool ign_case
Ignore case for local string_match searches.
Definition: lib.h:76
+ 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 = mutt_buffer_pool_get();
159 struct Buffer *tok_buf = mutt_buffer_pool_get();
160 bool rc = false;
161
162 FILE *fp = NULL;
163
164 const char *const c_external_search_command = cs_subset_string(NeoMutt->sub, "external_search_command");
165 if (!c_external_search_command)
166 {
167 mutt_buffer_printf(err, "%s", _("No search command defined"));
168 goto out;
169 }
170
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 goto out;
177 }
178 if (*tok_buf->data == '\0')
179 {
180 mutt_buffer_printf(err, "%s", _("Empty expression"));
181 goto out;
182 }
183
184 mutt_buffer_addstr(cmd_buf, c_external_search_command);
185 mutt_buffer_addch(cmd_buf, ' ');
186
187 if (m)
188 {
189 char *escaped_folder = mutt_path_escape(mailbox_path(m));
190 mutt_debug(LL_DEBUG2, "escaped folder path: %s\n", escaped_folder);
191 mutt_buffer_addch(cmd_buf, '\'');
192 mutt_buffer_addstr(cmd_buf, escaped_folder);
193 mutt_buffer_addch(cmd_buf, '\'');
194 }
195 else
196 {
197 mutt_buffer_addch(cmd_buf, '/');
198 }
199 mutt_buffer_addch(cmd_buf, ' ');
200 mutt_buffer_addstr(cmd_buf, tok_buf->data);
201
202 mutt_message(_("Running search command: %s ..."), cmd_buf->data);
203 pat->is_multi = true;
205 pid_t pid = filter_create(cmd_buf->data, NULL, &fp, NULL);
206 if (pid < 0)
207 {
208 mutt_buffer_printf(err, "unable to fork command: %s\n", cmd_buf->data);
209 goto out;
210 }
211
213 mutt_file_fclose(&fp);
214 filter_wait(pid);
215
216 rc = true;
217
218out:
219 mutt_buffer_pool_release(&cmd_buf);
220 mutt_buffer_pool_release(&tok_buf);
221 return rc;
222}
size_t mutt_buffer_addch(struct Buffer *buf, char c)
Add a single character to a Buffer.
Definition: buffer.c:248
size_t mutt_buffer_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition: buffer.c:233
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:317
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:152
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:822
#define MUTT_RL_NO_FLAGS
No flags are set.
Definition: file.h:38
int filter_wait(pid_t pid)
Wait for the exit of a process and return its status.
Definition: filter.c:217
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_message(...)
Definition: logging.h:86
#define mutt_debug(LEVEL,...)
Definition: logging.h:84
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
void mutt_list_clear(struct ListHead *h)
Free a list, but NOT its strings.
Definition: list.c:167
@ LL_DEBUG2
Log at debug level 2.
Definition: logging.h:41
static const char * mailbox_path(const struct Mailbox *m)
Get the Mailbox's path string.
Definition: mailbox.h:210
char * mutt_path_escape(const char *src)
Escapes single quotes in a path for a command string.
Definition: path.c:520
Container for Accounts, Notifications.
Definition: neomutt.h:37
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
struct ListHead multi_cases
Multiple strings for ~I pattern.
Definition: lib.h:88
bool is_multi
Multiple case (only for ~I pattern now)
Definition: lib.h:80
+ 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 628 of file compile.c.

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

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

979{
980 struct Buffer *tmp = mutt_buffer_pool_get();
981 bool rc = false;
982
983 char *pexpr = s->dptr;
985 {
986 mutt_buffer_printf(err, _("Error in expression: %s"), pexpr);
987 goto out;
988 }
989
990 if (mutt_buffer_is_empty(tmp))
991 {
992 mutt_buffer_printf(err, "%s", _("Empty expression"));
993 goto out;
994 }
995
996 if (flags & MUTT_PC_PATTERN_DYNAMIC)
997 {
998 pat->dynamic = true;
999 pat->p.str = mutt_str_dup(tmp->data);
1000 }
1001
1002 rc = eval_date_minmax(pat, tmp->data, err);
1003
1004out:
1006 return rc;
1007}
bool mutt_buffer_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition: buffer.c:260
bool eval_date_minmax(struct Pattern *pat, const char *s, struct Buffer *err)
Evaluate a date-range pattern against 'now'.
Definition: compile.c:500
#define MUTT_PC_PATTERN_DYNAMIC
Enable runtime date range evaluation.
Definition: lib.h:63
bool dynamic
Evaluate date ranges at run time.
Definition: lib.h:78
+ Here is the call graph for this function:
+ Here is the caller graph for this function: