NeoMutt  2025-01-09-117-gace867
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 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 49 of file extract.c.

50{
51 if (!dest || !tok)
52 return -1;
53
54 char ch;
55 char qc = '\0'; /* quote char */
56 char *pc = NULL;
57
58 buf_reset(dest);
59
60 SKIPWS(tok->dptr);
61 while ((ch = *tok->dptr))
62 {
63 if (qc == '\0')
64 {
65 if (isspace(ch) && !(flags & TOKEN_SPACE))
66 break;
67 if ((ch == '#') && !(flags & TOKEN_COMMENT))
68 break;
69 if ((ch == '+') && (flags & TOKEN_PLUS))
70 break;
71 if ((ch == '-') && (flags & TOKEN_MINUS))
72 break;
73 if ((ch == '=') && (flags & TOKEN_EQUAL))
74 break;
75 if ((ch == '?') && (flags & TOKEN_QUESTION))
76 break;
77 if ((ch == ';') && !(flags & TOKEN_SEMICOLON))
78 break;
79 if ((flags & TOKEN_PATTERN) && strchr("~%=!|", ch))
80 break;
81 }
82
83 tok->dptr++;
84
85 if (ch == qc)
86 {
87 qc = 0; /* end of quote */
88 }
89 else if (!qc && ((ch == '\'') || (ch == '"')) && !(flags & TOKEN_QUOTE))
90 {
91 qc = ch;
92 }
93 else if ((ch == '\\') && (qc != '\''))
94 {
95 if (tok->dptr[0] == '\0')
96 return -1; /* premature end of token */
97 switch (ch = *tok->dptr++)
98 {
99 case 'c':
100 case 'C':
101 if (tok->dptr[0] == '\0')
102 return -1; /* premature end of token */
103 buf_addch(dest, (toupper((unsigned char) tok->dptr[0]) - '@') & 0x7f);
104 tok->dptr++;
105 break;
106 case 'e':
107 buf_addch(dest, '\033'); // Escape
108 break;
109 case 'f':
110 buf_addch(dest, '\f');
111 break;
112 case 'n':
113 buf_addch(dest, '\n');
114 break;
115 case 'r':
116 buf_addch(dest, '\r');
117 break;
118 case 't':
119 buf_addch(dest, '\t');
120 break;
121 default:
122 if (isdigit((unsigned char) ch) && isdigit((unsigned char) tok->dptr[0]) &&
123 isdigit((unsigned char) tok->dptr[1]))
124 {
125 buf_addch(dest, (ch << 6) + (tok->dptr[0] << 3) + tok->dptr[1] - 3504);
126 tok->dptr += 2;
127 }
128 else
129 {
130 buf_addch(dest, ch);
131 }
132 }
133 }
134 else if ((ch == '^') && (flags & TOKEN_CONDENSE))
135 {
136 if (tok->dptr[0] == '\0')
137 return -1; /* premature end of token */
138 ch = *tok->dptr++;
139 if (ch == '^')
140 {
141 buf_addch(dest, ch);
142 }
143 else if (ch == '[')
144 {
145 buf_addch(dest, '\033'); // Escape
146 }
147 else if (isalpha((unsigned char) ch))
148 {
149 buf_addch(dest, toupper((unsigned char) ch) - '@');
150 }
151 else
152 {
153 buf_addch(dest, '^');
154 buf_addch(dest, ch);
155 }
156 }
157 else if ((ch == '`') && (!qc || (qc == '"')))
158 {
159 FILE *fp = NULL;
160 pid_t pid;
161
162 pc = tok->dptr;
163 do
164 {
165 pc = strpbrk(pc, "\\`");
166 if (pc)
167 {
168 /* skip any quoted chars */
169 if (*pc == '\\')
170 {
171 if (*(pc + 1))
172 pc += 2;
173 else
174 pc = NULL;
175 }
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 = buf_pool_get();
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 buf_strcpy(cmd, tok->dptr);
195 }
196 *pc = '`';
197 pid = filter_create(buf_string(cmd), NULL, &fp, NULL, NeoMutt->env);
198 if (pid < 0)
199 {
200 mutt_debug(LL_DEBUG1, "unable to fork command: %s\n", buf_string(cmd));
201 buf_pool_release(&cmd);
202 return -1;
203 }
204
205 tok->dptr = pc + 1;
206
207 /* read line */
208 char *expn = NULL;
209 size_t expn_len = 0;
210 expn = mutt_file_read_line(expn, &expn_len, fp, NULL, MUTT_RL_NO_FLAGS);
211 mutt_file_fclose(&fp);
212 int rc = filter_wait(pid);
213 if (rc != 0)
214 {
215 mutt_debug(LL_DEBUG1, "backticks exited code %d for command: %s\n", rc,
216 buf_string(cmd));
217 }
218 buf_pool_release(&cmd);
219
220 /* if we got output, make a new string consisting of the shell output
221 * plus whatever else was left on the original line */
222 /* BUT: If this is inside a quoted string, directly add output to
223 * the token */
224 if (expn)
225 {
226 if (qc)
227 {
228 buf_addstr(dest, expn);
229 }
230 else
231 {
232 struct Buffer *copy = buf_pool_get();
233 buf_strcpy(copy, expn);
234 buf_addstr(copy, tok->dptr);
235 buf_copy(tok, copy);
236 buf_seek(tok, 0);
237 buf_pool_release(&copy);
238 }
239 FREE(&expn);
240 }
241 }
242 else if ((ch == '$') && (!qc || (qc == '"')) &&
243 ((tok->dptr[0] == '{') || isalpha((unsigned char) tok->dptr[0])))
244 {
245 const char *env = NULL;
246 char *var = NULL;
247
248 if (tok->dptr[0] == '{')
249 {
250 pc = strchr(tok->dptr, '}');
251 if (pc)
252 {
253 var = mutt_strn_dup(tok->dptr + 1, pc - (tok->dptr + 1));
254 tok->dptr = pc + 1;
255
256 if ((flags & TOKEN_NOSHELL))
257 {
258 buf_addch(dest, ch);
259 buf_addch(dest, '{');
260 buf_addstr(dest, var);
261 buf_addch(dest, '}');
262 FREE(&var);
263 }
264 }
265 }
266 else
267 {
268 for (pc = tok->dptr; isalnum((unsigned char) *pc) || (pc[0] == '_'); pc++)
269 ; // do nothing
270
271 var = mutt_strn_dup(tok->dptr, pc - tok->dptr);
272 tok->dptr = pc;
273 }
274 if (var)
275 {
276 struct Buffer *result = buf_pool_get();
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, buf_string(result));
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 buf_pool_release(&result);
294 }
295 }
296 else
297 {
298 buf_addch(dest, ch);
299 }
300 }
301
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:622
void buf_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition: buffer.c:76
size_t buf_addch(struct Buffer *buf, char c)
Add a single character to a Buffer.
Definition: buffer.c:241
size_t buf_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition: buffer.c:226
size_t buf_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:395
size_t buf_copy(struct Buffer *dst, const struct Buffer *src)
Copy a Buffer's contents to another Buffer.
Definition: buffer.c:601
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:96
#define CSR_RESULT(x)
Definition: set.h:50
#define CSR_SUCCESS
Action completed successfully.
Definition: set.h:33
int parse_extract_token(struct Buffer *dest, struct Buffer *tok, TokenFlags flags)
Extract one token from a string.
Definition: extract.c:49
#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:685
#define mutt_file_fclose(FP)
Definition: file.h:139
#define MUTT_RL_NO_FLAGS
No flags are set.
Definition: file.h:40
#define mutt_debug(LEVEL,...)
Definition: logging2.h:90
@ LL_DEBUG1
Log at debug level 1.
Definition: logging2.h:44
#define FREE(x)
Definition: memory.h:55
int filter_wait(pid_t pid)
Wait for the exit of a process and return its status.
Definition: filter.c:220
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:209
char * mutt_strn_dup(const char *begin, size_t len)
Duplicate a sub-string.
Definition: string.c:381
const char * mutt_str_getenv(const char *name)
Get an environment variable.
Definition: string.c:727
struct Buffer * buf_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:82
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
Definition: pool.c:96
#define SKIPWS(ch)
Definition: string2.h:45
String manipulation buffer.
Definition: buffer.h:36
char * dptr
Current read/write position.
Definition: buffer.h:38
Container for Accounts, Notifications.
Definition: neomutt.h:43
char ** env
Private copy of the environment variables.
Definition: neomutt.h:55
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:47
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:350
+ Here is the call graph for this function: