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