1 /***********************************************************************
2 *                                                                      *
3 *               This software is part of the ast package               *
4 *          Copyright (c) 1985-2011 AT&T Intellectual Property          *
5 *                      and is licensed under the                       *
6 *                 Eclipse Public License, Version 1.0                  *
7 *                    by AT&T Intellectual Property                     *
8 *                                                                      *
9 *                A copy of the License is available at                 *
10 *          http://www.eclipse.org/org/documents/epl-v10.html           *
11 *         (with md5 checksum b35adb5213ca9657e911e9befb180842)         *
12 *                                                                      *
13 *              Information and Software Systems Research               *
14 *                            AT&T Research                             *
15 *                           Florham Park NJ                            *
16 *                                                                      *
17 *                 Glenn Fowler <gsf@research.att.com>                  *
18 *                  David Korn <dgk@research.att.com>                   *
19 *                   Phong Vo <kpv@research.att.com>                    *
20 *                                                                      *
21 ***********************************************************************/
22 #pragma prototyped
23 /*
24  * Glenn Fowler
25  * AT&T Research
26  *
27  * return string with expanded escape chars
28  */
29 
30 #include <ast.h>
31 #include <ccode.h>
32 #include <ctype.h>
33 #if _hdr_wchar && _hdr_wctype
34 #include <wchar.h>
35 #include <wctype.h>
36 #endif
37 
38 /*
39  * quote string as of length n with qb...qe
40  * (flags&FMT_ALWAYS) always quotes, otherwise quote output only if necessary
41  * qe and the usual suspects are \... escaped
42  * (flags&FMT_WIDE) doesn't escape 8 bit chars
43  * (flags&FMT_ESCAPED) doesn't \... escape the usual suspects
44  * (flags&FMT_SHELL) escape $`"#;~&|()<>[]*?
45  */
46 
47 char*
fmtquote(const char * as,const char * qb,const char * qe,size_t n,int flags)48 fmtquote(const char* as, const char* qb, const char* qe, size_t n, int flags)
49 {
50 	register unsigned char*	s = (unsigned char*)as;
51 	register unsigned char*	e = s + n;
52 	register char*		b;
53 	register int		c;
54 	register int		m;
55 	register int		escaped;
56 	register int		spaced;
57 	register int		doublequote;
58 	register int		singlequote;
59 	int			shell;
60 	char*			f;
61 	char*			buf;
62 
63 	c = 4 * (n + 1);
64 	if (qb)
65 		c += strlen((char*)qb);
66 	if (qe)
67 		c += strlen((char*)qe);
68 	b = buf = fmtbuf(c);
69 	shell = 0;
70 	doublequote = 0;
71 	singlequote = 0;
72 	if (qb)
73 	{
74 		if (qb[0] == '$' && qb[1] == '\'' && qb[2] == 0)
75 			shell = 1;
76 		else if ((flags & FMT_SHELL) && qb[1] == 0)
77 		{
78 			if (qb[0] == '"')
79 				doublequote = 1;
80 			else if (qb[0] == '\'')
81 				singlequote = 1;
82 		}
83 		while (*b = *qb++)
84 			b++;
85 	}
86 	else if (flags & FMT_SHELL)
87 		doublequote = 1;
88 	f = b;
89 	escaped = spaced = !!(flags & FMT_ALWAYS);
90 	while (s < e)
91 	{
92 		if ((m = mbsize(s)) > 1 && (s + m) <= e)
93 		{
94 #if _hdr_wchar && _hdr_wctype
95 			c = mbchar(s);
96 			if (!spaced && !escaped && (iswspace(c) || iswcntrl(c)))
97 				spaced = 1;
98 			s -= m;
99 #endif
100 			while (m--)
101 				*b++ = *s++;
102 		}
103 		else
104 		{
105 			c = *s++;
106 			if (!(flags & FMT_ESCAPED) && (iscntrl(c) || !isprint(c) || c == '\\'))
107 			{
108 				escaped = 1;
109 				*b++ = '\\';
110 				switch (c)
111 				{
112 				case CC_bel:
113 					c = 'a';
114 					break;
115 				case '\b':
116 					c = 'b';
117 					break;
118 				case '\f':
119 					c = 'f';
120 					break;
121 				case '\n':
122 					c = 'n';
123 					break;
124 				case '\r':
125 					c = 'r';
126 					break;
127 				case '\t':
128 					c = 't';
129 					break;
130 				case CC_vt:
131 					c = 'v';
132 					break;
133 				case CC_esc:
134 					c = 'E';
135 					break;
136 				case '\\':
137 					break;
138 				default:
139 					if (!(flags & FMT_WIDE) || !(c & 0200))
140 					{
141 						*b++ = '0' + ((c >> 6) & 07);
142 						*b++ = '0' + ((c >> 3) & 07);
143 						c = '0' + (c & 07);
144 					}
145 					else
146 						b--;
147 					break;
148 				}
149 			}
150 			else if (c == '\\')
151 			{
152 				escaped = 1;
153 				*b++ = c;
154 				if (*s)
155 					c = *s++;
156 			}
157 			else if (qe && strchr(qe, c))
158 			{
159 				if (singlequote && c == '\'')
160 				{
161 					spaced = 1;
162 					*b++ = '\'';
163 					*b++ = '\\';
164 					*b++ = '\'';
165 					c = '\'';
166 				}
167 				else
168 				{
169 					escaped = 1;
170 					*b++ = '\\';
171 				}
172 			}
173 			else if (c == '$' || c == '`')
174 			{
175 				if (c == '$' && (flags & FMT_PARAM) && (*s == '{' || *s == '('))
176 				{
177 					if (singlequote || shell)
178 					{
179 						escaped = 1;
180 						*b++ = '\'';
181 						*b++ = c;
182 						*b++ = *s++;
183 						if (shell)
184 						{
185 							spaced = 1;
186 							*b++ = '$';
187 						}
188 						c = '\'';
189 					}
190 					else
191 					{
192 						escaped = 1;
193 						*b++ = c;
194 						c = *s++;
195 					}
196 				}
197 				else if (doublequote)
198 					*b++ = '\\';
199 				else if (singlequote || (flags & FMT_SHELL))
200 					spaced = 1;
201 			}
202 			else if (!spaced && !escaped && (isspace(c) || ((flags & FMT_SHELL) || shell) && (strchr("\";~&|()<>[]*?", c) || c == '#' && (b == f || isspace(*(b - 1))))))
203 				spaced = 1;
204 			*b++ = c;
205 		}
206 	}
207 	if (qb)
208 	{
209 		if (!escaped)
210 			buf += shell + !spaced;
211 		if (qe && (escaped || spaced))
212 			while (*b = *qe++)
213 				b++;
214 	}
215 	*b = 0;
216 	return buf;
217 }
218 
219 /*
220  * escape the usual suspects and quote chars in qs
221  * in length n string as
222  */
223 
224 char*
fmtnesq(const char * as,const char * qs,size_t n)225 fmtnesq(const char* as, const char* qs, size_t n)
226 {
227 	return fmtquote(as, NiL, qs, n, 0);
228 }
229 
230 /*
231  * escape the usual suspects and quote chars in qs
232  */
233 
234 char*
fmtesq(const char * as,const char * qs)235 fmtesq(const char* as, const char* qs)
236 {
237 	return fmtquote(as, NiL, qs, strlen((char*)as), 0);
238 }
239 
240 /*
241  * escape the usual suspects
242  */
243 
244 char*
fmtesc(const char * as)245 fmtesc(const char* as)
246 {
247 	return fmtquote(as, NiL, NiL, strlen((char*)as), 0);
248 }
249