xref: /freebsd/contrib/tcsh/sh.glob.c (revision 6560ac57ce879857203bc456cdc3849808dc0700)
1c80476e4SDavid E. O'Brien /*
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.
1629301572SMark Peek  * 3. Neither the name of the University nor the names of its contributors
17c80476e4SDavid E. O'Brien  *    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"
3429301572SMark Peek #include "tw.h"
35c80476e4SDavid E. O'Brien 
36c80476e4SDavid E. O'Brien #include "glob.h"
37c80476e4SDavid E. O'Brien 
38c80476e4SDavid E. O'Brien /*
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  */
6345e5710bSMark Peek static	Char	 *globtilde	(Char *);
6445e5710bSMark Peek static	Char     *handleone	(Char *, Char **, int);
6545e5710bSMark Peek static	Char	**libglob	(Char **);
6645e5710bSMark Peek 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);
72c80476e4SDavid E. O'Brien static Char *
globtilde(Char * s)7345e5710bSMark Peek globtilde(Char *s)
74c80476e4SDavid E. O'Brien {
7545e5710bSMark Peek     Char *name, *u, *home, *res;
76c80476e4SDavid E. O'Brien 
77c80476e4SDavid E. O'Brien     u = s;
78*5224c2a3SDmitry Chagin 
79*5224c2a3SDmitry Chagin     if (s[1] == '~')
80*5224c2a3SDmitry Chagin 	return Strsave(s);
81*5224c2a3SDmitry Chagin 
8245e5710bSMark Peek     for (s++; *s && *s != '/' && *s != ':'; s++)
83c80476e4SDavid E. O'Brien 	continue;
84*5224c2a3SDmitry Chagin 
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)
9445e5710bSMark Peek 	    stderror(ERR_UNKUSER, short2str(name));
95c80476e4SDavid E. O'Brien 	else
96c80476e4SDavid E. O'Brien 	    stderror(ERR_NOHOME);
97c80476e4SDavid E. O'Brien     }
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);
10545e5710bSMark Peek     return res;
106c80476e4SDavid E. O'Brien }
107c80476e4SDavid E. O'Brien 
10845e5710bSMark Peek /* Returns a newly allocated string, old or NULL */
109c80476e4SDavid E. O'Brien Char *
globequal(Char * old)11045e5710bSMark Peek globequal(Char *old)
111c80476e4SDavid E. O'Brien {
112c80476e4SDavid E. O'Brien     int     dig;
11345e5710bSMark Peek     const Char *dir;
11445e5710bSMark Peek     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] == '/')) {
121c80476e4SDavid E. O'Brien 	/* =- */
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)
12645e5710bSMark Peek 	    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;
142c80476e4SDavid E. O'Brien 
14345e5710bSMark Peek     dir = getstakd(dig);
14445e5710bSMark Peek     if (dir == NULL)
145c80476e4SDavid E. O'Brien 	return NULL;
14645e5710bSMark Peek     return Strspl(dir, b);
147c80476e4SDavid E. O'Brien }
148c80476e4SDavid E. O'Brien 
149c80476e4SDavid E. O'Brien static int
globbrace(const Char * s,Char *** bl)15045e5710bSMark Peek globbrace(const Char *s, Char ***bl)
151c80476e4SDavid E. O'Brien {
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;
15645e5710bSMark Peek     size_t prefix_len;
157c80476e4SDavid E. O'Brien 
158c80476e4SDavid E. O'Brien     /* copy part up to the brace */
15945e5710bSMark Peek     for (p = s; *p != LBRC; p++)
16045e5710bSMark Peek 	;
16145e5710bSMark Peek     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++)
168c80476e4SDavid E. O'Brien 		continue;
16945e5710bSMark Peek 	    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 	}
179c80476e4SDavid E. O'Brien 
18045e5710bSMark Peek     if (i != 0 || *pe == '\0')
181c80476e4SDavid E. O'Brien 	return (-RBRC);
18245e5710bSMark Peek 
18345e5710bSMark Peek     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;
190c80476e4SDavid E. O'Brien 	    if (*pm == EOS) {
19145e5710bSMark Peek 		bb_cleanup(&bb);
19245e5710bSMark Peek 		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;
208c80476e4SDavid E. O'Brien 	    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);
21345e5710bSMark Peek 		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;
219c80476e4SDavid E. O'Brien 	}
22045e5710bSMark Peek     *bl = bb_finish(&bb);
22145e5710bSMark Peek     xfree(gbuf.s);
22245e5710bSMark Peek     return bb.len;
223c80476e4SDavid E. O'Brien }
224c80476e4SDavid E. O'Brien 
225c80476e4SDavid E. O'Brien 
226c80476e4SDavid E. O'Brien static void
expbrace(Char *** nvp,Char *** elp,int size)22745e5710bSMark Peek 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;
234c80476e4SDavid E. O'Brien     else
23545e5710bSMark Peek 	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')))
242c80476e4SDavid E. O'Brien 	    continue;
24345e5710bSMark Peek 	if (Strchr(s, '{') != NULL) {
24445e5710bSMark Peek 	    Char  **bl = NULL;
245c80476e4SDavid E. O'Brien 	    int     len;
246c80476e4SDavid E. O'Brien 
24745e5710bSMark Peek 	    if ((len = globbrace(s, &bl)) < 0)
248c80476e4SDavid E. O'Brien 		stderror(ERR_MISSING, -len);
24945e5710bSMark Peek 	    xfree(s);
250c80476e4SDavid E. O'Brien 	    if (len == 1) {
251c80476e4SDavid E. O'Brien 		*vl-- = *bl;
25245e5710bSMark Peek 		xfree(bl);
253c80476e4SDavid E. O'Brien 		continue;
254c80476e4SDavid E. O'Brien 	    }
255c80476e4SDavid E. O'Brien 	    if (&el[len] >= &nv[size]) {
25645e5710bSMark Peek 		size_t l, e;
25745e5710bSMark Peek 		l = &el[len] - &nv[size];
258c80476e4SDavid E. O'Brien 		size += GLOBSPACE > l ? GLOBSPACE : l;
25945e5710bSMark Peek 		l = vl - nv;
26045e5710bSMark Peek 		e = el - nv;
26145e5710bSMark Peek 		nv = xrealloc(nv, size * sizeof(Char *));
26245e5710bSMark Peek 		*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++)
286c80476e4SDavid E. O'Brien 		continue;
28745e5710bSMark Peek 	    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 
295c80476e4SDavid E. O'Brien static Char **
globexpand(Char ** v,int noglob)29645e5710bSMark Peek globexpand(Char **v, int noglob)
297c80476e4SDavid E. O'Brien {
298c80476e4SDavid E. O'Brien     Char   *s;
29945e5710bSMark Peek     Char  ***fnv, **vl, **el;
300c80476e4SDavid E. O'Brien     int     size = GLOBSPACE;
301c80476e4SDavid E. O'Brien 
302c80476e4SDavid E. O'Brien 
30345e5710bSMark Peek     fnv = xmalloc(sizeof(Char ***));
30445e5710bSMark Peek     *fnv = vl = xmalloc(sizeof(Char *) * size);
305c80476e4SDavid E. O'Brien     *vl = NULL;
30645e5710bSMark Peek     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      */
311cc698b49SBrooks Davis     while ((s = *v++) != NULL) {
312c80476e4SDavid E. O'Brien 	if (Strchr(s, '`')) {
313c80476e4SDavid E. O'Brien 	    int     i;
31445e5710bSMark Peek 	    Char **expanded;
315c80476e4SDavid E. O'Brien 
31645e5710bSMark Peek 	    expanded = dobackp(s, 0);
31745e5710bSMark Peek 	    for (i = 0; expanded[i] != NULL; i++) {
31845e5710bSMark Peek 		*vl++ = expanded[i];
31945e5710bSMark Peek 		if (vl == &(*fnv)[size]) {
320c80476e4SDavid E. O'Brien 		    size += GLOBSPACE;
32145e5710bSMark Peek 		    *fnv = xrealloc(*fnv, size * sizeof(Char *));
32245e5710bSMark Peek 		    vl = &(*fnv)[size - GLOBSPACE];
323c80476e4SDavid E. O'Brien 		}
324c80476e4SDavid E. O'Brien 	    }
32545e5710bSMark Peek 	    xfree(expanded);
326c80476e4SDavid E. O'Brien 	}
327c80476e4SDavid E. O'Brien 	else {
328c80476e4SDavid E. O'Brien 	    *vl++ = Strsave(s);
32945e5710bSMark Peek 	    if (vl == &(*fnv)[size]) {
330c80476e4SDavid E. O'Brien 		size += GLOBSPACE;
33145e5710bSMark Peek 		*fnv = xrealloc(*fnv, size * sizeof(Char *));
33245e5710bSMark Peek 		vl = &(*fnv)[size - GLOBSPACE];
333c80476e4SDavid E. O'Brien 	    }
334c80476e4SDavid E. O'Brien 	}
335c80476e4SDavid E. O'Brien 	*vl = NULL;
33645e5710bSMark Peek     }
337c80476e4SDavid E. O'Brien 
338c80476e4SDavid E. O'Brien     if (noglob)
33945e5710bSMark Peek 	goto done;
340c80476e4SDavid E. O'Brien 
341c80476e4SDavid E. O'Brien     /*
342c80476e4SDavid E. O'Brien      * Step 2: expand braces
343c80476e4SDavid E. O'Brien      */
344c80476e4SDavid E. O'Brien     el = vl;
34545e5710bSMark Peek     expbrace(fnv, &el, size);
346c80476e4SDavid E. O'Brien 
347c80476e4SDavid E. O'Brien 
348c80476e4SDavid E. O'Brien     /*
349c80476e4SDavid E. O'Brien      * Step 3: expand ~ =
350c80476e4SDavid E. O'Brien      */
35145e5710bSMark Peek     vl = *fnv;
352c80476e4SDavid E. O'Brien     for (s = *vl; s; s = *++vl)
353c80476e4SDavid E. O'Brien 	switch (*s) {
35445e5710bSMark Peek 	    Char *ns;
355c80476e4SDavid E. O'Brien 	case '~':
35645e5710bSMark Peek 	    *vl = globtilde(s);
357c80476e4SDavid E. O'Brien 	    break;
358c80476e4SDavid E. O'Brien 	case '=':
35945e5710bSMark Peek 	    if ((ns = globequal(s)) == NULL) {
36045e5710bSMark Peek 		if (!adrof(STRnonomatch))
36145e5710bSMark Peek 		    stderror(ERR_DEEP); /* Error */
362c80476e4SDavid E. O'Brien 	    }
363c80476e4SDavid E. O'Brien 	    if (ns && ns != s) {
364c80476e4SDavid E. O'Brien 		/* Expansion succeeded */
36545e5710bSMark Peek 		xfree(s);
36645e5710bSMark Peek 		*vl = ns;
367c80476e4SDavid E. O'Brien 	    }
368c80476e4SDavid E. O'Brien 	    break;
369c80476e4SDavid E. O'Brien 	default:
370c80476e4SDavid E. O'Brien 	    break;
371c80476e4SDavid E. O'Brien 	}
37245e5710bSMark Peek     vl = *fnv;
373c80476e4SDavid E. O'Brien 
374c80476e4SDavid E. O'Brien     /*
375c80476e4SDavid E. O'Brien      * Step 4: expand .. if the variable symlinks==expand is set
376c80476e4SDavid E. O'Brien      */
3776767bd61SMark Peek     if (symlinks == SYM_EXPAND) {
378c80476e4SDavid E. O'Brien 	for (s = *vl; s; s = *++vl) {
379c80476e4SDavid E. O'Brien 	    *vl = dnormalize(s, 1);
38045e5710bSMark Peek 	    xfree(s);
381c80476e4SDavid E. O'Brien 	}
3823b6eaa7bSAndrey A. Chernov     }
383c80476e4SDavid E. O'Brien 
38445e5710bSMark Peek  done:
38545e5710bSMark Peek     cleanup_ignore(fnv);
38645e5710bSMark Peek     cleanup_until(fnv);
38745e5710bSMark Peek     vl = *fnv;
38845e5710bSMark Peek     xfree(fnv);
38945e5710bSMark Peek     return vl;
390c80476e4SDavid E. O'Brien }
391c80476e4SDavid E. O'Brien 
392c80476e4SDavid E. O'Brien static Char *
handleone(Char * str,Char ** vl,int action)39345e5710bSMark Peek handleone(Char *str, Char **vl, int action)
394c80476e4SDavid E. O'Brien {
39545e5710bSMark Peek     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:
405c80476e4SDavid E. O'Brien 	chars = 0;
40645e5710bSMark Peek 	for (t = vl; (p = *t++) != NULL; chars++)
40745e5710bSMark Peek 	    chars += Strlen(p);
40845e5710bSMark Peek 	str = xmalloc(chars * sizeof(Char));
409cc698b49SBrooks Davis 	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;
417c80476e4SDavid E. O'Brien     case G_IGNORE:
41845e5710bSMark Peek 	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 
427c80476e4SDavid E. O'Brien static Char **
libglob(Char ** vl)42845e5710bSMark Peek 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 
4359ccc37e3SMark Peek     if (adrof(STRglobdot))
4369ccc37e3SMark Peek        gflgs |= GLOB_DOT;
4379ccc37e3SMark Peek 
4389ccc37e3SMark Peek     if (adrof(STRglobstar))
4399ccc37e3SMark Peek        gflgs |= GLOB_STAR;
4409ccc37e3SMark Peek 
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);
473c80476e4SDavid E. O'Brien     vl = (globv.gl_pathc == 0 || (magic && !match && !nonomatch)) ?
474c80476e4SDavid E. O'Brien 	NULL : blk2short(globv.gl_pathv);
475c80476e4SDavid E. O'Brien     globfree(&globv);
476c80476e4SDavid E. O'Brien     return (vl);
477c80476e4SDavid E. O'Brien }
478c80476e4SDavid E. O'Brien 
479c80476e4SDavid E. O'Brien Char   *
globone(Char * str,int action)48045e5710bSMark Peek globone(Char *str, int action)
481c80476e4SDavid E. O'Brien {
482c80476e4SDavid E. O'Brien     Char   *v[2], **vl, **vo;
48345e5710bSMark Peek     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;
48845e5710bSMark Peek     gflg = tglob(v);
489c80476e4SDavid E. O'Brien     if (gflg == G_NONE)
490c80476e4SDavid E. O'Brien 	return (strip(Strsave(str)));
491c80476e4SDavid E. O'Brien 
492c80476e4SDavid E. O'Brien     if (gflg & G_CSH) {
493c80476e4SDavid E. O'Brien 	/*
494c80476e4SDavid E. O'Brien 	 * Expand back-quote, tilde and brace
495c80476e4SDavid E. O'Brien 	 */
49645e5710bSMark Peek 	vo = globexpand(v, noglob);
497c80476e4SDavid E. O'Brien 	if (noglob || (gflg & G_GLOB) == 0) {
49845e5710bSMark Peek 	    vl = vo;
49945e5710bSMark Peek 	    goto result;
500c80476e4SDavid E. O'Brien 	}
50145e5710bSMark Peek 	cleanup_push(vo, blk_cleanup);
502c80476e4SDavid E. O'Brien     }
503c80476e4SDavid E. O'Brien     else if (noglob || (gflg & G_GLOB) == 0)
504c80476e4SDavid E. O'Brien 	return (strip(Strsave(str)));
505c80476e4SDavid E. O'Brien     else
506c80476e4SDavid E. O'Brien 	vo = v;
507c80476e4SDavid E. O'Brien 
508c80476e4SDavid E. O'Brien     vl = libglob(vo);
50945e5710bSMark Peek     if (gflg & G_CSH) {
51045e5710bSMark Peek     	if (vl != vo)
51145e5710bSMark Peek 	    cleanup_until(vo);
51245e5710bSMark Peek 	else
51345e5710bSMark Peek 	    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     }
51945e5710bSMark Peek  result:
5209ccc37e3SMark Peek     if (vl && vl[0] == NULL) {
521*5224c2a3SDmitry Chagin 	if (vl != v)
52245e5710bSMark Peek 	    xfree(vl);
523c80476e4SDavid E. O'Brien 	return (Strsave(STRNULL));
524c80476e4SDavid E. O'Brien     }
5259ccc37e3SMark Peek     if (vl && vl[1])
526c80476e4SDavid E. O'Brien 	return (handleone(str, vl, action));
527c80476e4SDavid E. O'Brien     else {
528c80476e4SDavid E. O'Brien 	str = strip(*vl);
529*5224c2a3SDmitry Chagin 	if (vl != v)
53045e5710bSMark Peek 	    xfree(vl);
531c80476e4SDavid E. O'Brien 	return (str);
532c80476e4SDavid E. O'Brien     }
533c80476e4SDavid E. O'Brien }
534c80476e4SDavid E. O'Brien 
535c80476e4SDavid E. O'Brien Char  **
globall(Char ** v,int gflg)53645e5710bSMark Peek globall(Char **v, int gflg)
537c80476e4SDavid E. O'Brien {
538c80476e4SDavid E. O'Brien     Char  **vl, **vo;
53945e5710bSMark Peek     int noglob;
540c80476e4SDavid E. O'Brien 
54145e5710bSMark Peek     if (!v || !v[0])
54245e5710bSMark Peek 	return saveblk(v);
543c80476e4SDavid E. O'Brien 
544c80476e4SDavid E. O'Brien     noglob = adrof(STRnoglob) != 0;
545c80476e4SDavid E. O'Brien 
546c80476e4SDavid E. O'Brien     if (gflg & G_CSH)
547c80476e4SDavid E. O'Brien 	/*
548c80476e4SDavid E. O'Brien 	 * Expand back-quote, tilde and brace
549c80476e4SDavid E. O'Brien 	 */
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);
55745e5710bSMark Peek 	if (vl == vo)
55845e5710bSMark Peek 	    cleanup_ignore(vo);
55945e5710bSMark Peek 	cleanup_until(vo);
560c80476e4SDavid E. O'Brien     }
561c80476e4SDavid E. O'Brien     else
562c80476e4SDavid E. O'Brien 	trim(vl);
563c80476e4SDavid E. O'Brien 
56445e5710bSMark Peek     return vl;
565c80476e4SDavid E. O'Brien }
566c80476e4SDavid E. O'Brien 
56745e5710bSMark Peek Char **
glob_all_or_error(Char ** v)56845e5710bSMark Peek glob_all_or_error(Char **v)
569c80476e4SDavid E. O'Brien {
57045e5710bSMark Peek     int gflag;
57145e5710bSMark Peek 
57245e5710bSMark Peek     gflag = tglob(v);
57345e5710bSMark Peek     if (gflag) {
57445e5710bSMark Peek 	v = globall(v, gflag);
57545e5710bSMark Peek 	if (v == NULL)
57645e5710bSMark Peek 	    stderror(ERR_NAME | ERR_NOMATCH);
57745e5710bSMark Peek     } else {
57845e5710bSMark Peek 	v = saveblk(v);
57945e5710bSMark Peek 	trim(v);
58045e5710bSMark Peek     }
58145e5710bSMark Peek     return v;
582c80476e4SDavid E. O'Brien }
583c80476e4SDavid E. O'Brien 
584c80476e4SDavid E. O'Brien void
rscan(Char ** t,void (* f)(Char))58545e5710bSMark Peek rscan(Char **t, void (*f) (Char))
586c80476e4SDavid E. O'Brien {
58723338178SMark Peek     Char *p;
588c80476e4SDavid E. O'Brien 
589cc698b49SBrooks Davis     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)
596c80476e4SDavid E. O'Brien {
59723338178SMark Peek     Char *p;
598c80476e4SDavid E. O'Brien 
599cc698b49SBrooks Davis     while ((p = *t++) != NULL)
60019d2e3deSDmitry Chagin 	while (*p) {
60119d2e3deSDmitry Chagin #if INVALID_BYTE != 0
60219d2e3deSDmitry Chagin 	    if ((*p & INVALID_BYTE) != INVALID_BYTE)	/* *p < INVALID_BYTE */
60319d2e3deSDmitry Chagin #endif
60419d2e3deSDmitry Chagin 		*p &= TRIM;
60519d2e3deSDmitry Chagin 	    p++;
60619d2e3deSDmitry Chagin 	}
607c80476e4SDavid E. O'Brien }
608c80476e4SDavid E. O'Brien 
60945e5710bSMark Peek int
tglob(Char ** t)61045e5710bSMark Peek tglob(Char **t)
611c80476e4SDavid E. O'Brien {
61245e5710bSMark Peek     int gflag;
61345e5710bSMark Peek     const Char *p;
614c80476e4SDavid E. O'Brien 
61545e5710bSMark Peek     gflag = 0;
616cc698b49SBrooks Davis     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;
62245e5710bSMark Peek 	while (*p != '\0') {
62345e5710bSMark Peek 	    if (*p == '`') {
624c80476e4SDavid E. O'Brien 		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\
628c80476e4SDavid E. O'Brien 		 * 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++ == '\\') {
633c80476e4SDavid E. O'Brien 			if (*p)		/* Quoted chars */
634c80476e4SDavid E. O'Brien 			    p++;
635c80476e4SDavid E. O'Brien 			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 	    }
64245e5710bSMark Peek 	    else if (*p == '{')
643c80476e4SDavid E. O'Brien 		gflag |= G_CSH;
64445e5710bSMark Peek 	    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++;
650c80476e4SDavid E. O'Brien 	}
651c80476e4SDavid E. O'Brien     }
65245e5710bSMark Peek     return gflag;
653c80476e4SDavid E. O'Brien }
654c80476e4SDavid E. O'Brien 
655c80476e4SDavid E. O'Brien /*
656c80476e4SDavid E. O'Brien  * Command substitute cp.  If literal, then this is a substitution from a
657c80476e4SDavid E. O'Brien  * << redirection, and so we should not crunch blanks and tabs, separating
658c80476e4SDavid E. O'Brien  * words only at newlines.
659c80476e4SDavid E. O'Brien  */
660c80476e4SDavid E. O'Brien Char  **
dobackp(Char * cp,int literal)66145e5710bSMark Peek dobackp(Char *cp, int literal)
662c80476e4SDavid E. O'Brien {
66345e5710bSMark Peek     struct Strbuf word = Strbuf_INIT;
66445e5710bSMark Peek     struct blk_buf bb = BLK_BUF_INIT;
66545e5710bSMark Peek     Char *lp, *rp, *ep;
666c80476e4SDavid E. O'Brien 
66745e5710bSMark Peek     cleanup_push(&bb, bb_cleanup);
66845e5710bSMark Peek     cleanup_push(&word, Strbuf_cleanup);
669c80476e4SDavid E. O'Brien     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;
675c80476e4SDavid E. O'Brien 	lp++;
676c80476e4SDavid E. O'Brien 	for (rp = lp; *rp && *rp != '`'; rp++)
677c80476e4SDavid E. O'Brien 	    if (*rp == '\\') {
678c80476e4SDavid E. O'Brien 		rp++;
679c80476e4SDavid E. O'Brien 		if (!*rp)
680c80476e4SDavid E. O'Brien 		    goto oops;
681c80476e4SDavid E. O'Brien 	    }
68245e5710bSMark Peek 	if (!*rp) {
68345e5710bSMark Peek 	oops:
684a15e6f9aSMark Peek 	    cleanup_until(&bb);
68545e5710bSMark Peek 	    stderror(ERR_UNMATCHED, '`');
68645e5710bSMark Peek 	}
68745e5710bSMark Peek 	ep = Strnsave(lp, rp - lp);
68845e5710bSMark Peek 	cleanup_push(ep, xfree);
68945e5710bSMark Peek 	backeval(&bb, &word, ep, literal);
69045e5710bSMark Peek 	cleanup_until(ep);
691c80476e4SDavid E. O'Brien 	cp = rp + 1;
692c80476e4SDavid E. O'Brien     }
69345e5710bSMark Peek     if (word.len != 0)
69445e5710bSMark Peek 	pword(&bb, &word);
69545e5710bSMark Peek     cleanup_ignore(&bb);
69645e5710bSMark Peek     cleanup_until(&bb);
69745e5710bSMark Peek     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)70245e5710bSMark Peek backeval(struct blk_buf *bb, struct Strbuf *word, Char *cp, int literal)
703c80476e4SDavid E. O'Brien {
7049ccc37e3SMark Peek     ssize_t icnt;
70523338178SMark Peek     Char c, *ip;
706c80476e4SDavid E. O'Brien     struct command faket;
70723338178SMark Peek     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;
71319d2e3deSDmitry Chagin     if (!literal) {
71419d2e3deSDmitry Chagin 	for (ip = cp; (*ip & QUOTE) != 0; ip++)
71519d2e3deSDmitry Chagin 		continue;
71619d2e3deSDmitry Chagin 	quoted = *ip == '\0';
71719d2e3deSDmitry Chagin     } else
71819d2e3deSDmitry Chagin 	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;
725c80476e4SDavid E. O'Brien     fakecom[0] = STRfakecom1;
726c80476e4SDavid E. O'Brien     fakecom[1] = 0;
727c80476e4SDavid E. O'Brien 
728c80476e4SDavid E. O'Brien     /*
729c80476e4SDavid E. O'Brien      * We do the psave job to temporarily change the current job so that the
730c80476e4SDavid E. O'Brien      * 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
732c80476e4SDavid E. O'Brien      * 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();
73645e5710bSMark Peek     cleanup_push(&faket, psavejob_cleanup); /* faket is only a marker */
737c80476e4SDavid E. O'Brien 
738c80476e4SDavid E. O'Brien     /*
739c80476e4SDavid E. O'Brien      * It would be nicer if we could integrate this redirection more with the
740c80476e4SDavid E. O'Brien      * routines in sh.sem.c by doing a fake execute on a builtin function that
741c80476e4SDavid E. O'Brien      * was piped out.
742c80476e4SDavid E. O'Brien      */
743c80476e4SDavid E. O'Brien     mypipe(pvec);
74445e5710bSMark Peek     cleanup_push(&pvec[0], open_cleanup);
74545e5710bSMark Peek     cleanup_push(&pvec[1], open_cleanup);
746c80476e4SDavid E. O'Brien     if (pfork(&faket, -1) == 0) {
74723338178SMark Peek 	jmp_buf_t osetexit;
74845e5710bSMark Peek 	struct command *t;
74945e5710bSMark Peek 	size_t omark;
750c80476e4SDavid E. O'Brien 
75145e5710bSMark Peek 	xclose(pvec[0]);
752c80476e4SDavid E. O'Brien 	(void) dmove(pvec[1], 1);
753c80476e4SDavid E. O'Brien 	(void) dmove(SHDIAG,  2);
754c80476e4SDavid E. O'Brien 	initdesc();
75529301572SMark Peek 	closem();
756c80476e4SDavid E. O'Brien 	arginp = cp;
75729301572SMark Peek 	for (arginp = cp; *cp; cp++) {
75829301572SMark Peek 	    *cp &= TRIM;
75923338178SMark Peek 	    if (is_set(STRcsubstnonl) && (*cp == '\n' || *cp == '\r'))
76029301572SMark Peek 		*cp = ' ';
76129301572SMark Peek 	}
762c80476e4SDavid E. O'Brien 
763c80476e4SDavid E. O'Brien         /*
764c80476e4SDavid E. O'Brien 	 * In the child ``forget'' everything about current aliases or
765c80476e4SDavid E. O'Brien 	 * eval vectors.
766c80476e4SDavid E. O'Brien 	 */
767c80476e4SDavid E. O'Brien 	alvec = NULL;
768c80476e4SDavid E. O'Brien 	evalvec = NULL;
769c80476e4SDavid E. O'Brien 	alvecp = NULL;
770c80476e4SDavid E. O'Brien 	evalp = NULL;
77123338178SMark Peek 
77245e5710bSMark Peek 	omark = cleanup_push_mark();
77323338178SMark Peek 	getexit(osetexit);
77423338178SMark Peek 	for (;;) {
77519d2e3deSDmitry Chagin 	    struct wordent paraml1;
77619d2e3deSDmitry Chagin 	    initlex(&paraml1);
77719d2e3deSDmitry Chagin 
77823338178SMark Peek 	    (void) setexit();
77923338178SMark Peek 	    justpr = 0;
78023338178SMark Peek 
78123338178SMark Peek 	    if (haderr) {
78223338178SMark Peek 		/* unwind */
78323338178SMark Peek 		doneinp = 0;
78445e5710bSMark Peek 		cleanup_pop_mark(omark);
78523338178SMark Peek 		resexit(osetexit);
78623338178SMark Peek 		reset();
78723338178SMark Peek 	    }
78823338178SMark Peek 	    if (seterr) {
78945e5710bSMark Peek 		xfree(seterr);
79023338178SMark Peek 		seterr = NULL;
79123338178SMark Peek 	    }
79223338178SMark Peek 
79319d2e3deSDmitry Chagin 	    freelex(&paraml1);
79419d2e3deSDmitry Chagin 	    (void) lex(&paraml1);
79519d2e3deSDmitry Chagin 	    cleanup_push(&paraml1, lex_cleanup);
796c80476e4SDavid E. O'Brien 	    if (seterr)
797c80476e4SDavid E. O'Brien 		stderror(ERR_OLD);
79819d2e3deSDmitry Chagin 	    alias(&paraml1);
79919d2e3deSDmitry Chagin 	    t = syntax(paraml1.next, &paraml1, 0);
80045e5710bSMark Peek 	    cleanup_push(t, syntax_cleanup);
8019ccc37e3SMark Peek 	    /* The F_BACKQ flag must set so the job output is correct if
8029ccc37e3SMark Peek 	     * printexitvalue is set.  If it's not set, the job output
8039ccc37e3SMark Peek 	     * will have "Exit N" appended where N is the exit status. */
80419d2e3deSDmitry Chagin 	    if (t)
8059ccc37e3SMark Peek 		    t->t_dflg = F_BACKQ|F_NOFORK;
806c80476e4SDavid E. O'Brien 	    if (seterr)
807c80476e4SDavid E. O'Brien 		stderror(ERR_OLD);
808c80476e4SDavid E. O'Brien #ifdef SIGTSTP
80945e5710bSMark Peek 	    signal(SIGTSTP, SIG_IGN);
810c80476e4SDavid E. O'Brien #endif
811c80476e4SDavid E. O'Brien #ifdef SIGTTIN
81245e5710bSMark Peek 	    signal(SIGTTIN, SIG_IGN);
813c80476e4SDavid E. O'Brien #endif
814c80476e4SDavid E. O'Brien #ifdef SIGTTOU
81545e5710bSMark Peek 	    signal(SIGTTOU, SIG_IGN);
816c80476e4SDavid E. O'Brien #endif
81729301572SMark Peek 	    execute(t, -1, NULL, NULL, TRUE);
81823338178SMark Peek 
81919d2e3deSDmitry Chagin 	    cleanup_until(&paraml1);
82023338178SMark Peek 	}
821c80476e4SDavid E. O'Brien     }
82245e5710bSMark Peek     cleanup_until(&pvec[1]);
823c80476e4SDavid E. O'Brien     c = 0;
824c80476e4SDavid E. O'Brien     ip = NULL;
825c80476e4SDavid E. O'Brien     do {
8269ccc37e3SMark Peek 	ssize_t     cnt = 0;
827c80476e4SDavid E. O'Brien 
828c80476e4SDavid E. O'Brien 	for (;;) {
82919d2e3deSDmitry Chagin 	    if (icnt == 0) {
830c80476e4SDavid E. O'Brien 		ip = ibuf;
83119d2e3deSDmitry Chagin 		icnt = wide_read(pvec[0], ibuf, BUFSIZE, 0);
83219d2e3deSDmitry Chagin 		if (icnt <= 0)
83323338178SMark Peek 		    goto eof;
834c80476e4SDavid E. O'Brien 	    }
835c80476e4SDavid E. O'Brien 	    if (hadnl)
836c80476e4SDavid E. O'Brien 		break;
837c80476e4SDavid E. O'Brien 	    --icnt;
838c80476e4SDavid E. O'Brien 	    c = (*ip++ & TRIM);
839c80476e4SDavid E. O'Brien 	    if (c == 0)
840c80476e4SDavid E. O'Brien 		break;
841a15e6f9aSMark Peek #if defined(WINNT_NATIVE) || defined(__CYGWIN__)
842c80476e4SDavid E. O'Brien 	    if (c == '\r')
843c80476e4SDavid E. O'Brien 	    	c = ' ';
844a15e6f9aSMark Peek #endif /* WINNT_NATIVE || __CYGWIN__ */
845c80476e4SDavid E. O'Brien 	    if (c == '\n') {
846c80476e4SDavid E. O'Brien 		/*
847c80476e4SDavid E. O'Brien 		 * Continue around the loop one more time, so that we can eat
848c80476e4SDavid E. O'Brien 		 * 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++;
85619d2e3deSDmitry Chagin 	    if (c == '\\' || quoted)
85719d2e3deSDmitry Chagin 		c |= QUOTE;
85819d2e3deSDmitry Chagin 	    Strbuf_append1(word, c);
859c80476e4SDavid E. O'Brien 	}
860c80476e4SDavid E. O'Brien 	/*
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 	 */
86623338178SMark Peek 	if (c != 0 && (cnt || literal))
86745e5710bSMark Peek 	    pword(bb, word);
868c80476e4SDavid E. O'Brien 	hadnl = 0;
86923338178SMark Peek     } while (c > 0);
87023338178SMark Peek  eof:
87145e5710bSMark Peek     cleanup_until(&pvec[0]);
872c80476e4SDavid E. O'Brien     pwait();
87345e5710bSMark Peek     cleanup_until(&faket); /* psavejob_cleanup(); */
874c80476e4SDavid E. O'Brien }
875c80476e4SDavid E. O'Brien 
876c80476e4SDavid E. O'Brien static void
pword(struct blk_buf * bb,struct Strbuf * word)87745e5710bSMark Peek 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);
88245e5710bSMark Peek     bb_append(bb, s);
88345e5710bSMark Peek     *word = Strbuf_init;
884c80476e4SDavid E. O'Brien }
885c80476e4SDavid E. O'Brien 
886c80476e4SDavid E. O'Brien int
Gmatch(const Char * string,const Char * pattern)88745e5710bSMark Peek Gmatch(const Char *string, const Char *pattern)
888c80476e4SDavid E. O'Brien {
889c80476e4SDavid E. O'Brien     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)89345e5710bSMark Peek Gnmatch(const Char *string, const Char *pattern, const Char **endstr)
894c80476e4SDavid E. O'Brien {
89545e5710bSMark Peek     Char ***fblk, **p;
89645e5710bSMark Peek     const Char *tstring = string;
897c80476e4SDavid E. O'Brien     int	   gpol = 1, gres = 0;
898c80476e4SDavid E. O'Brien 
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 
90445e5710bSMark Peek     fblk = xmalloc(sizeof(Char ***));
90545e5710bSMark Peek     *fblk = xmalloc(GLOBSPACE * sizeof(Char *));
90645e5710bSMark Peek     (*fblk)[0] = Strsave(pattern);
90745e5710bSMark Peek     (*fblk)[1] = NULL;
908c80476e4SDavid E. O'Brien 
90945e5710bSMark Peek     cleanup_push(fblk, blk_indirect_cleanup);
91045e5710bSMark Peek     expbrace(fblk, NULL, GLOBSPACE);
911c80476e4SDavid E. O'Brien 
912c80476e4SDavid E. O'Brien     if (endstr == NULL)
913c80476e4SDavid E. O'Brien 	/* Exact matches only */
91445e5710bSMark Peek 	for (p = *fblk; *p; p++)
91523338178SMark Peek 	    gres |= t_pmatch(string, *p, &tstring, 1) == 2 ? 1 : 0;
916c80476e4SDavid E. O'Brien     else {
91745e5710bSMark Peek 	const Char *end;
91845e5710bSMark Peek 
919c80476e4SDavid E. O'Brien 	/* partial matches */
92045e5710bSMark Peek         end = Strend(string);
92145e5710bSMark Peek 	for (p = *fblk; *p; p++)
92223338178SMark Peek 	    if (t_pmatch(string, *p, &tstring, 1) != 0) {
923c80476e4SDavid E. O'Brien 		gres |= 1;
92445e5710bSMark Peek 		if (end > tstring)
92545e5710bSMark Peek 		    end = tstring;
926c80476e4SDavid E. O'Brien 	    }
92745e5710bSMark Peek 	*endstr = end;
928c80476e4SDavid E. O'Brien     }
929c80476e4SDavid E. O'Brien 
93045e5710bSMark Peek     cleanup_until(fblk);
931c80476e4SDavid E. O'Brien     return(gres == gpol);
932c80476e4SDavid E. O'Brien }
933c80476e4SDavid E. O'Brien 
934b2d5d167SMark Peek /* t_pmatch():
935c80476e4SDavid E. O'Brien  *	Return 2 on exact match,
936c80476e4SDavid E. O'Brien  *	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  */
940b2d5d167SMark Peek int
t_pmatch(const Char * string,const Char * pattern,const Char ** estr,int cs)94145e5710bSMark Peek t_pmatch(const Char *string, const Char *pattern, const Char **estr, int cs)
942c80476e4SDavid E. O'Brien {
94345e5710bSMark Peek     Char stringc, patternc, rangec;
944c80476e4SDavid E. O'Brien     int     match, negate_range;
94545e5710bSMark Peek     const Char *pestr, *nstring;
946c80476e4SDavid E. O'Brien 
94723338178SMark Peek     for (nstring = string;; string = nstring) {
94845e5710bSMark Peek 	stringc = *nstring++ & TRIM;
94945e5710bSMark Peek 	patternc = *pattern++ & TRIM;
950c80476e4SDavid E. O'Brien 	switch (patternc) {
95123338178SMark Peek 	case '\0':
952c80476e4SDavid E. O'Brien 	    *estr = string;
95323338178SMark Peek 	    return (stringc == '\0' ? 2 : 1);
954c80476e4SDavid E. O'Brien 	case '?':
955c80476e4SDavid E. O'Brien 	    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) {
96045e5710bSMark Peek 		*estr = Strend(string);
961c80476e4SDavid E. O'Brien 		return (2);
962c80476e4SDavid E. O'Brien 	    }
963c80476e4SDavid E. O'Brien 	    pestr = NULL;
964c80476e4SDavid E. O'Brien 
96523338178SMark Peek 	    for (;;) {
966b2d5d167SMark Peek 		switch(t_pmatch(string, pattern, estr, cs)) {
967c80476e4SDavid E. O'Brien 		case 0:
968c80476e4SDavid E. O'Brien 		    break;
969c80476e4SDavid E. O'Brien 		case 1:
97045e5710bSMark Peek 		    pestr = *estr;/*FIXME: does not guarantee longest match */
971c80476e4SDavid E. O'Brien 		    break;
972c80476e4SDavid E. O'Brien 		case 2:
973c80476e4SDavid E. O'Brien 		    return 2;
974c80476e4SDavid E. O'Brien 		default:
975c80476e4SDavid E. O'Brien 		    abort();	/* Cannot happen */
976c80476e4SDavid E. O'Brien 		}
97745e5710bSMark Peek 		stringc = *string++ & TRIM;
97823338178SMark Peek 		if (!stringc)
97923338178SMark Peek 		    break;
980c80476e4SDavid E. O'Brien 	    }
981c80476e4SDavid E. O'Brien 
982c80476e4SDavid E. O'Brien 	    if (pestr) {
983c80476e4SDavid E. O'Brien 		*estr = pestr;
984c80476e4SDavid E. O'Brien 		return 1;
985c80476e4SDavid E. O'Brien 	    }
98645e5710bSMark Peek 	    else
987c80476e4SDavid E. O'Brien 		return 0;
988c80476e4SDavid E. O'Brien 
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++;
99345e5710bSMark Peek 	    while ((rangec = *pattern++ & TRIM) != '\0') {
994c80476e4SDavid E. O'Brien 		if (rangec == ']')
995c80476e4SDavid E. O'Brien 		    break;
996c80476e4SDavid E. O'Brien 		if (match)
997c80476e4SDavid E. O'Brien 		    continue;
99823338178SMark Peek 		if (*pattern == '-' && pattern[1] != ']') {
99945e5710bSMark Peek 		    Char rangec2;
1000c80476e4SDavid E. O'Brien 		    pattern++;
100145e5710bSMark Peek 		    rangec2 = *pattern++ & TRIM;
100223338178SMark Peek 		    match = (globcharcoll(stringc, rangec2, 0) <= 0 &&
100323338178SMark Peek 			globcharcoll(rangec, stringc, 0) <= 0);
1004c80476e4SDavid E. O'Brien 		}
1005c80476e4SDavid E. O'Brien 		else
100623338178SMark Peek 		    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'))
101123338178SMark Peek 		return (0);
1012c80476e4SDavid E. O'Brien 	    if (match == negate_range)
1013c80476e4SDavid E. O'Brien 		return (0);
1014c80476e4SDavid E. O'Brien 	    break;
1015c80476e4SDavid E. O'Brien 	default:
101623338178SMark Peek 	    if (cs ? patternc  != stringc
101723338178SMark Peek 		: Tolower(patternc) != Tolower(stringc))
1018c80476e4SDavid E. O'Brien 		return (0);
1019c80476e4SDavid E. O'Brien 	    break;
1020c80476e4SDavid E. O'Brien 	}
1021c80476e4SDavid E. O'Brien     }
1022c80476e4SDavid E. O'Brien }
1023