NeoMutt  2024-03-23-23-gec7045
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
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 "globals.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.
 

Detailed Description

Text parser.

Authors
  • Naveen Nathan
  • Richard Russon
  • Pietro Cerutti

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

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