xref: /freebsd/contrib/tcsh/sh.glob.c (revision 45e5710b)
145e5710bSMark Peek /*
2c80476e4SDavid E. O'Brien  * sh.glob.c: Regular expression expansion
3c80476e4SDavid E. O'Brien  */
4c80476e4SDavid E. O'Brien /*-
5c80476e4SDavid E. O'Brien  * Copyright (c) 1980, 1991 The Regents of the University of California.
6c80476e4SDavid E. O'Brien  * All rights reserved.
7c80476e4SDavid E. O'Brien  *
8c80476e4SDavid E. O'Brien  * Redistribution and use in source and binary forms, with or without
9c80476e4SDavid E. O'Brien  * modification, are permitted provided that the following conditions
10c80476e4SDavid E. O'Brien  * are met:
11c80476e4SDavid E. O'Brien  * 1. Redistributions of source code must retain the above copyright
12c80476e4SDavid E. O'Brien  *    notice, this list of conditions and the following disclaimer.
13c80476e4SDavid E. O'Brien  * 2. Redistributions in binary form must reproduce the above copyright
14c80476e4SDavid E. O'Brien  *    notice, this list of conditions and the following disclaimer in the
15c80476e4SDavid E. O'Brien  *    documentation and/or other materials provided with the distribution.
16c80476e4SDavid E. O'Brien  * 3. Neither the name of the University nor the names of its contributors
1729301572SMark Peek  *    may be used to endorse or promote products derived from this software
18c80476e4SDavid E. O'Brien  *    without specific prior written permission.
19c80476e4SDavid E. O'Brien  *
20c80476e4SDavid E. O'Brien  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21c80476e4SDavid E. O'Brien  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22c80476e4SDavid E. O'Brien  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23c80476e4SDavid E. O'Brien  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24c80476e4SDavid E. O'Brien  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25c80476e4SDavid E. O'Brien  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26c80476e4SDavid E. O'Brien  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27c80476e4SDavid E. O'Brien  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28c80476e4SDavid E. O'Brien  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29c80476e4SDavid E. O'Brien  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30c80476e4SDavid E. O'Brien  * SUCH DAMAGE.
31c80476e4SDavid E. O'Brien  */
32c80476e4SDavid E. O'Brien #include "sh.h"
33c80476e4SDavid E. O'Brien #include "tc.h"
34c80476e4SDavid E. O'Brien #include "tw.h"
3545e5710bSMark Peek 
36c80476e4SDavid E. O'Brien #include "glob.h"
37c80476e4SDavid E. O'Brien 
3829301572SMark Peek /*
39c80476e4SDavid E. O'Brien  * Values for gflag
40c80476e4SDavid E. O'Brien  */
41c80476e4SDavid E. O'Brien #define	G_NONE	0		/* No globbing needed			*/
42c80476e4SDavid E. O'Brien #define	G_GLOB	1		/* string contains *?[] characters	*/
43c80476e4SDavid E. O'Brien #define	G_CSH	2		/* string contains ~`{ characters	*/
44c80476e4SDavid E. O'Brien 
45c80476e4SDavid E. O'Brien #define	GLOBSPACE	100	/* Alloc increment			*/
46c80476e4SDavid E. O'Brien 
47c80476e4SDavid E. O'Brien 
48c80476e4SDavid E. O'Brien #define LBRC '{'
49c80476e4SDavid E. O'Brien #define RBRC '}'
50c80476e4SDavid E. O'Brien #define LBRK '['
51c80476e4SDavid E. O'Brien #define RBRK ']'
52c80476e4SDavid E. O'Brien #define EOS '\0'
53c80476e4SDavid E. O'Brien 
54c80476e4SDavid E. O'Brien /*
55c80476e4SDavid E. O'Brien  * globbing is now done in two stages. In the first pass we expand
56c80476e4SDavid E. O'Brien  * csh globbing idioms ~`{ and then we proceed doing the normal
57c80476e4SDavid E. O'Brien  * globbing if needed ?*[
58c80476e4SDavid E. O'Brien  *
59c80476e4SDavid E. O'Brien  * Csh type globbing is handled in globexpand() and the rest is
60c80476e4SDavid E. O'Brien  * handled in glob() which is part of the 4.4BSD libc.
61c80476e4SDavid E. O'Brien  *
62c80476e4SDavid E. O'Brien  */
63c80476e4SDavid E. O'Brien static	Char	 *globtilde	(Char *);
64c80476e4SDavid E. O'Brien static	Char     *handleone	(Char *, Char **, int);
65c80476e4SDavid E. O'Brien static	Char	**libglob	(Char **);
66c80476e4SDavid E. O'Brien static	Char	**globexpand	(Char **, int);
6745e5710bSMark Peek static	int	  globbrace	(const Char *, Char ***);
6845e5710bSMark Peek static  void	  expbrace	(Char ***, Char ***, int);
6945e5710bSMark Peek static	void	  pword		(struct blk_buf *, struct Strbuf *);
7045e5710bSMark Peek static	void	  backeval	(struct blk_buf *, struct Strbuf *, Char *,
7145e5710bSMark Peek 				 int);
7245e5710bSMark Peek static Char *
globtilde(Char * s)7345e5710bSMark Peek globtilde(Char *s)
7445e5710bSMark Peek {
7545e5710bSMark Peek     Char *name, *u, *home, *res;
76c80476e4SDavid E. O'Brien 
7745e5710bSMark Peek     u = s;
78c80476e4SDavid E. O'Brien 
7945e5710bSMark Peek     if (s[1] == '~')
80c80476e4SDavid E. O'Brien 	return Strsave(s);
81c80476e4SDavid E. O'Brien 
8245e5710bSMark Peek     for (s++; *s && *s != '/' && *s != ':'; s++)
83c80476e4SDavid E. O'Brien 	continue;
8445e5710bSMark Peek 
8545e5710bSMark Peek     name = Strnsave(u + 1, s - (u + 1));
8645e5710bSMark Peek     cleanup_push(name, xfree);
8745e5710bSMark Peek     home = gethdir(name);
8845e5710bSMark Peek     if (home == NULL) {
8945e5710bSMark Peek 	if (adrof(STRnonomatch)) {
9045e5710bSMark Peek 	    cleanup_until(name);
9145e5710bSMark Peek 	    return u;
9245e5710bSMark Peek 	}
9345e5710bSMark Peek 	if (*name)
94c80476e4SDavid E. O'Brien 	    stderror(ERR_UNKUSER, short2str(name));
95c80476e4SDavid E. O'Brien 	else
96c80476e4SDavid E. O'Brien 	    stderror(ERR_NOHOME);
9745e5710bSMark Peek     }
9845e5710bSMark Peek     cleanup_until(name);
9945e5710bSMark Peek     if (home[0] == '/' && home[1] == '\0' && s[0] == '/')
10045e5710bSMark Peek 	res = Strsave(s);
10145e5710bSMark Peek     else
10245e5710bSMark Peek 	res = Strspl(home, s);
10345e5710bSMark Peek     xfree(home);
10445e5710bSMark Peek     xfree(u);
105c80476e4SDavid E. O'Brien     return res;
106c80476e4SDavid E. O'Brien }
10745e5710bSMark Peek 
108c80476e4SDavid E. O'Brien /* Returns a newly allocated string, old or NULL */
10945e5710bSMark Peek Char *
globequal(Char * old)110c80476e4SDavid E. O'Brien globequal(Char *old)
111c80476e4SDavid E. O'Brien {
11245e5710bSMark Peek     int     dig;
11345e5710bSMark Peek     const Char *dir;
114c80476e4SDavid E. O'Brien     Char    *b;
115c80476e4SDavid E. O'Brien 
116c80476e4SDavid E. O'Brien     /*
117c80476e4SDavid E. O'Brien      * kfk - 17 Jan 1984 - stack hack allows user to get at arbitrary dir names
118c80476e4SDavid E. O'Brien      * in stack. PWP: let =foobar pass through (for X windows)
119c80476e4SDavid E. O'Brien      */
120c80476e4SDavid E. O'Brien     if (old[1] == '-' && (old[2] == '\0' || old[2] == '/')) {
12145e5710bSMark Peek 	/* =- */
12245e5710bSMark Peek 	const Char *olddir = varval (STRowd);
12345e5710bSMark Peek 
12445e5710bSMark Peek 	if (olddir && *olddir &&
12545e5710bSMark Peek 	    !dcwd->di_next->di_name && !dcwd->di_prev->di_name)
126c80476e4SDavid E. O'Brien 	    return Strspl(olddir, &old[2]);
127c80476e4SDavid E. O'Brien 	dig = -1;
128c80476e4SDavid E. O'Brien 	b = &old[2];
129c80476e4SDavid E. O'Brien     }
130c80476e4SDavid E. O'Brien     else if (Isdigit(old[1])) {
131c80476e4SDavid E. O'Brien 	/* =<number> */
132c80476e4SDavid E. O'Brien 	dig = old[1] - '0';
133c80476e4SDavid E. O'Brien 	for (b = &old[2]; Isdigit(*b); b++)
134c80476e4SDavid E. O'Brien 	    dig = dig * 10 + (*b - '0');
135c80476e4SDavid E. O'Brien 	if (*b != '\0' && *b != '/')
136c80476e4SDavid E. O'Brien 	    /* =<number>foobar */
137c80476e4SDavid E. O'Brien 	    return old;
138c80476e4SDavid E. O'Brien     }
139c80476e4SDavid E. O'Brien     else
140c80476e4SDavid E. O'Brien 	/* =foobar */
141c80476e4SDavid E. O'Brien 	return old;
14245e5710bSMark Peek 
14345e5710bSMark Peek     dir = getstakd(dig);
144c80476e4SDavid E. O'Brien     if (dir == NULL)
14545e5710bSMark Peek 	return NULL;
146c80476e4SDavid E. O'Brien     return Strspl(dir, b);
147c80476e4SDavid E. O'Brien }
148c80476e4SDavid E. O'Brien 
14945e5710bSMark Peek static int
globbrace(const Char * s,Char *** bl)150c80476e4SDavid E. O'Brien globbrace(const Char *s, Char ***bl)
15145e5710bSMark Peek {
15245e5710bSMark Peek     struct Strbuf gbuf = Strbuf_INIT;
15345e5710bSMark Peek     struct blk_buf bb = BLK_BUF_INIT;
15445e5710bSMark Peek     int     i;
15545e5710bSMark Peek     const Char *p, *pm, *pe, *pl;
156c80476e4SDavid E. O'Brien     size_t prefix_len;
157c80476e4SDavid E. O'Brien 
15845e5710bSMark Peek     /* copy part up to the brace */
15945e5710bSMark Peek     for (p = s; *p != LBRC; p++)
16045e5710bSMark Peek 	;
161c80476e4SDavid E. O'Brien     prefix_len = p - s;
162c80476e4SDavid E. O'Brien 
163c80476e4SDavid E. O'Brien     /* check for balanced braces */
164c80476e4SDavid E. O'Brien     for (i = 0, pe = ++p; *pe; pe++)
165c80476e4SDavid E. O'Brien 	if (*pe == LBRK) {
166c80476e4SDavid E. O'Brien 	    /* Ignore everything between [] */
167c80476e4SDavid E. O'Brien 	    for (++pe; *pe != RBRK && *pe != EOS; pe++)
16845e5710bSMark Peek 		continue;
169c80476e4SDavid E. O'Brien 	    if (*pe == EOS)
170c80476e4SDavid E. O'Brien 		return (-RBRK);
171c80476e4SDavid E. O'Brien 	}
172c80476e4SDavid E. O'Brien 	else if (*pe == LBRC)
173c80476e4SDavid E. O'Brien 	    i++;
174c80476e4SDavid E. O'Brien 	else if (*pe == RBRC) {
175c80476e4SDavid E. O'Brien 	    if (i == 0)
176c80476e4SDavid E. O'Brien 		break;
177c80476e4SDavid E. O'Brien 	    i--;
178c80476e4SDavid E. O'Brien 	}
17945e5710bSMark Peek 
180c80476e4SDavid E. O'Brien     if (i != 0 || *pe == '\0')
18145e5710bSMark Peek 	return (-RBRC);
18245e5710bSMark Peek 
183c80476e4SDavid E. O'Brien     Strbuf_appendn(&gbuf, s, prefix_len);
184c80476e4SDavid E. O'Brien 
185c80476e4SDavid E. O'Brien     for (i = 0, pl = pm = p; pm <= pe; pm++)
186c80476e4SDavid E. O'Brien 	switch (*pm) {
187c80476e4SDavid E. O'Brien 	case LBRK:
188c80476e4SDavid E. O'Brien 	    for (++pm; *pm != RBRK && *pm != EOS; pm++)
189c80476e4SDavid E. O'Brien 		continue;
19045e5710bSMark Peek 	    if (*pm == EOS) {
19145e5710bSMark Peek 		bb_cleanup(&bb);
192c80476e4SDavid E. O'Brien 		xfree(gbuf.s);
193c80476e4SDavid E. O'Brien 		return (-RBRK);
194c80476e4SDavid E. O'Brien 	    }
195c80476e4SDavid E. O'Brien 	    break;
196c80476e4SDavid E. O'Brien 	case LBRC:
197c80476e4SDavid E. O'Brien 	    i++;
198c80476e4SDavid E. O'Brien 	    break;
199c80476e4SDavid E. O'Brien 	case RBRC:
200c80476e4SDavid E. O'Brien 	    if (i) {
201c80476e4SDavid E. O'Brien 		i--;
202c80476e4SDavid E. O'Brien 		break;
203c80476e4SDavid E. O'Brien 	    }
204c80476e4SDavid E. O'Brien 	    /* FALLTHROUGH */
205c80476e4SDavid E. O'Brien 	case ',':
206c80476e4SDavid E. O'Brien 	    if (i && *pm == ',')
207c80476e4SDavid E. O'Brien 		break;
20845e5710bSMark Peek 	    else {
20945e5710bSMark Peek 		gbuf.len = prefix_len;
21045e5710bSMark Peek 		Strbuf_appendn(&gbuf, pl, pm - pl);
21145e5710bSMark Peek 		Strbuf_append(&gbuf, pe + 1);
21245e5710bSMark Peek 		Strbuf_terminate(&gbuf);
213c80476e4SDavid E. O'Brien 		bb_append(&bb, Strsave(gbuf.s));
214c80476e4SDavid E. O'Brien 		pl = pm + 1;
215c80476e4SDavid E. O'Brien 	    }
216c80476e4SDavid E. O'Brien 	    break;
217c80476e4SDavid E. O'Brien 	default:
218c80476e4SDavid E. O'Brien 	    break;
21945e5710bSMark Peek 	}
22045e5710bSMark Peek     *bl = bb_finish(&bb);
22145e5710bSMark Peek     xfree(gbuf.s);
222c80476e4SDavid E. O'Brien     return bb.len;
223c80476e4SDavid E. O'Brien }
224c80476e4SDavid E. O'Brien 
225c80476e4SDavid E. O'Brien 
22645e5710bSMark Peek static void
expbrace(Char *** nvp,Char *** elp,int size)227c80476e4SDavid E. O'Brien expbrace(Char ***nvp, Char ***elp, int size)
228c80476e4SDavid E. O'Brien {
229c80476e4SDavid E. O'Brien     Char **vl, **el, **nv, *s;
230c80476e4SDavid E. O'Brien 
231c80476e4SDavid E. O'Brien     vl = nv = *nvp;
232c80476e4SDavid E. O'Brien     if (elp != NULL)
233c80476e4SDavid E. O'Brien 	el = *elp;
23445e5710bSMark Peek     else
235c80476e4SDavid E. O'Brien 	el = vl + blklen(vl);
236c80476e4SDavid E. O'Brien 
237c80476e4SDavid E. O'Brien     for (s = *vl; s; s = *++vl) {
238c80476e4SDavid E. O'Brien 	Char  **vp, **bp;
239c80476e4SDavid E. O'Brien 
240c80476e4SDavid E. O'Brien 	/* leave {} untouched for find */
241c80476e4SDavid E. O'Brien 	if (s[0] == '{' && (s[1] == '\0' || (s[1] == '}' && s[2] == '\0')))
24245e5710bSMark Peek 	    continue;
24345e5710bSMark Peek 	if (Strchr(s, '{') != NULL) {
244c80476e4SDavid E. O'Brien 	    Char  **bl = NULL;
245c80476e4SDavid E. O'Brien 	    int     len;
24645e5710bSMark Peek 
247c80476e4SDavid E. O'Brien 	    if ((len = globbrace(s, &bl)) < 0)
24845e5710bSMark Peek 		stderror(ERR_MISSING, -len);
249c80476e4SDavid E. O'Brien 	    xfree(s);
250c80476e4SDavid E. O'Brien 	    if (len == 1) {
25145e5710bSMark Peek 		*vl-- = *bl;
252c80476e4SDavid E. O'Brien 		xfree(bl);
253c80476e4SDavid E. O'Brien 		continue;
254c80476e4SDavid E. O'Brien 	    }
25545e5710bSMark Peek 	    if (&el[len] >= &nv[size]) {
25645e5710bSMark Peek 		size_t l, e;
257c80476e4SDavid E. O'Brien 		l = &el[len] - &nv[size];
25845e5710bSMark Peek 		size += GLOBSPACE > l ? GLOBSPACE : l;
25945e5710bSMark Peek 		l = vl - nv;
26045e5710bSMark Peek 		e = el - nv;
26145e5710bSMark Peek 		nv = xrealloc(nv, size * sizeof(Char *));
262c80476e4SDavid E. O'Brien 		*nvp = nv; /* To keep cleanups working */
263c80476e4SDavid E. O'Brien 		vl = nv + l;
264c80476e4SDavid E. O'Brien 		el = nv + e;
265c80476e4SDavid E. O'Brien 	    }
266c80476e4SDavid E. O'Brien 	    /* nv vl   el     bl
267c80476e4SDavid E. O'Brien 	     * |  |    |      |
268c80476e4SDavid E. O'Brien 	     * -.--..--	      x--
269c80476e4SDavid E. O'Brien 	     *   |            len
270c80476e4SDavid E. O'Brien 	     *   vp
271c80476e4SDavid E. O'Brien 	     */
272c80476e4SDavid E. O'Brien 	    vp = vl--;
273c80476e4SDavid E. O'Brien 	    *vp = *bl;
274c80476e4SDavid E. O'Brien 	    len--;
275c80476e4SDavid E. O'Brien 	    for (bp = el; bp != vp; bp--)
276c80476e4SDavid E. O'Brien 		bp[len] = *bp;
277c80476e4SDavid E. O'Brien 	    el += len;
278c80476e4SDavid E. O'Brien 	    /* nv vl    el bl
279c80476e4SDavid E. O'Brien 	     * |  |     |  |
280c80476e4SDavid E. O'Brien 	     * -.-x  ---    --
281c80476e4SDavid E. O'Brien 	     *   |len
282c80476e4SDavid E. O'Brien 	     *   vp
283c80476e4SDavid E. O'Brien 	     */
284c80476e4SDavid E. O'Brien 	    vp++;
285c80476e4SDavid E. O'Brien 	    for (bp = bl + 1; *bp; *vp++ = *bp++)
28645e5710bSMark Peek 		continue;
287c80476e4SDavid E. O'Brien 	    xfree(bl);
288c80476e4SDavid E. O'Brien 	}
289c80476e4SDavid E. O'Brien 
290c80476e4SDavid E. O'Brien     }
291c80476e4SDavid E. O'Brien     if (elp != NULL)
292c80476e4SDavid E. O'Brien 	*elp = el;
293c80476e4SDavid E. O'Brien }
294c80476e4SDavid E. O'Brien 
29545e5710bSMark Peek static Char **
globexpand(Char ** v,int noglob)296c80476e4SDavid E. O'Brien globexpand(Char **v, int noglob)
297c80476e4SDavid E. O'Brien {
29845e5710bSMark Peek     Char   *s;
299c80476e4SDavid E. O'Brien     Char  ***fnv, **vl, **el;
300c80476e4SDavid E. O'Brien     int     size = GLOBSPACE;
301c80476e4SDavid E. O'Brien 
30245e5710bSMark Peek 
30345e5710bSMark Peek     fnv = xmalloc(sizeof(Char ***));
304c80476e4SDavid E. O'Brien     *fnv = vl = xmalloc(sizeof(Char *) * size);
30545e5710bSMark Peek     *vl = NULL;
306c80476e4SDavid E. O'Brien     cleanup_push(fnv, blk_indirect_cleanup);
307c80476e4SDavid E. O'Brien 
308c80476e4SDavid E. O'Brien     /*
309c80476e4SDavid E. O'Brien      * Step 1: expand backquotes.
310c80476e4SDavid E. O'Brien      */
311c80476e4SDavid E. O'Brien     while ((s = *v++) != NULL) {
312c80476e4SDavid E. O'Brien 	if (Strchr(s, '`')) {
31345e5710bSMark Peek 	    int     i;
314c80476e4SDavid E. O'Brien 	    Char **expanded;
31545e5710bSMark Peek 
31645e5710bSMark Peek 	    expanded = dobackp(s, 0);
31745e5710bSMark Peek 	    for (i = 0; expanded[i] != NULL; i++) {
31845e5710bSMark Peek 		*vl++ = expanded[i];
319c80476e4SDavid E. O'Brien 		if (vl == &(*fnv)[size]) {
32045e5710bSMark Peek 		    size += GLOBSPACE;
32145e5710bSMark Peek 		    *fnv = xrealloc(*fnv, size * sizeof(Char *));
322c80476e4SDavid E. O'Brien 		    vl = &(*fnv)[size - GLOBSPACE];
323c80476e4SDavid E. O'Brien 		}
32445e5710bSMark Peek 	    }
325c80476e4SDavid E. O'Brien 	    xfree(expanded);
326c80476e4SDavid E. O'Brien 	}
327c80476e4SDavid E. O'Brien 	else {
32845e5710bSMark Peek 	    *vl++ = Strsave(s);
329c80476e4SDavid E. O'Brien 	    if (vl == &(*fnv)[size]) {
33045e5710bSMark Peek 		size += GLOBSPACE;
33145e5710bSMark Peek 		*fnv = xrealloc(*fnv, size * sizeof(Char *));
332c80476e4SDavid E. O'Brien 		vl = &(*fnv)[size - GLOBSPACE];
333c80476e4SDavid E. O'Brien 	    }
334c80476e4SDavid E. O'Brien 	}
33545e5710bSMark Peek 	*vl = NULL;
336c80476e4SDavid E. O'Brien     }
337c80476e4SDavid E. O'Brien 
33845e5710bSMark Peek     if (noglob)
339c80476e4SDavid E. O'Brien 	goto done;
340c80476e4SDavid E. O'Brien 
341c80476e4SDavid E. O'Brien     /*
342c80476e4SDavid E. O'Brien      * Step 2: expand braces
343c80476e4SDavid E. O'Brien      */
34445e5710bSMark Peek     el = vl;
345c80476e4SDavid E. O'Brien     expbrace(fnv, &el, size);
346c80476e4SDavid E. O'Brien 
347c80476e4SDavid E. O'Brien 
348c80476e4SDavid E. O'Brien     /*
349c80476e4SDavid E. O'Brien      * Step 3: expand ~ =
35045e5710bSMark Peek      */
351c80476e4SDavid E. O'Brien     vl = *fnv;
352c80476e4SDavid E. O'Brien     for (s = *vl; s; s = *++vl)
35345e5710bSMark Peek 	switch (*s) {
354c80476e4SDavid E. O'Brien 	    Char *ns;
35545e5710bSMark Peek 	case '~':
356c80476e4SDavid E. O'Brien 	    *vl = globtilde(s);
357c80476e4SDavid E. O'Brien 	    break;
35845e5710bSMark Peek 	case '=':
35945e5710bSMark Peek 	    if ((ns = globequal(s)) == NULL) {
36045e5710bSMark Peek 		if (!adrof(STRnonomatch))
361c80476e4SDavid E. O'Brien 		    stderror(ERR_DEEP); /* Error */
362c80476e4SDavid E. O'Brien 	    }
363c80476e4SDavid E. O'Brien 	    if (ns && ns != s) {
36445e5710bSMark Peek 		/* Expansion succeeded */
36545e5710bSMark Peek 		xfree(s);
366c80476e4SDavid E. O'Brien 		*vl = ns;
367c80476e4SDavid E. O'Brien 	    }
368c80476e4SDavid E. O'Brien 	    break;
369c80476e4SDavid E. O'Brien 	default:
370c80476e4SDavid E. O'Brien 	    break;
37145e5710bSMark Peek 	}
372c80476e4SDavid E. O'Brien     vl = *fnv;
373c80476e4SDavid E. O'Brien 
374c80476e4SDavid E. O'Brien     /*
375c80476e4SDavid E. O'Brien      * Step 4: expand .. if the variable symlinks==expand is set
3766767bd61SMark Peek      */
377c80476e4SDavid E. O'Brien     if (symlinks == SYM_EXPAND) {
378c80476e4SDavid E. O'Brien 	for (s = *vl; s; s = *++vl) {
37945e5710bSMark Peek 	    *vl = dnormalize(s, 1);
380c80476e4SDavid E. O'Brien 	    xfree(s);
3813b6eaa7bSAndrey A. Chernov 	}
382c80476e4SDavid E. O'Brien     }
38345e5710bSMark Peek 
38445e5710bSMark Peek  done:
38545e5710bSMark Peek     cleanup_ignore(fnv);
38645e5710bSMark Peek     cleanup_until(fnv);
38745e5710bSMark Peek     vl = *fnv;
38845e5710bSMark Peek     xfree(fnv);
389c80476e4SDavid E. O'Brien     return vl;
390c80476e4SDavid E. O'Brien }
391c80476e4SDavid E. O'Brien 
39245e5710bSMark Peek static Char *
handleone(Char * str,Char ** vl,int action)393c80476e4SDavid E. O'Brien handleone(Char *str, Char **vl, int action)
39445e5710bSMark Peek {
395c80476e4SDavid E. O'Brien     size_t chars;
396c80476e4SDavid E. O'Brien     Char **t, *p, *strp;
397c80476e4SDavid E. O'Brien 
398c80476e4SDavid E. O'Brien     switch (action) {
399c80476e4SDavid E. O'Brien     case G_ERROR:
400c80476e4SDavid E. O'Brien 	setname(short2str(str));
401c80476e4SDavid E. O'Brien 	blkfree(vl);
402c80476e4SDavid E. O'Brien 	stderror(ERR_NAME | ERR_AMBIG);
403c80476e4SDavid E. O'Brien 	break;
404c80476e4SDavid E. O'Brien     case G_APPEND:
40545e5710bSMark Peek 	chars = 0;
40645e5710bSMark Peek 	for (t = vl; (p = *t++) != NULL; chars++)
40745e5710bSMark Peek 	    chars += Strlen(p);
40845e5710bSMark Peek 	str = xmalloc(chars * sizeof(Char));
409c80476e4SDavid E. O'Brien 	for (t = vl, strp = str; (p = *t++) != NULL; chars++) {
410c80476e4SDavid E. O'Brien 	    while (*p)
411c80476e4SDavid E. O'Brien 		 *strp++ = *p++ & TRIM;
412c80476e4SDavid E. O'Brien 	    *strp++ = ' ';
413c80476e4SDavid E. O'Brien 	}
414c80476e4SDavid E. O'Brien 	*--strp = '\0';
415c80476e4SDavid E. O'Brien 	blkfree(vl);
416c80476e4SDavid E. O'Brien 	break;
41745e5710bSMark Peek     case G_IGNORE:
418c80476e4SDavid E. O'Brien 	str = Strsave(strip(*vl));
419c80476e4SDavid E. O'Brien 	blkfree(vl);
420c80476e4SDavid E. O'Brien 	break;
421c80476e4SDavid E. O'Brien     default:
422c80476e4SDavid E. O'Brien 	break;
423c80476e4SDavid E. O'Brien     }
424c80476e4SDavid E. O'Brien     return (str);
425c80476e4SDavid E. O'Brien }
426c80476e4SDavid E. O'Brien 
42745e5710bSMark Peek static Char **
libglob(Char ** vl)428c80476e4SDavid E. O'Brien libglob(Char **vl)
429c80476e4SDavid E. O'Brien {
430c80476e4SDavid E. O'Brien     int     gflgs = GLOB_QUOTE | GLOB_NOMAGIC | GLOB_ALTNOT;
431c80476e4SDavid E. O'Brien     glob_t  globv;
432c80476e4SDavid E. O'Brien     char   *ptr;
433c80476e4SDavid E. O'Brien     int     nonomatch = adrof(STRnonomatch) != 0, magic = 0, match = 0;
434c80476e4SDavid E. O'Brien 
435c80476e4SDavid E. O'Brien     if (adrof(STRglobdot))
436c80476e4SDavid E. O'Brien        gflgs |= GLOB_DOT;
437c80476e4SDavid E. O'Brien 
438c80476e4SDavid E. O'Brien     if (adrof(STRglobstar))
439c80476e4SDavid E. O'Brien        gflgs |= GLOB_STAR;
440c80476e4SDavid E. O'Brien 
441c80476e4SDavid E. O'Brien     if (!vl || !vl[0])
442c80476e4SDavid E. O'Brien 	return(vl);
443c80476e4SDavid E. O'Brien 
444c80476e4SDavid E. O'Brien     globv.gl_offs = 0;
445c80476e4SDavid E. O'Brien     globv.gl_pathv = 0;
446c80476e4SDavid E. O'Brien     globv.gl_pathc = 0;
447c80476e4SDavid E. O'Brien 
448c80476e4SDavid E. O'Brien     if (nonomatch)
449c80476e4SDavid E. O'Brien 	gflgs |= GLOB_NOCHECK;
450c80476e4SDavid E. O'Brien 
451c80476e4SDavid E. O'Brien     do {
452c80476e4SDavid E. O'Brien 	ptr = short2qstr(*vl);
453c80476e4SDavid E. O'Brien 	switch (glob(ptr, gflgs, 0, &globv)) {
454c80476e4SDavid E. O'Brien 	case GLOB_ABEND:
455c80476e4SDavid E. O'Brien 	    globfree(&globv);
456c80476e4SDavid E. O'Brien 	    setname(ptr);
457c80476e4SDavid E. O'Brien 	    stderror(ERR_NAME | ERR_GLOB);
458c80476e4SDavid E. O'Brien 	    /* NOTREACHED */
459c80476e4SDavid E. O'Brien 	case GLOB_NOSPACE:
460c80476e4SDavid E. O'Brien 	    globfree(&globv);
461c80476e4SDavid E. O'Brien 	    stderror(ERR_NOMEM);
462c80476e4SDavid E. O'Brien 	    /* NOTREACHED */
463c80476e4SDavid E. O'Brien 	default:
464c80476e4SDavid E. O'Brien 	    break;
465c80476e4SDavid E. O'Brien 	}
466c80476e4SDavid E. O'Brien 	if (globv.gl_flags & GLOB_MAGCHAR) {
467c80476e4SDavid E. O'Brien 	    match |= (globv.gl_matchc != 0);
468c80476e4SDavid E. O'Brien 	    magic = 1;
469c80476e4SDavid E. O'Brien 	}
470c80476e4SDavid E. O'Brien 	gflgs |= GLOB_APPEND;
471c80476e4SDavid E. O'Brien     }
472c80476e4SDavid E. O'Brien     while (*++vl);
47345e5710bSMark Peek     vl = (globv.gl_pathc == 0 || (magic && !match && !nonomatch)) ?
474c80476e4SDavid E. O'Brien 	NULL : blk2short(globv.gl_pathv);
475c80476e4SDavid E. O'Brien     globfree(&globv);
47645e5710bSMark Peek     return (vl);
477c80476e4SDavid E. O'Brien }
478c80476e4SDavid E. O'Brien 
479c80476e4SDavid E. O'Brien Char   *
globone(Char * str,int action)480c80476e4SDavid E. O'Brien globone(Char *str, int action)
48145e5710bSMark Peek {
482c80476e4SDavid E. O'Brien     Char   *v[2], **vl, **vo;
483c80476e4SDavid E. O'Brien     int gflg, noglob;
484c80476e4SDavid E. O'Brien 
485c80476e4SDavid E. O'Brien     noglob = adrof(STRnoglob) != 0;
486c80476e4SDavid E. O'Brien     v[0] = str;
487c80476e4SDavid E. O'Brien     v[1] = 0;
488c80476e4SDavid E. O'Brien     gflg = tglob(v);
48945e5710bSMark Peek     if (gflg == G_NONE)
490c80476e4SDavid E. O'Brien 	return (strip(Strsave(str)));
49145e5710bSMark Peek 
49245e5710bSMark Peek     if (gflg & G_CSH) {
493c80476e4SDavid E. O'Brien 	/*
49445e5710bSMark Peek 	 * Expand back-quote, tilde and brace
495c80476e4SDavid E. O'Brien 	 */
496c80476e4SDavid E. O'Brien 	vo = globexpand(v, noglob);
497c80476e4SDavid E. O'Brien 	if (noglob || (gflg & G_GLOB) == 0) {
498c80476e4SDavid E. O'Brien 	    vl = vo;
499c80476e4SDavid E. O'Brien 	    goto result;
500c80476e4SDavid E. O'Brien 	}
501c80476e4SDavid E. O'Brien 	cleanup_push(vo, blk_cleanup);
50245e5710bSMark Peek     }
50345e5710bSMark Peek     else if (noglob || (gflg & G_GLOB) == 0)
50445e5710bSMark Peek 	return (strip(Strsave(str)));
50545e5710bSMark Peek     else
50645e5710bSMark Peek 	vo = v;
50745e5710bSMark Peek 
508c80476e4SDavid E. O'Brien     vl = libglob(vo);
509c80476e4SDavid E. O'Brien     if (gflg & G_CSH) {
510c80476e4SDavid E. O'Brien     	if (vl != vo)
511c80476e4SDavid E. O'Brien 	    cleanup_until(vo);
51245e5710bSMark Peek 	else
513c80476e4SDavid E. O'Brien 	    cleanup_ignore(vo);
51445e5710bSMark Peek     }
515c80476e4SDavid E. O'Brien     if (vl == NULL) {
516c80476e4SDavid E. O'Brien 	setname(short2str(str));
517c80476e4SDavid E. O'Brien 	stderror(ERR_NAME | ERR_NOMATCH);
518c80476e4SDavid E. O'Brien     }
519c80476e4SDavid E. O'Brien  result:
520c80476e4SDavid E. O'Brien     if (vl && vl[0] == NULL) {
52145e5710bSMark Peek 	if (vl != v)
522c80476e4SDavid E. O'Brien 	    xfree(vl);
523c80476e4SDavid E. O'Brien 	return (Strsave(STRNULL));
524c80476e4SDavid E. O'Brien     }
525c80476e4SDavid E. O'Brien     if (vl && vl[1])
526c80476e4SDavid E. O'Brien 	return (handleone(str, vl, action));
52745e5710bSMark Peek     else {
528c80476e4SDavid E. O'Brien 	str = strip(*vl);
529c80476e4SDavid E. O'Brien 	if (vl != v)
53045e5710bSMark Peek 	    xfree(vl);
531c80476e4SDavid E. O'Brien 	return (str);
53245e5710bSMark Peek     }
53345e5710bSMark Peek }
534c80476e4SDavid E. O'Brien 
535c80476e4SDavid E. O'Brien Char  **
globall(Char ** v,int gflg)536c80476e4SDavid E. O'Brien globall(Char **v, int gflg)
537c80476e4SDavid E. O'Brien {
538c80476e4SDavid E. O'Brien     Char  **vl, **vo;
539c80476e4SDavid E. O'Brien     int noglob;
540c80476e4SDavid E. O'Brien 
54145e5710bSMark Peek     if (!v || !v[0])
542c80476e4SDavid E. O'Brien 	return saveblk(v);
543c80476e4SDavid E. O'Brien 
544c80476e4SDavid E. O'Brien     noglob = adrof(STRnoglob) != 0;
545c80476e4SDavid E. O'Brien 
54645e5710bSMark Peek     if (gflg & G_CSH)
547c80476e4SDavid E. O'Brien 	/*
54845e5710bSMark Peek 	 * Expand back-quote, tilde and brace
54945e5710bSMark Peek 	 */
55045e5710bSMark Peek 	vl = vo = globexpand(v, noglob);
551c80476e4SDavid E. O'Brien     else
552c80476e4SDavid E. O'Brien 	vl = vo = saveblk(v);
553c80476e4SDavid E. O'Brien 
554c80476e4SDavid E. O'Brien     if (!noglob && (gflg & G_GLOB)) {
55545e5710bSMark Peek 	cleanup_push(vo, blk_cleanup);
556c80476e4SDavid E. O'Brien 	vl = libglob(vo);
557c80476e4SDavid E. O'Brien 	if (vl == vo)
55845e5710bSMark Peek 	    cleanup_ignore(vo);
55945e5710bSMark Peek 	cleanup_until(vo);
560c80476e4SDavid E. O'Brien     }
56145e5710bSMark Peek     else
56245e5710bSMark Peek 	trim(vl);
56345e5710bSMark Peek 
56445e5710bSMark Peek     return vl;
56545e5710bSMark Peek }
56645e5710bSMark Peek 
56745e5710bSMark Peek Char **
glob_all_or_error(Char ** v)56845e5710bSMark Peek glob_all_or_error(Char **v)
56945e5710bSMark Peek {
57045e5710bSMark Peek     int gflag;
57145e5710bSMark Peek 
57245e5710bSMark Peek     gflag = tglob(v);
573c80476e4SDavid E. O'Brien     if (gflag) {
574c80476e4SDavid E. O'Brien 	v = globall(v, gflag);
575c80476e4SDavid E. O'Brien 	if (v == NULL)
57645e5710bSMark Peek 	    stderror(ERR_NAME | ERR_NOMATCH);
577c80476e4SDavid E. O'Brien     } else {
57823338178SMark Peek 	v = saveblk(v);
579c80476e4SDavid E. O'Brien 	trim(v);
580c80476e4SDavid E. O'Brien     }
581c80476e4SDavid E. O'Brien     return v;
582c80476e4SDavid E. O'Brien }
583c80476e4SDavid E. O'Brien 
584c80476e4SDavid E. O'Brien void
rscan(Char ** t,void (* f)(Char))585c80476e4SDavid E. O'Brien rscan(Char **t, void (*f) (Char))
58645e5710bSMark Peek {
587c80476e4SDavid E. O'Brien     Char *p;
58823338178SMark Peek 
589c80476e4SDavid E. O'Brien     while ((p = *t++) != NULL)
590c80476e4SDavid E. O'Brien 	while (*p)
591c80476e4SDavid E. O'Brien 	    (*f) (*p++);
592c80476e4SDavid E. O'Brien }
593c80476e4SDavid E. O'Brien 
594c80476e4SDavid E. O'Brien void
trim(Char ** t)59545e5710bSMark Peek trim(Char **t)
59645e5710bSMark Peek {
597c80476e4SDavid E. O'Brien     Char *p;
59845e5710bSMark Peek 
59945e5710bSMark Peek     while ((p = *t++) != NULL)
600c80476e4SDavid E. O'Brien 	while (*p) {
60145e5710bSMark Peek #if INVALID_BYTE != 0
602c80476e4SDavid E. O'Brien 	    if ((*p & INVALID_BYTE) != INVALID_BYTE)	/* *p < INVALID_BYTE */
603c80476e4SDavid E. O'Brien #endif
604c80476e4SDavid E. O'Brien 		*p &= TRIM;
605c80476e4SDavid E. O'Brien 	    p++;
606c80476e4SDavid E. O'Brien 	}
607c80476e4SDavid E. O'Brien }
60845e5710bSMark Peek 
60945e5710bSMark Peek int
tglob(Char ** t)610c80476e4SDavid E. O'Brien tglob(Char **t)
611c80476e4SDavid E. O'Brien {
612c80476e4SDavid E. O'Brien     int gflag;
613c80476e4SDavid E. O'Brien     const Char *p;
614c80476e4SDavid E. O'Brien 
615c80476e4SDavid E. O'Brien     gflag = 0;
61645e5710bSMark Peek     while ((p = *t++) != NULL) {
617c80476e4SDavid E. O'Brien 	if (*p == '~' || *p == '=')
618c80476e4SDavid E. O'Brien 	    gflag |= G_CSH;
619c80476e4SDavid E. O'Brien 	else if (*p == '{' &&
620c80476e4SDavid E. O'Brien 		 (p[1] == '\0' || (p[1] == '}' && p[2] == '\0')))
621c80476e4SDavid E. O'Brien 	    continue;
622c80476e4SDavid E. O'Brien 	while (*p != '\0') {
623c80476e4SDavid E. O'Brien 	    if (*p == '`') {
62445e5710bSMark Peek 		gflag |= G_CSH;
625c80476e4SDavid E. O'Brien #ifdef notdef
626c80476e4SDavid E. O'Brien 		/*
627c80476e4SDavid E. O'Brien 		 * We do want to expand echo `echo '*'`, so we don't\
62845e5710bSMark Peek 		 * use this piece of code anymore.
629c80476e4SDavid E. O'Brien 		 */
63045e5710bSMark Peek 		p++;
631c80476e4SDavid E. O'Brien 		while (*p && *p != '`')
632c80476e4SDavid E. O'Brien 		    if (*p++ == '\\') {
63345e5710bSMark Peek 			if (*p)		/* Quoted chars */
634c80476e4SDavid E. O'Brien 			    p++;
63545e5710bSMark Peek 			else
636c80476e4SDavid E. O'Brien 			    break;
637c80476e4SDavid E. O'Brien 		    }
63845e5710bSMark Peek 		if (!*p)		/* The matching ` */
639c80476e4SDavid E. O'Brien 		    break;
640c80476e4SDavid E. O'Brien #endif
641c80476e4SDavid E. O'Brien 	    }
642c80476e4SDavid E. O'Brien 	    else if (*p == '{')
643c80476e4SDavid E. O'Brien 		gflag |= G_CSH;
644c80476e4SDavid E. O'Brien 	    else if (isglob(*p))
645c80476e4SDavid E. O'Brien 		gflag |= G_GLOB;
646c80476e4SDavid E. O'Brien 	    else if (symlinks == SYM_EXPAND &&
64745e5710bSMark Peek 		p[1] && ISDOTDOT(p) && (p == *(t-1) || *(p-1) == '/') )
648c80476e4SDavid E. O'Brien 	    	gflag |= G_CSH;
64945e5710bSMark Peek 	    p++;
65045e5710bSMark Peek 	}
65145e5710bSMark Peek     }
652c80476e4SDavid E. O'Brien     return gflag;
65345e5710bSMark Peek }
65445e5710bSMark Peek 
655c80476e4SDavid E. O'Brien /*
65645e5710bSMark Peek  * Command substitute cp.  If literal, then this is a substitution from a
65745e5710bSMark Peek  * << redirection, and so we should not crunch blanks and tabs, separating
65845e5710bSMark Peek  * words only at newlines.
65945e5710bSMark Peek  */
66045e5710bSMark Peek Char  **
dobackp(Char * cp,int literal)661c80476e4SDavid E. O'Brien dobackp(Char *cp, int literal)
662c80476e4SDavid E. O'Brien {
663c80476e4SDavid E. O'Brien     struct Strbuf word = Strbuf_INIT;
664c80476e4SDavid E. O'Brien     struct blk_buf bb = BLK_BUF_INIT;
665c80476e4SDavid E. O'Brien     Char *lp, *rp, *ep;
666c80476e4SDavid E. O'Brien 
667c80476e4SDavid E. O'Brien     cleanup_push(&bb, bb_cleanup);
66845e5710bSMark Peek     cleanup_push(&word, Strbuf_cleanup);
66945e5710bSMark Peek     for (;;) {
67045e5710bSMark Peek 	for (lp = cp; *lp != '\0' && *lp != '`'; lp++)
67145e5710bSMark Peek 	    ;
67245e5710bSMark Peek 	Strbuf_appendn(&word, cp, lp - cp);
67345e5710bSMark Peek 	if (*lp == 0)
67445e5710bSMark Peek 	    break;
67545e5710bSMark Peek 	lp++;
676c80476e4SDavid E. O'Brien 	for (rp = lp; *rp && *rp != '`'; rp++)
677c80476e4SDavid E. O'Brien 	    if (*rp == '\\') {
67845e5710bSMark Peek 		rp++;
67945e5710bSMark Peek 		if (!*rp)
68045e5710bSMark Peek 		    goto oops;
68145e5710bSMark Peek 	    }
68245e5710bSMark Peek 	if (!*rp) {
683c80476e4SDavid E. O'Brien 	oops:
684c80476e4SDavid E. O'Brien 	    cleanup_until(&bb);
685c80476e4SDavid E. O'Brien 	    stderror(ERR_UNMATCHED, '`');
686c80476e4SDavid E. O'Brien 	}
68745e5710bSMark Peek 	ep = Strnsave(lp, rp - lp);
688c80476e4SDavid E. O'Brien 	cleanup_push(ep, xfree);
68923338178SMark Peek 	backeval(&bb, &word, ep, literal);
69023338178SMark Peek 	cleanup_until(ep);
691c80476e4SDavid E. O'Brien 	cp = rp + 1;
69223338178SMark Peek     }
693c80476e4SDavid E. O'Brien     if (word.len != 0)
694c80476e4SDavid E. O'Brien 	pword(&bb, &word);
695c80476e4SDavid E. O'Brien     cleanup_ignore(&bb);
696c80476e4SDavid E. O'Brien     cleanup_until(&bb);
697c80476e4SDavid E. O'Brien     return bb_finish(&bb);
698c80476e4SDavid E. O'Brien }
699c80476e4SDavid E. O'Brien 
700c80476e4SDavid E. O'Brien 
701c80476e4SDavid E. O'Brien static void
backeval(struct blk_buf * bb,struct Strbuf * word,Char * cp,int literal)702c80476e4SDavid E. O'Brien backeval(struct blk_buf *bb, struct Strbuf *word, Char *cp, int literal)
703c80476e4SDavid E. O'Brien {
704c80476e4SDavid E. O'Brien     ssize_t icnt;
705c80476e4SDavid E. O'Brien     Char c, *ip;
706c80476e4SDavid E. O'Brien     struct command faket;
707c80476e4SDavid E. O'Brien     int    hadnl;
708c80476e4SDavid E. O'Brien     int     pvec[2], quoted;
709c80476e4SDavid E. O'Brien     Char   *fakecom[2], ibuf[BUFSIZE];
710c80476e4SDavid E. O'Brien 
711c80476e4SDavid E. O'Brien     hadnl = 0;
712c80476e4SDavid E. O'Brien     icnt = 0;
713c80476e4SDavid E. O'Brien     if (!literal) {
714c80476e4SDavid E. O'Brien 	for (ip = cp; (*ip & QUOTE) != 0; ip++)
715c80476e4SDavid E. O'Brien 		continue;
716c80476e4SDavid E. O'Brien 	quoted = *ip == '\0';
71745e5710bSMark Peek     } else
718c80476e4SDavid E. O'Brien 	quoted = literal;
719c80476e4SDavid E. O'Brien     faket.t_dtyp = NODE_COMMAND;
720c80476e4SDavid E. O'Brien     faket.t_dflg = F_BACKQ;
721c80476e4SDavid E. O'Brien     faket.t_dlef = 0;
722c80476e4SDavid E. O'Brien     faket.t_drit = 0;
723c80476e4SDavid E. O'Brien     faket.t_dspr = 0;
724c80476e4SDavid E. O'Brien     faket.t_dcom = fakecom;
72545e5710bSMark Peek     fakecom[0] = STRfakecom1;
72645e5710bSMark Peek     fakecom[1] = 0;
727c80476e4SDavid E. O'Brien 
72823338178SMark Peek     /*
72945e5710bSMark Peek      * We do the psave job to temporarily change the current job so that the
73045e5710bSMark Peek      * following fork is considered a separate job.  This is so that when
731c80476e4SDavid E. O'Brien      * backquotes are used in a builtin function that calls glob the "current
73245e5710bSMark Peek      * job" is not corrupted.  We only need one level of pushed jobs as long as
733c80476e4SDavid E. O'Brien      * we are sure to fork here.
734c80476e4SDavid E. O'Brien      */
735c80476e4SDavid E. O'Brien     psavejob();
73629301572SMark Peek     cleanup_push(&faket, psavejob_cleanup); /* faket is only a marker */
737c80476e4SDavid E. O'Brien 
73829301572SMark Peek     /*
73929301572SMark Peek      * It would be nicer if we could integrate this redirection more with the
74023338178SMark Peek      * routines in sh.sem.c by doing a fake execute on a builtin function that
74129301572SMark Peek      * was piped out.
74229301572SMark Peek      */
743c80476e4SDavid E. O'Brien     mypipe(pvec);
744c80476e4SDavid E. O'Brien     cleanup_push(&pvec[0], open_cleanup);
745c80476e4SDavid E. O'Brien     cleanup_push(&pvec[1], open_cleanup);
746c80476e4SDavid E. O'Brien     if (pfork(&faket, -1) == 0) {
747c80476e4SDavid E. O'Brien 	jmp_buf_t osetexit;
748c80476e4SDavid E. O'Brien 	struct command *t;
749c80476e4SDavid E. O'Brien 	size_t omark;
750c80476e4SDavid E. O'Brien 
751c80476e4SDavid E. O'Brien 	xclose(pvec[0]);
75223338178SMark Peek 	(void) dmove(pvec[1], 1);
75345e5710bSMark Peek 	(void) dmove(SHDIAG,  2);
75423338178SMark Peek 	initdesc();
75523338178SMark Peek 	closem();
75623338178SMark Peek 	arginp = cp;
75723338178SMark Peek 	for (arginp = cp; *cp; cp++) {
75823338178SMark Peek 	    *cp &= TRIM;
75923338178SMark Peek 	    if (is_set(STRcsubstnonl) && (*cp == '\n' || *cp == '\r'))
76023338178SMark Peek 		*cp = ' ';
76123338178SMark Peek 	}
76245e5710bSMark Peek 
76323338178SMark Peek         /*
76423338178SMark Peek 	 * In the child ``forget'' everything about current aliases or
76523338178SMark Peek 	 * eval vectors.
76623338178SMark Peek 	 */
76745e5710bSMark Peek 	alvec = NULL;
76823338178SMark Peek 	evalvec = NULL;
76923338178SMark Peek 	alvecp = NULL;
77023338178SMark Peek 	evalp = NULL;
771c80476e4SDavid E. O'Brien 
77245e5710bSMark Peek 	omark = cleanup_push_mark();
773c80476e4SDavid E. O'Brien 	getexit(osetexit);
774c80476e4SDavid E. O'Brien 	for (;;) {
775c80476e4SDavid E. O'Brien 	    struct wordent paraml1;
776c80476e4SDavid E. O'Brien 	    initlex(&paraml1);
77745e5710bSMark Peek 
778c80476e4SDavid E. O'Brien 	    (void) setexit();
779c80476e4SDavid E. O'Brien 	    justpr = 0;
780c80476e4SDavid E. O'Brien 
78145e5710bSMark Peek 	    if (haderr) {
782c80476e4SDavid E. O'Brien 		/* unwind */
783c80476e4SDavid E. O'Brien 		doneinp = 0;
78445e5710bSMark Peek 		cleanup_pop_mark(omark);
785c80476e4SDavid E. O'Brien 		resexit(osetexit);
786c80476e4SDavid E. O'Brien 		reset();
78745e5710bSMark Peek 	    }
788c80476e4SDavid E. O'Brien 	    if (seterr) {
78929301572SMark Peek 		xfree(seterr);
79023338178SMark Peek 		seterr = NULL;
79145e5710bSMark Peek 	    }
79223338178SMark Peek 
793c80476e4SDavid E. O'Brien 	    freelex(&paraml1);
79445e5710bSMark Peek 	    (void) lex(&paraml1);
795c80476e4SDavid E. O'Brien 	    cleanup_push(&paraml1, lex_cleanup);
796c80476e4SDavid E. O'Brien 	    if (seterr)
797c80476e4SDavid E. O'Brien 		stderror(ERR_OLD);
798c80476e4SDavid E. O'Brien 	    alias(&paraml1);
79923338178SMark Peek 	    t = syntax(paraml1.next, &paraml1, 0);
800c80476e4SDavid E. O'Brien 	    cleanup_push(t, syntax_cleanup);
80123338178SMark Peek 	    /* The F_BACKQ flag must set so the job output is correct if
802c80476e4SDavid E. O'Brien 	     * printexitvalue is set.  If it's not set, the job output
80323338178SMark Peek 	     * will have "Exit N" appended where N is the exit status. */
80423338178SMark Peek 	    if (t)
805c80476e4SDavid E. O'Brien 		    t->t_dflg = F_BACKQ|F_NOFORK;
806c80476e4SDavid E. O'Brien 	    if (seterr)
80745e5710bSMark Peek 		stderror(ERR_OLD);
80823338178SMark Peek #ifdef SIGTSTP
809c80476e4SDavid E. O'Brien 	    signal(SIGTSTP, SIG_IGN);
81023338178SMark Peek #endif
81123338178SMark Peek #ifdef SIGTTIN
81223338178SMark Peek 	    signal(SIGTTIN, SIG_IGN);
81323338178SMark Peek #endif
814c80476e4SDavid E. O'Brien #ifdef SIGTTOU
81523338178SMark Peek 	    signal(SIGTTOU, SIG_IGN);
81623338178SMark Peek #endif
81723338178SMark Peek 	    execute(t, -1, NULL, NULL, TRUE);
81823338178SMark Peek 
81923338178SMark Peek 	    cleanup_until(&paraml1);
82023338178SMark Peek 	}
82123338178SMark Peek     }
82223338178SMark Peek     cleanup_until(&pvec[1]);
82323338178SMark Peek     c = 0;
82423338178SMark Peek     ip = NULL;
82523338178SMark Peek     do {
82623338178SMark Peek 	ssize_t     cnt = 0;
82723338178SMark Peek 
82823338178SMark Peek 	for (;;) {
82923338178SMark Peek 	    if (icnt == 0) {
83023338178SMark Peek 		ip = ibuf;
83123338178SMark Peek 		icnt = wide_read(pvec[0], ibuf, BUFSIZE, 0);
83223338178SMark Peek 		if (icnt <= 0)
83323338178SMark Peek 		    goto eof;
83423338178SMark Peek 	    }
83523338178SMark Peek 	    if (hadnl)
83623338178SMark Peek 		break;
83723338178SMark Peek 	    --icnt;
838c80476e4SDavid E. O'Brien 	    c = (*ip++ & TRIM);
839c80476e4SDavid E. O'Brien 	    if (c == 0)
840c80476e4SDavid E. O'Brien 		break;
841c80476e4SDavid E. O'Brien #if defined(WINNT_NATIVE) || defined(__CYGWIN__)
842c80476e4SDavid E. O'Brien 	    if (c == '\r')
843c80476e4SDavid E. O'Brien 	    	c = ' ';
844c80476e4SDavid E. O'Brien #endif /* WINNT_NATIVE || __CYGWIN__ */
8453b6eaa7bSAndrey A. Chernov 	    if (c == '\n') {
846c80476e4SDavid E. O'Brien 		/*
847c80476e4SDavid E. O'Brien 		 * Continue around the loop one more time, so that we can eat
8483b6eaa7bSAndrey A. Chernov 		 * the last newline without terminating this word.
849c80476e4SDavid E. O'Brien 		 */
850c80476e4SDavid E. O'Brien 		hadnl = 1;
851c80476e4SDavid E. O'Brien 		continue;
852c80476e4SDavid E. O'Brien 	    }
853c80476e4SDavid E. O'Brien 	    if (!quoted && (c == ' ' || c == '\t'))
854c80476e4SDavid E. O'Brien 		break;
855c80476e4SDavid E. O'Brien 	    cnt++;
856c80476e4SDavid E. O'Brien 	    if (c == '\\' || quoted)
857c80476e4SDavid E. O'Brien 		c |= QUOTE;
858c80476e4SDavid E. O'Brien 	    Strbuf_append1(word, c);
859c80476e4SDavid E. O'Brien 	}
86045e5710bSMark Peek 	/*
861c80476e4SDavid E. O'Brien 	 * Unless at end-of-file, we will form a new word here if there were
862c80476e4SDavid E. O'Brien 	 * characters in the word, or in any case when we take text literally.
863c80476e4SDavid E. O'Brien 	 * If we didn't make empty words here when literal was set then we
864c80476e4SDavid E. O'Brien 	 * would lose blank lines.
865c80476e4SDavid E. O'Brien 	 */
866c80476e4SDavid E. O'Brien 	if (c != 0 && (cnt || literal))
867c80476e4SDavid E. O'Brien 	    pword(bb, word);
86823338178SMark Peek 	hadnl = 0;
86945e5710bSMark Peek     } while (c > 0);
870c80476e4SDavid E. O'Brien  eof:
87123338178SMark Peek     cleanup_until(&pvec[0]);
87223338178SMark Peek     pwait();
87345e5710bSMark Peek     cleanup_until(&faket); /* psavejob_cleanup(); */
874c80476e4SDavid E. O'Brien }
87545e5710bSMark Peek 
876c80476e4SDavid E. O'Brien static void
pword(struct blk_buf * bb,struct Strbuf * word)877c80476e4SDavid E. O'Brien pword(struct blk_buf *bb, struct Strbuf *word)
878c80476e4SDavid E. O'Brien {
87945e5710bSMark Peek     Char *s;
880c80476e4SDavid E. O'Brien 
88145e5710bSMark Peek     s = Strbuf_finish(word);
882c80476e4SDavid E. O'Brien     bb_append(bb, s);
88345e5710bSMark Peek     *word = Strbuf_init;
88445e5710bSMark Peek }
88545e5710bSMark Peek 
886c80476e4SDavid E. O'Brien int
Gmatch(const Char * string,const Char * pattern)887c80476e4SDavid E. O'Brien Gmatch(const Char *string, const Char *pattern)
888c80476e4SDavid E. O'Brien {
88945e5710bSMark Peek     return Gnmatch(string, pattern, NULL);
890c80476e4SDavid E. O'Brien }
891c80476e4SDavid E. O'Brien 
892c80476e4SDavid E. O'Brien int
Gnmatch(const Char * string,const Char * pattern,const Char ** endstr)893c80476e4SDavid E. O'Brien Gnmatch(const Char *string, const Char *pattern, const Char **endstr)
894c80476e4SDavid E. O'Brien {
89545e5710bSMark Peek     Char ***fblk, **p;
896c80476e4SDavid E. O'Brien     const Char *tstring = string;
89745e5710bSMark Peek     int	   gpol = 1, gres = 0;
89845e5710bSMark Peek 
899c80476e4SDavid E. O'Brien     if (*pattern == '^') {
900c80476e4SDavid E. O'Brien 	gpol = 0;
901c80476e4SDavid E. O'Brien 	pattern++;
902c80476e4SDavid E. O'Brien     }
903c80476e4SDavid E. O'Brien 
904c80476e4SDavid E. O'Brien     fblk = xmalloc(sizeof(Char ***));
905c80476e4SDavid E. O'Brien     *fblk = xmalloc(GLOBSPACE * sizeof(Char *));
90645e5710bSMark Peek     (*fblk)[0] = Strsave(pattern);
90745e5710bSMark Peek     (*fblk)[1] = NULL;
90845e5710bSMark Peek 
90945e5710bSMark Peek     cleanup_push(fblk, blk_indirect_cleanup);
910c80476e4SDavid E. O'Brien     expbrace(fblk, NULL, GLOBSPACE);
91145e5710bSMark Peek 
91245e5710bSMark Peek     if (endstr == NULL)
913c80476e4SDavid E. O'Brien 	/* Exact matches only */
914c80476e4SDavid E. O'Brien 	for (p = *fblk; *p; p++)
915c80476e4SDavid E. O'Brien 	    gres |= t_pmatch(string, *p, &tstring, 1) == 2 ? 1 : 0;
91645e5710bSMark Peek     else {
91723338178SMark Peek 	const Char *end;
918c80476e4SDavid E. O'Brien 
91945e5710bSMark Peek 	/* partial matches */
92045e5710bSMark Peek         end = Strend(string);
921c80476e4SDavid E. O'Brien 	for (p = *fblk; *p; p++)
92245e5710bSMark Peek 	    if (t_pmatch(string, *p, &tstring, 1) != 0) {
92345e5710bSMark Peek 		gres |= 1;
92423338178SMark Peek 		if (end > tstring)
925c80476e4SDavid E. O'Brien 		    end = tstring;
92645e5710bSMark Peek 	    }
92745e5710bSMark Peek 	*endstr = end;
928c80476e4SDavid E. O'Brien     }
92945e5710bSMark Peek 
930c80476e4SDavid E. O'Brien     cleanup_until(fblk);
931c80476e4SDavid E. O'Brien     return(gres == gpol);
93245e5710bSMark Peek }
933c80476e4SDavid E. O'Brien 
934c80476e4SDavid E. O'Brien /* t_pmatch():
935c80476e4SDavid E. O'Brien  *	Return 2 on exact match,
936b2d5d167SMark Peek  *	Return 1 on substring match.
937c80476e4SDavid E. O'Brien  *	Return 0 on no match.
938c80476e4SDavid E. O'Brien  *	*estr will point to the end of the longest exact or substring match.
939c80476e4SDavid E. O'Brien  */
940c80476e4SDavid E. O'Brien int
t_pmatch(const Char * string,const Char * pattern,const Char ** estr,int cs)941c80476e4SDavid E. O'Brien t_pmatch(const Char *string, const Char *pattern, const Char **estr, int cs)
942b2d5d167SMark Peek {
94345e5710bSMark Peek     Char stringc, patternc, rangec;
944c80476e4SDavid E. O'Brien     int     match, negate_range;
94545e5710bSMark Peek     const Char *pestr, *nstring;
946c80476e4SDavid E. O'Brien 
94745e5710bSMark Peek     for (nstring = string;; string = nstring) {
948c80476e4SDavid E. O'Brien 	stringc = *nstring++ & TRIM;
94923338178SMark Peek 	patternc = *pattern++ & TRIM;
95045e5710bSMark Peek 	switch (patternc) {
95145e5710bSMark Peek 	case '\0':
952c80476e4SDavid E. O'Brien 	    *estr = string;
95323338178SMark Peek 	    return (stringc == '\0' ? 2 : 1);
954c80476e4SDavid E. O'Brien 	case '?':
95523338178SMark Peek 	    if (stringc == 0)
956c80476e4SDavid E. O'Brien 		return (0);
957c80476e4SDavid E. O'Brien 	    break;
958c80476e4SDavid E. O'Brien 	case '*':
959c80476e4SDavid E. O'Brien 	    if (!*pattern) {
960c80476e4SDavid E. O'Brien 		*estr = Strend(string);
961c80476e4SDavid E. O'Brien 		return (2);
96245e5710bSMark Peek 	    }
963c80476e4SDavid E. O'Brien 	    pestr = NULL;
964c80476e4SDavid E. O'Brien 
965c80476e4SDavid E. O'Brien 	    for (;;) {
966c80476e4SDavid E. O'Brien 		switch(t_pmatch(string, pattern, estr, cs)) {
96723338178SMark Peek 		case 0:
968b2d5d167SMark Peek 		    break;
969c80476e4SDavid E. O'Brien 		case 1:
970c80476e4SDavid E. O'Brien 		    pestr = *estr;/*FIXME: does not guarantee longest match */
971c80476e4SDavid E. O'Brien 		    break;
97245e5710bSMark Peek 		case 2:
973c80476e4SDavid E. O'Brien 		    return 2;
974c80476e4SDavid E. O'Brien 		default:
975c80476e4SDavid E. O'Brien 		    abort();	/* Cannot happen */
976c80476e4SDavid E. O'Brien 		}
977c80476e4SDavid E. O'Brien 		stringc = *string++ & TRIM;
978c80476e4SDavid E. O'Brien 		if (!stringc)
97945e5710bSMark Peek 		    break;
98023338178SMark Peek 	    }
98123338178SMark Peek 
982c80476e4SDavid E. O'Brien 	    if (pestr) {
983c80476e4SDavid E. O'Brien 		*estr = pestr;
984c80476e4SDavid E. O'Brien 		return 1;
985c80476e4SDavid E. O'Brien 	    }
986c80476e4SDavid E. O'Brien 	    else
987c80476e4SDavid E. O'Brien 		return 0;
98845e5710bSMark Peek 
989c80476e4SDavid E. O'Brien 	case '[':
990c80476e4SDavid E. O'Brien 	    match = 0;
991c80476e4SDavid E. O'Brien 	    if ((negate_range = (*pattern == '^')) != 0)
992c80476e4SDavid E. O'Brien 		pattern++;
993c80476e4SDavid E. O'Brien 	    while ((rangec = *pattern++ & TRIM) != '\0') {
994c80476e4SDavid E. O'Brien 		if (rangec == ']')
99545e5710bSMark Peek 		    break;
996c80476e4SDavid E. O'Brien 		if (match)
997c80476e4SDavid E. O'Brien 		    continue;
998c80476e4SDavid E. O'Brien 		if (*pattern == '-' && pattern[1] != ']') {
999c80476e4SDavid E. O'Brien 		    Char rangec2;
100023338178SMark Peek 		    pattern++;
100145e5710bSMark Peek 		    rangec2 = *pattern++ & TRIM;
1002c80476e4SDavid E. O'Brien 		    match = (globcharcoll(stringc, rangec2, 0) <= 0 &&
100345e5710bSMark Peek 			globcharcoll(rangec, stringc, 0) <= 0);
100423338178SMark Peek 		}
100523338178SMark Peek 		else
1006c80476e4SDavid E. O'Brien 		    match = (stringc == rangec);
1007c80476e4SDavid E. O'Brien 	    }
100823338178SMark Peek 	    if (rangec == '\0')
1009c80476e4SDavid E. O'Brien 		stderror(ERR_NAME | ERR_MISSING, ']');
101023338178SMark Peek 	    if ((!match) && (stringc == '\0'))
1011c80476e4SDavid E. O'Brien 		return (0);
101223338178SMark Peek 	    if (match == negate_range)
101323338178SMark Peek 		return (0);
1014c80476e4SDavid E. O'Brien 	    break;
1015c80476e4SDavid E. O'Brien 	default:
1016c80476e4SDavid E. O'Brien 	    if (cs ? patternc  != stringc
1017c80476e4SDavid E. O'Brien 		: Tolower(patternc) != Tolower(stringc))
101823338178SMark Peek 		return (0);
101923338178SMark Peek 	    break;
1020c80476e4SDavid E. O'Brien 	}
1021c80476e4SDavid E. O'Brien     }
1022c80476e4SDavid E. O'Brien }
1023c80476e4SDavid E. O'Brien