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