NeoMutt  2023-03-22
Teaching an old dog new tricks
DOXYGEN
regex.c
Go to the documentation of this file.
1
35#include "config.h"
36#include <stddef.h>
37#include <stdbool.h>
38#include <stdint.h>
39#include "mutt/lib.h"
40#include "regex2.h"
41#include "set.h"
42#include "types.h"
43
48void regex_free(struct Regex **r)
49{
50 if (!r || !*r)
51 return;
52
53 FREE(&(*r)->pattern);
54 if ((*r)->regex)
55 regfree((*r)->regex);
56 FREE(&(*r)->regex);
57 FREE(r);
58}
59
63static void regex_destroy(const struct ConfigSet *cs, void *var, const struct ConfigDef *cdef)
64{
65 struct Regex **r = var;
66 if (!*r)
67 return;
68
69 regex_free(r);
70}
71
80struct Regex *regex_new(const char *str, uint32_t flags, struct Buffer *err)
81{
82 if (!str)
83 return NULL;
84
85 int rflags = 0;
86 struct Regex *reg = mutt_mem_calloc(1, sizeof(struct Regex));
87
88 reg->regex = mutt_mem_calloc(1, sizeof(regex_t));
89 reg->pattern = mutt_str_dup(str);
90
91 /* Should we use smart case matching? */
92 if (((flags & DT_REGEX_MATCH_CASE) == 0) && mutt_mb_is_lower(str))
93 rflags |= REG_ICASE;
94
95 if ((flags & DT_REGEX_NOSUB))
96 rflags |= REG_NOSUB;
97
98 /* Is a prefix of '!' allowed? */
99 if (((flags & DT_REGEX_ALLOW_NOT) != 0) && (str[0] == '!'))
100 {
101 reg->pat_not = true;
102 str++;
103 }
104
105 int rc = REG_COMP(reg->regex, str, rflags);
106 if (rc != 0)
107 {
108 if (err)
109 regerror(rc, reg->regex, err->data, err->dsize);
110 regex_free(&reg);
111 return NULL;
112 }
113
114 return reg;
115}
116
120static int regex_string_set(const struct ConfigSet *cs, void *var, struct ConfigDef *cdef,
121 const char *value, struct Buffer *err)
122{
123 /* Store empty regexes as NULL */
124 if (value && (value[0] == '\0'))
125 value = NULL;
126
127 struct Regex *r = NULL;
128
129 int rc = CSR_SUCCESS;
130
131 if (var)
132 {
133 struct Regex *curval = *(struct Regex **) var;
134 if (curval && mutt_str_equal(value, curval->pattern))
136
137 if (value)
138 {
139 r = regex_new(value, cdef->type, err);
140 if (!r)
141 return CSR_ERR_INVALID;
142 }
143
144 if (cdef->validator)
145 {
146 rc = cdef->validator(cs, cdef, (intptr_t) r, err);
147
148 if (CSR_RESULT(rc) != CSR_SUCCESS)
149 {
150 regex_free(&r);
151 return rc | CSR_INV_VALIDATOR;
152 }
153 }
154
155 regex_destroy(cs, var, cdef);
156
157 *(struct Regex **) var = r;
158
159 if (!r)
160 rc |= CSR_SUC_EMPTY;
161 }
162 else
163 {
164 if (cdef->type & DT_INITIAL_SET)
165 FREE(&cdef->initial);
166
167 cdef->type |= DT_INITIAL_SET;
168 cdef->initial = (intptr_t) mutt_str_dup(value);
169 }
170
171 return rc;
172}
173
177static int regex_string_get(const struct ConfigSet *cs, void *var,
178 const struct ConfigDef *cdef, struct Buffer *result)
179{
180 const char *str = NULL;
181
182 if (var)
183 {
184 struct Regex *r = *(struct Regex **) var;
185 if (r)
186 str = r->pattern;
187 }
188 else
189 {
190 str = (char *) cdef->initial;
191 }
192
193 if (!str)
194 return CSR_SUCCESS | CSR_SUC_EMPTY; /* empty string */
195
196 mutt_buffer_addstr(result, str);
197 return CSR_SUCCESS;
198}
199
203static int regex_native_set(const struct ConfigSet *cs, void *var,
204 const struct ConfigDef *cdef, intptr_t value, struct Buffer *err)
205{
206 int rc;
207
208 if (cdef->validator)
209 {
210 rc = cdef->validator(cs, cdef, value, err);
211
212 if (CSR_RESULT(rc) != CSR_SUCCESS)
213 return rc | CSR_INV_VALIDATOR;
214 }
215
216 rc = CSR_SUCCESS;
217 struct Regex *orig = (struct Regex *) value;
218 struct Regex *r = NULL;
219
220 if (orig && orig->pattern)
221 {
222 const uint32_t flags = orig->pat_not ? DT_REGEX_ALLOW_NOT : 0;
223 r = regex_new(orig->pattern, flags, err);
224 if (!r)
225 rc = CSR_ERR_INVALID;
226 }
227 else
228 {
229 rc |= CSR_SUC_EMPTY;
230 }
231
232 if (CSR_RESULT(rc) == CSR_SUCCESS)
233 {
234 regex_free(var);
235 *(struct Regex **) var = r;
236 }
237
238 return rc;
239}
240
244static intptr_t regex_native_get(const struct ConfigSet *cs, void *var,
245 const struct ConfigDef *cdef, struct Buffer *err)
246{
247 struct Regex *r = *(struct Regex **) var;
248
249 return (intptr_t) r;
250}
251
255static int regex_reset(const struct ConfigSet *cs, void *var,
256 const struct ConfigDef *cdef, struct Buffer *err)
257{
258 struct Regex *r = NULL;
259 const char *initial = (const char *) cdef->initial;
260
261 struct Regex *currx = *(struct Regex **) var;
262 const char *curval = currx ? currx->pattern : NULL;
263
264 int rc = CSR_SUCCESS;
265 if (!currx)
266 rc |= CSR_SUC_EMPTY;
267
268 if (mutt_str_equal(initial, curval))
269 return rc | CSR_SUC_NO_CHANGE;
270
271 if (initial)
272 {
273 r = regex_new(initial, cdef->type, err);
274 if (!r)
275 return CSR_ERR_CODE;
276 }
277
278 if (cdef->validator)
279 {
280 rc = cdef->validator(cs, cdef, (intptr_t) r, err);
281
282 if (CSR_RESULT(rc) != CSR_SUCCESS)
283 {
284 regex_destroy(cs, &r, cdef);
285 return rc | CSR_INV_VALIDATOR;
286 }
287 }
288
289 if (!r)
290 rc |= CSR_SUC_EMPTY;
291
292 regex_destroy(cs, var, cdef);
293
294 *(struct Regex **) var = r;
295 return rc;
296}
297
301const struct ConfigSetType CstRegex = {
302 DT_REGEX,
303 "regex",
308 NULL, // string_plus_equals
309 NULL, // string_minus_equals
312};
size_t mutt_buffer_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition: buffer.c:233
struct Regex * regex_new(const char *str, uint32_t flags, struct Buffer *err)
Create an Regex from a string.
Definition: regex.c:80
void regex_free(struct Regex **r)
Free a Regex object.
Definition: regex.c:48
const struct ConfigSetType CstRegex
Config type representing a regular expression.
Definition: regex.c:301
#define CSR_ERR_INVALID
Value hasn't been set.
Definition: set.h:38
#define CSR_INV_VALIDATOR
Value was rejected by the validator.
Definition: set.h:48
#define CSR_SUC_NO_CHANGE
The value hasn't changed.
Definition: set.h:44
#define CSR_ERR_CODE
Problem with the code.
Definition: set.h:36
#define CSR_RESULT(x)
Definition: set.h:52
#define CSR_SUC_EMPTY
Value is empty/unset.
Definition: set.h:42
#define CSR_SUCCESS
Action completed successfully.
Definition: set.h:35
static void regex_destroy(const struct ConfigSet *cs, void *var, const struct ConfigDef *cdef)
Destroy a Regex object - Implements ConfigSetType::destroy() -.
Definition: regex.c:63
static intptr_t regex_native_get(const struct ConfigSet *cs, void *var, const struct ConfigDef *cdef, struct Buffer *err)
Get a Regex object from a Regex config item - Implements ConfigSetType::native_get() -.
Definition: regex.c:244
static int regex_native_set(const struct ConfigSet *cs, void *var, const struct ConfigDef *cdef, intptr_t value, struct Buffer *err)
Set a Regex config item by Regex object - Implements ConfigSetType::native_set() -.
Definition: regex.c:203
static int regex_reset(const struct ConfigSet *cs, void *var, const struct ConfigDef *cdef, struct Buffer *err)
Reset a Regex to its initial value - Implements ConfigSetType::reset() -.
Definition: regex.c:255
static int regex_string_get(const struct ConfigSet *cs, void *var, const struct ConfigDef *cdef, struct Buffer *result)
Get a Regex as a string - Implements ConfigSetType::string_get() -.
Definition: regex.c:177
static int regex_string_set(const struct ConfigSet *cs, void *var, struct ConfigDef *cdef, const char *value, struct Buffer *err)
Set a Regex by string - Implements ConfigSetType::string_set() -.
Definition: regex.c:120
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
Convenience wrapper for the library headers.
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:250
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:807
Parse the 'set' command.
Type representing a regular expression.
#define DT_REGEX_ALLOW_NOT
Regex can begin with '!'.
Definition: regex3.h:36
#define DT_REGEX_MATCH_CASE
Case-sensitive matching.
Definition: regex3.h:35
#define REG_COMP(preg, regex, cflags)
Compile a regular expression.
Definition: regex3.h:53
#define DT_REGEX_NOSUB
Do not report what was matched (REG_NOSUB)
Definition: regex3.h:37
String manipulation buffer.
Definition: buffer.h:34
size_t dsize
Length of data.
Definition: buffer.h:37
char * data
Pointer to data.
Definition: buffer.h:35
Definition: set.h:64
int(* validator)(const struct ConfigSet *cs, const struct ConfigDef *cdef, intptr_t value, struct Buffer *err)
Definition: set.h:82
intptr_t initial
Initial value.
Definition: set.h:67
uint32_t type
Variable type, e.g. DT_STRING.
Definition: set.h:66
Container for lots of config items.
Definition: set.h:252
Cached regular expression.
Definition: regex3.h:89
char * pattern
printable version
Definition: regex3.h:90
bool pat_not
do not match
Definition: regex3.h:92
regex_t * regex
compiled expression
Definition: regex3.h:91
Constants for all the config types.
#define DT_INITIAL_SET
Config item must have its initial value freed.
Definition: types.h:77
#define DT_REGEX
regular expressions
Definition: types.h:38