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