]> git.ipfire.org Git - thirdparty/bash.git/blame - lib/sh/shquote.c
bash-5.2 distribution sources and documentation
[thirdparty/bash.git] / lib / sh / shquote.c
CommitLineData
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
39extern char *ansic_quote PARAMS((char *, int, int *));
40extern int ansic_shouldquote PARAMS((const char *));
a0c0a00f 41
ac50fbac
CR
42/* Default set of characters that should be backslash-quoted in strings */
43static 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. */
94char *
28ef6c31 95sh_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. */
134char *
28ef6c31 135sh_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. */
182char *
183sh_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 222char *
28ef6c31 223sh_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 261char *
ac50fbac 262sh_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 317char *
74091dd4 318sh_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
360char *
361sh_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 385int
28ef6c31 386sh_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
420int
421sh_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}