NeoMutt
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
extract.h File Reference

Text parser. More...

#include <ctype.h>
#include <stdint.h>
+ Include dependency graph for extract.h:
+ This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Macros

#define MoreArgs(buf)   (*(buf)->dptr && (*(buf)->dptr != ';') && (*(buf)->dptr != '#'))
 
#define MoreArgsF(buf, flags)
 
#define TOKEN_NO_FLAGS   0
 No flags are set.
 
#define TOKEN_EQUAL   (1 << 0)
 Treat '=' as a special.
 
#define TOKEN_CONDENSE   (1 << 1)
 ^(char) to control chars (macros)
 
#define TOKEN_SPACE   (1 << 2)
 Don't treat whitespace as a term.
 
#define TOKEN_QUOTE   (1 << 3)
 Don't interpret quotes.
 
#define TOKEN_PATTERN   (1 << 4)
 ~%=!| are terms (for patterns)
 
#define TOKEN_COMMENT   (1 << 5)
 Don't reap comments.
 
#define TOKEN_SEMICOLON   (1 << 6)
 Don't treat ; as special.
 
#define TOKEN_BACKTICK_VARS   (1 << 7)
 Expand variables within backticks.
 
#define TOKEN_NOSHELL   (1 << 8)
 Don't expand environment variables.
 
#define TOKEN_QUESTION   (1 << 9)
 Treat '?' as a special.
 
#define TOKEN_PLUS   (1 << 10)
 Treat '+' as a special.
 
#define TOKEN_MINUS   (1 << 11)
 Treat '-' as a special.
 

Typedefs

typedef uint16_t TokenFlags
 Flags for parse_extract_token(), e.g. TOKEN_EQUAL.
 

Functions

int parse_extract_token (struct Buffer *dest, struct Buffer *tok, TokenFlags flags)
 Extract one token from a string.
 

Detailed Description

Text parser.

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 extract.h.

Macro Definition Documentation

◆ MoreArgs

#define MoreArgs (   buf)    (*(buf)->dptr && (*(buf)->dptr != ';') && (*(buf)->dptr != '#'))

Definition at line 31 of file extract.h.

◆ MoreArgsF

#define MoreArgsF (   buf,
  flags 
)
Value:
(*(buf)->dptr && \
(!isspace(*(buf)->dptr) || ((flags) & TOKEN_SPACE)) && \
((*(buf)->dptr != '#') || ((flags) & TOKEN_COMMENT)) && \
((*(buf)->dptr != '+') || !((flags) & TOKEN_PLUS)) && \
((*(buf)->dptr != '-') || !((flags) & TOKEN_MINUS)) && \
((*(buf)->dptr != '=') || !((flags) & TOKEN_EQUAL)) && \
((*(buf)->dptr != '?') || !((flags) & TOKEN_QUESTION)) && \
((*(buf)->dptr != ';') || ((flags) & TOKEN_SEMICOLON)) && \
(!((flags) & TOKEN_PATTERN) || strchr("~%=!|", *(buf)->dptr)))
#define TOKEN_SPACE
Don't treat whitespace as a term.
Definition: extract.h:48
#define TOKEN_EQUAL
Treat '=' as a special.
Definition: extract.h:46
#define TOKEN_PLUS
Treat '+' as a special.
Definition: extract.h:56
#define TOKEN_COMMENT
Don't reap comments.
Definition: extract.h:51
#define TOKEN_MINUS
Treat '-' as a special.
Definition: extract.h:57
#define TOKEN_PATTERN
~%=!| are terms (for patterns)
Definition: extract.h:50
#define TOKEN_SEMICOLON
Don't treat ; as special.
Definition: extract.h:52
#define TOKEN_QUESTION
Treat '?' as a special.
Definition: extract.h:55

Definition at line 34 of file extract.h.

◆ TOKEN_NO_FLAGS

#define TOKEN_NO_FLAGS   0

No flags are set.

Definition at line 45 of file extract.h.

◆ TOKEN_EQUAL

#define TOKEN_EQUAL   (1 << 0)

Treat '=' as a special.

Definition at line 46 of file extract.h.

◆ TOKEN_CONDENSE

#define TOKEN_CONDENSE   (1 << 1)

^(char) to control chars (macros)

Definition at line 47 of file extract.h.

◆ TOKEN_SPACE

#define TOKEN_SPACE   (1 << 2)

Don't treat whitespace as a term.

Definition at line 48 of file extract.h.

◆ TOKEN_QUOTE

#define TOKEN_QUOTE   (1 << 3)

Don't interpret quotes.

Definition at line 49 of file extract.h.

◆ TOKEN_PATTERN

#define TOKEN_PATTERN   (1 << 4)

~%=!| are terms (for patterns)

Definition at line 50 of file extract.h.

◆ TOKEN_COMMENT

#define TOKEN_COMMENT   (1 << 5)

Don't reap comments.

Definition at line 51 of file extract.h.

◆ TOKEN_SEMICOLON

#define TOKEN_SEMICOLON   (1 << 6)

Don't treat ; as special.

Definition at line 52 of file extract.h.

◆ TOKEN_BACKTICK_VARS

#define TOKEN_BACKTICK_VARS   (1 << 7)

Expand variables within backticks.

Definition at line 53 of file extract.h.

◆ TOKEN_NOSHELL

#define TOKEN_NOSHELL   (1 << 8)

Don't expand environment variables.

Definition at line 54 of file extract.h.

◆ TOKEN_QUESTION

#define TOKEN_QUESTION   (1 << 9)

Treat '?' as a special.

Definition at line 55 of file extract.h.

◆ TOKEN_PLUS

#define TOKEN_PLUS   (1 << 10)

Treat '+' as a special.

Definition at line 56 of file extract.h.

◆ TOKEN_MINUS

#define TOKEN_MINUS   (1 << 11)

Treat '-' as a special.

Definition at line 57 of file extract.h.

Typedef Documentation

◆ TokenFlags

typedef uint16_t TokenFlags

Flags for parse_extract_token(), e.g. TOKEN_EQUAL.

Definition at line 44 of file extract.h.

Function Documentation

◆ parse_extract_token()

int parse_extract_token ( struct Buffer dest,
struct Buffer tok,
TokenFlags  flags 
)

Extract one token from a string.

Parameters
destBuffer for the result
tokBuffer containing tokens
flagsFlags, see TokenFlags
Return values
0Success
-1Error

Definition at line 48 of file extract.c.

49{
50 if (!dest || !tok)
51 return -1;
52
53 char ch;
54 char qc = '\0'; /* quote char */
55 char *pc = NULL;
56
57 /* Some callers used to rely on the (bad) assumption that dest->data would be
58 * non-NULL after calling this function. Perhaps I've missed a few cases, or
59 * a future caller might make the same mistake. */
60 if (!dest->data)
61 buf_alloc(dest, 256);
62
63 buf_reset(dest);
64
65 SKIPWS(tok->dptr);
66 while ((ch = *tok->dptr))
67 {
68 if (qc == '\0')
69 {
70 if (isspace(ch) && !(flags & TOKEN_SPACE))
71 break;
72 if ((ch == '#') && !(flags & TOKEN_COMMENT))
73 break;
74 if ((ch == '+') && (flags & TOKEN_PLUS))
75 break;
76 if ((ch == '-') && (flags & TOKEN_MINUS))
77 break;
78 if ((ch == '=') && (flags & TOKEN_EQUAL))
79 break;
80 if ((ch == '?') && (flags & TOKEN_QUESTION))
81 break;
82 if ((ch == ';') && !(flags & TOKEN_SEMICOLON))
83 break;
84 if ((flags & TOKEN_PATTERN) && strchr("~%=!|", ch))
85 break;
86 }
87
88 tok->dptr++;
89
90 if (ch == qc)
91 {
92 qc = 0; /* end of quote */
93 }
94 else if (!qc && ((ch == '\'') || (ch == '"')) && !(flags & TOKEN_QUOTE))
95 {
96 qc = ch;
97 }
98 else if ((ch == '\\') && (qc != '\''))
99 {
100 if (tok->dptr[0] == '\0')
101 return -1; /* premature end of token */
102 switch (ch = *tok->dptr++)
103 {
104 case 'c':
105 case 'C':
106 if (tok->dptr[0] == '\0')
107 return -1; /* premature end of token */
108 buf_addch(dest, (toupper((unsigned char) tok->dptr[0]) - '@') & 0x7f);
109 tok->dptr++;
110 break;
111 case 'e':
112 buf_addch(dest, '\033'); // Escape
113 break;
114 case 'f':
115 buf_addch(dest, '\f');
116 break;
117 case 'n':
118 buf_addch(dest, '\n');
119 break;
120 case 'r':
121 buf_addch(dest, '\r');
122 break;
123 case 't':
124 buf_addch(dest, '\t');
125 break;
126 default:
127 if (isdigit((unsigned char) ch) && isdigit((unsigned char) tok->dptr[0]) &&
128 isdigit((unsigned char) tok->dptr[1]))
129 {
130 buf_addch(dest, (ch << 6) + (tok->dptr[0] << 3) + tok->dptr[1] - 3504);
131 tok->dptr += 2;
132 }
133 else
134 {
135 buf_addch(dest, ch);
136 }
137 }
138 }
139 else if ((ch == '^') && (flags & TOKEN_CONDENSE))
140 {
141 if (tok->dptr[0] == '\0')
142 return -1; /* premature end of token */
143 ch = *tok->dptr++;
144 if (ch == '^')
145 {
146 buf_addch(dest, ch);
147 }
148 else if (ch == '[')
149 {
150 buf_addch(dest, '\033'); // Escape
151 }
152 else if (isalpha((unsigned char) ch))
153 {
154 buf_addch(dest, toupper((unsigned char) ch) - '@');
155 }
156 else
157 {
158 buf_addch(dest, '^');
159 buf_addch(dest, ch);
160 }
161 }
162 else if ((ch == '`') && (!qc || (qc == '"')))
163 {
164 FILE *fp = NULL;
165 pid_t pid;
166
167 pc = tok->dptr;
168 do
169 {
170 pc = strpbrk(pc, "\\`");
171 if (pc)
172 {
173 /* skip any quoted chars */
174 if (*pc == '\\')
175 pc += 2;
176 }
177 } while (pc && (pc[0] != '`'));
178 if (!pc)
179 {
180 mutt_debug(LL_DEBUG1, "mismatched backticks\n");
181 return -1;
182 }
183 struct Buffer cmd;
184 buf_init(&cmd);
185 *pc = '\0';
186 if (flags & TOKEN_BACKTICK_VARS)
187 {
188 /* recursively extract tokens to interpolate variables */
189 parse_extract_token(&cmd, tok,
192 }
193 else
194 {
195 cmd.data = mutt_str_dup(tok->dptr);
196 }
197 *pc = '`';
198 pid = filter_create(cmd.data, NULL, &fp, NULL, EnvList);
199 if (pid < 0)
200 {
201 mutt_debug(LL_DEBUG1, "unable to fork command: %s\n", cmd.data);
202 FREE(&cmd.data);
203 return -1;
204 }
205
206 tok->dptr = pc + 1;
207
208 /* read line */
209 struct Buffer expn = buf_make(0);
210 expn.data = mutt_file_read_line(NULL, &expn.dsize, fp, NULL, MUTT_RL_NO_FLAGS);
211 mutt_file_fclose(&fp);
212 int rc = filter_wait(pid);
213 if (rc != 0)
214 mutt_debug(LL_DEBUG1, "backticks exited code %d for command: %s\n", rc,
215 buf_string(&cmd));
216 FREE(&cmd.data);
217
218 /* if we got output, make a new string consisting of the shell output
219 * plus whatever else was left on the original line */
220 /* BUT: If this is inside a quoted string, directly add output to
221 * the token */
222 if (expn.data)
223 {
224 if (qc)
225 {
226 buf_addstr(dest, expn.data);
227 }
228 else
229 {
230 struct Buffer *copy = buf_pool_get();
231 buf_fix_dptr(&expn);
232 buf_copy(copy, &expn);
233 buf_addstr(copy, tok->dptr);
234 buf_copy(tok, copy);
235 buf_seek(tok, 0);
236 buf_pool_release(&copy);
237 }
238 FREE(&expn.data);
239 }
240 }
241 else if ((ch == '$') && (!qc || (qc == '"')) &&
242 ((tok->dptr[0] == '{') || isalpha((unsigned char) tok->dptr[0])))
243 {
244 const char *env = NULL;
245 char *var = NULL;
246
247 if (tok->dptr[0] == '{')
248 {
249 pc = strchr(tok->dptr, '}');
250 if (pc)
251 {
252 var = mutt_strn_dup(tok->dptr + 1, pc - (tok->dptr + 1));
253 tok->dptr = pc + 1;
254
255 if ((flags & TOKEN_NOSHELL))
256 {
257 buf_addch(dest, ch);
258 buf_addch(dest, '{');
259 buf_addstr(dest, var);
260 buf_addch(dest, '}');
261 FREE(&var);
262 }
263 }
264 }
265 else
266 {
267 for (pc = tok->dptr; isalnum((unsigned char) *pc) || (pc[0] == '_'); pc++)
268 ; // do nothing
269
270 var = mutt_strn_dup(tok->dptr, pc - tok->dptr);
271 tok->dptr = pc;
272 }
273 if (var)
274 {
275 struct Buffer result;
276 buf_init(&result);
277 int rc = cs_subset_str_string_get(NeoMutt->sub, var, &result);
278
279 if (CSR_RESULT(rc) == CSR_SUCCESS)
280 {
281 buf_addstr(dest, result.data);
282 FREE(&result.data);
283 }
284 else if (!(flags & TOKEN_NOSHELL) && (env = mutt_str_getenv(var)))
285 {
286 buf_addstr(dest, env);
287 }
288 else
289 {
290 buf_addch(dest, ch);
291 buf_addstr(dest, var);
292 }
293 FREE(&var);
294 }
295 }
296 else
297 {
298 buf_addch(dest, ch);
299 }
300 }
301 buf_addch(dest, 0); /* terminate the string */
302 SKIPWS(tok->dptr);
303 return 0;
304}
void buf_seek(struct Buffer *buf, size_t offset)
Set current read/write position to offset from beginning.
Definition: buffer.c:593
void buf_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition: buffer.c:88
struct Buffer buf_make(size_t size)
Make a new buffer on the stack.
Definition: buffer.c:70
void buf_fix_dptr(struct Buffer *buf)
Move the dptr to end of the Buffer.
Definition: buffer.c:194
struct Buffer * buf_init(struct Buffer *buf)
Initialise a new Buffer.
Definition: buffer.c:55
size_t buf_addch(struct Buffer *buf, char c)
Add a single character to a Buffer.
Definition: buffer.c:253
size_t buf_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition: buffer.c:238
size_t buf_copy(struct Buffer *dst, const struct Buffer *src)
Copy a Buffer's contents to another Buffer.
Definition: buffer.c:572
void buf_alloc(struct Buffer *buf, size_t new_size)
Make sure a buffer can store at least new_size bytes.
Definition: buffer.c:349
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:93
#define CSR_RESULT(x)
Definition: set.h:52
#define CSR_SUCCESS
Action completed successfully.
Definition: set.h:35
int parse_extract_token(struct Buffer *dest, struct Buffer *tok, TokenFlags flags)
Extract one token from a string.
Definition: extract.c:48
#define TOKEN_BACKTICK_VARS
Expand variables within backticks.
Definition: extract.h:53
#define TOKEN_QUOTE
Don't interpret quotes.
Definition: extract.h:49
#define TOKEN_NOSHELL
Don't expand environment variables.
Definition: extract.h:54
#define TOKEN_CONDENSE
^(char) to control chars (macros)
Definition: extract.h:47
char * mutt_file_read_line(char *line, size_t *size, FILE *fp, int *line_num, ReadLineFlags flags)
Read a line from a file.
Definition: file.c:763
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:152
#define MUTT_RL_NO_FLAGS
No flags are set.
Definition: file.h:39
int filter_wait(pid_t pid)
Wait for the exit of a process and return its status.
Definition: filter.c:218
pid_t filter_create(const char *cmd, FILE **fp_in, FILE **fp_out, FILE **fp_err, char **envlist)
Set up filter program.
Definition: filter.c:207
char ** EnvList
Private copy of the environment variables.
Definition: globals.c:85
#define mutt_debug(LEVEL,...)
Definition: logging2.h:89
@ LL_DEBUG1
Log at debug level 1.
Definition: logging2.h:43
#define FREE(x)
Definition: memory.h:45
char * mutt_strn_dup(const char *begin, size_t len)
Duplicate a sub-string.
Definition: string.c:452
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:251
const char * mutt_str_getenv(const char *name)
Get an environment variable.
Definition: string.c:918
struct Buffer * buf_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:81
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
Definition: pool.c:94
#define SKIPWS(ch)
Definition: string2.h:45
String manipulation buffer.
Definition: buffer.h:34
char * dptr
Current read/write position.
Definition: buffer.h:36
size_t dsize
Length of data.
Definition: buffer.h:37
char * data
Pointer to data.
Definition: buffer.h:35
Container for Accounts, Notifications.
Definition: neomutt.h:41
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:45
int cs_subset_str_string_get(const struct ConfigSubset *sub, const char *name, struct Buffer *result)
Get a config item as a string.
Definition: subset.c:369
+ Here is the call graph for this function: