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  * POSIX 1003.2 wordexp implementation
25  */
26 
27 #include	<ast.h>
28 #include	<wordexp.h>
29 #include	<stak.h>
30 
31 struct 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  */
sh_unquote(char * string)41 static 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 
wordexp(const char * string,wordexp_t * wdarg,register int flags)65 int	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;
190 err:
191 	if(offset)
192 		stakset(savebase,offset);
193 	else
194 		stakseek(0);
195 	return(c);
196 }
197 
198 /*
199  * free fields in <wdarg>
200  */
wordfree(register wordexp_t * wdarg)201 int 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