]> git.ipfire.org Git - thirdparty/bash.git/blob - lib/sh/strtrans.c
fix for SIGINT in sourced script
[thirdparty/bash.git] / lib / sh / strtrans.c
1 /* strtrans.c - Translate and untranslate strings with ANSI-C escape sequences. */
2
3 /* Copyright (C) 2000-2015 Free Software Foundation, Inc.
4
5 This file is part of GNU Bash, the Bourne Again SHell.
6
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 */
20
21 #include <config.h>
22
23 #if defined (HAVE_UNISTD_H)
24 # include <unistd.h>
25 #endif
26
27 #include <bashansi.h>
28 #include <stdio.h>
29 #include <chartypes.h>
30
31 #include "shell.h"
32
33 #include "shmbchar.h"
34 #include "shmbutil.h"
35
36 #ifdef ESC
37 #undef ESC
38 #endif
39 #define ESC '\033' /* ASCII */
40
41 /* Convert STRING by expanding the escape sequences specified by the
42 ANSI C standard. If SAWC is non-null, recognize `\c' and use that
43 as a string terminator. If we see \c, set *SAWC to 1 before
44 returning. LEN is the length of STRING. If (FLAGS&1) is non-zero,
45 that we're translating a string for `echo -e', and therefore should not
46 treat a single quote as a character that may be escaped with a backslash.
47 If (FLAGS&2) is non-zero, we're expanding for the parser and want to
48 quote CTLESC and CTLNUL with CTLESC. If (flags&4) is non-zero, we want
49 to remove the backslash before any unrecognized escape sequence. */
50 char *
51 ansicstr (string, len, flags, sawc, rlen)
52 char *string;
53 int len, flags, *sawc, *rlen;
54 {
55 int c, temp;
56 char *ret, *r, *s;
57 unsigned long v;
58
59 if (string == 0 || *string == '\0')
60 return ((char *)NULL);
61
62 #if defined (HANDLE_MULTIBYTE)
63 temp = 4*len + 1;
64 if (temp < 12)
65 temp = 12; /* ensure enough for eventual u32cesc */
66 ret = (char *)xmalloc (temp);
67 #else
68 ret = (char *)xmalloc (2*len + 1); /* 2*len for possible CTLESC */
69 #endif
70 for (r = ret, s = string; s && *s; )
71 {
72 c = *s++;
73 if (c != '\\' || *s == '\0')
74 *r++ = c;
75 else
76 {
77 switch (c = *s++)
78 {
79 #if defined (__STDC__)
80 case 'a': c = '\a'; break;
81 case 'v': c = '\v'; break;
82 #else
83 case 'a': c = (int) 0x07; break;
84 case 'v': c = (int) 0x0B; break;
85 #endif
86 case 'b': c = '\b'; break;
87 case 'e': case 'E': /* ESC -- non-ANSI */
88 c = ESC; break;
89 case 'f': c = '\f'; break;
90 case 'n': c = '\n'; break;
91 case 'r': c = '\r'; break;
92 case 't': c = '\t'; break;
93 case '1': case '2': case '3':
94 case '4': case '5': case '6':
95 case '7':
96 #if 1
97 if (flags & 1)
98 {
99 *r++ = '\\';
100 break;
101 }
102 /*FALLTHROUGH*/
103 #endif
104 case '0':
105 /* If (FLAGS & 1), we're translating a string for echo -e (or
106 the equivalent xpg_echo option), so we obey the SUSv3/
107 POSIX-2001 requirement and accept 0-3 octal digits after
108 a leading `0'. */
109 temp = 2 + ((flags & 1) && (c == '0'));
110 for (c -= '0'; ISOCTAL (*s) && temp--; s++)
111 c = (c * 8) + OCTVALUE (*s);
112 c &= 0xFF;
113 break;
114 case 'x': /* Hex digit -- non-ANSI */
115 if ((flags & 2) && *s == '{')
116 {
117 flags |= 16; /* internal flag value */
118 s++;
119 }
120 /* Consume at least two hex characters */
121 for (temp = 2, c = 0; ISXDIGIT ((unsigned char)*s) && temp--; s++)
122 c = (c * 16) + HEXVALUE (*s);
123 /* DGK says that after a `\x{' ksh93 consumes ISXDIGIT chars
124 until a non-xdigit or `}', so potentially more than two
125 chars are consumed. */
126 if (flags & 16)
127 {
128 for ( ; ISXDIGIT ((unsigned char)*s); s++)
129 c = (c * 16) + HEXVALUE (*s);
130 flags &= ~16;
131 if (*s == '}')
132 s++;
133 }
134 /* \x followed by non-hex digits is passed through unchanged */
135 else if (temp == 2)
136 {
137 *r++ = '\\';
138 c = 'x';
139 }
140 c &= 0xFF;
141 break;
142 #if defined (HANDLE_MULTIBYTE)
143 case 'u':
144 case 'U':
145 temp = (c == 'u') ? 4 : 8; /* \uNNNN \UNNNNNNNN */
146 for (v = 0; ISXDIGIT ((unsigned char)*s) && temp--; s++)
147 v = (v * 16) + HEXVALUE (*s);
148 if (temp == ((c == 'u') ? 4 : 8))
149 {
150 *r++ = '\\'; /* c remains unchanged */
151 break;
152 }
153 else if (v <= 0x7f) /* <= 0x7f translates directly */
154 {
155 c = v;
156 break;
157 }
158 else
159 {
160 temp = u32cconv (v, r);
161 r += temp;
162 continue;
163 }
164 #endif
165 case '\\':
166 break;
167 case '\'': case '"': case '?':
168 if (flags & 1)
169 *r++ = '\\';
170 break;
171 case 'c':
172 if (sawc)
173 {
174 *sawc = 1;
175 *r = '\0';
176 if (rlen)
177 *rlen = r - ret;
178 return ret;
179 }
180 else if ((flags & 1) == 0 && *s == 0)
181 ; /* pass \c through */
182 else if ((flags & 1) == 0 && (c = *s))
183 {
184 s++;
185 if ((flags & 2) && c == '\\' && c == *s)
186 s++; /* Posix requires $'\c\\' do backslash escaping */
187 c = TOCTRL(c);
188 break;
189 }
190 /*FALLTHROUGH*/
191 default:
192 if ((flags & 4) == 0)
193 *r++ = '\\';
194 break;
195 }
196 if ((flags & 2) && (c == CTLESC || c == CTLNUL))
197 *r++ = CTLESC;
198 *r++ = c;
199 }
200 }
201 *r = '\0';
202 if (rlen)
203 *rlen = r - ret;
204 return ret;
205 }
206
207 /* Take a string STR, possibly containing non-printing characters, and turn it
208 into a $'...' ANSI-C style quoted string. Returns a new string. */
209 char *
210 ansic_quote (str, flags, rlen)
211 char *str;
212 int flags, *rlen;
213 {
214 char *r, *ret, *s;
215 int l, rsize;
216 unsigned char c;
217 size_t clen;
218 int b;
219 #if defined (HANDLE_MULTIBYTE)
220 wchar_t wc;
221 #endif
222
223 if (str == 0 || *str == 0)
224 return ((char *)0);
225
226 l = strlen (str);
227 rsize = 4 * l + 4;
228 r = ret = (char *)xmalloc (rsize);
229
230 *r++ = '$';
231 *r++ = '\'';
232
233 s = str;
234
235 for (s = str; c = *s; s++)
236 {
237 b = l = 1; /* 1 == add backslash; 0 == no backslash */
238 clen = 1;
239
240 switch (c)
241 {
242 case ESC: c = 'E'; break;
243 #ifdef __STDC__
244 case '\a': c = 'a'; break;
245 case '\v': c = 'v'; break;
246 #else
247 case 0x07: c = 'a'; break;
248 case 0x0b: c = 'v'; break;
249 #endif
250
251 case '\b': c = 'b'; break;
252 case '\f': c = 'f'; break;
253 case '\n': c = 'n'; break;
254 case '\r': c = 'r'; break;
255 case '\t': c = 't'; break;
256 case '\\':
257 case '\'':
258 break;
259 default:
260 #if defined (HANDLE_MULTIBYTE)
261 b = is_basic (c);
262 /* XXX - clen comparison to 0 is dicey */
263 if ((b == 0 && ((clen = mbrtowc (&wc, s, MB_CUR_MAX, 0)) < 0 || MB_INVALIDCH (clen) || iswprint (wc) == 0)) ||
264 (b == 1 && ISPRINT (c) == 0))
265 #else
266 if (ISPRINT (c) == 0)
267 #endif
268 {
269 *r++ = '\\';
270 *r++ = TOCHAR ((c >> 6) & 07);
271 *r++ = TOCHAR ((c >> 3) & 07);
272 *r++ = TOCHAR (c & 07);
273 continue;
274 }
275 l = 0;
276 break;
277 }
278 if (b == 0 && clen == 0)
279 break;
280
281 if (l)
282 *r++ = '\\';
283
284 if (clen == 1)
285 *r++ = c;
286 else
287 {
288 for (b = 0; b < (int)clen; b++)
289 *r++ = (unsigned char)s[b];
290 s += clen - 1; /* -1 because of the increment above */
291 }
292 }
293
294 *r++ = '\'';
295 *r = '\0';
296 if (rlen)
297 *rlen = r - ret;
298 return ret;
299 }
300
301 #if defined (HANDLE_MULTIBYTE)
302 int
303 ansic_wshouldquote (string)
304 const char *string;
305 {
306 const wchar_t *wcs;
307 wchar_t wcc;
308
309 wchar_t *wcstr = NULL;
310 size_t slen;
311
312
313 slen = mbstowcs (wcstr, string, 0);
314
315 if (slen == (size_t)-1)
316 return 1;
317
318 wcstr = (wchar_t *)xmalloc (sizeof (wchar_t) * (slen + 1));
319 mbstowcs (wcstr, string, slen + 1);
320
321 for (wcs = wcstr; wcc = *wcs; wcs++)
322 if (iswprint(wcc) == 0)
323 {
324 free (wcstr);
325 return 1;
326 }
327
328 free (wcstr);
329 return 0;
330 }
331 #endif
332
333 /* return 1 if we need to quote with $'...' because of non-printing chars. */
334 int
335 ansic_shouldquote (string)
336 const char *string;
337 {
338 const char *s;
339 unsigned char c;
340
341 if (string == 0)
342 return 0;
343
344 for (s = string; c = *s; s++)
345 {
346 #if defined (HANDLE_MULTIBYTE)
347 if (is_basic (c) == 0)
348 return (ansic_wshouldquote (s));
349 #endif
350 if (ISPRINT (c) == 0)
351 return 1;
352 }
353
354 return 0;
355 }
356
357 /* $'...' ANSI-C expand the portion of STRING between START and END and
358 return the result. The result cannot be longer than the input string. */
359 char *
360 ansiexpand (string, start, end, lenp)
361 char *string;
362 int start, end, *lenp;
363 {
364 char *temp, *t;
365 int len, tlen;
366
367 temp = (char *)xmalloc (end - start + 1);
368 for (tlen = 0, len = start; len < end; )
369 temp[tlen++] = string[len++];
370 temp[tlen] = '\0';
371
372 if (*temp)
373 {
374 t = ansicstr (temp, tlen, 2, (int *)NULL, lenp);
375 free (temp);
376 return (t);
377 }
378 else
379 {
380 if (lenp)
381 *lenp = 0;
382 return (temp);
383 }
384 }