a1e9146bfa8171ae43bf62b44fc3a12f03c098b5
[platform/upstream/bash.git] / lib / sh / shquote.c
1 /* shquote - functions to quote and dequote strings */
2
3 /* Copyright (C) 1999 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 #  ifdef _MINIX
25 #    include <sys/types.h>
26 #  endif
27 #  include <unistd.h>
28 #endif
29
30 #include <stdio.h>
31
32 #include "syntax.h"
33 #include <xmalloc.h>
34
35 /* **************************************************************** */
36 /*                                                                  */
37 /*       Functions for quoting strings to be re-read as input       */
38 /*                                                                  */
39 /* **************************************************************** */
40
41 /* Return a new string which is the single-quoted version of STRING.
42    Used by alias and trap, among others. */
43 char *
44 sh_single_quote (string)
45      const char *string;
46 {
47   register int c;
48   char *result, *r;
49   const char *s;
50
51   result = (char *)xmalloc (3 + (4 * strlen (string)));
52   r = result;
53   *r++ = '\'';
54
55   for (s = string; s && (c = *s); s++)
56     {
57       *r++ = c;
58
59       if (c == '\'')
60         {
61           *r++ = '\\';  /* insert escaped single quote */
62           *r++ = '\'';
63           *r++ = '\'';  /* start new quoted string */
64         }
65     }
66
67   *r++ = '\'';
68   *r = '\0';
69
70   return (result);
71 }
72
73 /* Quote STRING using double quotes.  Return a new string. */
74 char *
75 sh_double_quote (string)
76      const char *string;
77 {
78   register unsigned char c;
79   char *result, *r;
80   const char *s;
81
82   result = (char *)xmalloc (3 + (2 * strlen (string)));
83   r = result;
84   *r++ = '"';
85
86   for (s = string; s && (c = *s); s++)
87     {
88       /* Backslash-newline disappears within double quotes, so don't add one. */
89       if ((sh_syntaxtab[c] & CBSDQUOTE) && c != '\n')
90         *r++ = '\\';
91       else if (c == CTLESC || c == CTLNUL)
92         *r++ = CTLESC;          /* could be '\\'? */
93
94       *r++ = c;
95     }
96
97   *r++ = '"';
98   *r = '\0';
99
100   return (result);
101 }
102
103 /* Turn S into a simple double-quoted string.  If FLAGS is non-zero, quote
104    double quote characters in S with backslashes. */
105 char *
106 sh_mkdoublequoted (s, slen, flags)
107      const char *s;
108      int slen, flags;
109 {
110   char *r, *ret;
111   int rlen;
112
113   rlen = (flags == 0) ? slen + 3 : (2 * slen) + 1;
114   ret = r = (char *)xmalloc (rlen);
115   
116   *r++ = '"';
117   while (*s)
118     {
119       if (flags && *s == '"')
120         *r++ = '\\';
121       *r++ = *s++;
122     }
123   *r++ = '"';
124   *r = '\0';
125
126   return ret;
127 }
128
129 /* Remove backslashes that are quoting characters that are special between
130    double quotes.  Return a new string.  XXX - should this handle CTLESC
131    and CTLNUL? */
132 char *
133 sh_un_double_quote (string)
134      char *string;
135 {
136   register int c, pass_next;
137   char *result, *r, *s;
138
139   r = result = (char *)xmalloc (strlen (string) + 1);
140
141   for (pass_next = 0, s = string; s && (c = *s); s++)
142     {
143       if (pass_next)
144         {
145           *r++ = c;
146           pass_next = 0;
147           continue;
148         }
149       if (c == '\\' && (sh_syntaxtab[(unsigned char) s[1]] & CBSDQUOTE))
150         {
151           pass_next = 1;
152           continue;
153         }
154       *r++ = c;
155     }
156
157   *r = '\0';
158   return result;
159 }
160
161 /* Quote special characters in STRING using backslashes.  Return a new
162    string.  NOTE:  if the string is to be further expanded, we need a
163    way to protect the CTLESC and CTLNUL characters.  As I write this,
164    the current callers will never cause the string to be expanded without
165    going through the shell parser, which will protect the internal
166    quoting characters. */
167 char *
168 sh_backslash_quote (string)
169      char *string;
170 {
171   int c;
172   char *result, *r, *s;
173
174   result = (char *)xmalloc (2 * strlen (string) + 1);
175
176   for (r = result, s = string; s && (c = *s); s++)
177     {
178       switch (c)
179         {
180         case ' ': case '\t': case '\n':         /* IFS white space */
181         case '\'': case '"': case '\\':         /* quoting chars */
182         case '|': case '&': case ';':           /* shell metacharacters */
183         case '(': case ')': case '<': case '>':
184         case '!': case '{': case '}':           /* reserved words */
185         case '*': case '[': case '?': case ']': /* globbing chars */
186         case '^':
187         case '$': case '`':                     /* expansion chars */
188         case ',':                               /* brace expansion */
189           *r++ = '\\';
190           *r++ = c;
191           break;
192 #if 0
193         case '~':                               /* tilde expansion */
194           if (s == string || s[-1] == '=' || s[-1] == ':')
195             *r++ = '\\';
196           *r++ = c;
197           break;
198
199         case CTLESC: case CTLNUL:               /* internal quoting characters */
200           *r++ = CTLESC;                        /* could be '\\'? */
201           *r++ = c;
202           break;
203 #endif
204
205         case '#':                               /* comment char */
206           if (s == string)
207             *r++ = '\\';
208           /* FALLTHROUGH */
209         default:
210           *r++ = c;
211           break;
212         }
213     }
214
215   *r = '\0';
216   return (result);
217 }
218
219 #if defined (PROMPT_STRING_DECODE)
220 /* Quote characters that get special treatment when in double quotes in STRING
221    using backslashes.  Return a new string. */
222 char *
223 sh_backslash_quote_for_double_quotes (string)
224      char *string;
225 {
226   unsigned char c;
227   char *result, *r, *s;
228
229   result = (char *)xmalloc (2 * strlen (string) + 1);
230
231   for (r = result, s = string; s && (c = *s); s++)
232     {
233       if (sh_syntaxtab[c] & CBSDQUOTE)
234         *r++ = '\\';
235       /* I should probably add flags for these to sh_syntaxtab[] */
236       else if (c == CTLESC || c == CTLNUL)
237         *r++ = CTLESC;          /* could be '\\'? */
238
239       *r++ = c;
240     }
241
242   *r = '\0';
243   return (result);
244 }
245 #endif /* PROMPT_STRING_DECODE */
246
247 int
248 sh_contains_shell_metas (string)
249      char *string;
250 {
251   char *s;
252
253   for (s = string; s && *s; s++)
254     {
255       switch (*s)
256         {
257         case ' ': case '\t': case '\n':         /* IFS white space */
258         case '\'': case '"': case '\\':         /* quoting chars */
259         case '|': case '&': case ';':           /* shell metacharacters */
260         case '(': case ')': case '<': case '>':
261         case '!': case '{': case '}':           /* reserved words */
262         case '*': case '[': case '?': case ']': /* globbing chars */
263         case '^':
264         case '$': case '`':                     /* expansion chars */
265           return (1);
266         case '~':                               /* tilde expansion */
267           if (s == string || s[-1] == '=' || s[-1] == ':')
268             return (1);
269           break;
270         case '#':
271           if (s == string)                      /* comment char */
272             return (1);
273           /* FALLTHROUGH */
274         default:
275           break;
276         }
277     }
278
279   return (0);
280 }