]>
Commit | Line | Data |
---|---|---|
3185942a JA |
1 | /* shquote - functions to quote and dequote strings */ |
2 | ||
8868edaf | 3 | /* Copyright (C) 1999-2020 Free Software Foundation, Inc. |
bb70624e JA |
4 | |
5 | This file is part of GNU Bash, the Bourne Again SHell. | |
6 | ||
3185942a JA |
7 | Bash is free software: you can redistribute it and/or modify |
8 | it under the terms of the GNU General Public License as published by | |
9 | the Free Software Foundation, either version 3 of the License, or | |
10 | (at your option) any later version. | |
11 | ||
12 | Bash is distributed in the hope that it will be useful, | |
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | GNU General Public License for more details. | |
16 | ||
17 | You should have received a copy of the GNU General Public License | |
18 | along with Bash. If not, see <http://www.gnu.org/licenses/>. | |
19 | */ | |
bb70624e JA |
20 | |
21 | #include <config.h> | |
22 | ||
23 | #if defined (HAVE_UNISTD_H) | |
24 | # ifdef _MINIX | |
25 | # include <sys/types.h> | |
26 | # endif | |
27 | # include <unistd.h> | |
28 | #endif | |
29 | ||
30 | #include <stdio.h> | |
a0c0a00f | 31 | #include <stdc.h> |
bb70624e | 32 | |
28ef6c31 | 33 | #include "syntax.h" |
f73dda09 | 34 | #include <xmalloc.h> |
bb70624e | 35 | |
a0c0a00f CR |
36 | #include "shmbchar.h" |
37 | #include "shmbutil.h" | |
38 | ||
8868edaf CR |
39 | extern char *ansic_quote PARAMS((char *, int, int *)); |
40 | extern int ansic_shouldquote PARAMS((const char *)); | |
a0c0a00f | 41 | |
ac50fbac CR |
42 | /* Default set of characters that should be backslash-quoted in strings */ |
43 | static const char bstab[256] = | |
44 | { | |
45 | 0, 0, 0, 0, 0, 0, 0, 0, | |
46 | 0, 1, 1, 0, 0, 0, 0, 0, /* TAB, NL */ | |
47 | 0, 0, 0, 0, 0, 0, 0, 0, | |
48 | 0, 0, 0, 0, 0, 0, 0, 0, | |
49 | ||
50 | 1, 1, 1, 0, 1, 0, 1, 1, /* SPACE, !, DQUOTE, DOL, AMP, SQUOTE */ | |
51 | 1, 1, 1, 0, 1, 0, 0, 0, /* LPAR, RPAR, STAR, COMMA */ | |
52 | 0, 0, 0, 0, 0, 0, 0, 0, | |
53 | 0, 0, 0, 1, 1, 0, 1, 1, /* SEMI, LESSTHAN, GREATERTHAN, QUEST */ | |
54 | ||
55 | 0, 0, 0, 0, 0, 0, 0, 0, | |
56 | 0, 0, 0, 0, 0, 0, 0, 0, | |
57 | 0, 0, 0, 0, 0, 0, 0, 0, | |
58 | 0, 0, 0, 1, 1, 1, 1, 0, /* LBRACK, BS, RBRACK, CARAT */ | |
59 | ||
60 | 1, 0, 0, 0, 0, 0, 0, 0, /* BACKQ */ | |
61 | 0, 0, 0, 0, 0, 0, 0, 0, | |
62 | 0, 0, 0, 0, 0, 0, 0, 0, | |
63 | 0, 0, 0, 1, 1, 1, 0, 0, /* LBRACE, BAR, RBRACE */ | |
64 | ||
65 | 0, 0, 0, 0, 0, 0, 0, 0, | |
66 | 0, 0, 0, 0, 0, 0, 0, 0, | |
67 | 0, 0, 0, 0, 0, 0, 0, 0, | |
68 | 0, 0, 0, 0, 0, 0, 0, 0, | |
69 | ||
70 | 0, 0, 0, 0, 0, 0, 0, 0, | |
71 | 0, 0, 0, 0, 0, 0, 0, 0, | |
72 | 0, 0, 0, 0, 0, 0, 0, 0, | |
73 | 0, 0, 0, 0, 0, 0, 0, 0, | |
74 | ||
75 | 0, 0, 0, 0, 0, 0, 0, 0, | |
76 | 0, 0, 0, 0, 0, 0, 0, 0, | |
77 | 0, 0, 0, 0, 0, 0, 0, 0, | |
78 | 0, 0, 0, 0, 0, 0, 0, 0, | |
79 | ||
80 | 0, 0, 0, 0, 0, 0, 0, 0, | |
81 | 0, 0, 0, 0, 0, 0, 0, 0, | |
82 | 0, 0, 0, 0, 0, 0, 0, 0, | |
83 | 0, 0, 0, 0, 0, 0, 0, 0, | |
84 | }; | |
85 | ||
bb70624e JA |
86 | /* **************************************************************** */ |
87 | /* */ | |
88 | /* Functions for quoting strings to be re-read as input */ | |
89 | /* */ | |
90 | /* **************************************************************** */ | |
91 | ||
92 | /* Return a new string which is the single-quoted version of STRING. | |
93 | Used by alias and trap, among others. */ | |
94 | char * | |
28ef6c31 | 95 | sh_single_quote (string) |
495aee44 | 96 | const char *string; |
bb70624e JA |
97 | { |
98 | register int c; | |
495aee44 CR |
99 | char *result, *r; |
100 | const char *s; | |
bb70624e | 101 | |
f73dda09 | 102 | result = (char *)xmalloc (3 + (4 * strlen (string))); |
bb70624e | 103 | r = result; |
ac50fbac CR |
104 | |
105 | if (string[0] == '\'' && string[1] == 0) | |
106 | { | |
107 | *r++ = '\\'; | |
108 | *r++ = '\''; | |
109 | *r++ = 0; | |
110 | return result; | |
111 | } | |
112 | ||
bb70624e JA |
113 | *r++ = '\''; |
114 | ||
115 | for (s = string; s && (c = *s); s++) | |
116 | { | |
117 | *r++ = c; | |
118 | ||
119 | if (c == '\'') | |
120 | { | |
121 | *r++ = '\\'; /* insert escaped single quote */ | |
122 | *r++ = '\''; | |
123 | *r++ = '\''; /* start new quoted string */ | |
124 | } | |
125 | } | |
126 | ||
127 | *r++ = '\''; | |
128 | *r = '\0'; | |
129 | ||
130 | return (result); | |
131 | } | |
132 | ||
133 | /* Quote STRING using double quotes. Return a new string. */ | |
134 | char * | |
28ef6c31 | 135 | sh_double_quote (string) |
495aee44 | 136 | const char *string; |
bb70624e | 137 | { |
f73dda09 | 138 | register unsigned char c; |
8868edaf | 139 | int mb_cur_max; |
495aee44 | 140 | char *result, *r; |
8868edaf CR |
141 | size_t slen; |
142 | const char *s, *send; | |
143 | DECLARE_MBSTATE; | |
144 | ||
145 | slen = strlen (string); | |
146 | send = string + slen; | |
147 | mb_cur_max = MB_CUR_MAX; | |
bb70624e | 148 | |
f73dda09 | 149 | result = (char *)xmalloc (3 + (2 * strlen (string))); |
bb70624e JA |
150 | r = result; |
151 | *r++ = '"'; | |
152 | ||
153 | for (s = string; s && (c = *s); s++) | |
154 | { | |
95732b49 JA |
155 | /* Backslash-newline disappears within double quotes, so don't add one. */ |
156 | if ((sh_syntaxtab[c] & CBSDQUOTE) && c != '\n') | |
28ef6c31 | 157 | *r++ = '\\'; |
8868edaf CR |
158 | |
159 | #if defined (HANDLE_MULTIBYTE) | |
160 | if ((locale_utf8locale && (c & 0x80)) || | |
161 | (locale_utf8locale == 0 && mb_cur_max > 1 && is_basic (c) == 0)) | |
162 | { | |
163 | COPY_CHAR_P (r, s, send); | |
164 | s--; /* compensate for auto-increment in loop above */ | |
165 | continue; | |
166 | } | |
a0c0a00f | 167 | #endif |
28ef6c31 | 168 | |
8868edaf CR |
169 | /* Assume that the string will not be further expanded, so no need to |
170 | add CTLESC to protect CTLESC or CTLNUL. */ | |
28ef6c31 | 171 | *r++ = c; |
bb70624e JA |
172 | } |
173 | ||
174 | *r++ = '"'; | |
175 | *r = '\0'; | |
176 | ||
177 | return (result); | |
178 | } | |
179 | ||
95732b49 JA |
180 | /* Turn S into a simple double-quoted string. If FLAGS is non-zero, quote |
181 | double quote characters in S with backslashes. */ | |
182 | char * | |
183 | sh_mkdoublequoted (s, slen, flags) | |
184 | const char *s; | |
185 | int slen, flags; | |
186 | { | |
187 | char *r, *ret; | |
8868edaf CR |
188 | const char *send; |
189 | int rlen, mb_cur_max; | |
190 | DECLARE_MBSTATE; | |
95732b49 | 191 | |
8868edaf CR |
192 | send = s + slen; |
193 | mb_cur_max = flags ? MB_CUR_MAX : 1; | |
95732b49 JA |
194 | rlen = (flags == 0) ? slen + 3 : (2 * slen) + 1; |
195 | ret = r = (char *)xmalloc (rlen); | |
8868edaf | 196 | |
95732b49 JA |
197 | *r++ = '"'; |
198 | while (*s) | |
199 | { | |
200 | if (flags && *s == '"') | |
201 | *r++ = '\\'; | |
8868edaf CR |
202 | |
203 | #if defined (HANDLE_MULTIBYTE) | |
204 | if (flags && ((locale_utf8locale && (*s & 0x80)) || | |
205 | (locale_utf8locale == 0 && mb_cur_max > 1 && is_basic (*s) == 0))) | |
206 | { | |
207 | COPY_CHAR_P (r, s, send); | |
208 | continue; | |
209 | } | |
210 | #endif | |
95732b49 JA |
211 | *r++ = *s++; |
212 | } | |
213 | *r++ = '"'; | |
214 | *r = '\0'; | |
215 | ||
216 | return ret; | |
217 | } | |
218 | ||
bb70624e | 219 | /* Remove backslashes that are quoting characters that are special between |
b80f6443 JA |
220 | double quotes. Return a new string. XXX - should this handle CTLESC |
221 | and CTLNUL? */ | |
bb70624e | 222 | char * |
28ef6c31 | 223 | sh_un_double_quote (string) |
bb70624e JA |
224 | char *string; |
225 | { | |
226 | register int c, pass_next; | |
227 | char *result, *r, *s; | |
228 | ||
f73dda09 | 229 | r = result = (char *)xmalloc (strlen (string) + 1); |
bb70624e JA |
230 | |
231 | for (pass_next = 0, s = string; s && (c = *s); s++) | |
232 | { | |
233 | if (pass_next) | |
234 | { | |
235 | *r++ = c; | |
236 | pass_next = 0; | |
237 | continue; | |
238 | } | |
f73dda09 | 239 | if (c == '\\' && (sh_syntaxtab[(unsigned char) s[1]] & CBSDQUOTE)) |
bb70624e JA |
240 | { |
241 | pass_next = 1; | |
242 | continue; | |
243 | } | |
244 | *r++ = c; | |
245 | } | |
246 | ||
247 | *r = '\0'; | |
248 | return result; | |
249 | } | |
250 | ||
251 | /* Quote special characters in STRING using backslashes. Return a new | |
95732b49 JA |
252 | string. NOTE: if the string is to be further expanded, we need a |
253 | way to protect the CTLESC and CTLNUL characters. As I write this, | |
254 | the current callers will never cause the string to be expanded without | |
255 | going through the shell parser, which will protect the internal | |
ac50fbac CR |
256 | quoting characters. TABLE, if set, points to a map of the ascii code |
257 | set with char needing to be backslash-quoted if table[char]==1. FLAGS, | |
d233b485 CR |
258 | if 1, causes tildes to be quoted as well. If FLAGS&2, backslash-quote |
259 | other shell blank characters. */ | |
ac50fbac | 260 | |
bb70624e | 261 | char * |
ac50fbac | 262 | sh_backslash_quote (string, table, flags) |
bb70624e | 263 | char *string; |
ac50fbac CR |
264 | char *table; |
265 | int flags; | |
bb70624e | 266 | { |
a0c0a00f CR |
267 | int c, mb_cur_max; |
268 | size_t slen; | |
269 | char *result, *r, *s, *backslash_table, *send; | |
270 | DECLARE_MBSTATE; | |
bb70624e | 271 | |
a0c0a00f CR |
272 | slen = strlen (string); |
273 | send = string + slen; | |
274 | result = (char *)xmalloc (2 * slen + 1); | |
bb70624e | 275 | |
ac50fbac | 276 | backslash_table = table ? table : (char *)bstab; |
a0c0a00f CR |
277 | mb_cur_max = MB_CUR_MAX; |
278 | ||
bb70624e JA |
279 | for (r = result, s = string; s && (c = *s); s++) |
280 | { | |
a0c0a00f CR |
281 | #if defined (HANDLE_MULTIBYTE) |
282 | /* XXX - isascii, even if is_basic(c) == 0 - works in most cases. */ | |
283 | if (c >= 0 && c <= 127 && backslash_table[(unsigned char)c] == 1) | |
284 | { | |
285 | *r++ = '\\'; | |
286 | *r++ = c; | |
287 | continue; | |
288 | } | |
8868edaf CR |
289 | if ((locale_utf8locale && (c & 0x80)) || |
290 | (locale_utf8locale == 0 && mb_cur_max > 1 && is_basic (c) == 0)) | |
a0c0a00f CR |
291 | { |
292 | COPY_CHAR_P (r, s, send); | |
293 | s--; /* compensate for auto-increment in loop above */ | |
294 | continue; | |
295 | } | |
296 | #endif | |
297 | if (backslash_table[(unsigned char)c] == 1) | |
ac50fbac CR |
298 | *r++ = '\\'; |
299 | else if (c == '#' && s == string) /* comment char */ | |
300 | *r++ = '\\'; | |
301 | else if ((flags&1) && c == '~' && (s == string || s[-1] == ':' || s[-1] == '=')) | |
302 | /* Tildes are special at the start of a word or after a `:' or `=' | |
303 | (technically unquoted, but it doesn't make a difference in practice) */ | |
304 | *r++ = '\\'; | |
d233b485 CR |
305 | else if ((flags&2) && shellblank((unsigned char)c)) |
306 | *r++ = '\\'; | |
ac50fbac | 307 | *r++ = c; |
bb70624e JA |
308 | } |
309 | ||
310 | *r = '\0'; | |
311 | return (result); | |
312 | } | |
313 | ||
74091dd4 | 314 | #if defined (PROMPT_STRING_DECODE) || defined (TRANSLATABLE_STRINGS) |
28ef6c31 | 315 | /* Quote characters that get special treatment when in double quotes in STRING |
74091dd4 | 316 | using backslashes. FLAGS is reserved for future use. Return a new string. */ |
28ef6c31 | 317 | char * |
74091dd4 | 318 | sh_backslash_quote_for_double_quotes (string, flags) |
28ef6c31 | 319 | char *string; |
74091dd4 | 320 | int flags; |
28ef6c31 | 321 | { |
f73dda09 | 322 | unsigned char c; |
8868edaf CR |
323 | char *result, *r, *s, *send; |
324 | size_t slen; | |
325 | int mb_cur_max; | |
326 | DECLARE_MBSTATE; | |
327 | ||
328 | slen = strlen (string); | |
329 | send = string + slen; | |
330 | mb_cur_max = MB_CUR_MAX; | |
331 | result = (char *)xmalloc (2 * slen + 1); | |
28ef6c31 JA |
332 | |
333 | for (r = result, s = string; s && (c = *s); s++) | |
334 | { | |
8868edaf CR |
335 | /* Backslash-newline disappears within double quotes, so don't add one. */ |
336 | if ((sh_syntaxtab[c] & CBSDQUOTE) && c != '\n') | |
28ef6c31 | 337 | *r++ = '\\'; |
8868edaf | 338 | /* I should probably use the CSPECL flag for these in sh_syntaxtab[] */ |
b80f6443 JA |
339 | else if (c == CTLESC || c == CTLNUL) |
340 | *r++ = CTLESC; /* could be '\\'? */ | |
28ef6c31 | 341 | |
8868edaf CR |
342 | #if defined (HANDLE_MULTIBYTE) |
343 | if ((locale_utf8locale && (c & 0x80)) || | |
344 | (locale_utf8locale == 0 && mb_cur_max > 1 && is_basic (c) == 0)) | |
345 | { | |
346 | COPY_CHAR_P (r, s, send); | |
347 | s--; /* compensate for auto-increment in loop above */ | |
348 | continue; | |
349 | } | |
350 | #endif | |
351 | ||
28ef6c31 JA |
352 | *r++ = c; |
353 | } | |
354 | ||
355 | *r = '\0'; | |
356 | return (result); | |
357 | } | |
358 | #endif /* PROMPT_STRING_DECODE */ | |
359 | ||
a0c0a00f CR |
360 | char * |
361 | sh_quote_reusable (s, flags) | |
362 | char *s; | |
363 | int flags; | |
364 | { | |
365 | char *ret; | |
366 | ||
367 | if (s == 0) | |
368 | return s; | |
369 | else if (*s == 0) | |
370 | { | |
371 | ret = (char *)xmalloc (3); | |
372 | ret[0] = ret[1] = '\''; | |
373 | ret[2] = '\0'; | |
374 | } | |
375 | else if (ansic_shouldquote (s)) | |
376 | ret = ansic_quote (s, 0, (int *)0); | |
377 | else if (flags) | |
378 | ret = sh_backslash_quote (s, 0, 1); | |
379 | else | |
380 | ret = sh_single_quote (s); | |
381 | ||
382 | return ret; | |
383 | } | |
384 | ||
bb70624e | 385 | int |
28ef6c31 | 386 | sh_contains_shell_metas (string) |
a0c0a00f | 387 | const char *string; |
bb70624e | 388 | { |
a0c0a00f | 389 | const char *s; |
bb70624e JA |
390 | |
391 | for (s = string; s && *s; s++) | |
392 | { | |
393 | switch (*s) | |
394 | { | |
395 | case ' ': case '\t': case '\n': /* IFS white space */ | |
396 | case '\'': case '"': case '\\': /* quoting chars */ | |
397 | case '|': case '&': case ';': /* shell metacharacters */ | |
398 | case '(': case ')': case '<': case '>': | |
399 | case '!': case '{': case '}': /* reserved words */ | |
400 | case '*': case '[': case '?': case ']': /* globbing chars */ | |
401 | case '^': | |
402 | case '$': case '`': /* expansion chars */ | |
403 | return (1); | |
404 | case '~': /* tilde expansion */ | |
405 | if (s == string || s[-1] == '=' || s[-1] == ':') | |
406 | return (1); | |
f73dda09 | 407 | break; |
bb70624e JA |
408 | case '#': |
409 | if (s == string) /* comment char */ | |
410 | return (1); | |
411 | /* FALLTHROUGH */ | |
412 | default: | |
413 | break; | |
414 | } | |
415 | } | |
416 | ||
417 | return (0); | |
418 | } | |
2b76266c CR |
419 | |
420 | int | |
421 | sh_contains_quotes (string) | |
a0c0a00f | 422 | const char *string; |
2b76266c | 423 | { |
a0c0a00f | 424 | const char *s; |
2b76266c CR |
425 | |
426 | for (s = string; s && *s; s++) | |
427 | { | |
428 | if (*s == '\'' || *s == '"' || *s == '\\') | |
429 | return 1; | |
430 | } | |
431 | return 0; | |
432 | } |