]>
Commit | Line | Data |
---|---|---|
2e4498b3 CR |
1 | /* shquote - functions to quote and dequote strings */ |
2 | ||
81e3a4fb | 3 | /* Copyright (C) 1999-2020,2022 Free Software Foundation, Inc. |
bb70624e JA |
4 | |
5 | This file is part of GNU Bash, the Bourne Again SHell. | |
6 | ||
2e4498b3 CR |
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> | |
09f70f2f | 31 | #include <stdc.h> |
bb70624e | 32 | |
28ef6c31 | 33 | #include "syntax.h" |
f73dda09 | 34 | #include <xmalloc.h> |
bb70624e | 35 | |
c4c90ef8 CR |
36 | #include "shmbchar.h" |
37 | #include "shmbutil.h" | |
38 | ||
81e3a4fb CR |
39 | extern char *ansic_quote (char *, int, int *); |
40 | extern int ansic_shouldquote (const char *); | |
09f70f2f | 41 | |
ddef12ff 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 * | |
81e3a4fb | 95 | sh_single_quote (const char *string) |
bb70624e | 96 | { |
2e725f73 | 97 | int c; |
89c77bc7 CR |
98 | char *result, *r; |
99 | const char *s; | |
bb70624e | 100 | |
f73dda09 | 101 | result = (char *)xmalloc (3 + (4 * strlen (string))); |
bb70624e | 102 | r = result; |
1e8fce0f CR |
103 | |
104 | if (string[0] == '\'' && string[1] == 0) | |
105 | { | |
106 | *r++ = '\\'; | |
107 | *r++ = '\''; | |
108 | *r++ = 0; | |
109 | return result; | |
110 | } | |
111 | ||
bb70624e JA |
112 | *r++ = '\''; |
113 | ||
114 | for (s = string; s && (c = *s); s++) | |
115 | { | |
116 | *r++ = c; | |
117 | ||
118 | if (c == '\'') | |
119 | { | |
120 | *r++ = '\\'; /* insert escaped single quote */ | |
121 | *r++ = '\''; | |
122 | *r++ = '\''; /* start new quoted string */ | |
123 | } | |
124 | } | |
125 | ||
126 | *r++ = '\''; | |
127 | *r = '\0'; | |
128 | ||
129 | return (result); | |
130 | } | |
131 | ||
132 | /* Quote STRING using double quotes. Return a new string. */ | |
133 | char * | |
81e3a4fb | 134 | sh_double_quote (const char *string) |
bb70624e | 135 | { |
2e725f73 | 136 | unsigned char c; |
203f479c | 137 | int mb_cur_max; |
89c77bc7 | 138 | char *result, *r; |
203f479c CR |
139 | size_t slen; |
140 | const char *s, *send; | |
141 | DECLARE_MBSTATE; | |
142 | ||
143 | slen = strlen (string); | |
144 | send = string + slen; | |
145 | mb_cur_max = MB_CUR_MAX; | |
bb70624e | 146 | |
f73dda09 | 147 | result = (char *)xmalloc (3 + (2 * strlen (string))); |
bb70624e JA |
148 | r = result; |
149 | *r++ = '"'; | |
150 | ||
151 | for (s = string; s && (c = *s); s++) | |
152 | { | |
da719982 CR |
153 | /* Backslash-newline disappears within double quotes, so don't add one. */ |
154 | if ((sh_syntaxtab[c] & CBSDQUOTE) && c != '\n') | |
28ef6c31 | 155 | *r++ = '\\'; |
203f479c CR |
156 | |
157 | #if defined (HANDLE_MULTIBYTE) | |
158 | if ((locale_utf8locale && (c & 0x80)) || | |
159 | (locale_utf8locale == 0 && mb_cur_max > 1 && is_basic (c) == 0)) | |
160 | { | |
161 | COPY_CHAR_P (r, s, send); | |
162 | s--; /* compensate for auto-increment in loop above */ | |
163 | continue; | |
164 | } | |
7afeb718 | 165 | #endif |
28ef6c31 | 166 | |
203f479c CR |
167 | /* Assume that the string will not be further expanded, so no need to |
168 | add CTLESC to protect CTLESC or CTLNUL. */ | |
28ef6c31 | 169 | *r++ = c; |
bb70624e JA |
170 | } |
171 | ||
172 | *r++ = '"'; | |
173 | *r = '\0'; | |
174 | ||
175 | return (result); | |
176 | } | |
177 | ||
c3271763 CR |
178 | /* Turn S into a simple double-quoted string. If FLAGS is non-zero, quote |
179 | double quote characters in S with backslashes. */ | |
180 | char * | |
2e725f73 | 181 | sh_mkdoublequoted (const char *s, size_t slen, int flags) |
c3271763 CR |
182 | { |
183 | char *r, *ret; | |
203f479c | 184 | const char *send; |
2e725f73 CR |
185 | int mb_cur_max; |
186 | size_t rlen; | |
203f479c | 187 | DECLARE_MBSTATE; |
c3271763 | 188 | |
203f479c CR |
189 | send = s + slen; |
190 | mb_cur_max = flags ? MB_CUR_MAX : 1; | |
c3271763 CR |
191 | rlen = (flags == 0) ? slen + 3 : (2 * slen) + 1; |
192 | ret = r = (char *)xmalloc (rlen); | |
203f479c | 193 | |
c3271763 CR |
194 | *r++ = '"'; |
195 | while (*s) | |
196 | { | |
197 | if (flags && *s == '"') | |
198 | *r++ = '\\'; | |
203f479c CR |
199 | |
200 | #if defined (HANDLE_MULTIBYTE) | |
201 | if (flags && ((locale_utf8locale && (*s & 0x80)) || | |
202 | (locale_utf8locale == 0 && mb_cur_max > 1 && is_basic (*s) == 0))) | |
203 | { | |
204 | COPY_CHAR_P (r, s, send); | |
205 | continue; | |
206 | } | |
207 | #endif | |
c3271763 CR |
208 | *r++ = *s++; |
209 | } | |
210 | *r++ = '"'; | |
211 | *r = '\0'; | |
212 | ||
213 | return ret; | |
214 | } | |
215 | ||
bb70624e | 216 | /* Remove backslashes that are quoting characters that are special between |
d3a24ed2 CR |
217 | double quotes. Return a new string. XXX - should this handle CTLESC |
218 | and CTLNUL? */ | |
bb70624e | 219 | char * |
81e3a4fb | 220 | sh_un_double_quote (char *string) |
bb70624e | 221 | { |
2e725f73 | 222 | int c, pass_next; |
bb70624e JA |
223 | char *result, *r, *s; |
224 | ||
f73dda09 | 225 | r = result = (char *)xmalloc (strlen (string) + 1); |
bb70624e JA |
226 | |
227 | for (pass_next = 0, s = string; s && (c = *s); s++) | |
228 | { | |
229 | if (pass_next) | |
230 | { | |
231 | *r++ = c; | |
232 | pass_next = 0; | |
233 | continue; | |
234 | } | |
f73dda09 | 235 | if (c == '\\' && (sh_syntaxtab[(unsigned char) s[1]] & CBSDQUOTE)) |
bb70624e JA |
236 | { |
237 | pass_next = 1; | |
238 | continue; | |
239 | } | |
240 | *r++ = c; | |
241 | } | |
242 | ||
243 | *r = '\0'; | |
244 | return result; | |
245 | } | |
246 | ||
247 | /* Quote special characters in STRING using backslashes. Return a new | |
633e5c6d CR |
248 | string. NOTE: if the string is to be further expanded, we need a |
249 | way to protect the CTLESC and CTLNUL characters. As I write this, | |
250 | the current callers will never cause the string to be expanded without | |
251 | going through the shell parser, which will protect the internal | |
8360b906 CR |
252 | quoting characters. TABLE, if set, points to a map of the ascii code |
253 | set with char needing to be backslash-quoted if table[char]==1. FLAGS, | |
a57ed9e9 CR |
254 | if 1, causes tildes to be quoted as well. If FLAGS&2, backslash-quote |
255 | other shell blank characters. */ | |
8360b906 | 256 | |
bb70624e | 257 | char * |
81e3a4fb | 258 | sh_backslash_quote (char *string, char *table, int flags) |
bb70624e | 259 | { |
3bf257a5 | 260 | int c, mb_cur_max; |
c4c90ef8 CR |
261 | size_t slen; |
262 | char *result, *r, *s, *backslash_table, *send; | |
263 | DECLARE_MBSTATE; | |
bb70624e | 264 | |
c4c90ef8 CR |
265 | slen = strlen (string); |
266 | send = string + slen; | |
267 | result = (char *)xmalloc (2 * slen + 1); | |
bb70624e | 268 | |
f14388d3 | 269 | backslash_table = table ? table : (char *)bstab; |
3bf257a5 CR |
270 | mb_cur_max = MB_CUR_MAX; |
271 | ||
bb70624e JA |
272 | for (r = result, s = string; s && (c = *s); s++) |
273 | { | |
c4c90ef8 | 274 | #if defined (HANDLE_MULTIBYTE) |
74b8cbb4 CR |
275 | /* XXX - isascii, even if is_basic(c) == 0 - works in most cases. */ |
276 | if (c >= 0 && c <= 127 && backslash_table[(unsigned char)c] == 1) | |
277 | { | |
278 | *r++ = '\\'; | |
279 | *r++ = c; | |
280 | continue; | |
281 | } | |
203f479c CR |
282 | if ((locale_utf8locale && (c & 0x80)) || |
283 | (locale_utf8locale == 0 && mb_cur_max > 1 && is_basic (c) == 0)) | |
c4c90ef8 CR |
284 | { |
285 | COPY_CHAR_P (r, s, send); | |
286 | s--; /* compensate for auto-increment in loop above */ | |
287 | continue; | |
288 | } | |
289 | #endif | |
2171061f | 290 | if (backslash_table[(unsigned char)c] == 1) |
ddef12ff CR |
291 | *r++ = '\\'; |
292 | else if (c == '#' && s == string) /* comment char */ | |
293 | *r++ = '\\'; | |
8360b906 | 294 | else if ((flags&1) && c == '~' && (s == string || s[-1] == ':' || s[-1] == '=')) |
863d31ae CR |
295 | /* Tildes are special at the start of a word or after a `:' or `=' |
296 | (technically unquoted, but it doesn't make a difference in practice) */ | |
297 | *r++ = '\\'; | |
a57ed9e9 CR |
298 | else if ((flags&2) && shellblank((unsigned char)c)) |
299 | *r++ = '\\'; | |
ddef12ff | 300 | *r++ = c; |
bb70624e JA |
301 | } |
302 | ||
303 | *r = '\0'; | |
304 | return (result); | |
305 | } | |
306 | ||
006856ed | 307 | #if defined (PROMPT_STRING_DECODE) || defined (TRANSLATABLE_STRINGS) |
28ef6c31 | 308 | /* Quote characters that get special treatment when in double quotes in STRING |
68ab281e | 309 | using backslashes. FLAGS is reserved for future use. Return a new string. */ |
28ef6c31 | 310 | char * |
81e3a4fb | 311 | sh_backslash_quote_for_double_quotes (char *string, int flags) |
28ef6c31 | 312 | { |
f73dda09 | 313 | unsigned char c; |
68ab281e CR |
314 | char *result, *r, *s, *send; |
315 | size_t slen; | |
203f479c CR |
316 | int mb_cur_max; |
317 | DECLARE_MBSTATE; | |
318 | ||
319 | slen = strlen (string); | |
320 | send = string + slen; | |
321 | mb_cur_max = MB_CUR_MAX; | |
68ab281e | 322 | result = (char *)xmalloc (2 * slen + 1); |
28ef6c31 | 323 | |
68ab281e | 324 | for (r = result, s = string; s && (c = *s); s++) |
28ef6c31 | 325 | { |
203f479c CR |
326 | /* Backslash-newline disappears within double quotes, so don't add one. */ |
327 | if ((sh_syntaxtab[c] & CBSDQUOTE) && c != '\n') | |
68ab281e | 328 | *r++ = '\\'; |
203f479c | 329 | /* I should probably use the CSPECL flag for these in sh_syntaxtab[] */ |
d3a24ed2 | 330 | else if (c == CTLESC || c == CTLNUL) |
68ab281e | 331 | *r++ = CTLESC; /* could be '\\'? */ |
28ef6c31 | 332 | |
203f479c CR |
333 | #if defined (HANDLE_MULTIBYTE) |
334 | if ((locale_utf8locale && (c & 0x80)) || | |
335 | (locale_utf8locale == 0 && mb_cur_max > 1 && is_basic (c) == 0)) | |
336 | { | |
68ab281e CR |
337 | COPY_CHAR_P (r, s, send); |
338 | s--; /* compensate for auto-increment in loop above */ | |
203f479c CR |
339 | continue; |
340 | } | |
341 | #endif | |
342 | ||
68ab281e | 343 | *r++ = c; |
28ef6c31 JA |
344 | } |
345 | ||
68ab281e | 346 | *r = '\0'; |
28ef6c31 JA |
347 | return (result); |
348 | } | |
349 | #endif /* PROMPT_STRING_DECODE */ | |
350 | ||
09f70f2f | 351 | char * |
81e3a4fb | 352 | sh_quote_reusable (char *s, int flags) |
09f70f2f CR |
353 | { |
354 | char *ret; | |
355 | ||
356 | if (s == 0) | |
357 | return s; | |
358 | else if (*s == 0) | |
359 | { | |
360 | ret = (char *)xmalloc (3); | |
361 | ret[0] = ret[1] = '\''; | |
362 | ret[2] = '\0'; | |
363 | } | |
364 | else if (ansic_shouldquote (s)) | |
365 | ret = ansic_quote (s, 0, (int *)0); | |
366 | else if (flags) | |
367 | ret = sh_backslash_quote (s, 0, 1); | |
368 | else | |
369 | ret = sh_single_quote (s); | |
370 | ||
371 | return ret; | |
372 | } | |
373 | ||
bb70624e | 374 | int |
81e3a4fb | 375 | sh_contains_shell_metas (const char *string) |
bb70624e | 376 | { |
8f50a023 | 377 | const char *s; |
bb70624e JA |
378 | |
379 | for (s = string; s && *s; s++) | |
380 | { | |
381 | switch (*s) | |
382 | { | |
383 | case ' ': case '\t': case '\n': /* IFS white space */ | |
384 | case '\'': case '"': case '\\': /* quoting chars */ | |
385 | case '|': case '&': case ';': /* shell metacharacters */ | |
386 | case '(': case ')': case '<': case '>': | |
387 | case '!': case '{': case '}': /* reserved words */ | |
388 | case '*': case '[': case '?': case ']': /* globbing chars */ | |
389 | case '^': | |
390 | case '$': case '`': /* expansion chars */ | |
391 | return (1); | |
392 | case '~': /* tilde expansion */ | |
393 | if (s == string || s[-1] == '=' || s[-1] == ':') | |
394 | return (1); | |
f73dda09 | 395 | break; |
bb70624e JA |
396 | case '#': |
397 | if (s == string) /* comment char */ | |
398 | return (1); | |
399 | /* FALLTHROUGH */ | |
400 | default: | |
401 | break; | |
402 | } | |
403 | } | |
404 | ||
405 | return (0); | |
406 | } | |
939d190e CR |
407 | |
408 | int | |
81e3a4fb | 409 | sh_contains_quotes (const char *string) |
939d190e | 410 | { |
8f50a023 | 411 | const char *s; |
939d190e CR |
412 | |
413 | for (s = string; s && *s; s++) | |
414 | { | |
415 | if (*s == '\'' || *s == '"' || *s == '\\') | |
416 | return 1; | |
417 | } | |
418 | return 0; | |
419 | } |