xref: /titanic_52/usr/src/cmd/csh/sh.glob.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * Copyright 2001 Sun Microsystems, Inc.  All rights reserved.
3*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
4*7c478bd9Sstevel@tonic-gate  */
5*7c478bd9Sstevel@tonic-gate 
6*7c478bd9Sstevel@tonic-gate /*	Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T	*/
7*7c478bd9Sstevel@tonic-gate /*	  All Rights Reserved  	*/
8*7c478bd9Sstevel@tonic-gate 
9*7c478bd9Sstevel@tonic-gate /*
10*7c478bd9Sstevel@tonic-gate  * Copyright (c) 1980 Regents of the University of California.
11*7c478bd9Sstevel@tonic-gate  * All rights reserved.  The Berkeley Software License Agreement
12*7c478bd9Sstevel@tonic-gate  * specifies the terms and conditions for redistribution.
13*7c478bd9Sstevel@tonic-gate  */
14*7c478bd9Sstevel@tonic-gate 
15*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
16*7c478bd9Sstevel@tonic-gate 
17*7c478bd9Sstevel@tonic-gate #include "sh.h"
18*7c478bd9Sstevel@tonic-gate #include "sh.tconst.h"
19*7c478bd9Sstevel@tonic-gate #include <dirent.h>
20*7c478bd9Sstevel@tonic-gate #ifdef MBCHAR
21*7c478bd9Sstevel@tonic-gate #include <widec.h>	/* wcsetno() */
22*7c478bd9Sstevel@tonic-gate #include <fnmatch.h>	/* fnmatch() */
23*7c478bd9Sstevel@tonic-gate #endif /* MBCHAR */
24*7c478bd9Sstevel@tonic-gate 
25*7c478bd9Sstevel@tonic-gate /*
26*7c478bd9Sstevel@tonic-gate  * C Shell
27*7c478bd9Sstevel@tonic-gate  */
28*7c478bd9Sstevel@tonic-gate 
29*7c478bd9Sstevel@tonic-gate int	globcnt;
30*7c478bd9Sstevel@tonic-gate 
31*7c478bd9Sstevel@tonic-gate tchar	*gpath, *gpathp, *lastgpathp;
32*7c478bd9Sstevel@tonic-gate int	globbed;
33*7c478bd9Sstevel@tonic-gate bool	noglob;
34*7c478bd9Sstevel@tonic-gate bool	nonomatch;
35*7c478bd9Sstevel@tonic-gate tchar	*entp;
36*7c478bd9Sstevel@tonic-gate tchar	**sortbas;
37*7c478bd9Sstevel@tonic-gate int	sortscmp();
38*7c478bd9Sstevel@tonic-gate extern	DIR *opendir_();
39*7c478bd9Sstevel@tonic-gate 
40*7c478bd9Sstevel@tonic-gate #define	sort()	qsort((char *)sortbas, &gargv[gargc] - sortbas, \
41*7c478bd9Sstevel@tonic-gate 			sizeof (*sortbas), (int (*)(const void *, \
42*7c478bd9Sstevel@tonic-gate 			const void *)) sortscmp), sortbas = &gargv[gargc]
43*7c478bd9Sstevel@tonic-gate 
44*7c478bd9Sstevel@tonic-gate 
45*7c478bd9Sstevel@tonic-gate tchar **
46*7c478bd9Sstevel@tonic-gate glob(v)
47*7c478bd9Sstevel@tonic-gate 	register tchar **v;
48*7c478bd9Sstevel@tonic-gate {
49*7c478bd9Sstevel@tonic-gate 	tchar agpath[BUFSIZ];
50*7c478bd9Sstevel@tonic-gate 	tchar *agargv[GAVSIZ];
51*7c478bd9Sstevel@tonic-gate 
52*7c478bd9Sstevel@tonic-gate 	gpath = agpath; gpathp = gpath; *gpathp = 0;
53*7c478bd9Sstevel@tonic-gate 	lastgpathp = &gpath[BUFSIZ - 2];
54*7c478bd9Sstevel@tonic-gate 	ginit(agargv); globcnt = 0;
55*7c478bd9Sstevel@tonic-gate #ifdef TRACE
56*7c478bd9Sstevel@tonic-gate 	tprintf("TRACE- glob()\n");
57*7c478bd9Sstevel@tonic-gate #endif
58*7c478bd9Sstevel@tonic-gate #ifdef GDEBUG
59*7c478bd9Sstevel@tonic-gate 	printf("glob entered: "); blkpr(v); printf("\n");
60*7c478bd9Sstevel@tonic-gate #endif
61*7c478bd9Sstevel@tonic-gate 	noglob = adrof(S_noglob /* "noglob" */) != 0;
62*7c478bd9Sstevel@tonic-gate 	nonomatch = adrof(S_nonomatch /* "nonomatch" */) != 0;
63*7c478bd9Sstevel@tonic-gate 	globcnt = noglob | nonomatch;
64*7c478bd9Sstevel@tonic-gate 	while (*v)
65*7c478bd9Sstevel@tonic-gate 		collect(*v++);
66*7c478bd9Sstevel@tonic-gate #ifdef GDEBUG
67*7c478bd9Sstevel@tonic-gate 	printf("glob done, globcnt=%d, gflag=%d: ", globcnt, gflag);
68*7c478bd9Sstevel@tonic-gate 	blkpr(gargv); printf("\n");
69*7c478bd9Sstevel@tonic-gate #endif
70*7c478bd9Sstevel@tonic-gate 	if (globcnt == 0 && (gflag&1)) {
71*7c478bd9Sstevel@tonic-gate 		blkfree(gargv), gargv = 0;
72*7c478bd9Sstevel@tonic-gate 		return (0);
73*7c478bd9Sstevel@tonic-gate 	} else
74*7c478bd9Sstevel@tonic-gate 		return (gargv = copyblk(gargv));
75*7c478bd9Sstevel@tonic-gate }
76*7c478bd9Sstevel@tonic-gate 
77*7c478bd9Sstevel@tonic-gate ginit(agargv)
78*7c478bd9Sstevel@tonic-gate 	tchar **agargv;
79*7c478bd9Sstevel@tonic-gate {
80*7c478bd9Sstevel@tonic-gate 
81*7c478bd9Sstevel@tonic-gate 	agargv[0] = 0; gargv = agargv; sortbas = agargv; gargc = 0;
82*7c478bd9Sstevel@tonic-gate 	gnleft = NCARGS - 4;
83*7c478bd9Sstevel@tonic-gate }
84*7c478bd9Sstevel@tonic-gate 
85*7c478bd9Sstevel@tonic-gate collect(as)
86*7c478bd9Sstevel@tonic-gate 	register tchar *as;
87*7c478bd9Sstevel@tonic-gate {
88*7c478bd9Sstevel@tonic-gate 	register int i;
89*7c478bd9Sstevel@tonic-gate 
90*7c478bd9Sstevel@tonic-gate #ifdef TRACE
91*7c478bd9Sstevel@tonic-gate 	tprintf("TRACE- collect()\n");
92*7c478bd9Sstevel@tonic-gate #endif
93*7c478bd9Sstevel@tonic-gate 	if (any('`', as)) {
94*7c478bd9Sstevel@tonic-gate #ifdef GDEBUG
95*7c478bd9Sstevel@tonic-gate 		printf("doing backp of %t\n", as);
96*7c478bd9Sstevel@tonic-gate #endif
97*7c478bd9Sstevel@tonic-gate 		(void) dobackp(as, 0);
98*7c478bd9Sstevel@tonic-gate #ifdef GDEBUG
99*7c478bd9Sstevel@tonic-gate 		printf("backp done, acollect'ing\n");
100*7c478bd9Sstevel@tonic-gate #endif
101*7c478bd9Sstevel@tonic-gate 		/*
102*7c478bd9Sstevel@tonic-gate 		 * dobackp has the side effect of messing with
103*7c478bd9Sstevel@tonic-gate 		 * gflag, since it does more globbing, so check
104*7c478bd9Sstevel@tonic-gate 		 * if the results is still globbable
105*7c478bd9Sstevel@tonic-gate 		*/
106*7c478bd9Sstevel@tonic-gate 		tglob(pargv);
107*7c478bd9Sstevel@tonic-gate 
108*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < pargc; i++)
109*7c478bd9Sstevel@tonic-gate 			if (noglob) {
110*7c478bd9Sstevel@tonic-gate 				Gcat(pargv[i], S_ /* "" */);
111*7c478bd9Sstevel@tonic-gate 				sortbas = &gargv[gargc];
112*7c478bd9Sstevel@tonic-gate 			} else
113*7c478bd9Sstevel@tonic-gate 				acollect(pargv[i]);
114*7c478bd9Sstevel@tonic-gate 		if (pargv)
115*7c478bd9Sstevel@tonic-gate 			blkfree(pargv), pargv = 0;
116*7c478bd9Sstevel@tonic-gate #ifdef GDEBUG
117*7c478bd9Sstevel@tonic-gate 		printf("acollect done\n");
118*7c478bd9Sstevel@tonic-gate #endif
119*7c478bd9Sstevel@tonic-gate 	} else if (noglob || eq(as, S_LBRA /* "{" */) ||
120*7c478bd9Sstevel@tonic-gate 			eq(as, S_BRABRA /* "{}" */)) {
121*7c478bd9Sstevel@tonic-gate 		Gcat(as, S_ /* "" */);
122*7c478bd9Sstevel@tonic-gate 		sort();
123*7c478bd9Sstevel@tonic-gate 	} else
124*7c478bd9Sstevel@tonic-gate 		acollect(as);
125*7c478bd9Sstevel@tonic-gate }
126*7c478bd9Sstevel@tonic-gate 
127*7c478bd9Sstevel@tonic-gate acollect(as)
128*7c478bd9Sstevel@tonic-gate 	register tchar *as;
129*7c478bd9Sstevel@tonic-gate {
130*7c478bd9Sstevel@tonic-gate 	register long ogargc = gargc;
131*7c478bd9Sstevel@tonic-gate 
132*7c478bd9Sstevel@tonic-gate #ifdef TRACE
133*7c478bd9Sstevel@tonic-gate 	tprintf("TRACE- acollect()\n");
134*7c478bd9Sstevel@tonic-gate #endif
135*7c478bd9Sstevel@tonic-gate 	gpathp = gpath; *gpathp = 0; globbed = 0;
136*7c478bd9Sstevel@tonic-gate 	expand(as);
137*7c478bd9Sstevel@tonic-gate 	if (gargc == ogargc) {
138*7c478bd9Sstevel@tonic-gate 		if (nonomatch) {
139*7c478bd9Sstevel@tonic-gate 			Gcat(as, S_ /* "" */);
140*7c478bd9Sstevel@tonic-gate 			sort();
141*7c478bd9Sstevel@tonic-gate 		}
142*7c478bd9Sstevel@tonic-gate 	} else
143*7c478bd9Sstevel@tonic-gate 		sort();
144*7c478bd9Sstevel@tonic-gate }
145*7c478bd9Sstevel@tonic-gate 
146*7c478bd9Sstevel@tonic-gate /*
147*7c478bd9Sstevel@tonic-gate  * String compare for qsort.  Also used by filec code in sh.file.c.
148*7c478bd9Sstevel@tonic-gate  */
149*7c478bd9Sstevel@tonic-gate sortscmp(a1, a2)
150*7c478bd9Sstevel@tonic-gate 	tchar **a1, **a2;
151*7c478bd9Sstevel@tonic-gate {
152*7c478bd9Sstevel@tonic-gate 
153*7c478bd9Sstevel@tonic-gate 	return (strcoll_(*a1, *a2));
154*7c478bd9Sstevel@tonic-gate }
155*7c478bd9Sstevel@tonic-gate 
156*7c478bd9Sstevel@tonic-gate expand(as)
157*7c478bd9Sstevel@tonic-gate 	tchar *as;
158*7c478bd9Sstevel@tonic-gate {
159*7c478bd9Sstevel@tonic-gate 	register tchar *cs;
160*7c478bd9Sstevel@tonic-gate 	register tchar *sgpathp, *oldcs;
161*7c478bd9Sstevel@tonic-gate 	struct stat stb;
162*7c478bd9Sstevel@tonic-gate 
163*7c478bd9Sstevel@tonic-gate #ifdef TRACE
164*7c478bd9Sstevel@tonic-gate 	tprintf("TRACE- expand()\n");
165*7c478bd9Sstevel@tonic-gate #endif
166*7c478bd9Sstevel@tonic-gate 	sgpathp = gpathp;
167*7c478bd9Sstevel@tonic-gate 	cs = as;
168*7c478bd9Sstevel@tonic-gate 	if (*cs == '~' && gpathp == gpath) {
169*7c478bd9Sstevel@tonic-gate 		addpath('~');
170*7c478bd9Sstevel@tonic-gate 		for (cs++; alnum(*cs) || *cs == '-'; )
171*7c478bd9Sstevel@tonic-gate 			addpath(*cs++);
172*7c478bd9Sstevel@tonic-gate 		if (!*cs || *cs == '/') {
173*7c478bd9Sstevel@tonic-gate 			if (gpathp != gpath + 1) {
174*7c478bd9Sstevel@tonic-gate 				*gpathp = 0;
175*7c478bd9Sstevel@tonic-gate 				if (gethdir(gpath + 1))
176*7c478bd9Sstevel@tonic-gate 					/*
177*7c478bd9Sstevel@tonic-gate 					 * modified from %s to %t
178*7c478bd9Sstevel@tonic-gate 					 */
179*7c478bd9Sstevel@tonic-gate 					error("Unknown user: %t", gpath + 1);
180*7c478bd9Sstevel@tonic-gate 				(void) strcpy_(gpath, gpath + 1);
181*7c478bd9Sstevel@tonic-gate 			} else
182*7c478bd9Sstevel@tonic-gate 				(void) strcpy_(gpath,
183*7c478bd9Sstevel@tonic-gate 					value(S_home /* "home" */));
184*7c478bd9Sstevel@tonic-gate 			gpathp = strend(gpath);
185*7c478bd9Sstevel@tonic-gate 		}
186*7c478bd9Sstevel@tonic-gate 	}
187*7c478bd9Sstevel@tonic-gate 	while (!isglob(*cs)) {
188*7c478bd9Sstevel@tonic-gate 		if (*cs == 0) {
189*7c478bd9Sstevel@tonic-gate 			if (!globbed)
190*7c478bd9Sstevel@tonic-gate 				Gcat(gpath, S_ /* "" */);
191*7c478bd9Sstevel@tonic-gate 			else if (lstat_(gpath, &stb) >= 0) {
192*7c478bd9Sstevel@tonic-gate 				Gcat(gpath, S_ /* "" */);
193*7c478bd9Sstevel@tonic-gate 				globcnt++;
194*7c478bd9Sstevel@tonic-gate 			}
195*7c478bd9Sstevel@tonic-gate 			goto endit;
196*7c478bd9Sstevel@tonic-gate 		}
197*7c478bd9Sstevel@tonic-gate 		addpath(*cs++);
198*7c478bd9Sstevel@tonic-gate 	}
199*7c478bd9Sstevel@tonic-gate 	oldcs = cs;
200*7c478bd9Sstevel@tonic-gate 	while (cs > as && *cs != '/')
201*7c478bd9Sstevel@tonic-gate 		cs--, gpathp--;
202*7c478bd9Sstevel@tonic-gate 	if (*cs == '/')
203*7c478bd9Sstevel@tonic-gate 		cs++, gpathp++;
204*7c478bd9Sstevel@tonic-gate 	*gpathp = 0;
205*7c478bd9Sstevel@tonic-gate 	if (*oldcs == '{') {
206*7c478bd9Sstevel@tonic-gate 		(void) execbrc(cs, NOSTR);
207*7c478bd9Sstevel@tonic-gate 		return;
208*7c478bd9Sstevel@tonic-gate 	}
209*7c478bd9Sstevel@tonic-gate 	matchdir_(cs);
210*7c478bd9Sstevel@tonic-gate endit:
211*7c478bd9Sstevel@tonic-gate 	gpathp = sgpathp;
212*7c478bd9Sstevel@tonic-gate 	*gpathp = 0;
213*7c478bd9Sstevel@tonic-gate }
214*7c478bd9Sstevel@tonic-gate 
215*7c478bd9Sstevel@tonic-gate matchdir_(pattern)
216*7c478bd9Sstevel@tonic-gate 	tchar *pattern;
217*7c478bd9Sstevel@tonic-gate {
218*7c478bd9Sstevel@tonic-gate 	struct stat stb;
219*7c478bd9Sstevel@tonic-gate 	register struct dirent *dp;
220*7c478bd9Sstevel@tonic-gate 	register DIR *dirp;
221*7c478bd9Sstevel@tonic-gate 	tchar curdir_[MAXNAMLEN+1];
222*7c478bd9Sstevel@tonic-gate 	int slproc = 0;
223*7c478bd9Sstevel@tonic-gate 
224*7c478bd9Sstevel@tonic-gate #ifdef TRACE
225*7c478bd9Sstevel@tonic-gate 	tprintf("TRACE- matchdir()\n");
226*7c478bd9Sstevel@tonic-gate #endif
227*7c478bd9Sstevel@tonic-gate 	/*
228*7c478bd9Sstevel@tonic-gate 	 * BSD's opendir would open "." if argument is NULL, but not S5
229*7c478bd9Sstevel@tonic-gate  */
230*7c478bd9Sstevel@tonic-gate 
231*7c478bd9Sstevel@tonic-gate 	if (*gpath == NULL)
232*7c478bd9Sstevel@tonic-gate 		dirp = opendir_(S_DOT /* "." */);
233*7c478bd9Sstevel@tonic-gate 	else
234*7c478bd9Sstevel@tonic-gate 		dirp = opendir_(gpath);
235*7c478bd9Sstevel@tonic-gate 	if (dirp == NULL) {
236*7c478bd9Sstevel@tonic-gate 		if (globbed)
237*7c478bd9Sstevel@tonic-gate 			return;
238*7c478bd9Sstevel@tonic-gate 		goto patherr2;
239*7c478bd9Sstevel@tonic-gate 	}
240*7c478bd9Sstevel@tonic-gate 	if (fstat(dirp->dd_fd, &stb) < 0)
241*7c478bd9Sstevel@tonic-gate 		goto patherr1;
242*7c478bd9Sstevel@tonic-gate 	if (!isdir(stb)) {
243*7c478bd9Sstevel@tonic-gate 		errno = ENOTDIR;
244*7c478bd9Sstevel@tonic-gate 		goto patherr1;
245*7c478bd9Sstevel@tonic-gate 	}
246*7c478bd9Sstevel@tonic-gate 	while ((dp = readdir(dirp)) != NULL) {
247*7c478bd9Sstevel@tonic-gate 
248*7c478bd9Sstevel@tonic-gate 		if (dp->d_ino == 0)
249*7c478bd9Sstevel@tonic-gate 			continue;
250*7c478bd9Sstevel@tonic-gate 		strtots(curdir_, dp->d_name);
251*7c478bd9Sstevel@tonic-gate 		slproc = 0;
252*7c478bd9Sstevel@tonic-gate 		if (match(curdir_, pattern, &slproc)) {
253*7c478bd9Sstevel@tonic-gate 			Gcat(gpath, curdir_);
254*7c478bd9Sstevel@tonic-gate 			globcnt++;
255*7c478bd9Sstevel@tonic-gate 		}
256*7c478bd9Sstevel@tonic-gate 	}
257*7c478bd9Sstevel@tonic-gate 	unsetfd(dirp->dd_fd);
258*7c478bd9Sstevel@tonic-gate 	closedir_(dirp);
259*7c478bd9Sstevel@tonic-gate 	return;
260*7c478bd9Sstevel@tonic-gate 
261*7c478bd9Sstevel@tonic-gate patherr1:
262*7c478bd9Sstevel@tonic-gate 	unsetfd(dirp->dd_fd);
263*7c478bd9Sstevel@tonic-gate 	closedir_(dirp);
264*7c478bd9Sstevel@tonic-gate patherr2:
265*7c478bd9Sstevel@tonic-gate 	Perror(gpath);
266*7c478bd9Sstevel@tonic-gate }
267*7c478bd9Sstevel@tonic-gate 
268*7c478bd9Sstevel@tonic-gate execbrc(p, s)
269*7c478bd9Sstevel@tonic-gate 	tchar *p, *s;
270*7c478bd9Sstevel@tonic-gate {
271*7c478bd9Sstevel@tonic-gate 	tchar restbuf[BUFSIZ + 2];
272*7c478bd9Sstevel@tonic-gate 	register tchar *pe, *pm, *pl;
273*7c478bd9Sstevel@tonic-gate 	int brclev = 0;
274*7c478bd9Sstevel@tonic-gate 	tchar *lm, savec, *sgpathp;
275*7c478bd9Sstevel@tonic-gate 	int slproc = 0;
276*7c478bd9Sstevel@tonic-gate 
277*7c478bd9Sstevel@tonic-gate #ifdef TRACE
278*7c478bd9Sstevel@tonic-gate 	tprintf("TRACE- execbrc()\n");
279*7c478bd9Sstevel@tonic-gate #endif
280*7c478bd9Sstevel@tonic-gate 	for (lm = restbuf; *p != '{'; *lm++ = *p++)
281*7c478bd9Sstevel@tonic-gate 		continue;
282*7c478bd9Sstevel@tonic-gate 	for (pe = ++p; *pe; pe++)
283*7c478bd9Sstevel@tonic-gate 	switch (*pe) {
284*7c478bd9Sstevel@tonic-gate 
285*7c478bd9Sstevel@tonic-gate 	case '{':
286*7c478bd9Sstevel@tonic-gate 		brclev++;
287*7c478bd9Sstevel@tonic-gate 		continue;
288*7c478bd9Sstevel@tonic-gate 
289*7c478bd9Sstevel@tonic-gate 	case '}':
290*7c478bd9Sstevel@tonic-gate 		if (brclev == 0)
291*7c478bd9Sstevel@tonic-gate 			goto pend;
292*7c478bd9Sstevel@tonic-gate 		brclev--;
293*7c478bd9Sstevel@tonic-gate 		continue;
294*7c478bd9Sstevel@tonic-gate 
295*7c478bd9Sstevel@tonic-gate 	case '[':
296*7c478bd9Sstevel@tonic-gate 		for (pe++; *pe && *pe != ']'; pe++)
297*7c478bd9Sstevel@tonic-gate 			continue;
298*7c478bd9Sstevel@tonic-gate 		if (!*pe)
299*7c478bd9Sstevel@tonic-gate 			error("Missing ]");
300*7c478bd9Sstevel@tonic-gate 		continue;
301*7c478bd9Sstevel@tonic-gate 	}
302*7c478bd9Sstevel@tonic-gate pend:
303*7c478bd9Sstevel@tonic-gate 	if (brclev || !*pe)
304*7c478bd9Sstevel@tonic-gate 		error("Missing }");
305*7c478bd9Sstevel@tonic-gate 	for (pl = pm = p; pm <= pe; pm++)
306*7c478bd9Sstevel@tonic-gate 	switch (*pm & (QUOTE|TRIM)) {
307*7c478bd9Sstevel@tonic-gate 
308*7c478bd9Sstevel@tonic-gate 	case '{':
309*7c478bd9Sstevel@tonic-gate 		brclev++;
310*7c478bd9Sstevel@tonic-gate 		continue;
311*7c478bd9Sstevel@tonic-gate 
312*7c478bd9Sstevel@tonic-gate 	case '}':
313*7c478bd9Sstevel@tonic-gate 		if (brclev) {
314*7c478bd9Sstevel@tonic-gate 			brclev--;
315*7c478bd9Sstevel@tonic-gate 			continue;
316*7c478bd9Sstevel@tonic-gate 		}
317*7c478bd9Sstevel@tonic-gate 		goto doit;
318*7c478bd9Sstevel@tonic-gate 
319*7c478bd9Sstevel@tonic-gate 	case ',':
320*7c478bd9Sstevel@tonic-gate 		if (brclev)
321*7c478bd9Sstevel@tonic-gate 			continue;
322*7c478bd9Sstevel@tonic-gate doit:
323*7c478bd9Sstevel@tonic-gate 		savec = *pm;
324*7c478bd9Sstevel@tonic-gate 		*pm = 0;
325*7c478bd9Sstevel@tonic-gate 		(void) strcpy_(lm, pl);
326*7c478bd9Sstevel@tonic-gate 		(void) strcat_(restbuf, pe + 1);
327*7c478bd9Sstevel@tonic-gate 		*pm = savec;
328*7c478bd9Sstevel@tonic-gate 		if (s == 0) {
329*7c478bd9Sstevel@tonic-gate 			sgpathp = gpathp;
330*7c478bd9Sstevel@tonic-gate 			expand(restbuf);
331*7c478bd9Sstevel@tonic-gate 			gpathp = sgpathp;
332*7c478bd9Sstevel@tonic-gate 			*gpathp = 0;
333*7c478bd9Sstevel@tonic-gate 		} else if (amatch(s, restbuf, &slproc))
334*7c478bd9Sstevel@tonic-gate 			return (1);
335*7c478bd9Sstevel@tonic-gate 		sort();
336*7c478bd9Sstevel@tonic-gate 		pl = pm + 1;
337*7c478bd9Sstevel@tonic-gate 		continue;
338*7c478bd9Sstevel@tonic-gate 
339*7c478bd9Sstevel@tonic-gate 	case '[':
340*7c478bd9Sstevel@tonic-gate 		for (pm++; *pm && *pm != ']'; pm++)
341*7c478bd9Sstevel@tonic-gate 			continue;
342*7c478bd9Sstevel@tonic-gate 		if (!*pm)
343*7c478bd9Sstevel@tonic-gate 			error("Missing ]");
344*7c478bd9Sstevel@tonic-gate 		continue;
345*7c478bd9Sstevel@tonic-gate 	}
346*7c478bd9Sstevel@tonic-gate 	return (0);
347*7c478bd9Sstevel@tonic-gate }
348*7c478bd9Sstevel@tonic-gate 
349*7c478bd9Sstevel@tonic-gate match(s, p, slproc)
350*7c478bd9Sstevel@tonic-gate 	tchar *s, *p;
351*7c478bd9Sstevel@tonic-gate 	int *slproc;
352*7c478bd9Sstevel@tonic-gate {
353*7c478bd9Sstevel@tonic-gate 	register int c;
354*7c478bd9Sstevel@tonic-gate 	register tchar *sentp;
355*7c478bd9Sstevel@tonic-gate 	tchar sglobbed = globbed;
356*7c478bd9Sstevel@tonic-gate 
357*7c478bd9Sstevel@tonic-gate #ifdef TRACE
358*7c478bd9Sstevel@tonic-gate 	tprintf("TRACE- match()\n");
359*7c478bd9Sstevel@tonic-gate #endif
360*7c478bd9Sstevel@tonic-gate 	if (*s == '.' && *p != '.')
361*7c478bd9Sstevel@tonic-gate 		return (0);
362*7c478bd9Sstevel@tonic-gate 	sentp = entp;
363*7c478bd9Sstevel@tonic-gate 	entp = s;
364*7c478bd9Sstevel@tonic-gate 	c = amatch(s, p, slproc);
365*7c478bd9Sstevel@tonic-gate 	entp = sentp;
366*7c478bd9Sstevel@tonic-gate 	globbed = sglobbed;
367*7c478bd9Sstevel@tonic-gate 	return (c);
368*7c478bd9Sstevel@tonic-gate }
369*7c478bd9Sstevel@tonic-gate 
370*7c478bd9Sstevel@tonic-gate amatch(s, p, slproc)
371*7c478bd9Sstevel@tonic-gate 	register tchar *s, *p;
372*7c478bd9Sstevel@tonic-gate 	int *slproc;
373*7c478bd9Sstevel@tonic-gate {
374*7c478bd9Sstevel@tonic-gate 	register int scc;
375*7c478bd9Sstevel@tonic-gate 	int ok, lc;
376*7c478bd9Sstevel@tonic-gate 	tchar *sgpathp;
377*7c478bd9Sstevel@tonic-gate 	struct stat stb;
378*7c478bd9Sstevel@tonic-gate 	int c, cc;
379*7c478bd9Sstevel@tonic-gate 
380*7c478bd9Sstevel@tonic-gate #ifdef TRACE
381*7c478bd9Sstevel@tonic-gate 	tprintf("TRACE- amatch()\n");
382*7c478bd9Sstevel@tonic-gate #endif
383*7c478bd9Sstevel@tonic-gate 	globbed = 1;
384*7c478bd9Sstevel@tonic-gate 	for (;;) {
385*7c478bd9Sstevel@tonic-gate 		scc = *s++ & TRIM;
386*7c478bd9Sstevel@tonic-gate 		switch (c = *p++) {
387*7c478bd9Sstevel@tonic-gate 
388*7c478bd9Sstevel@tonic-gate 		case '{':
389*7c478bd9Sstevel@tonic-gate 			return (execbrc(p - 1, s - 1));
390*7c478bd9Sstevel@tonic-gate 
391*7c478bd9Sstevel@tonic-gate 		case '[':
392*7c478bd9Sstevel@tonic-gate 			ok = 0;
393*7c478bd9Sstevel@tonic-gate 			lc = TRIM;
394*7c478bd9Sstevel@tonic-gate 			while (cc = *p++) {
395*7c478bd9Sstevel@tonic-gate 				if (cc == ']') {
396*7c478bd9Sstevel@tonic-gate 					if (ok)
397*7c478bd9Sstevel@tonic-gate 						break;
398*7c478bd9Sstevel@tonic-gate 					return (0);
399*7c478bd9Sstevel@tonic-gate 				}
400*7c478bd9Sstevel@tonic-gate 				if (cc == '-') {
401*7c478bd9Sstevel@tonic-gate #ifdef MBCHAR
402*7c478bd9Sstevel@tonic-gate 					wchar_t rc = *p++;
403*7c478bd9Sstevel@tonic-gate 					if (rc == ']') {
404*7c478bd9Sstevel@tonic-gate 						p--;
405*7c478bd9Sstevel@tonic-gate 						continue;
406*7c478bd9Sstevel@tonic-gate 					}
407*7c478bd9Sstevel@tonic-gate 					/*
408*7c478bd9Sstevel@tonic-gate 					 * Both ends of the char range
409*7c478bd9Sstevel@tonic-gate 					 * must belong to the same codeset.
410*7c478bd9Sstevel@tonic-gate 					 */
411*7c478bd9Sstevel@tonic-gate 					if (sh_bracket_exp(scc, lc, rc))
412*7c478bd9Sstevel@tonic-gate 						ok++;
413*7c478bd9Sstevel@tonic-gate #else /* !MBCHAR */
414*7c478bd9Sstevel@tonic-gate 					if (lc <= scc && scc <= (int) *p++)
415*7c478bd9Sstevel@tonic-gate 						ok++;
416*7c478bd9Sstevel@tonic-gate #endif /* !MBCHAR */
417*7c478bd9Sstevel@tonic-gate 				} else
418*7c478bd9Sstevel@tonic-gate 					if (scc == (lc = cc))
419*7c478bd9Sstevel@tonic-gate 						ok++;
420*7c478bd9Sstevel@tonic-gate 			}
421*7c478bd9Sstevel@tonic-gate 			if (cc == 0)
422*7c478bd9Sstevel@tonic-gate 				error("Missing ]");
423*7c478bd9Sstevel@tonic-gate 			continue;
424*7c478bd9Sstevel@tonic-gate 
425*7c478bd9Sstevel@tonic-gate 		case '*':
426*7c478bd9Sstevel@tonic-gate 			if (!*p)
427*7c478bd9Sstevel@tonic-gate 				return (1);
428*7c478bd9Sstevel@tonic-gate 			if (*p == '/') {
429*7c478bd9Sstevel@tonic-gate 				p++;
430*7c478bd9Sstevel@tonic-gate 				goto slash;
431*7c478bd9Sstevel@tonic-gate 			} else if (*p == '*') {
432*7c478bd9Sstevel@tonic-gate 				s--;
433*7c478bd9Sstevel@tonic-gate 				continue;
434*7c478bd9Sstevel@tonic-gate 			}
435*7c478bd9Sstevel@tonic-gate 
436*7c478bd9Sstevel@tonic-gate 			for (s--; *s; s++)
437*7c478bd9Sstevel@tonic-gate 				if (amatch(s, p, slproc))
438*7c478bd9Sstevel@tonic-gate 					return (1);
439*7c478bd9Sstevel@tonic-gate 
440*7c478bd9Sstevel@tonic-gate 			return (0);
441*7c478bd9Sstevel@tonic-gate 
442*7c478bd9Sstevel@tonic-gate 		case 0:
443*7c478bd9Sstevel@tonic-gate 			return (scc == 0);
444*7c478bd9Sstevel@tonic-gate 
445*7c478bd9Sstevel@tonic-gate 		default:
446*7c478bd9Sstevel@tonic-gate 			if ((c & TRIM) != scc)
447*7c478bd9Sstevel@tonic-gate 				return (0);
448*7c478bd9Sstevel@tonic-gate 			continue;
449*7c478bd9Sstevel@tonic-gate 
450*7c478bd9Sstevel@tonic-gate 		case '?':
451*7c478bd9Sstevel@tonic-gate 			if (scc == 0)
452*7c478bd9Sstevel@tonic-gate 				return (0);
453*7c478bd9Sstevel@tonic-gate 			continue;
454*7c478bd9Sstevel@tonic-gate 
455*7c478bd9Sstevel@tonic-gate 		case '/':
456*7c478bd9Sstevel@tonic-gate 			if (scc)
457*7c478bd9Sstevel@tonic-gate 				return (0);
458*7c478bd9Sstevel@tonic-gate slash:
459*7c478bd9Sstevel@tonic-gate 			if (*slproc)	/* Need to expand "/" only once */
460*7c478bd9Sstevel@tonic-gate 				return (0);
461*7c478bd9Sstevel@tonic-gate 			else
462*7c478bd9Sstevel@tonic-gate 				*slproc = 1;
463*7c478bd9Sstevel@tonic-gate 
464*7c478bd9Sstevel@tonic-gate 			s = entp;
465*7c478bd9Sstevel@tonic-gate 			sgpathp = gpathp;
466*7c478bd9Sstevel@tonic-gate 			while (*s)
467*7c478bd9Sstevel@tonic-gate 				addpath(*s++);
468*7c478bd9Sstevel@tonic-gate 			addpath('/');
469*7c478bd9Sstevel@tonic-gate 			if (stat_(gpath, &stb) == 0 && isdir(stb))
470*7c478bd9Sstevel@tonic-gate 				if (*p == 0) {
471*7c478bd9Sstevel@tonic-gate 					Gcat(gpath, S_ /* "" */);
472*7c478bd9Sstevel@tonic-gate 					globcnt++;
473*7c478bd9Sstevel@tonic-gate 				} else
474*7c478bd9Sstevel@tonic-gate 					expand(p);
475*7c478bd9Sstevel@tonic-gate 			gpathp = sgpathp;
476*7c478bd9Sstevel@tonic-gate 			*gpathp = 0;
477*7c478bd9Sstevel@tonic-gate 			return (0);
478*7c478bd9Sstevel@tonic-gate 		}
479*7c478bd9Sstevel@tonic-gate 	}
480*7c478bd9Sstevel@tonic-gate }
481*7c478bd9Sstevel@tonic-gate 
482*7c478bd9Sstevel@tonic-gate Gmatch(s, p)
483*7c478bd9Sstevel@tonic-gate 	register tchar *s, *p;
484*7c478bd9Sstevel@tonic-gate {
485*7c478bd9Sstevel@tonic-gate 	register int scc;
486*7c478bd9Sstevel@tonic-gate 	int ok, lc;
487*7c478bd9Sstevel@tonic-gate 	int c, cc;
488*7c478bd9Sstevel@tonic-gate 
489*7c478bd9Sstevel@tonic-gate #ifdef TRACE
490*7c478bd9Sstevel@tonic-gate 	tprintf("TRACE- Gmatch()\n");
491*7c478bd9Sstevel@tonic-gate #endif
492*7c478bd9Sstevel@tonic-gate 	for (;;) {
493*7c478bd9Sstevel@tonic-gate 		scc = *s++ & TRIM;
494*7c478bd9Sstevel@tonic-gate 		switch (c = *p++) {
495*7c478bd9Sstevel@tonic-gate 
496*7c478bd9Sstevel@tonic-gate 		case '[':
497*7c478bd9Sstevel@tonic-gate 			ok = 0;
498*7c478bd9Sstevel@tonic-gate 			lc = TRIM;
499*7c478bd9Sstevel@tonic-gate 			while (cc = *p++) {
500*7c478bd9Sstevel@tonic-gate 				if (cc == ']') {
501*7c478bd9Sstevel@tonic-gate 					if (ok)
502*7c478bd9Sstevel@tonic-gate 						break;
503*7c478bd9Sstevel@tonic-gate 					return (0);
504*7c478bd9Sstevel@tonic-gate 				}
505*7c478bd9Sstevel@tonic-gate 				if (cc == '-') {
506*7c478bd9Sstevel@tonic-gate #ifdef MBCHAR
507*7c478bd9Sstevel@tonic-gate 					wchar_t rc = *p++;
508*7c478bd9Sstevel@tonic-gate 					/*
509*7c478bd9Sstevel@tonic-gate 					 * Both ends of the char range
510*7c478bd9Sstevel@tonic-gate 					 * must belong to the same codeset...
511*7c478bd9Sstevel@tonic-gate 					 */
512*7c478bd9Sstevel@tonic-gate 					if (sh_bracket_exp(scc, lc, rc))
513*7c478bd9Sstevel@tonic-gate 						ok++;
514*7c478bd9Sstevel@tonic-gate #else /* !MBCHAR */
515*7c478bd9Sstevel@tonic-gate 					if (lc <= scc && scc <= (int) *p++)
516*7c478bd9Sstevel@tonic-gate 						ok++;
517*7c478bd9Sstevel@tonic-gate #endif /* !MBCHAR */
518*7c478bd9Sstevel@tonic-gate 				} else
519*7c478bd9Sstevel@tonic-gate 					if (scc == (lc = cc))
520*7c478bd9Sstevel@tonic-gate 						ok++;
521*7c478bd9Sstevel@tonic-gate 			}
522*7c478bd9Sstevel@tonic-gate 			if (cc == 0)
523*7c478bd9Sstevel@tonic-gate 				bferr("Missing ]");
524*7c478bd9Sstevel@tonic-gate 			continue;
525*7c478bd9Sstevel@tonic-gate 
526*7c478bd9Sstevel@tonic-gate 		case '*':
527*7c478bd9Sstevel@tonic-gate 			if (!*p)
528*7c478bd9Sstevel@tonic-gate 				return (1);
529*7c478bd9Sstevel@tonic-gate 			for (s--; *s; s++)
530*7c478bd9Sstevel@tonic-gate 				if (Gmatch(s, p))
531*7c478bd9Sstevel@tonic-gate 					return (1);
532*7c478bd9Sstevel@tonic-gate 			return (0);
533*7c478bd9Sstevel@tonic-gate 
534*7c478bd9Sstevel@tonic-gate 		case 0:
535*7c478bd9Sstevel@tonic-gate 			return (scc == 0);
536*7c478bd9Sstevel@tonic-gate 
537*7c478bd9Sstevel@tonic-gate 		default:
538*7c478bd9Sstevel@tonic-gate 			if ((c & TRIM) != scc)
539*7c478bd9Sstevel@tonic-gate 				return (0);
540*7c478bd9Sstevel@tonic-gate 			continue;
541*7c478bd9Sstevel@tonic-gate 
542*7c478bd9Sstevel@tonic-gate 		case '?':
543*7c478bd9Sstevel@tonic-gate 			if (scc == 0)
544*7c478bd9Sstevel@tonic-gate 				return (0);
545*7c478bd9Sstevel@tonic-gate 			continue;
546*7c478bd9Sstevel@tonic-gate 
547*7c478bd9Sstevel@tonic-gate 		}
548*7c478bd9Sstevel@tonic-gate 	}
549*7c478bd9Sstevel@tonic-gate }
550*7c478bd9Sstevel@tonic-gate 
551*7c478bd9Sstevel@tonic-gate Gcat(s1, s2)
552*7c478bd9Sstevel@tonic-gate 	tchar *s1, *s2;
553*7c478bd9Sstevel@tonic-gate {
554*7c478bd9Sstevel@tonic-gate 	register tchar *p, *q;
555*7c478bd9Sstevel@tonic-gate 	int n;
556*7c478bd9Sstevel@tonic-gate 
557*7c478bd9Sstevel@tonic-gate #ifdef TRACE
558*7c478bd9Sstevel@tonic-gate 	tprintf("TRACE- Gcat()\n");
559*7c478bd9Sstevel@tonic-gate #endif
560*7c478bd9Sstevel@tonic-gate 	for (p = s1; *p++; )
561*7c478bd9Sstevel@tonic-gate 		;
562*7c478bd9Sstevel@tonic-gate 	for (q = s2; *q++; )
563*7c478bd9Sstevel@tonic-gate 		;
564*7c478bd9Sstevel@tonic-gate 	gnleft -= (n = (p - s1) + (q - s2) - 1);
565*7c478bd9Sstevel@tonic-gate 	if (gnleft <= 0 || ++gargc >= GAVSIZ)
566*7c478bd9Sstevel@tonic-gate 		error("Arguments too long");
567*7c478bd9Sstevel@tonic-gate 	gargv[gargc] = 0;
568*7c478bd9Sstevel@tonic-gate 	p = gargv[gargc - 1] = (tchar *) xalloc((unsigned)n*sizeof (tchar));
569*7c478bd9Sstevel@tonic-gate 
570*7c478bd9Sstevel@tonic-gate 	for (q = s1; *p++ = *q++; )
571*7c478bd9Sstevel@tonic-gate 		;
572*7c478bd9Sstevel@tonic-gate 	for (p--, q = s2; *p++ = *q++; )
573*7c478bd9Sstevel@tonic-gate 		;
574*7c478bd9Sstevel@tonic-gate }
575*7c478bd9Sstevel@tonic-gate 
576*7c478bd9Sstevel@tonic-gate addpath(c)
577*7c478bd9Sstevel@tonic-gate 	tchar c;
578*7c478bd9Sstevel@tonic-gate {
579*7c478bd9Sstevel@tonic-gate 
580*7c478bd9Sstevel@tonic-gate #ifdef TRACE
581*7c478bd9Sstevel@tonic-gate 	tprintf("TRACE- addpath()\n");
582*7c478bd9Sstevel@tonic-gate #endif
583*7c478bd9Sstevel@tonic-gate 	if (gpathp >= lastgpathp)
584*7c478bd9Sstevel@tonic-gate 		error("Pathname too long");
585*7c478bd9Sstevel@tonic-gate 	*gpathp++ = c & TRIM;
586*7c478bd9Sstevel@tonic-gate 	*gpathp = 0;
587*7c478bd9Sstevel@tonic-gate }
588*7c478bd9Sstevel@tonic-gate 
589*7c478bd9Sstevel@tonic-gate rscan(t, f)
590*7c478bd9Sstevel@tonic-gate 	register tchar **t;
591*7c478bd9Sstevel@tonic-gate 	int (*f)();
592*7c478bd9Sstevel@tonic-gate {
593*7c478bd9Sstevel@tonic-gate 	register tchar *p;
594*7c478bd9Sstevel@tonic-gate 
595*7c478bd9Sstevel@tonic-gate #ifdef TRACE
596*7c478bd9Sstevel@tonic-gate 	tprintf("TRACE- rscan()\n");
597*7c478bd9Sstevel@tonic-gate #endif
598*7c478bd9Sstevel@tonic-gate 	while (p = *t++)
599*7c478bd9Sstevel@tonic-gate 		while (*p)
600*7c478bd9Sstevel@tonic-gate 			(*f)(*p++);
601*7c478bd9Sstevel@tonic-gate }
602*7c478bd9Sstevel@tonic-gate 
603*7c478bd9Sstevel@tonic-gate trim(t)
604*7c478bd9Sstevel@tonic-gate 	register tchar **t;
605*7c478bd9Sstevel@tonic-gate {
606*7c478bd9Sstevel@tonic-gate 	register tchar *p;
607*7c478bd9Sstevel@tonic-gate 
608*7c478bd9Sstevel@tonic-gate #ifdef TRACE
609*7c478bd9Sstevel@tonic-gate 	tprintf("TRACE- trim()\n");
610*7c478bd9Sstevel@tonic-gate #endif
611*7c478bd9Sstevel@tonic-gate 	while (p = *t++)
612*7c478bd9Sstevel@tonic-gate 		while (*p)
613*7c478bd9Sstevel@tonic-gate 			*p++ &= TRIM;
614*7c478bd9Sstevel@tonic-gate }
615*7c478bd9Sstevel@tonic-gate 
616*7c478bd9Sstevel@tonic-gate tglob(t)
617*7c478bd9Sstevel@tonic-gate 	register tchar **t;
618*7c478bd9Sstevel@tonic-gate {
619*7c478bd9Sstevel@tonic-gate 	register tchar *p, c;
620*7c478bd9Sstevel@tonic-gate 
621*7c478bd9Sstevel@tonic-gate #ifdef TRACE
622*7c478bd9Sstevel@tonic-gate 	tprintf("TRACE- tglob()\n");
623*7c478bd9Sstevel@tonic-gate #endif
624*7c478bd9Sstevel@tonic-gate 	while (p = *t++) {
625*7c478bd9Sstevel@tonic-gate 		if (*p == '~')
626*7c478bd9Sstevel@tonic-gate 			gflag |= 2;
627*7c478bd9Sstevel@tonic-gate 		else if (*p == '{' && (p[1] == '\0' ||
628*7c478bd9Sstevel@tonic-gate 			p[1] == '}' && p[2] == '\0'))
629*7c478bd9Sstevel@tonic-gate 			continue;
630*7c478bd9Sstevel@tonic-gate 		while (c = *p++)
631*7c478bd9Sstevel@tonic-gate 			if (isglob(c))
632*7c478bd9Sstevel@tonic-gate 				gflag |= c == '{' ? 2 : 1;
633*7c478bd9Sstevel@tonic-gate 	}
634*7c478bd9Sstevel@tonic-gate }
635*7c478bd9Sstevel@tonic-gate 
636*7c478bd9Sstevel@tonic-gate tchar *
637*7c478bd9Sstevel@tonic-gate globone(str)
638*7c478bd9Sstevel@tonic-gate 	register tchar *str;
639*7c478bd9Sstevel@tonic-gate {
640*7c478bd9Sstevel@tonic-gate 	tchar *gv[2];
641*7c478bd9Sstevel@tonic-gate 	register tchar **gvp;
642*7c478bd9Sstevel@tonic-gate 	register tchar *cp;
643*7c478bd9Sstevel@tonic-gate 
644*7c478bd9Sstevel@tonic-gate #ifdef TRACE
645*7c478bd9Sstevel@tonic-gate 	tprintf("TRACE- globone()\n");
646*7c478bd9Sstevel@tonic-gate #endif
647*7c478bd9Sstevel@tonic-gate 	gv[0] = str;
648*7c478bd9Sstevel@tonic-gate 	gv[1] = 0;
649*7c478bd9Sstevel@tonic-gate 	gflag = 0;
650*7c478bd9Sstevel@tonic-gate 	tglob(gv);
651*7c478bd9Sstevel@tonic-gate 	if (gflag) {
652*7c478bd9Sstevel@tonic-gate 		gvp = glob(gv);
653*7c478bd9Sstevel@tonic-gate 		if (gvp == 0) {
654*7c478bd9Sstevel@tonic-gate 			setname(str);
655*7c478bd9Sstevel@tonic-gate 			bferr("No match");
656*7c478bd9Sstevel@tonic-gate 		}
657*7c478bd9Sstevel@tonic-gate 		cp = *gvp++;
658*7c478bd9Sstevel@tonic-gate 		if (cp == 0)
659*7c478bd9Sstevel@tonic-gate 			cp = S_ /* "" */;
660*7c478bd9Sstevel@tonic-gate 		else if (*gvp) {
661*7c478bd9Sstevel@tonic-gate 			setname(str);
662*7c478bd9Sstevel@tonic-gate 			bferr("Ambiguous");
663*7c478bd9Sstevel@tonic-gate 		} else
664*7c478bd9Sstevel@tonic-gate 			cp = strip(cp);
665*7c478bd9Sstevel@tonic-gate /*
666*7c478bd9Sstevel@tonic-gate 		if (cp == 0 || *gvp) {
667*7c478bd9Sstevel@tonic-gate 			setname(str);
668*7c478bd9Sstevel@tonic-gate 			bferr(cp ? "Ambiguous" : "No output");
669*7c478bd9Sstevel@tonic-gate 		}
670*7c478bd9Sstevel@tonic-gate */
671*7c478bd9Sstevel@tonic-gate 		xfree((char *)gargv); gargv = 0;
672*7c478bd9Sstevel@tonic-gate 	} else {
673*7c478bd9Sstevel@tonic-gate 		trim(gv);
674*7c478bd9Sstevel@tonic-gate 		cp = savestr(gv[0]);
675*7c478bd9Sstevel@tonic-gate 	}
676*7c478bd9Sstevel@tonic-gate 	return (cp);
677*7c478bd9Sstevel@tonic-gate }
678*7c478bd9Sstevel@tonic-gate 
679*7c478bd9Sstevel@tonic-gate /*
680*7c478bd9Sstevel@tonic-gate  * Command substitute cp.  If literal, then this is
681*7c478bd9Sstevel@tonic-gate  * a substitution from a << redirection, and so we should
682*7c478bd9Sstevel@tonic-gate  * not crunch blanks and tabs, separating words only at newlines.
683*7c478bd9Sstevel@tonic-gate  */
684*7c478bd9Sstevel@tonic-gate tchar **
685*7c478bd9Sstevel@tonic-gate dobackp(cp, literal)
686*7c478bd9Sstevel@tonic-gate 	tchar *cp;
687*7c478bd9Sstevel@tonic-gate 	bool literal;
688*7c478bd9Sstevel@tonic-gate {
689*7c478bd9Sstevel@tonic-gate 	register tchar *lp, *rp;
690*7c478bd9Sstevel@tonic-gate 	tchar *ep;
691*7c478bd9Sstevel@tonic-gate 	tchar word[BUFSIZ];
692*7c478bd9Sstevel@tonic-gate 	tchar *apargv[GAVSIZ + 2];
693*7c478bd9Sstevel@tonic-gate 
694*7c478bd9Sstevel@tonic-gate #ifdef TRACE
695*7c478bd9Sstevel@tonic-gate 	tprintf("TRACE- dobackp()\n");
696*7c478bd9Sstevel@tonic-gate #endif
697*7c478bd9Sstevel@tonic-gate 	if (pargv) {
698*7c478bd9Sstevel@tonic-gate 		blkfree(pargv);
699*7c478bd9Sstevel@tonic-gate 	}
700*7c478bd9Sstevel@tonic-gate 	pargv = apargv;
701*7c478bd9Sstevel@tonic-gate 	pargv[0] = NOSTR;
702*7c478bd9Sstevel@tonic-gate 	pargcp = pargs = word;
703*7c478bd9Sstevel@tonic-gate 	pargc = 0;
704*7c478bd9Sstevel@tonic-gate 	pnleft = BUFSIZ - 4;
705*7c478bd9Sstevel@tonic-gate 	for (;;) {
706*7c478bd9Sstevel@tonic-gate 		for (lp = cp; *lp != '`'; lp++) {
707*7c478bd9Sstevel@tonic-gate 			if (*lp == 0) {
708*7c478bd9Sstevel@tonic-gate 				if (pargcp != pargs)
709*7c478bd9Sstevel@tonic-gate 					pword();
710*7c478bd9Sstevel@tonic-gate #ifdef GDEBUG
711*7c478bd9Sstevel@tonic-gate 				printf("leaving dobackp\n");
712*7c478bd9Sstevel@tonic-gate #endif
713*7c478bd9Sstevel@tonic-gate 				return (pargv = copyblk(pargv));
714*7c478bd9Sstevel@tonic-gate 			}
715*7c478bd9Sstevel@tonic-gate 			psave(*lp);
716*7c478bd9Sstevel@tonic-gate 		}
717*7c478bd9Sstevel@tonic-gate 		lp++;
718*7c478bd9Sstevel@tonic-gate 		for (rp = lp; *rp && *rp != '`'; rp++)
719*7c478bd9Sstevel@tonic-gate 			if (*rp == '\\') {
720*7c478bd9Sstevel@tonic-gate 				rp++;
721*7c478bd9Sstevel@tonic-gate 				if (!*rp)
722*7c478bd9Sstevel@tonic-gate 					goto oops;
723*7c478bd9Sstevel@tonic-gate 			}
724*7c478bd9Sstevel@tonic-gate 		if (!*rp)
725*7c478bd9Sstevel@tonic-gate oops:
726*7c478bd9Sstevel@tonic-gate 			error("Unmatched `");
727*7c478bd9Sstevel@tonic-gate 		ep = savestr(lp);
728*7c478bd9Sstevel@tonic-gate 		ep[rp - lp] = 0;
729*7c478bd9Sstevel@tonic-gate 		backeval(ep, literal);
730*7c478bd9Sstevel@tonic-gate #ifdef GDEBUG
731*7c478bd9Sstevel@tonic-gate 		printf("back from backeval\n");
732*7c478bd9Sstevel@tonic-gate #endif
733*7c478bd9Sstevel@tonic-gate 		cp = rp + 1;
734*7c478bd9Sstevel@tonic-gate 	}
735*7c478bd9Sstevel@tonic-gate }
736*7c478bd9Sstevel@tonic-gate 
737*7c478bd9Sstevel@tonic-gate backeval(cp, literal)
738*7c478bd9Sstevel@tonic-gate 	tchar *cp;
739*7c478bd9Sstevel@tonic-gate 	bool literal;
740*7c478bd9Sstevel@tonic-gate {
741*7c478bd9Sstevel@tonic-gate 	int pvec[2];
742*7c478bd9Sstevel@tonic-gate 	int quoted = (literal || (cp[0] & QUOTE)) ? QUOTE : 0;
743*7c478bd9Sstevel@tonic-gate 	tchar ibuf[BUFSIZ];
744*7c478bd9Sstevel@tonic-gate 	register int icnt = 0, c;
745*7c478bd9Sstevel@tonic-gate 	register tchar *ip;
746*7c478bd9Sstevel@tonic-gate 	bool hadnl = 0;
747*7c478bd9Sstevel@tonic-gate 	tchar *fakecom[2];
748*7c478bd9Sstevel@tonic-gate 	struct command faket;
749*7c478bd9Sstevel@tonic-gate 
750*7c478bd9Sstevel@tonic-gate #ifdef TRACE
751*7c478bd9Sstevel@tonic-gate 	tprintf("TRACE- backeval()\n");
752*7c478bd9Sstevel@tonic-gate #endif
753*7c478bd9Sstevel@tonic-gate 	faket.t_dtyp = TCOM;
754*7c478bd9Sstevel@tonic-gate 	faket.t_dflg = 0;
755*7c478bd9Sstevel@tonic-gate 	faket.t_dlef = 0;
756*7c478bd9Sstevel@tonic-gate 	faket.t_drit = 0;
757*7c478bd9Sstevel@tonic-gate 	faket.t_dspr = 0;
758*7c478bd9Sstevel@tonic-gate 	faket.t_dcom = fakecom;
759*7c478bd9Sstevel@tonic-gate 	fakecom[0] = S_QPPPQ; /* "` ... `" */;
760*7c478bd9Sstevel@tonic-gate 	fakecom[1] = 0;
761*7c478bd9Sstevel@tonic-gate 	/*
762*7c478bd9Sstevel@tonic-gate 	 * We do the psave job to temporarily change the current job
763*7c478bd9Sstevel@tonic-gate 	 * so that the following fork is considered a separate job.
764*7c478bd9Sstevel@tonic-gate 	 * This is so that when backquotes are used in a
765*7c478bd9Sstevel@tonic-gate 	 * builtin function that calls glob the "current job" is not corrupted.
766*7c478bd9Sstevel@tonic-gate 	 * We only need one level of pushed jobs as long as we are sure to
767*7c478bd9Sstevel@tonic-gate 	 * fork here.
768*7c478bd9Sstevel@tonic-gate 	 */
769*7c478bd9Sstevel@tonic-gate 	psavejob();
770*7c478bd9Sstevel@tonic-gate 	/*
771*7c478bd9Sstevel@tonic-gate 	 * It would be nicer if we could integrate this redirection more
772*7c478bd9Sstevel@tonic-gate 	 * with the routines in sh.sem.c by doing a fake execute on a builtin
773*7c478bd9Sstevel@tonic-gate 	 * function that was piped out.
774*7c478bd9Sstevel@tonic-gate 	 */
775*7c478bd9Sstevel@tonic-gate 	mypipe(pvec);
776*7c478bd9Sstevel@tonic-gate 	if (pfork(&faket, -1) == 0) {
777*7c478bd9Sstevel@tonic-gate 		struct wordent paraml;
778*7c478bd9Sstevel@tonic-gate 		struct command *t;
779*7c478bd9Sstevel@tonic-gate 		tchar oHIST;
780*7c478bd9Sstevel@tonic-gate 
781*7c478bd9Sstevel@tonic-gate 		new_process();
782*7c478bd9Sstevel@tonic-gate 		(void) close(pvec[0]);
783*7c478bd9Sstevel@tonic-gate 		unsetfd(pvec[0]);
784*7c478bd9Sstevel@tonic-gate 		(void) dmove(pvec[1], 1);
785*7c478bd9Sstevel@tonic-gate 		(void) dmove(SHDIAG, 2);
786*7c478bd9Sstevel@tonic-gate 		reinitdesc(0, NULL);
787*7c478bd9Sstevel@tonic-gate 		arginp = cp;
788*7c478bd9Sstevel@tonic-gate 		while (*cp)
789*7c478bd9Sstevel@tonic-gate 			*cp++ &= TRIM;
790*7c478bd9Sstevel@tonic-gate 		/*
791*7c478bd9Sstevel@tonic-gate 		 *	disable history subsitution in sub-shell
792*7c478bd9Sstevel@tonic-gate 		 *  of `` evaluation prevents possible
793*7c478bd9Sstevel@tonic-gate 		 *  infinite recursion of `` evaluation
794*7c478bd9Sstevel@tonic-gate 		 */
795*7c478bd9Sstevel@tonic-gate 		oHIST = HIST;
796*7c478bd9Sstevel@tonic-gate 		HIST = 0;
797*7c478bd9Sstevel@tonic-gate 		(void) lex(&paraml);
798*7c478bd9Sstevel@tonic-gate 		HIST = oHIST;
799*7c478bd9Sstevel@tonic-gate 		if (err)
800*7c478bd9Sstevel@tonic-gate 			error("%s", gettext(err));
801*7c478bd9Sstevel@tonic-gate 		alias(&paraml);
802*7c478bd9Sstevel@tonic-gate 		t = syntax(paraml.next, &paraml, 0);
803*7c478bd9Sstevel@tonic-gate 		if (err)
804*7c478bd9Sstevel@tonic-gate 			error("%s", gettext(err));
805*7c478bd9Sstevel@tonic-gate 		if (t)
806*7c478bd9Sstevel@tonic-gate 			t->t_dflg |= FPAR;
807*7c478bd9Sstevel@tonic-gate 		(void) signal(SIGTSTP, SIG_IGN);
808*7c478bd9Sstevel@tonic-gate 		(void) signal(SIGTTIN, SIG_IGN);
809*7c478bd9Sstevel@tonic-gate 		(void) signal(SIGTTOU, SIG_IGN);
810*7c478bd9Sstevel@tonic-gate 		execute(t, -1);
811*7c478bd9Sstevel@tonic-gate 		exitstat();
812*7c478bd9Sstevel@tonic-gate 	}
813*7c478bd9Sstevel@tonic-gate 	xfree(cp);
814*7c478bd9Sstevel@tonic-gate 	(void) close(pvec[1]);
815*7c478bd9Sstevel@tonic-gate 	unsetfd(pvec[1]);
816*7c478bd9Sstevel@tonic-gate 	do {
817*7c478bd9Sstevel@tonic-gate 		int cnt = 0;
818*7c478bd9Sstevel@tonic-gate 		for (;;) {
819*7c478bd9Sstevel@tonic-gate 			if (icnt == 0) {
820*7c478bd9Sstevel@tonic-gate 				ip = ibuf;
821*7c478bd9Sstevel@tonic-gate 				icnt = read_(pvec[0], ip, BUFSIZ);
822*7c478bd9Sstevel@tonic-gate 				if (icnt <= 0) {
823*7c478bd9Sstevel@tonic-gate 					c = -1;
824*7c478bd9Sstevel@tonic-gate 					break;
825*7c478bd9Sstevel@tonic-gate 				}
826*7c478bd9Sstevel@tonic-gate 			}
827*7c478bd9Sstevel@tonic-gate 			if (hadnl)
828*7c478bd9Sstevel@tonic-gate 				break;
829*7c478bd9Sstevel@tonic-gate 			--icnt;
830*7c478bd9Sstevel@tonic-gate 			c = (*ip++ & TRIM);
831*7c478bd9Sstevel@tonic-gate 			if (c == 0)
832*7c478bd9Sstevel@tonic-gate 				break;
833*7c478bd9Sstevel@tonic-gate 			if (c == '\n') {
834*7c478bd9Sstevel@tonic-gate 				/*
835*7c478bd9Sstevel@tonic-gate 				 * Continue around the loop one
836*7c478bd9Sstevel@tonic-gate 				 * more time, so that we can eat
837*7c478bd9Sstevel@tonic-gate 				 * the last newline without terminating
838*7c478bd9Sstevel@tonic-gate 				 * this word.
839*7c478bd9Sstevel@tonic-gate 				 */
840*7c478bd9Sstevel@tonic-gate 				hadnl = 1;
841*7c478bd9Sstevel@tonic-gate 				continue;
842*7c478bd9Sstevel@tonic-gate 			}
843*7c478bd9Sstevel@tonic-gate 			if (!quoted && issp(c))
844*7c478bd9Sstevel@tonic-gate 				break;
845*7c478bd9Sstevel@tonic-gate 			cnt++;
846*7c478bd9Sstevel@tonic-gate 			psave(c | quoted);
847*7c478bd9Sstevel@tonic-gate 		}
848*7c478bd9Sstevel@tonic-gate 		/*
849*7c478bd9Sstevel@tonic-gate 		 * Unless at end-of-file, we will form a new word
850*7c478bd9Sstevel@tonic-gate 		 * here if there were characters in the word, or in
851*7c478bd9Sstevel@tonic-gate 		 * any case when we take text literally.  If
852*7c478bd9Sstevel@tonic-gate 		 * we didn't make empty words here when literal was
853*7c478bd9Sstevel@tonic-gate 		 * set then we would lose blank lines.
854*7c478bd9Sstevel@tonic-gate 		 */
855*7c478bd9Sstevel@tonic-gate 		if (c != -1 && (cnt || literal)) {
856*7c478bd9Sstevel@tonic-gate 			if (pargc == GAVSIZ)
857*7c478bd9Sstevel@tonic-gate 				break;
858*7c478bd9Sstevel@tonic-gate 			pword();
859*7c478bd9Sstevel@tonic-gate 		}
860*7c478bd9Sstevel@tonic-gate 		hadnl = 0;
861*7c478bd9Sstevel@tonic-gate 	} while (c >= 0);
862*7c478bd9Sstevel@tonic-gate #ifdef GDEBUG
863*7c478bd9Sstevel@tonic-gate 	printf("done in backeval, pvec: %d %d\n", pvec[0], pvec[1]);
864*7c478bd9Sstevel@tonic-gate 	printf("also c = %c <%o>\n", (tchar) c, (tchar) c);
865*7c478bd9Sstevel@tonic-gate #endif
866*7c478bd9Sstevel@tonic-gate 	(void) close(pvec[0]);
867*7c478bd9Sstevel@tonic-gate 	unsetfd(pvec[0]);
868*7c478bd9Sstevel@tonic-gate 	pwait();
869*7c478bd9Sstevel@tonic-gate 	prestjob();
870*7c478bd9Sstevel@tonic-gate }
871*7c478bd9Sstevel@tonic-gate 
872*7c478bd9Sstevel@tonic-gate psave(c)
873*7c478bd9Sstevel@tonic-gate 	tchar c;
874*7c478bd9Sstevel@tonic-gate {
875*7c478bd9Sstevel@tonic-gate #ifdef TRACE
876*7c478bd9Sstevel@tonic-gate 	tprintf("TRACE- psave()\n");
877*7c478bd9Sstevel@tonic-gate #endif
878*7c478bd9Sstevel@tonic-gate 
879*7c478bd9Sstevel@tonic-gate 	if (--pnleft <= 0)
880*7c478bd9Sstevel@tonic-gate 		error("Word too long");
881*7c478bd9Sstevel@tonic-gate 	*pargcp++ = c;
882*7c478bd9Sstevel@tonic-gate }
883*7c478bd9Sstevel@tonic-gate 
884*7c478bd9Sstevel@tonic-gate pword()
885*7c478bd9Sstevel@tonic-gate {
886*7c478bd9Sstevel@tonic-gate #ifdef TRACE
887*7c478bd9Sstevel@tonic-gate 	tprintf("TRACE- pword()\n");
888*7c478bd9Sstevel@tonic-gate #endif
889*7c478bd9Sstevel@tonic-gate 
890*7c478bd9Sstevel@tonic-gate 	psave(0);
891*7c478bd9Sstevel@tonic-gate 	if (pargc == GAVSIZ)
892*7c478bd9Sstevel@tonic-gate 		error("Too many words from ``");
893*7c478bd9Sstevel@tonic-gate 	pargv[pargc++] = savestr(pargs);
894*7c478bd9Sstevel@tonic-gate 	pargv[pargc] = NOSTR;
895*7c478bd9Sstevel@tonic-gate #ifdef GDEBUG
896*7c478bd9Sstevel@tonic-gate 	printf("got word %t\n", pargv[pargc-1]);
897*7c478bd9Sstevel@tonic-gate #endif
898*7c478bd9Sstevel@tonic-gate 	pargcp = pargs;
899*7c478bd9Sstevel@tonic-gate 	pnleft = BUFSIZ - 4;
900*7c478bd9Sstevel@tonic-gate }
901*7c478bd9Sstevel@tonic-gate 
902*7c478bd9Sstevel@tonic-gate 
903*7c478bd9Sstevel@tonic-gate 
904*7c478bd9Sstevel@tonic-gate /*
905*7c478bd9Sstevel@tonic-gate  * returns pathname of the form dir/file;
906*7c478bd9Sstevel@tonic-gate  *  dir is a null-terminated string;
907*7c478bd9Sstevel@tonic-gate  */
908*7c478bd9Sstevel@tonic-gate char *
909*7c478bd9Sstevel@tonic-gate makename(dir, file)
910*7c478bd9Sstevel@tonic-gate 	char *dir;
911*7c478bd9Sstevel@tonic-gate 	char *file;
912*7c478bd9Sstevel@tonic-gate {
913*7c478bd9Sstevel@tonic-gate 	/*
914*7c478bd9Sstevel@tonic-gate 	 *  Maximum length of a
915*7c478bd9Sstevel@tonic-gate 	 *  file/dir name in ls-command;
916*7c478bd9Sstevel@tonic-gate 	 *  dfile is static as this is returned
917*7c478bd9Sstevel@tonic-gate 	 *  by makename();
918*7c478bd9Sstevel@tonic-gate 	 */
919*7c478bd9Sstevel@tonic-gate 	static char dfile[MAXNAMLEN];
920*7c478bd9Sstevel@tonic-gate 
921*7c478bd9Sstevel@tonic-gate 	register char *dp, *fp;
922*7c478bd9Sstevel@tonic-gate 
923*7c478bd9Sstevel@tonic-gate 	dp = dfile;
924*7c478bd9Sstevel@tonic-gate 	fp = dir;
925*7c478bd9Sstevel@tonic-gate 	while (*fp)
926*7c478bd9Sstevel@tonic-gate 		*dp++ = *fp++;
927*7c478bd9Sstevel@tonic-gate 	if (dp > dfile && *(dp - 1) != '/')
928*7c478bd9Sstevel@tonic-gate 		*dp++ = '/';
929*7c478bd9Sstevel@tonic-gate 	fp = file;
930*7c478bd9Sstevel@tonic-gate 	while (*fp)
931*7c478bd9Sstevel@tonic-gate 		*dp++ = *fp++;
932*7c478bd9Sstevel@tonic-gate 	*dp = '\0';
933*7c478bd9Sstevel@tonic-gate 	/*
934*7c478bd9Sstevel@tonic-gate 	 * dfile points to the absolute pathname. We are
935*7c478bd9Sstevel@tonic-gate 	 * only interested in the last component.
936*7c478bd9Sstevel@tonic-gate 	 */
937*7c478bd9Sstevel@tonic-gate 	return (rindex(dfile, '/') + 1);
938*7c478bd9Sstevel@tonic-gate }
939*7c478bd9Sstevel@tonic-gate 
940*7c478bd9Sstevel@tonic-gate sh_bracket_exp(t_ch, t_fch, t_lch)
941*7c478bd9Sstevel@tonic-gate tchar	t_ch;
942*7c478bd9Sstevel@tonic-gate tchar	t_fch;
943*7c478bd9Sstevel@tonic-gate tchar	t_lch;
944*7c478bd9Sstevel@tonic-gate {
945*7c478bd9Sstevel@tonic-gate 	char	t_char[MB_LEN_MAX + 1];
946*7c478bd9Sstevel@tonic-gate 	char	t_patan[MB_LEN_MAX * 2 + 8];
947*7c478bd9Sstevel@tonic-gate 	char	*p;
948*7c478bd9Sstevel@tonic-gate 	int	i;
949*7c478bd9Sstevel@tonic-gate 
950*7c478bd9Sstevel@tonic-gate 	if ((t_ch == t_fch) || (t_ch == t_lch))
951*7c478bd9Sstevel@tonic-gate 		return(1);
952*7c478bd9Sstevel@tonic-gate 
953*7c478bd9Sstevel@tonic-gate 	p = t_patan;
954*7c478bd9Sstevel@tonic-gate 	if ((i = wctomb(t_char, (wchar_t)t_ch)) <= 0)
955*7c478bd9Sstevel@tonic-gate 		return(0);
956*7c478bd9Sstevel@tonic-gate 	t_char[i] = 0;
957*7c478bd9Sstevel@tonic-gate 
958*7c478bd9Sstevel@tonic-gate 	*p++ = '[';
959*7c478bd9Sstevel@tonic-gate 	if ((i = wctomb(p, (wchar_t)t_fch)) <= 0)
960*7c478bd9Sstevel@tonic-gate 		return(0);
961*7c478bd9Sstevel@tonic-gate 	p += i;
962*7c478bd9Sstevel@tonic-gate 	*p++ = '-';
963*7c478bd9Sstevel@tonic-gate 	if ((i = wctomb(p, (wchar_t)t_lch)) <= 0)
964*7c478bd9Sstevel@tonic-gate 		return(0);
965*7c478bd9Sstevel@tonic-gate 	p += i;
966*7c478bd9Sstevel@tonic-gate 	*p++ = ']';
967*7c478bd9Sstevel@tonic-gate 	*p = 0;
968*7c478bd9Sstevel@tonic-gate 
969*7c478bd9Sstevel@tonic-gate 	if (fnmatch(t_patan, t_char, FNM_NOESCAPE))
970*7c478bd9Sstevel@tonic-gate 		return(0);
971*7c478bd9Sstevel@tonic-gate 	return(1);
972*7c478bd9Sstevel@tonic-gate }
973