NeoMutt  2023-05-17-16-g61469c
Teaching an old dog new tricks
DOXYGEN
extract.c File Reference

Text parser. More...

#include "config.h"
#include <ctype.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include "mutt/lib.h"
#include "config/lib.h"
#include "core/lib.h"
#include "extract.h"
+ Include dependency graph for extract.c:

Go to the source code of this file.

Functions

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

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.c.

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 47 of file extract.c.

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