159243Sobrien/*
259243Sobrien * sh.glob.c: Regular expression expansion
359243Sobrien */
459243Sobrien/*-
559243Sobrien * Copyright (c) 1980, 1991 The Regents of the University of California.
659243Sobrien * All rights reserved.
759243Sobrien *
859243Sobrien * Redistribution and use in source and binary forms, with or without
959243Sobrien * modification, are permitted provided that the following conditions
1059243Sobrien * are met:
1159243Sobrien * 1. Redistributions of source code must retain the above copyright
1259243Sobrien *    notice, this list of conditions and the following disclaimer.
1359243Sobrien * 2. Redistributions in binary form must reproduce the above copyright
1459243Sobrien *    notice, this list of conditions and the following disclaimer in the
1559243Sobrien *    documentation and/or other materials provided with the distribution.
16100616Smp * 3. Neither the name of the University nor the names of its contributors
1759243Sobrien *    may be used to endorse or promote products derived from this software
1859243Sobrien *    without specific prior written permission.
1959243Sobrien *
2059243Sobrien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2159243Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2259243Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2359243Sobrien * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2459243Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2559243Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2659243Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2759243Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2859243Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2959243Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3059243Sobrien * SUCH DAMAGE.
3159243Sobrien */
3259243Sobrien#include "sh.h"
3359243Sobrien#include "tc.h"
34100616Smp#include "tw.h"
3559243Sobrien
3659243Sobrien#include "glob.h"
3759243Sobrien
3859243Sobrien/*
3959243Sobrien * Values for gflag
4059243Sobrien */
4159243Sobrien#define	G_NONE	0		/* No globbing needed			*/
4259243Sobrien#define	G_GLOB	1		/* string contains *?[] characters	*/
4359243Sobrien#define	G_CSH	2		/* string contains ~`{ characters	*/
4459243Sobrien
4559243Sobrien#define	GLOBSPACE	100	/* Alloc increment			*/
4659243Sobrien
4759243Sobrien
4859243Sobrien#define LBRC '{'
4959243Sobrien#define RBRC '}'
5059243Sobrien#define LBRK '['
5159243Sobrien#define RBRK ']'
5259243Sobrien#define EOS '\0'
5359243Sobrien
5459243Sobrien/*
5559243Sobrien * globbing is now done in two stages. In the first pass we expand
5659243Sobrien * csh globbing idioms ~`{ and then we proceed doing the normal
5759243Sobrien * globbing if needed ?*[
5859243Sobrien *
5959243Sobrien * Csh type globbing is handled in globexpand() and the rest is
6059243Sobrien * handled in glob() which is part of the 4.4BSD libc.
6159243Sobrien *
6259243Sobrien */
63167465Smpstatic	Char	 *globtilde	(Char *);
64167465Smpstatic	Char     *handleone	(Char *, Char **, int);
65167465Smpstatic	Char	**libglob	(Char **);
66167465Smpstatic	Char	**globexpand	(Char **, int);
67167465Smpstatic	int	  globbrace	(const Char *, Char ***);
68167465Smpstatic  void	  expbrace	(Char ***, Char ***, int);
69167465Smpstatic	void	  pword		(struct blk_buf *, struct Strbuf *);
70167465Smpstatic	void	  backeval	(struct blk_buf *, struct Strbuf *, Char *,
71167465Smp				 int);
7259243Sobrienstatic Char *
73167465Smpglobtilde(Char *s)
7459243Sobrien{
75167465Smp    Char *name, *u, *home, *res;
7659243Sobrien
7759243Sobrien    u = s;
78167465Smp    for (s++; *s && *s != '/' && *s != ':'; s++)
7959243Sobrien	continue;
80167465Smp    name = Strnsave(u + 1, s - (u + 1));
81167465Smp    cleanup_push(name, xfree);
82167465Smp    home = gethdir(name);
83167465Smp    if (home == NULL) {
84167465Smp	if (adrof(STRnonomatch)) {
85167465Smp	    cleanup_until(name);
86167465Smp	    return u;
87167465Smp	}
88167465Smp	if (*name)
89167465Smp	    stderror(ERR_UNKUSER, short2str(name));
9059243Sobrien	else
9159243Sobrien	    stderror(ERR_NOHOME);
9259243Sobrien    }
93167465Smp    cleanup_until(name);
94167465Smp    if (home[0] == '/' && home[1] == '\0' && s[0] == '/')
95167465Smp	res = Strsave(s);
96167465Smp    else
97167465Smp	res = Strspl(home, s);
98167465Smp    xfree(home);
99167465Smp    xfree(u);
100167465Smp    return res;
10159243Sobrien}
10259243Sobrien
103167465Smp/* Returns a newly allocated string, old or NULL */
10459243SobrienChar *
105167465Smpglobequal(Char *old)
10659243Sobrien{
10759243Sobrien    int     dig;
108167465Smp    const Char *dir;
109167465Smp    Char    *b;
11059243Sobrien
11159243Sobrien    /*
11259243Sobrien     * kfk - 17 Jan 1984 - stack hack allows user to get at arbitrary dir names
11359243Sobrien     * in stack. PWP: let =foobar pass through (for X windows)
11459243Sobrien     */
11559243Sobrien    if (old[1] == '-' && (old[2] == '\0' || old[2] == '/')) {
11659243Sobrien	/* =- */
117167465Smp	const Char *olddir = varval (STRowd);
118167465Smp
119167465Smp	if (olddir && *olddir &&
120167465Smp	    !dcwd->di_next->di_name && !dcwd->di_prev->di_name)
121167465Smp	    return Strspl(olddir, &old[2]);
12259243Sobrien	dig = -1;
12359243Sobrien	b = &old[2];
12459243Sobrien    }
12559243Sobrien    else if (Isdigit(old[1])) {
12659243Sobrien	/* =<number> */
12759243Sobrien	dig = old[1] - '0';
12859243Sobrien	for (b = &old[2]; Isdigit(*b); b++)
12959243Sobrien	    dig = dig * 10 + (*b - '0');
13059243Sobrien	if (*b != '\0' && *b != '/')
13159243Sobrien	    /* =<number>foobar */
13259243Sobrien	    return old;
13359243Sobrien    }
13459243Sobrien    else
13559243Sobrien	/* =foobar */
13659243Sobrien	return old;
13759243Sobrien
138167465Smp    dir = getstakd(dig);
139167465Smp    if (dir == NULL)
14059243Sobrien	return NULL;
141167465Smp    return Strspl(dir, b);
14259243Sobrien}
14359243Sobrien
14459243Sobrienstatic int
145167465Smpglobbrace(const Char *s, Char ***bl)
14659243Sobrien{
147167465Smp    struct Strbuf gbuf = Strbuf_INIT;
148167465Smp    struct blk_buf bb = BLK_BUF_INIT;
149167465Smp    int     i;
150167465Smp    const Char *p, *pm, *pe, *pl;
151167465Smp    size_t prefix_len;
15259243Sobrien
15359243Sobrien    /* copy part up to the brace */
154167465Smp    for (p = s; *p != LBRC; p++)
155167465Smp	;
156167465Smp    prefix_len = p - s;
15759243Sobrien
15859243Sobrien    /* check for balanced braces */
15959243Sobrien    for (i = 0, pe = ++p; *pe; pe++)
16059243Sobrien	if (*pe == LBRK) {
16159243Sobrien	    /* Ignore everything between [] */
16259243Sobrien	    for (++pe; *pe != RBRK && *pe != EOS; pe++)
16359243Sobrien		continue;
164167465Smp	    if (*pe == EOS)
16559243Sobrien		return (-RBRK);
16659243Sobrien	}
16759243Sobrien	else if (*pe == LBRC)
16859243Sobrien	    i++;
16959243Sobrien	else if (*pe == RBRC) {
17059243Sobrien	    if (i == 0)
17159243Sobrien		break;
17259243Sobrien	    i--;
17359243Sobrien	}
17459243Sobrien
175167465Smp    if (i != 0 || *pe == '\0')
17659243Sobrien	return (-RBRC);
17759243Sobrien
178167465Smp    Strbuf_appendn(&gbuf, s, prefix_len);
179167465Smp
18059243Sobrien    for (i = 0, pl = pm = p; pm <= pe; pm++)
18159243Sobrien	switch (*pm) {
18259243Sobrien	case LBRK:
18359243Sobrien	    for (++pm; *pm != RBRK && *pm != EOS; pm++)
18459243Sobrien		continue;
18559243Sobrien	    if (*pm == EOS) {
186167465Smp		bb_cleanup(&bb);
187167465Smp		xfree(gbuf.s);
18859243Sobrien		return (-RBRK);
18959243Sobrien	    }
19059243Sobrien	    break;
19159243Sobrien	case LBRC:
19259243Sobrien	    i++;
19359243Sobrien	    break;
19459243Sobrien	case RBRC:
19559243Sobrien	    if (i) {
19659243Sobrien		i--;
19759243Sobrien		break;
19859243Sobrien	    }
19959243Sobrien	    /* FALLTHROUGH */
20059243Sobrien	case ',':
20159243Sobrien	    if (i && *pm == ',')
20259243Sobrien		break;
20359243Sobrien	    else {
204167465Smp		gbuf.len = prefix_len;
205167465Smp		Strbuf_appendn(&gbuf, pl, pm - pl);
206167465Smp		Strbuf_append(&gbuf, pe + 1);
207167465Smp		Strbuf_terminate(&gbuf);
208167465Smp		bb_append(&bb, Strsave(gbuf.s));
20959243Sobrien		pl = pm + 1;
21059243Sobrien	    }
21159243Sobrien	    break;
21259243Sobrien	default:
21359243Sobrien	    break;
21459243Sobrien	}
215167465Smp    *bl = bb_finish(&bb);
216167465Smp    xfree(gbuf.s);
217167465Smp    return bb.len;
21859243Sobrien}
21959243Sobrien
22059243Sobrien
22159243Sobrienstatic void
222167465Smpexpbrace(Char ***nvp, Char ***elp, int size)
22359243Sobrien{
22459243Sobrien    Char **vl, **el, **nv, *s;
22559243Sobrien
22659243Sobrien    vl = nv = *nvp;
22759243Sobrien    if (elp != NULL)
22859243Sobrien	el = *elp;
22959243Sobrien    else
230167465Smp	el = vl + blklen(vl);
23159243Sobrien
23259243Sobrien    for (s = *vl; s; s = *++vl) {
23359243Sobrien	Char  **vp, **bp;
23459243Sobrien
23559243Sobrien	/* leave {} untouched for find */
23659243Sobrien	if (s[0] == '{' && (s[1] == '\0' || (s[1] == '}' && s[2] == '\0')))
23759243Sobrien	    continue;
238167465Smp	if (Strchr(s, '{') != NULL) {
239167465Smp	    Char  **bl = NULL;
24059243Sobrien	    int     len;
24159243Sobrien
242167465Smp	    if ((len = globbrace(s, &bl)) < 0)
24359243Sobrien		stderror(ERR_MISSING, -len);
244167465Smp	    xfree(s);
24559243Sobrien	    if (len == 1) {
24659243Sobrien		*vl-- = *bl;
247167465Smp		xfree(bl);
24859243Sobrien		continue;
24959243Sobrien	    }
25059243Sobrien	    if (&el[len] >= &nv[size]) {
251167465Smp		size_t l, e;
252167465Smp		l = &el[len] - &nv[size];
25359243Sobrien		size += GLOBSPACE > l ? GLOBSPACE : l;
254167465Smp		l = vl - nv;
255167465Smp		e = el - nv;
256167465Smp		nv = xrealloc(nv, size * sizeof(Char *));
257167465Smp		*nvp = nv; /* To keep cleanups working */
25859243Sobrien		vl = nv + l;
25959243Sobrien		el = nv + e;
26059243Sobrien	    }
26159243Sobrien	    /* nv vl   el     bl
26259243Sobrien	     * |  |    |      |
26359243Sobrien	     * -.--..--	      x--
26459243Sobrien	     *   |            len
26559243Sobrien	     *   vp
26659243Sobrien	     */
26759243Sobrien	    vp = vl--;
26859243Sobrien	    *vp = *bl;
26959243Sobrien	    len--;
27059243Sobrien	    for (bp = el; bp != vp; bp--)
27159243Sobrien		bp[len] = *bp;
27259243Sobrien	    el += len;
27359243Sobrien	    /* nv vl    el bl
27459243Sobrien	     * |  |     |  |
27559243Sobrien	     * -.-x  ---    --
27659243Sobrien	     *   |len
27759243Sobrien	     *   vp
27859243Sobrien	     */
27959243Sobrien	    vp++;
28059243Sobrien	    for (bp = bl + 1; *bp; *vp++ = *bp++)
28159243Sobrien		continue;
282167465Smp	    xfree(bl);
28359243Sobrien	}
28459243Sobrien
28559243Sobrien    }
28659243Sobrien    if (elp != NULL)
28759243Sobrien	*elp = el;
28859243Sobrien}
28959243Sobrien
29059243Sobrienstatic Char **
291167465Smpglobexpand(Char **v, int noglob)
29259243Sobrien{
29359243Sobrien    Char   *s;
294167465Smp    Char  ***fnv, **vl, **el;
29559243Sobrien    int     size = GLOBSPACE;
29659243Sobrien
29759243Sobrien
298167465Smp    fnv = xmalloc(sizeof(Char ***));
299167465Smp    *fnv = vl = xmalloc(sizeof(Char *) * size);
30059243Sobrien    *vl = NULL;
301167465Smp    cleanup_push(fnv, blk_indirect_cleanup);
30259243Sobrien
30359243Sobrien    /*
30459243Sobrien     * Step 1: expand backquotes.
30559243Sobrien     */
306354195Sbrooks    while ((s = *v++) != NULL) {
30759243Sobrien	if (Strchr(s, '`')) {
30859243Sobrien	    int     i;
309167465Smp	    Char **expanded;
31059243Sobrien
311167465Smp	    expanded = dobackp(s, 0);
312167465Smp	    for (i = 0; expanded[i] != NULL; i++) {
313167465Smp		*vl++ = expanded[i];
314167465Smp		if (vl == &(*fnv)[size]) {
31559243Sobrien		    size += GLOBSPACE;
316167465Smp		    *fnv = xrealloc(*fnv, size * sizeof(Char *));
317167465Smp		    vl = &(*fnv)[size - GLOBSPACE];
31859243Sobrien		}
31959243Sobrien	    }
320167465Smp	    xfree(expanded);
32159243Sobrien	}
32259243Sobrien	else {
32359243Sobrien	    *vl++ = Strsave(s);
324167465Smp	    if (vl == &(*fnv)[size]) {
32559243Sobrien		size += GLOBSPACE;
326167465Smp		*fnv = xrealloc(*fnv, size * sizeof(Char *));
327167465Smp		vl = &(*fnv)[size - GLOBSPACE];
32859243Sobrien	    }
32959243Sobrien	}
330167465Smp	*vl = NULL;
33159243Sobrien    }
33259243Sobrien
33359243Sobrien    if (noglob)
334167465Smp	goto done;
33559243Sobrien
33659243Sobrien    /*
33759243Sobrien     * Step 2: expand braces
33859243Sobrien     */
33959243Sobrien    el = vl;
340167465Smp    expbrace(fnv, &el, size);
34159243Sobrien
34259243Sobrien
34359243Sobrien    /*
34459243Sobrien     * Step 3: expand ~ =
34559243Sobrien     */
346167465Smp    vl = *fnv;
34759243Sobrien    for (s = *vl; s; s = *++vl)
34859243Sobrien	switch (*s) {
349167465Smp	    Char *ns;
35059243Sobrien	case '~':
351167465Smp	    *vl = globtilde(s);
35259243Sobrien	    break;
35359243Sobrien	case '=':
354167465Smp	    if ((ns = globequal(s)) == NULL) {
355167465Smp		if (!adrof(STRnonomatch))
356167465Smp		    stderror(ERR_DEEP); /* Error */
35759243Sobrien	    }
35859243Sobrien	    if (ns && ns != s) {
35959243Sobrien		/* Expansion succeeded */
360167465Smp		xfree(s);
361167465Smp		*vl = ns;
36259243Sobrien	    }
36359243Sobrien	    break;
36459243Sobrien	default:
36559243Sobrien	    break;
36659243Sobrien	}
367167465Smp    vl = *fnv;
36859243Sobrien
36959243Sobrien    /*
37059243Sobrien     * Step 4: expand .. if the variable symlinks==expand is set
37159243Sobrien     */
37283098Smp    if (symlinks == SYM_EXPAND) {
37359243Sobrien	for (s = *vl; s; s = *++vl) {
37483098Smp	    *vl = dnormalize(s, 1);
375167465Smp	    xfree(s);
37659243Sobrien	}
37783098Smp    }
37859243Sobrien
379167465Smp done:
380167465Smp    cleanup_ignore(fnv);
381167465Smp    cleanup_until(fnv);
382167465Smp    vl = *fnv;
383167465Smp    xfree(fnv);
384167465Smp    return vl;
38559243Sobrien}
38659243Sobrien
38759243Sobrienstatic Char *
388167465Smphandleone(Char *str, Char **vl, int action)
38959243Sobrien{
390167465Smp    size_t chars;
39159243Sobrien    Char **t, *p, *strp;
39259243Sobrien
39359243Sobrien    switch (action) {
39459243Sobrien    case G_ERROR:
39559243Sobrien	setname(short2str(str));
39659243Sobrien	blkfree(vl);
39759243Sobrien	stderror(ERR_NAME | ERR_AMBIG);
39859243Sobrien	break;
39959243Sobrien    case G_APPEND:
40059243Sobrien	chars = 0;
401167465Smp	for (t = vl; (p = *t++) != NULL; chars++)
402167465Smp	    chars += Strlen(p);
403167465Smp	str = xmalloc(chars * sizeof(Char));
404354195Sbrooks	for (t = vl, strp = str; (p = *t++) != NULL; chars++) {
40559243Sobrien	    while (*p)
40659243Sobrien		 *strp++ = *p++ & TRIM;
40759243Sobrien	    *strp++ = ' ';
40859243Sobrien	}
40959243Sobrien	*--strp = '\0';
41059243Sobrien	blkfree(vl);
41159243Sobrien	break;
41259243Sobrien    case G_IGNORE:
413167465Smp	str = Strsave(strip(*vl));
41459243Sobrien	blkfree(vl);
41559243Sobrien	break;
41659243Sobrien    default:
41759243Sobrien	break;
41859243Sobrien    }
41959243Sobrien    return (str);
42059243Sobrien}
42159243Sobrien
42259243Sobrienstatic Char **
423167465Smplibglob(Char **vl)
42459243Sobrien{
42559243Sobrien    int     gflgs = GLOB_QUOTE | GLOB_NOMAGIC | GLOB_ALTNOT;
42659243Sobrien    glob_t  globv;
42759243Sobrien    char   *ptr;
42859243Sobrien    int     nonomatch = adrof(STRnonomatch) != 0, magic = 0, match = 0;
42959243Sobrien
430231990Smp    if (adrof(STRglobdot))
431231990Smp       gflgs |= GLOB_DOT;
432231990Smp
433231990Smp    if (adrof(STRglobstar))
434231990Smp       gflgs |= GLOB_STAR;
435231990Smp
43659243Sobrien    if (!vl || !vl[0])
43759243Sobrien	return(vl);
43859243Sobrien
43959243Sobrien    globv.gl_offs = 0;
44059243Sobrien    globv.gl_pathv = 0;
44159243Sobrien    globv.gl_pathc = 0;
44259243Sobrien
44359243Sobrien    if (nonomatch)
44459243Sobrien	gflgs |= GLOB_NOCHECK;
44559243Sobrien
44659243Sobrien    do {
44759243Sobrien	ptr = short2qstr(*vl);
44859243Sobrien	switch (glob(ptr, gflgs, 0, &globv)) {
44959243Sobrien	case GLOB_ABEND:
45059243Sobrien	    globfree(&globv);
45159243Sobrien	    setname(ptr);
45259243Sobrien	    stderror(ERR_NAME | ERR_GLOB);
45359243Sobrien	    /* NOTREACHED */
45459243Sobrien	case GLOB_NOSPACE:
45559243Sobrien	    globfree(&globv);
45659243Sobrien	    stderror(ERR_NOMEM);
45759243Sobrien	    /* NOTREACHED */
45859243Sobrien	default:
45959243Sobrien	    break;
46059243Sobrien	}
46159243Sobrien	if (globv.gl_flags & GLOB_MAGCHAR) {
46259243Sobrien	    match |= (globv.gl_matchc != 0);
46359243Sobrien	    magic = 1;
46459243Sobrien	}
46559243Sobrien	gflgs |= GLOB_APPEND;
46659243Sobrien    }
46759243Sobrien    while (*++vl);
46859243Sobrien    vl = (globv.gl_pathc == 0 || (magic && !match && !nonomatch)) ?
46959243Sobrien	NULL : blk2short(globv.gl_pathv);
47059243Sobrien    globfree(&globv);
47159243Sobrien    return (vl);
47259243Sobrien}
47359243Sobrien
47459243SobrienChar   *
475167465Smpglobone(Char *str, int action)
47659243Sobrien{
47759243Sobrien    Char   *v[2], **vl, **vo;
478167465Smp    int gflg, noglob;
47959243Sobrien
48059243Sobrien    noglob = adrof(STRnoglob) != 0;
48159243Sobrien    v[0] = str;
48259243Sobrien    v[1] = 0;
483167465Smp    gflg = tglob(v);
48459243Sobrien    if (gflg == G_NONE)
48559243Sobrien	return (strip(Strsave(str)));
48659243Sobrien
48759243Sobrien    if (gflg & G_CSH) {
48859243Sobrien	/*
48959243Sobrien	 * Expand back-quote, tilde and brace
49059243Sobrien	 */
491167465Smp	vo = globexpand(v, noglob);
49259243Sobrien	if (noglob || (gflg & G_GLOB) == 0) {
493167465Smp	    vl = vo;
494167465Smp	    goto result;
49559243Sobrien	}
496167465Smp	cleanup_push(vo, blk_cleanup);
49759243Sobrien    }
49859243Sobrien    else if (noglob || (gflg & G_GLOB) == 0)
49959243Sobrien	return (strip(Strsave(str)));
50059243Sobrien    else
50159243Sobrien	vo = v;
50259243Sobrien
50359243Sobrien    vl = libglob(vo);
504167465Smp    if (gflg & G_CSH) {
505167465Smp    	if (vl != vo)
506167465Smp	    cleanup_until(vo);
507167465Smp	else
508167465Smp	    cleanup_ignore(vo);
509167465Smp    }
51059243Sobrien    if (vl == NULL) {
51159243Sobrien	setname(short2str(str));
51259243Sobrien	stderror(ERR_NAME | ERR_NOMATCH);
51359243Sobrien    }
514167465Smp result:
515231990Smp    if (vl && vl[0] == NULL) {
516167465Smp	xfree(vl);
51759243Sobrien	return (Strsave(STRNULL));
51859243Sobrien    }
519231990Smp    if (vl && vl[1])
52059243Sobrien	return (handleone(str, vl, action));
52159243Sobrien    else {
52259243Sobrien	str = strip(*vl);
523167465Smp	xfree(vl);
52459243Sobrien	return (str);
52559243Sobrien    }
52659243Sobrien}
52759243Sobrien
52859243SobrienChar  **
529167465Smpgloball(Char **v, int gflg)
53059243Sobrien{
53159243Sobrien    Char  **vl, **vo;
532167465Smp    int noglob;
53359243Sobrien
534167465Smp    if (!v || !v[0])
535167465Smp	return saveblk(v);
53659243Sobrien
53759243Sobrien    noglob = adrof(STRnoglob) != 0;
53859243Sobrien
53959243Sobrien    if (gflg & G_CSH)
54059243Sobrien	/*
54159243Sobrien	 * Expand back-quote, tilde and brace
54259243Sobrien	 */
543167465Smp	vl = vo = globexpand(v, noglob);
54459243Sobrien    else
54559243Sobrien	vl = vo = saveblk(v);
54659243Sobrien
54759243Sobrien    if (!noglob && (gflg & G_GLOB)) {
548167465Smp	cleanup_push(vo, blk_cleanup);
54959243Sobrien	vl = libglob(vo);
550167465Smp	if (vl == vo)
551167465Smp	    cleanup_ignore(vo);
552167465Smp	cleanup_until(vo);
55359243Sobrien    }
55459243Sobrien    else
55559243Sobrien	trim(vl);
55659243Sobrien
557167465Smp    return vl;
55859243Sobrien}
55959243Sobrien
560167465SmpChar **
561167465Smpglob_all_or_error(Char **v)
56259243Sobrien{
563167465Smp    int gflag;
564167465Smp
565167465Smp    gflag = tglob(v);
566167465Smp    if (gflag) {
567167465Smp	v = globall(v, gflag);
568167465Smp	if (v == NULL)
569167465Smp	    stderror(ERR_NAME | ERR_NOMATCH);
570167465Smp    } else {
571167465Smp	v = saveblk(v);
572167465Smp	trim(v);
573167465Smp    }
574167465Smp    return v;
57559243Sobrien}
57659243Sobrien
57759243Sobrienvoid
578167465Smprscan(Char **t, void (*f) (Char))
57959243Sobrien{
580145479Smp    Char *p;
58159243Sobrien
582354195Sbrooks    while ((p = *t++) != NULL)
58359243Sobrien	while (*p)
58459243Sobrien	    (*f) (*p++);
58559243Sobrien}
58659243Sobrien
58759243Sobrienvoid
588167465Smptrim(Char **t)
58959243Sobrien{
590145479Smp    Char *p;
59159243Sobrien
592354195Sbrooks    while ((p = *t++) != NULL)
593316957Sdchagin	while (*p) {
594316957Sdchagin#if INVALID_BYTE != 0
595316957Sdchagin	    if ((*p & INVALID_BYTE) != INVALID_BYTE)	/* *p < INVALID_BYTE */
596316957Sdchagin#endif
597316957Sdchagin		*p &= TRIM;
598316957Sdchagin	    p++;
599316957Sdchagin	}
60059243Sobrien}
60159243Sobrien
602167465Smpint
603167465Smptglob(Char **t)
60459243Sobrien{
605167465Smp    int gflag;
606167465Smp    const Char *p;
60759243Sobrien
608167465Smp    gflag = 0;
609354195Sbrooks    while ((p = *t++) != NULL) {
61059243Sobrien	if (*p == '~' || *p == '=')
61159243Sobrien	    gflag |= G_CSH;
61259243Sobrien	else if (*p == '{' &&
61359243Sobrien		 (p[1] == '\0' || (p[1] == '}' && p[2] == '\0')))
61459243Sobrien	    continue;
615167465Smp	while (*p != '\0') {
616167465Smp	    if (*p == '`') {
61759243Sobrien		gflag |= G_CSH;
61859243Sobrien#ifdef notdef
61959243Sobrien		/*
62059243Sobrien		 * We do want to expand echo `echo '*'`, so we don't\
62159243Sobrien		 * use this piece of code anymore.
62259243Sobrien		 */
623167465Smp		p++;
62459243Sobrien		while (*p && *p != '`')
62559243Sobrien		    if (*p++ == '\\') {
62659243Sobrien			if (*p)		/* Quoted chars */
62759243Sobrien			    p++;
62859243Sobrien			else
62959243Sobrien			    break;
63059243Sobrien		    }
631167465Smp		if (!*p)		/* The matching ` */
63259243Sobrien		    break;
63359243Sobrien#endif
63459243Sobrien	    }
635167465Smp	    else if (*p == '{')
63659243Sobrien		gflag |= G_CSH;
637167465Smp	    else if (isglob(*p))
63859243Sobrien		gflag |= G_GLOB;
63959243Sobrien	    else if (symlinks == SYM_EXPAND &&
640167465Smp		p[1] && ISDOTDOT(p) && (p == *(t-1) || *(p-1) == '/') )
64159243Sobrien	    	gflag |= G_CSH;
642167465Smp	    p++;
64359243Sobrien	}
64459243Sobrien    }
645167465Smp    return gflag;
64659243Sobrien}
64759243Sobrien
64859243Sobrien/*
64959243Sobrien * Command substitute cp.  If literal, then this is a substitution from a
65059243Sobrien * << redirection, and so we should not crunch blanks and tabs, separating
65159243Sobrien * words only at newlines.
65259243Sobrien */
65359243SobrienChar  **
654167465Smpdobackp(Char *cp, int literal)
65559243Sobrien{
656167465Smp    struct Strbuf word = Strbuf_INIT;
657167465Smp    struct blk_buf bb = BLK_BUF_INIT;
658167465Smp    Char *lp, *rp, *ep;
65959243Sobrien
660167465Smp    cleanup_push(&bb, bb_cleanup);
661167465Smp    cleanup_push(&word, Strbuf_cleanup);
66259243Sobrien    for (;;) {
663167465Smp	for (lp = cp; *lp != '\0' && *lp != '`'; lp++)
664167465Smp	    ;
665167465Smp	Strbuf_appendn(&word, cp, lp - cp);
666167465Smp	if (*lp == 0)
667167465Smp	    break;
66859243Sobrien	lp++;
66959243Sobrien	for (rp = lp; *rp && *rp != '`'; rp++)
67059243Sobrien	    if (*rp == '\\') {
67159243Sobrien		rp++;
67259243Sobrien		if (!*rp)
67359243Sobrien		    goto oops;
67459243Sobrien	    }
675167465Smp	if (!*rp) {
676167465Smp	oops:
677195609Smp	    cleanup_until(&bb);
678167465Smp	    stderror(ERR_UNMATCHED, '`');
679167465Smp	}
680167465Smp	ep = Strnsave(lp, rp - lp);
681167465Smp	cleanup_push(ep, xfree);
682167465Smp	backeval(&bb, &word, ep, literal);
683167465Smp	cleanup_until(ep);
68459243Sobrien	cp = rp + 1;
68559243Sobrien    }
686167465Smp    if (word.len != 0)
687167465Smp	pword(&bb, &word);
688167465Smp    cleanup_ignore(&bb);
689167465Smp    cleanup_until(&bb);
690167465Smp    return bb_finish(&bb);
69159243Sobrien}
69259243Sobrien
69359243Sobrien
69459243Sobrienstatic void
695167465Smpbackeval(struct blk_buf *bb, struct Strbuf *word, Char *cp, int literal)
69659243Sobrien{
697231990Smp    ssize_t icnt;
698145479Smp    Char c, *ip;
69959243Sobrien    struct command faket;
700145479Smp    int    hadnl;
70159243Sobrien    int     pvec[2], quoted;
70259243Sobrien    Char   *fakecom[2], ibuf[BUFSIZE];
70359243Sobrien
70459243Sobrien    hadnl = 0;
70559243Sobrien    icnt = 0;
706316957Sdchagin    if (!literal) {
707316957Sdchagin	for (ip = cp; (*ip & QUOTE) != 0; ip++)
708316957Sdchagin		continue;
709316957Sdchagin	quoted = *ip == '\0';
710316957Sdchagin    } else
711316957Sdchagin	quoted = literal;
71259243Sobrien    faket.t_dtyp = NODE_COMMAND;
71359243Sobrien    faket.t_dflg = F_BACKQ;
71459243Sobrien    faket.t_dlef = 0;
71559243Sobrien    faket.t_drit = 0;
71659243Sobrien    faket.t_dspr = 0;
71759243Sobrien    faket.t_dcom = fakecom;
71859243Sobrien    fakecom[0] = STRfakecom1;
71959243Sobrien    fakecom[1] = 0;
72059243Sobrien
72159243Sobrien    /*
72259243Sobrien     * We do the psave job to temporarily change the current job so that the
72359243Sobrien     * following fork is considered a separate job.  This is so that when
72459243Sobrien     * backquotes are used in a builtin function that calls glob the "current
72559243Sobrien     * job" is not corrupted.  We only need one level of pushed jobs as long as
72659243Sobrien     * we are sure to fork here.
72759243Sobrien     */
72859243Sobrien    psavejob();
729167465Smp    cleanup_push(&faket, psavejob_cleanup); /* faket is only a marker */
73059243Sobrien
73159243Sobrien    /*
73259243Sobrien     * It would be nicer if we could integrate this redirection more with the
73359243Sobrien     * routines in sh.sem.c by doing a fake execute on a builtin function that
73459243Sobrien     * was piped out.
73559243Sobrien     */
73659243Sobrien    mypipe(pvec);
737167465Smp    cleanup_push(&pvec[0], open_cleanup);
738167465Smp    cleanup_push(&pvec[1], open_cleanup);
73959243Sobrien    if (pfork(&faket, -1) == 0) {
740145479Smp	jmp_buf_t osetexit;
741167465Smp	struct command *t;
742167465Smp	size_t omark;
74359243Sobrien
744167465Smp	xclose(pvec[0]);
74559243Sobrien	(void) dmove(pvec[1], 1);
74659243Sobrien	(void) dmove(SHDIAG,  2);
74759243Sobrien	initdesc();
748100616Smp	closem();
74959243Sobrien	arginp = cp;
750100616Smp	for (arginp = cp; *cp; cp++) {
751100616Smp	    *cp &= TRIM;
752145479Smp	    if (is_set(STRcsubstnonl) && (*cp == '\n' || *cp == '\r'))
753100616Smp		*cp = ' ';
754100616Smp	}
75559243Sobrien
75659243Sobrien        /*
75759243Sobrien	 * In the child ``forget'' everything about current aliases or
75859243Sobrien	 * eval vectors.
75959243Sobrien	 */
76059243Sobrien	alvec = NULL;
76159243Sobrien	evalvec = NULL;
76259243Sobrien	alvecp = NULL;
76359243Sobrien	evalp = NULL;
764145479Smp
765167465Smp	omark = cleanup_push_mark();
766145479Smp	getexit(osetexit);
767145479Smp	for (;;) {
768316957Sdchagin	    struct wordent paraml1;
769316957Sdchagin	    initlex(&paraml1);
770316957Sdchagin
771145479Smp	    (void) setexit();
772145479Smp	    justpr = 0;
773145479Smp
774145479Smp	    if (haderr) {
775145479Smp		/* unwind */
776145479Smp		doneinp = 0;
777167465Smp		cleanup_pop_mark(omark);
778145479Smp		resexit(osetexit);
779145479Smp		reset();
780145479Smp	    }
781145479Smp	    if (seterr) {
782167465Smp		xfree(seterr);
783145479Smp		seterr = NULL;
784145479Smp	    }
785145479Smp
786316957Sdchagin	    freelex(&paraml1);
787316957Sdchagin	    (void) lex(&paraml1);
788316957Sdchagin	    cleanup_push(&paraml1, lex_cleanup);
789145479Smp	    if (seterr)
790145479Smp		stderror(ERR_OLD);
791316957Sdchagin	    alias(&paraml1);
792316957Sdchagin	    t = syntax(paraml1.next, &paraml1, 0);
793167465Smp	    cleanup_push(t, syntax_cleanup);
794231990Smp	    /* The F_BACKQ flag must set so the job output is correct if
795231990Smp	     * printexitvalue is set.  If it's not set, the job output
796231990Smp	     * will have "Exit N" appended where N is the exit status. */
797316957Sdchagin	    if (t)
798316957Sdchagin		    t->t_dflg = F_BACKQ|F_NOFORK;
799145479Smp	    if (seterr)
800145479Smp		stderror(ERR_OLD);
80159243Sobrien#ifdef SIGTSTP
802167465Smp	    signal(SIGTSTP, SIG_IGN);
80359243Sobrien#endif
80459243Sobrien#ifdef SIGTTIN
805167465Smp	    signal(SIGTTIN, SIG_IGN);
80659243Sobrien#endif
80759243Sobrien#ifdef SIGTTOU
808167465Smp	    signal(SIGTTOU, SIG_IGN);
80959243Sobrien#endif
810145479Smp	    execute(t, -1, NULL, NULL, TRUE);
811145479Smp
812316957Sdchagin	    cleanup_until(&paraml1);
813145479Smp	}
81459243Sobrien    }
815167465Smp    cleanup_until(&pvec[1]);
81659243Sobrien    c = 0;
81759243Sobrien    ip = NULL;
81859243Sobrien    do {
819231990Smp	ssize_t     cnt = 0;
82059243Sobrien
82159243Sobrien	for (;;) {
822316957Sdchagin	    if (icnt == 0) {
82359243Sobrien		ip = ibuf;
824316957Sdchagin		icnt = wide_read(pvec[0], ibuf, BUFSIZE, 0);
825316957Sdchagin		if (icnt <= 0)
826316957Sdchagin		    goto eof;
82759243Sobrien	    }
82859243Sobrien	    if (hadnl)
82959243Sobrien		break;
83059243Sobrien	    --icnt;
83159243Sobrien	    c = (*ip++ & TRIM);
83259243Sobrien	    if (c == 0)
83359243Sobrien		break;
834195609Smp#if defined(WINNT_NATIVE) || defined(__CYGWIN__)
83559243Sobrien	    if (c == '\r')
83659243Sobrien	    	c = ' ';
837195609Smp#endif /* WINNT_NATIVE || __CYGWIN__ */
83859243Sobrien	    if (c == '\n') {
83959243Sobrien		/*
84059243Sobrien		 * Continue around the loop one more time, so that we can eat
84159243Sobrien		 * the last newline without terminating this word.
84259243Sobrien		 */
84359243Sobrien		hadnl = 1;
84459243Sobrien		continue;
84559243Sobrien	    }
84659243Sobrien	    if (!quoted && (c == ' ' || c == '\t'))
84759243Sobrien		break;
84859243Sobrien	    cnt++;
849316957Sdchagin	    if (c == '\\' || quoted)
850316957Sdchagin		c |= QUOTE;
851316957Sdchagin	    Strbuf_append1(word, c);
85259243Sobrien	}
85359243Sobrien	/*
85459243Sobrien	 * Unless at end-of-file, we will form a new word here if there were
85559243Sobrien	 * characters in the word, or in any case when we take text literally.
85659243Sobrien	 * If we didn't make empty words here when literal was set then we
85759243Sobrien	 * would lose blank lines.
85859243Sobrien	 */
859145479Smp	if (c != 0 && (cnt || literal))
860167465Smp	    pword(bb, word);
86159243Sobrien	hadnl = 0;
862145479Smp    } while (c > 0);
863145479Smp eof:
864167465Smp    cleanup_until(&pvec[0]);
86559243Sobrien    pwait();
866167465Smp    cleanup_until(&faket); /* psavejob_cleanup(); */
86759243Sobrien}
86859243Sobrien
86959243Sobrienstatic void
870167465Smppword(struct blk_buf *bb, struct Strbuf *word)
87159243Sobrien{
872167465Smp    Char *s;
87359243Sobrien
874167465Smp    s = Strbuf_finish(word);
875167465Smp    bb_append(bb, s);
876167465Smp    *word = Strbuf_init;
87759243Sobrien}
87859243Sobrien
87959243Sobrienint
880167465SmpGmatch(const Char *string, const Char *pattern)
88159243Sobrien{
88259243Sobrien    return Gnmatch(string, pattern, NULL);
88359243Sobrien}
88459243Sobrien
885167465Smpint
886167465SmpGnmatch(const Char *string, const Char *pattern, const Char **endstr)
88759243Sobrien{
888167465Smp    Char ***fblk, **p;
889167465Smp    const Char *tstring = string;
89059243Sobrien    int	   gpol = 1, gres = 0;
89159243Sobrien
89259243Sobrien    if (*pattern == '^') {
89359243Sobrien	gpol = 0;
89459243Sobrien	pattern++;
89559243Sobrien    }
89659243Sobrien
897167465Smp    fblk = xmalloc(sizeof(Char ***));
898167465Smp    *fblk = xmalloc(GLOBSPACE * sizeof(Char *));
899167465Smp    (*fblk)[0] = Strsave(pattern);
900167465Smp    (*fblk)[1] = NULL;
90159243Sobrien
902167465Smp    cleanup_push(fblk, blk_indirect_cleanup);
903167465Smp    expbrace(fblk, NULL, GLOBSPACE);
90459243Sobrien
90559243Sobrien    if (endstr == NULL)
90659243Sobrien	/* Exact matches only */
907167465Smp	for (p = *fblk; *p; p++)
908145479Smp	    gres |= t_pmatch(string, *p, &tstring, 1) == 2 ? 1 : 0;
90959243Sobrien    else {
910167465Smp	const Char *end;
911167465Smp
91259243Sobrien	/* partial matches */
913167465Smp        end = Strend(string);
914167465Smp	for (p = *fblk; *p; p++)
915145479Smp	    if (t_pmatch(string, *p, &tstring, 1) != 0) {
91659243Sobrien		gres |= 1;
917167465Smp		if (end > tstring)
918167465Smp		    end = tstring;
91959243Sobrien	    }
920167465Smp	*endstr = end;
92159243Sobrien    }
92259243Sobrien
923167465Smp    cleanup_until(fblk);
92459243Sobrien    return(gres == gpol);
92559243Sobrien}
92659243Sobrien
927131962Smp/* t_pmatch():
92859243Sobrien *	Return 2 on exact match,
92959243Sobrien *	Return 1 on substring match.
93059243Sobrien *	Return 0 on no match.
93159243Sobrien *	*estr will point to the end of the longest exact or substring match.
93259243Sobrien */
933131962Smpint
934167465Smpt_pmatch(const Char *string, const Char *pattern, const Char **estr, int cs)
93559243Sobrien{
936167465Smp    Char stringc, patternc, rangec;
93759243Sobrien    int     match, negate_range;
938167465Smp    const Char *pestr, *nstring;
93959243Sobrien
940145479Smp    for (nstring = string;; string = nstring) {
941167465Smp	stringc = *nstring++ & TRIM;
942167465Smp	patternc = *pattern++ & TRIM;
94359243Sobrien	switch (patternc) {
944145479Smp	case '\0':
94559243Sobrien	    *estr = string;
946145479Smp	    return (stringc == '\0' ? 2 : 1);
94759243Sobrien	case '?':
94859243Sobrien	    if (stringc == 0)
94959243Sobrien		return (0);
95059243Sobrien	    break;
95159243Sobrien	case '*':
95259243Sobrien	    if (!*pattern) {
953167465Smp		*estr = Strend(string);
95459243Sobrien		return (2);
95559243Sobrien	    }
95659243Sobrien	    pestr = NULL;
95759243Sobrien
958145479Smp	    for (;;) {
959131962Smp		switch(t_pmatch(string, pattern, estr, cs)) {
96059243Sobrien		case 0:
96159243Sobrien		    break;
96259243Sobrien		case 1:
963167465Smp		    pestr = *estr;/*FIXME: does not guarantee longest match */
96459243Sobrien		    break;
96559243Sobrien		case 2:
96659243Sobrien		    return 2;
96759243Sobrien		default:
96859243Sobrien		    abort();	/* Cannot happen */
96959243Sobrien		}
970167465Smp		stringc = *string++ & TRIM;
971145479Smp		if (!stringc)
972145479Smp		    break;
97359243Sobrien	    }
97459243Sobrien
97559243Sobrien	    if (pestr) {
97659243Sobrien		*estr = pestr;
97759243Sobrien		return 1;
97859243Sobrien	    }
979167465Smp	    else
98059243Sobrien		return 0;
98159243Sobrien
98259243Sobrien	case '[':
98359243Sobrien	    match = 0;
98459243Sobrien	    if ((negate_range = (*pattern == '^')) != 0)
98559243Sobrien		pattern++;
986167465Smp	    while ((rangec = *pattern++ & TRIM) != '\0') {
98759243Sobrien		if (rangec == ']')
98859243Sobrien		    break;
98959243Sobrien		if (match)
99059243Sobrien		    continue;
991145479Smp		if (*pattern == '-' && pattern[1] != ']') {
992167465Smp		    Char rangec2;
99359243Sobrien		    pattern++;
994167465Smp		    rangec2 = *pattern++ & TRIM;
995145479Smp		    match = (globcharcoll(stringc, rangec2, 0) <= 0 &&
996145479Smp			globcharcoll(rangec, stringc, 0) <= 0);
99759243Sobrien		}
99859243Sobrien		else
999145479Smp		    match = (stringc == rangec);
100059243Sobrien	    }
1001145479Smp	    if (rangec == '\0')
100259243Sobrien		stderror(ERR_NAME | ERR_MISSING, ']');
1003145479Smp	    if ((!match) && (stringc == '\0'))
1004145479Smp		return (0);
100559243Sobrien	    if (match == negate_range)
100659243Sobrien		return (0);
100759243Sobrien	    break;
100859243Sobrien	default:
1009145479Smp	    if (cs ? patternc  != stringc
1010145479Smp		: Tolower(patternc) != Tolower(stringc))
101159243Sobrien		return (0);
101259243Sobrien	    break;
101359243Sobrien	}
101459243Sobrien    }
101559243Sobrien}
1016