NeoMutt  2025-12-11-58-g09398d
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
extract.c File Reference

Text parser. More...

#include "config.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 *line, 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 * line,
TokenFlags flags )

Extract one token from a string.

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

Definition at line 48 of file extract.c.

49{
50 if (!dest || !line)
51 return -1;
52
53 char ch;
54 char qc = '\0'; /* quote char */
55 char *pc = NULL;
56
57 buf_reset(dest);
58
59 SKIPWS(line->dptr);
60 while ((ch = *line->dptr))
61 {
62 if (qc == '\0')
63 {
64 if (mutt_isspace(ch) && !(flags & TOKEN_SPACE))
65 break;
66 if ((ch == '#') && !(flags & TOKEN_COMMENT))
67 break;
68 if ((ch == '+') && (flags & TOKEN_PLUS))
69 break;
70 if ((ch == '-') && (flags & TOKEN_MINUS))
71 break;
72 if ((ch == '=') && (flags & TOKEN_EQUAL))
73 break;
74 if ((ch == '?') && (flags & TOKEN_QUESTION))
75 break;
76 if ((ch == ';') && !(flags & TOKEN_SEMICOLON))
77 break;
78 if ((flags & TOKEN_PATTERN) && strchr("~%=!|", ch))
79 break;
80 }
81
82 line->dptr++;
83
84 if (ch == qc)
85 {
86 qc = 0; /* end of quote */
87 }
88 else if (!qc && ((ch == '\'') || (ch == '"')) && !(flags & TOKEN_QUOTE))
89 {
90 qc = ch;
91 }
92 else if ((ch == '\\') && (qc != '\''))
93 {
94 if (line->dptr[0] == '\0')
95 return -1; /* premature end of token */
96 switch (ch = *line->dptr++)
97 {
98 case 'c':
99 case 'C':
100 if (line->dptr[0] == '\0')
101 return -1; /* premature end of token */
102 buf_addch(dest, (mutt_toupper(line->dptr[0]) - '@') & 0x7f);
103 line->dptr++;
104 break;
105 case 'e':
106 buf_addch(dest, '\033'); // Escape
107 break;
108 case 'f':
109 buf_addch(dest, '\f');
110 break;
111 case 'n':
112 buf_addch(dest, '\n');
113 break;
114 case 'r':
115 buf_addch(dest, '\r');
116 break;
117 case 't':
118 buf_addch(dest, '\t');
119 break;
120 default:
121 if (mutt_isdigit(ch) && mutt_isdigit(line->dptr[0]) &&
122 mutt_isdigit(line->dptr[1]))
123 {
124 buf_addch(dest, (ch << 6) + (line->dptr[0] << 3) + line->dptr[1] - 3504);
125 line->dptr += 2;
126 }
127 else
128 {
129 buf_addch(dest, ch);
130 }
131 }
132 }
133 else if ((ch == '^') && (flags & TOKEN_CONDENSE))
134 {
135 if (line->dptr[0] == '\0')
136 return -1; /* premature end of token */
137 ch = *line->dptr++;
138 if (ch == '^')
139 {
140 buf_addch(dest, ch);
141 }
142 else if (ch == '[')
143 {
144 buf_addch(dest, '\033'); // Escape
145 }
146 else if (mutt_isalpha(ch))
147 {
148 buf_addch(dest, mutt_toupper(ch) - '@');
149 }
150 else
151 {
152 buf_addch(dest, '^');
153 buf_addch(dest, ch);
154 }
155 }
156 else if ((ch == '`') && (!qc || (qc == '"')))
157 {
158 FILE *fp = NULL;
159 pid_t pid;
160
161 pc = line->dptr;
162 do
163 {
164 pc = strpbrk(pc, "\\`");
165 if (pc)
166 {
167 /* skip any quoted chars */
168 if (*pc == '\\')
169 {
170 if (*(pc + 1))
171 pc += 2;
172 else
173 pc = NULL;
174 }
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 = buf_pool_get();
183 *pc = '\0';
184 if (flags & TOKEN_BACKTICK_VARS)
185 {
186 /* recursively extract tokens to interpolate variables */
187 parse_extract_token(cmd, line,
190 }
191 else
192 {
193 buf_strcpy(cmd, line->dptr);
194 }
195 *pc = '`';
196 pid = filter_create(buf_string(cmd), NULL, &fp, NULL, NeoMutt->env);
197 if (pid < 0)
198 {
199 mutt_debug(LL_DEBUG1, "unable to fork command: %s\n", buf_string(cmd));
200 buf_pool_release(&cmd);
201 return -1;
202 }
203
204 line->dptr = pc + 1;
205
206 /* read line */
207 char *expn = NULL;
208 size_t expn_len = 0;
209 expn = mutt_file_read_line(expn, &expn_len, fp, NULL, MUTT_RL_NO_FLAGS);
210 mutt_file_fclose(&fp);
211 int rc = filter_wait(pid);
212 if (rc != 0)
213 {
214 mutt_debug(LL_DEBUG1, "backticks exited code %d for command: %s\n", rc,
215 buf_string(cmd));
216 }
217 buf_pool_release(&cmd);
218
219 /* if we got output, make a new string consisting of the shell output
220 * plus whatever else was left on the original line */
221 /* BUT: If this is inside a quoted string, directly add output to
222 * the token */
223 if (expn)
224 {
225 if (qc)
226 {
227 buf_addstr(dest, expn);
228 }
229 else
230 {
231 struct Buffer *copy = buf_pool_get();
232 buf_strcpy(copy, expn);
233 buf_addstr(copy, line->dptr);
234 buf_copy(line, copy);
235 buf_seek(line, 0);
236 buf_pool_release(&copy);
237 }
238 FREE(&expn);
239 }
240 }
241 else if ((ch == '$') && (!qc || (qc == '"')) &&
242 ((line->dptr[0] == '{') || mutt_isalpha(line->dptr[0])))
243 {
244 const char *env = NULL;
245 char *var = NULL;
246
247 if (line->dptr[0] == '{')
248 {
249 pc = strchr(line->dptr, '}');
250 if (pc)
251 {
252 var = mutt_strn_dup(line->dptr + 1, pc - (line->dptr + 1));
253 line->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 = line->dptr; mutt_isalnum(*pc) || (pc[0] == '_'); pc++)
268 ; // do nothing
269
270 var = mutt_strn_dup(line->dptr, pc - line->dptr);
271 line->dptr = pc;
272 }
273 if (var)
274 {
275 struct Buffer *result = buf_pool_get();
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, buf_string(result));
281 }
282 else if (!(flags & TOKEN_NOSHELL) && (env = mutt_str_getenv(var)))
283 {
284 buf_addstr(dest, env);
285 }
286 else
287 {
288 buf_addch(dest, ch);
289 buf_addstr(dest, var);
290 }
291 FREE(&var);
292 buf_pool_release(&result);
293 }
294 }
295 else
296 {
297 buf_addch(dest, ch);
298 }
299 }
300
301 SKIPWS(line->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: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
bool mutt_isspace(int arg)
Wrapper for isspace(3)
Definition ctype.c:95
bool mutt_isalpha(int arg)
Wrapper for isalpha(3)
Definition ctype.c:52
int mutt_toupper(int arg)
Wrapper for toupper(3)
Definition ctype.c:139
bool mutt_isalnum(int arg)
Wrapper for isalnum(3)
Definition ctype.c:39
bool mutt_isdigit(int arg)
Wrapper for isdigit(3)
Definition ctype.c:65
int parse_extract_token(struct Buffer *dest, struct Buffer *line, TokenFlags flags)
Extract one token from a string.
Definition extract.c:48
#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: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:62
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:382
const char * mutt_str_getenv(const char *name)
Get an environment variable.
Definition string.c:726
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:51
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:56
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:354
+ Here is the call graph for this function: