NeoMutt  2025-09-05-7-geaa2bd
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
message.c File Reference

Pattern handling for messages. More...

#include "config.h"
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "private.h"
#include "mutt/lib.h"
#include "core/lib.h"
#include "lib.h"
#include "menu/lib.h"
#include "mview.h"
+ Include dependency graph for message.c:

Go to the source code of this file.

Macros

#define KILO   1024
 
#define MEGA   1048576
 

Enumerations

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

Functions

static int report_regerror (int regerr, regex_t *preg, struct Buffer *err)
 Create a regex error message.
 
static bool is_menu_available (struct Buffer *s, regmatch_t pmatch[], int kind, struct Buffer *err, const struct Menu *menu)
 Do we need a MailboxView for this Pattern?
 
static int scan_range_num (struct Buffer *s, regmatch_t pmatch[], int group, int kind, struct MailboxView *mv)
 Parse a number range.
 
static int scan_range_slot (struct Buffer *s, regmatch_t pmatch[], int grp, int side, int kind, struct MailboxView *mv)
 Parse a range of message numbers.
 
static void order_range (struct Pattern *pat)
 Put a range in order.
 
static int eat_range_by_regex (struct Pattern *pat, struct Buffer *s, int kind, struct Buffer *err, struct MailboxView *mv)
 Parse a range given as a regex.
 
bool eat_message_range (struct Pattern *pat, PatternCompFlags flags, struct Buffer *s, struct Buffer *err, struct MailboxView *mv)
 Parse a range of message numbers - Implements eat_arg_t -.
 

Detailed Description

Pattern handling for messages.

Authors
  • Richard Russon

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program. If not, see http://www.gnu.org/licenses/.

Definition in file message.c.

Macro Definition Documentation

◆ KILO

#define KILO   1024

Definition at line 41 of file message.c.

◆ MEGA

#define MEGA   1048576

Definition at line 42 of file message.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_MVIEW 

Range requires MailboxView, but none available.

Definition at line 47 of file message.c.

48{
52};
@ RANGE_E_MVIEW
Range requires MailboxView, but none available.
Definition: message.c:51
@ RANGE_E_OK
Range is valid.
Definition: message.c:49
@ RANGE_E_SYNTAX
Range contains syntax error.
Definition: message.c:50

Function Documentation

◆ 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 61 of file message.c.

62{
63 size_t ds = err->dsize;
64
65 if (regerror(regerr, preg, err->data, ds) > ds)
66 mutt_debug(LL_DEBUG2, "warning: buffer too small for regerror\n");
67 /* The return value is fixed, exists only to shorten code at callsite */
68 return RANGE_E_SYNTAX;
69}
#define mutt_debug(LEVEL,...)
Definition: logging2.h:90
@ LL_DEBUG2
Log at debug level 2.
Definition: logging2.h:45
size_t dsize
Length of data.
Definition: buffer.h:39
char * data
Pointer to data.
Definition: buffer.h:37
+ 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,
const struct Menu menu 
)
static

Do we need a MailboxView for this Pattern?

Parameters
sString to check
pmatchRegex matches
kindRange type, e.g. RANGE_K_REL
errBuffer for error messages
menuCurrent Menu
Return values
falseMailboxView is required, but not available
trueOtherwise

Definition at line 81 of file message.c.

83{
84 const char *context_req_chars[] = {
85 [RANGE_K_REL] = ".0123456789",
86 [RANGE_K_ABS] = ".",
87 [RANGE_K_LT] = "",
88 [RANGE_K_GT] = "",
89 [RANGE_K_BARE] = ".",
90 };
91
92 /* First decide if we're going to need the menu at all.
93 * Relative patterns need it if they contain a dot or a number.
94 * Absolute patterns only need it if they contain a dot. */
95 char *context_loc = strpbrk(s->dptr + pmatch[0].rm_so, context_req_chars[kind]);
96 if (!context_loc || (context_loc >= &s->dptr[pmatch[0].rm_eo]))
97 return true;
98
99 /* We need a current message. Do we actually have one? */
100 if (menu)
101 return true;
102
103 /* Nope. */
104 buf_strcpy(err, _("No current message"));
105 return false;
106}
size_t buf_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:395
#define _(a)
Definition: message.h:28
@ RANGE_K_REL
Relative range.
Definition: private.h:90
@ RANGE_K_ABS
Absolute range.
Definition: private.h:91
@ RANGE_K_LT
Less-than range.
Definition: private.h:92
@ RANGE_K_BARE
Single symbol.
Definition: private.h:94
@ RANGE_K_GT
Greater-than range.
Definition: private.h:93
char * dptr
Current read/write position.
Definition: buffer.h:38
+ 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 MailboxView mv 
)
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
mvMailbox view
Return values
numParse number

Definition at line 117 of file message.c.

119{
120 int num = (int) strtol(&s->dptr[pmatch[group].rm_so], NULL, 0);
121 unsigned char c = (unsigned char) (s->dptr[pmatch[group].rm_eo - 1]);
122 if (mutt_toupper(c) == 'K')
123 num *= KILO;
124 else if (mutt_toupper(c) == 'M')
125 num *= MEGA;
126 switch (kind)
127 {
128 case RANGE_K_REL:
129 {
130 struct Mailbox *m = mv->mailbox;
131 struct Menu *menu = mv->menu;
132 struct Email *e = mutt_get_virt_email(m, menu_get_index(menu));
133 if (!e)
134 return num;
135 return num + email_msgno(e);
136 }
137 case RANGE_K_LT:
138 return num - 1;
139 case RANGE_K_GT:
140 return num + 1;
141 default:
142 return num;
143 }
144}
int mutt_toupper(int arg)
Wrapper for toupper(3)
Definition: ctype.c:139
int menu_get_index(struct Menu *menu)
Get the current selection in the Menu.
Definition: menu.c:160
struct Email * mutt_get_virt_email(struct Mailbox *m, int vnum)
Get a virtual Email.
Definition: mview.c:417
#define MEGA
Definition: message.c:42
#define KILO
Definition: message.c:41
static int email_msgno(struct Email *e)
Helper to get the Email's message number.
Definition: private.h:136
The envelope/body of an email.
Definition: email.h:39
struct Menu * menu
Needed for pattern compilation.
Definition: mview.h:47
struct Mailbox * mailbox
Current Mailbox.
Definition: mview.h:51
A mailbox.
Definition: mailbox.h:79
Definition: lib.h:79
+ 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 MailboxView mv 
)
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
mvMailbox view
Return values
numIndex number for the message specified

Definition at line 156 of file message.c.

158{
159 struct Mailbox *m = mv->mailbox;
160 struct Menu *menu = mv->menu;
161
162 /* This means the left or right subpattern was empty, e.g. ",." */
163 if ((pmatch[grp].rm_so == -1) || (pmatch[grp].rm_so == pmatch[grp].rm_eo))
164 {
165 if (side == RANGE_S_LEFT)
166 return 1;
167 if (side == RANGE_S_RIGHT)
168 return m->msg_count;
169 }
170 /* We have something, so determine what */
171 unsigned char c = (unsigned char) (s->dptr[pmatch[grp].rm_so]);
172 switch (c)
173 {
174 case RANGE_CIRCUM:
175 return 1;
176 case RANGE_DOLLAR:
177 return m->msg_count;
178 case RANGE_DOT:
179 {
180 struct Email *e = mutt_get_virt_email(m, menu_get_index(menu));
181 if (!e)
182 return 1;
183 return email_msgno(e);
184 }
185 case RANGE_LT:
186 case RANGE_GT:
187 return scan_range_num(s, pmatch, grp + 1, kind, mv);
188 default:
189 /* Only other possibility: a number */
190 return scan_range_num(s, pmatch, grp, kind, mv);
191 }
192}
static int scan_range_num(struct Buffer *s, regmatch_t pmatch[], int group, int kind, struct MailboxView *mv)
Parse a number range.
Definition: message.c:117
@ RANGE_S_LEFT
Left side of range.
Definition: private.h:127
@ RANGE_S_RIGHT
Right side of range.
Definition: private.h:128
#define RANGE_DOLLAR
Definition: private.h:118
#define RANGE_GT
Definition: private.h:120
#define RANGE_CIRCUM
Definition: private.h:117
#define RANGE_DOT
Definition: private.h:116
#define RANGE_LT
Definition: private.h:119
int msg_count
Total number of messages.
Definition: mailbox.h:88
+ 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 198 of file message.c.

199{
200 if (pat->min <= pat->max)
201 return;
202 long num = pat->min;
203 pat->min = pat->max;
204 pat->max = num;
205}
long min
Minimum for range checks.
Definition: lib.h:88
long max
Maximum for range checks.
Definition: lib.h:89
+ 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 MailboxView mv 
)
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
mvMailbox view
Return values
numEatRangeError code, e.g. RANGE_E_OK

Definition at line 216 of file message.c.

218{
219 int regerr;
220 regmatch_t pmatch[RANGE_RX_GROUPS] = { 0 };
221 struct RangeRegex *pspec = &RangeRegexes[kind];
222
223 /* First time through, compile the big regex */
224 if (!pspec->ready)
225 {
226 regerr = regcomp(&pspec->cooked, pspec->raw, REG_EXTENDED);
227 if (regerr != 0)
228 return report_regerror(regerr, &pspec->cooked, err);
229 pspec->ready = true;
230 }
231
232 /* Match the pattern buffer against the compiled regex.
233 * No match means syntax error. */
234 regerr = regexec(&pspec->cooked, s->dptr, RANGE_RX_GROUPS, pmatch, 0);
235 if (regerr != 0)
236 return report_regerror(regerr, &pspec->cooked, err);
237
238 struct Mailbox *m = mv->mailbox;
239 struct Menu *menu = mv->menu;
240 if (!is_menu_available(s, pmatch, kind, err, menu))
241 return RANGE_E_MVIEW;
242
243 /* Snarf the contents of the two sides of the range. */
244 pat->min = scan_range_slot(s, pmatch, pspec->lgrp, RANGE_S_LEFT, kind, mv);
245 pat->max = scan_range_slot(s, pmatch, pspec->rgrp, RANGE_S_RIGHT, kind, mv);
246 mutt_debug(LL_DEBUG1, "pat->min=%ld pat->max=%ld\n", pat->min, pat->max);
247
248 /* Special case for a bare 0. */
249 if ((kind == RANGE_K_BARE) && (pat->min == 0) && (pat->max == 0))
250 {
251 if (!m || !menu)
252 {
253 buf_strcpy(err, _("No current message"));
254 return RANGE_E_MVIEW;
255 }
256 struct Email *e = mutt_get_virt_email(m, menu_get_index(menu));
257 if (!e)
258 return RANGE_E_MVIEW;
259
260 pat->max = email_msgno(e);
261 pat->min = pat->max;
262 }
263
264 /* Since we don't enforce order, we must swap bounds if they're backward */
265 order_range(pat);
266
267 /* Slide pointer past the entire match. */
268 s->dptr += pmatch[0].rm_eo;
269 return RANGE_E_OK;
270}
@ LL_DEBUG1
Log at debug level 1.
Definition: logging2.h:44
static int scan_range_slot(struct Buffer *s, regmatch_t pmatch[], int grp, int side, int kind, struct MailboxView *mv)
Parse a range of message numbers.
Definition: message.c:156
static void order_range(struct Pattern *pat)
Put a range in order.
Definition: message.c:198
static int report_regerror(int regerr, regex_t *preg, struct Buffer *err)
Create a regex error message.
Definition: message.c:61
static bool is_menu_available(struct Buffer *s, regmatch_t pmatch[], int kind, struct Buffer *err, const struct Menu *menu)
Do we need a MailboxView for this Pattern?
Definition: message.c:81
#define RANGE_RX_GROUPS
Definition: private.h:114
struct RangeRegex RangeRegexes[]
Set of Regexes for various range types.
Definition: pattern.c:62
Regular expression representing a range.
Definition: private.h:77
int lgrp
Paren group matching the left side.
Definition: private.h:79
int rgrp
Paren group matching the right side.
Definition: private.h:80
regex_t cooked
Compiled form.
Definition: private.h:82
bool ready
Compiled yet?
Definition: private.h:81
const char * raw
Regex as string.
Definition: private.h:78
+ Here is the call graph for this function:
+ Here is the caller graph for this function: