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  * POSIX 1003.2 wordexp implementation
25*4887Schin  */
26*4887Schin 
27*4887Schin #include	<ast.h>
28*4887Schin #include	<wordexp.h>
29*4887Schin #include	<stak.h>
30*4887Schin 
31*4887Schin struct list
32*4887Schin {
33*4887Schin 	struct list *next;
34*4887Schin };
35*4887Schin 
36*4887Schin /*
37*4887Schin  * elimnates shell quoting as inserted with sh_fmtq
38*4887Schin  * result relaces <string>
39*4887Schin  * length of resulting string is returned.
40*4887Schin  */
41*4887Schin static int	sh_unquote(char* string)
42*4887Schin {
43*4887Schin 	register char *sp=string, *dp;
44*4887Schin 	register int c;
45*4887Schin 	while((c= *sp) && c!='\'')
46*4887Schin 		sp++;
47*4887Schin 	if(c==0)
48*4887Schin 		return(sp-string);
49*4887Schin 	if((dp=sp) > string && sp[-1]=='$')
50*4887Schin 	{
51*4887Schin 		register int n=stresc(sp+1);
52*4887Schin 		/* copy all but trailing ' */
53*4887Schin 		while(--n>0)
54*4887Schin 			*dp++ = *++sp;
55*4887Schin 	}
56*4887Schin 	else
57*4887Schin 	{
58*4887Schin 		while((c= *++sp) && c!='\'')
59*4887Schin 			*dp++ = c;
60*4887Schin 	}
61*4887Schin 	*dp=0;
62*4887Schin 	return(dp-string);
63*4887Schin }
64*4887Schin 
65*4887Schin int	wordexp(const char *string, wordexp_t *wdarg, register int flags)
66*4887Schin {
67*4887Schin 	register Sfio_t *iop;
68*4887Schin 	register char *cp=(char*)string;
69*4887Schin 	register int c,quoted=0,literal=0,ac=0;
70*4887Schin 	int offset;
71*4887Schin 	char *savebase,**av;
72*4887Schin 	if(offset=staktell())
73*4887Schin 		savebase = stakfreeze(0);
74*4887Schin 	if(flags&WRDE_REUSE)
75*4887Schin 		wordfree(wdarg);
76*4887Schin 	else if(!(flags&WRDE_APPEND))
77*4887Schin 	{
78*4887Schin 		wdarg->we_wordv = 0;
79*4887Schin 		wdarg->we_wordc = 0;
80*4887Schin 	}
81*4887Schin 	if(flags&WRDE_UNDEF)
82*4887Schin 		stakwrite("set -u\n",7);
83*4887Schin 	if(!(flags&WRDE_SHOWERR))
84*4887Schin 		stakwrite("exec 2> /dev/null\n",18);
85*4887Schin 	stakwrite("print -f \"%q\\n\" ",16);
86*4887Schin 	if(*cp=='#')
87*4887Schin 		stakputc('\\');
88*4887Schin 	while(c = *cp++)
89*4887Schin 	{
90*4887Schin 		if(c=='\'' && !quoted)
91*4887Schin 			literal = !literal;
92*4887Schin 		else if(!literal)
93*4887Schin 		{
94*4887Schin 			if(c=='\\' && (!quoted || strchr("\\\"`\n$",c)))
95*4887Schin 			{
96*4887Schin 				stakputc('\\');
97*4887Schin 				if(c= *cp)
98*4887Schin 					cp++;
99*4887Schin 				else
100*4887Schin 					c = '\\';
101*4887Schin 			}
102*4887Schin 			else if(c=='"')
103*4887Schin 				quoted = !quoted;
104*4887Schin 			else if(c=='`' || (c=='$' && *cp=='('))
105*4887Schin 			{
106*4887Schin 				if(flags&WRDE_NOCMD)
107*4887Schin 				{
108*4887Schin 					c=WRDE_CMDSUB;
109*4887Schin 					goto err;
110*4887Schin 				}
111*4887Schin 				/* only the shell can parse the rest */
112*4887Schin 				stakputs(cp-1);
113*4887Schin 				break;
114*4887Schin 			}
115*4887Schin 			else if(!quoted && strchr("|&\n;<>"+ac,c))
116*4887Schin 			{
117*4887Schin 				c=WRDE_BADCHAR;
118*4887Schin 				goto err;
119*4887Schin 			}
120*4887Schin 			else if(c=='(') /* allow | and & inside pattern */
121*4887Schin 				ac=2;
122*4887Schin 		}
123*4887Schin 		stakputc(c);
124*4887Schin 	}
125*4887Schin 	stakputc(0);
126*4887Schin 	if(!(iop = sfpopen((Sfio_t*)0,stakptr(0),"r")))
127*4887Schin 	{
128*4887Schin 		c = WRDE_NOSHELL;
129*4887Schin 		goto err;
130*4887Schin 	}
131*4887Schin 	stakseek(0);
132*4887Schin 	ac = 0;
133*4887Schin 	while((c=sfgetc(iop)) != EOF)
134*4887Schin 	{
135*4887Schin 		if(c=='\'')
136*4887Schin 			quoted = ! quoted;
137*4887Schin 		else if(!quoted && (c==' ' || c=='\n'))
138*4887Schin 		{
139*4887Schin 			ac++;
140*4887Schin 			c = 0;
141*4887Schin 		}
142*4887Schin 		stakputc(c);
143*4887Schin 	}
144*4887Schin 	if(c=sfclose(iop))
145*4887Schin 	{
146*4887Schin 		if(c==3 || !(flags&WRDE_UNDEF))
147*4887Schin 			c=WRDE_SYNTAX;
148*4887Schin 		else
149*4887Schin 			c=WRDE_BADVAL;
150*4887Schin 		goto err;
151*4887Schin 	}
152*4887Schin 	c = ac+2;
153*4887Schin 	if(flags&WRDE_DOOFFS)
154*4887Schin 		c += wdarg->we_offs;
155*4887Schin 	if(flags&WRDE_APPEND)
156*4887Schin 		av = (char**)realloc((void*)&wdarg->we_wordv[-1], (wdarg->we_wordc+c)*sizeof(char*));
157*4887Schin 	else if(av = (char**)malloc(c*sizeof(char*)))
158*4887Schin 	{
159*4887Schin 		if(flags&WRDE_DOOFFS)
160*4887Schin 			memset((void*)av,0,(wdarg->we_offs+1)*sizeof(char*));
161*4887Schin 		else
162*4887Schin 			av[0] = 0;
163*4887Schin 	}
164*4887Schin 	if(!av)
165*4887Schin 		return(WRDE_NOSPACE);
166*4887Schin 	c = staktell();
167*4887Schin 	if(!(cp = (char*)malloc(sizeof(char*)+c)))
168*4887Schin 	{
169*4887Schin 		c=WRDE_NOSPACE;
170*4887Schin 		goto err;
171*4887Schin 	}
172*4887Schin 	((struct list*)cp)->next = (struct list*)(*av);
173*4887Schin 	*av++ = (char*)cp;
174*4887Schin 	cp += sizeof(char*);
175*4887Schin 	wdarg->we_wordv = av;
176*4887Schin 	if(flags&WRDE_APPEND)
177*4887Schin 		av += wdarg->we_wordc;
178*4887Schin 	wdarg->we_wordc += ac;
179*4887Schin 	if(flags&WRDE_DOOFFS)
180*4887Schin 		av += wdarg->we_offs;
181*4887Schin 	memcpy((void*)cp,stakptr(offset),c);
182*4887Schin 	while(ac-- > 0)
183*4887Schin 	{
184*4887Schin 		*av++ = cp;
185*4887Schin 		sh_unquote(cp);
186*4887Schin 		while(c= *cp++);
187*4887Schin 	}
188*4887Schin 	*av = 0;
189*4887Schin 	c=0;
190*4887Schin err:
191*4887Schin 	if(offset)
192*4887Schin 		stakset(savebase,offset);
193*4887Schin 	else
194*4887Schin 		stakseek(0);
195*4887Schin 	return(c);
196*4887Schin }
197*4887Schin 
198*4887Schin /*
199*4887Schin  * free fields in <wdarg>
200*4887Schin  */
201*4887Schin int wordfree(register wordexp_t *wdarg)
202*4887Schin {
203*4887Schin 	struct list *arg, *argnext;
204*4887Schin 	if(wdarg->we_wordv)
205*4887Schin 	{
206*4887Schin 		argnext = (struct list*)wdarg->we_wordv[-1];
207*4887Schin 		while(arg=argnext)
208*4887Schin 		{
209*4887Schin 			argnext = arg->next;
210*4887Schin 			free((void*)arg);
211*4887Schin 		}
212*4887Schin 		free((void*)&wdarg->we_wordv[-1]);
213*4887Schin 		wdarg->we_wordv = 0;
214*4887Schin 	}
215*4887Schin 	wdarg->we_wordc=0;
216*4887Schin 	return(0);
217*4887Schin }
218