sh.glob.c revision 167465
1167465Smp/* $Header: /p/tcsh/cvsroot/tcsh/sh.glob.c,v 3.74 2006/10/14 17:57:21 christos Exp $ */
259243Sobrien/*
359243Sobrien * sh.glob.c: Regular expression expansion
459243Sobrien */
559243Sobrien/*-
659243Sobrien * Copyright (c) 1980, 1991 The Regents of the University of California.
759243Sobrien * All rights reserved.
859243Sobrien *
959243Sobrien * Redistribution and use in source and binary forms, with or without
1059243Sobrien * modification, are permitted provided that the following conditions
1159243Sobrien * are met:
1259243Sobrien * 1. Redistributions of source code must retain the above copyright
1359243Sobrien *    notice, this list of conditions and the following disclaimer.
1459243Sobrien * 2. Redistributions in binary form must reproduce the above copyright
1559243Sobrien *    notice, this list of conditions and the following disclaimer in the
1659243Sobrien *    documentation and/or other materials provided with the distribution.
17100616Smp * 3. Neither the name of the University nor the names of its contributors
1859243Sobrien *    may be used to endorse or promote products derived from this software
1959243Sobrien *    without specific prior written permission.
2059243Sobrien *
2159243Sobrien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2259243Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2359243Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2459243Sobrien * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2559243Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2659243Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2759243Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2859243Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2959243Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3059243Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3159243Sobrien * SUCH DAMAGE.
3259243Sobrien */
3359243Sobrien#include "sh.h"
3459243Sobrien
35167465SmpRCSID("$tcsh: sh.glob.c,v 3.74 2006/10/14 17:57:21 christos Exp $")
3659243Sobrien
3759243Sobrien#include "tc.h"
38100616Smp#include "tw.h"
3959243Sobrien
4059243Sobrien#include "glob.h"
4159243Sobrien
4259243Sobrien/*
4359243Sobrien * Values for gflag
4459243Sobrien */
4559243Sobrien#define	G_NONE	0		/* No globbing needed			*/
4659243Sobrien#define	G_GLOB	1		/* string contains *?[] characters	*/
4759243Sobrien#define	G_CSH	2		/* string contains ~`{ characters	*/
4859243Sobrien
4959243Sobrien#define	GLOBSPACE	100	/* Alloc increment			*/
5059243Sobrien
5159243Sobrien
5259243Sobrien#define LBRC '{'
5359243Sobrien#define RBRC '}'
5459243Sobrien#define LBRK '['
5559243Sobrien#define RBRK ']'
5659243Sobrien#define EOS '\0'
5759243Sobrien
5859243Sobrien/*
5959243Sobrien * globbing is now done in two stages. In the first pass we expand
6059243Sobrien * csh globbing idioms ~`{ and then we proceed doing the normal
6159243Sobrien * globbing if needed ?*[
6259243Sobrien *
6359243Sobrien * Csh type globbing is handled in globexpand() and the rest is
6459243Sobrien * handled in glob() which is part of the 4.4BSD libc.
6559243Sobrien *
6659243Sobrien */
67167465Smpstatic	Char	 *globtilde	(Char *);
68167465Smpstatic	Char     *handleone	(Char *, Char **, int);
69167465Smpstatic	Char	**libglob	(Char **);
70167465Smpstatic	Char	**globexpand	(Char **, int);
71167465Smpstatic	int	  globbrace	(const Char *, Char ***);
72167465Smpstatic  void	  expbrace	(Char ***, Char ***, int);
73167465Smpstatic	void	  pword		(struct blk_buf *, struct Strbuf *);
74167465Smpstatic	void	  backeval	(struct blk_buf *, struct Strbuf *, Char *,
75167465Smp				 int);
7659243Sobrienstatic Char *
77167465Smpglobtilde(Char *s)
7859243Sobrien{
79167465Smp    Char *name, *u, *home, *res;
8059243Sobrien
8159243Sobrien    u = s;
82167465Smp    for (s++; *s && *s != '/' && *s != ':'; s++)
8359243Sobrien	continue;
84167465Smp    name = Strnsave(u + 1, s - (u + 1));
85167465Smp    cleanup_push(name, xfree);
86167465Smp    home = gethdir(name);
87167465Smp    if (home == NULL) {
88167465Smp	if (adrof(STRnonomatch)) {
89167465Smp	    cleanup_until(name);
90167465Smp	    return u;
91167465Smp	}
92167465Smp	if (*name)
93167465Smp	    stderror(ERR_UNKUSER, short2str(name));
9459243Sobrien	else
9559243Sobrien	    stderror(ERR_NOHOME);
9659243Sobrien    }
97167465Smp    cleanup_until(name);
98167465Smp    if (home[0] == '/' && home[1] == '\0' && s[0] == '/')
99167465Smp	res = Strsave(s);
100167465Smp    else
101167465Smp	res = Strspl(home, s);
102167465Smp    xfree(home);
103167465Smp    xfree(u);
104167465Smp    return res;
10559243Sobrien}
10659243Sobrien
107167465Smp/* Returns a newly allocated string, old or NULL */
10859243SobrienChar *
109167465Smpglobequal(Char *old)
11059243Sobrien{
11159243Sobrien    int     dig;
112167465Smp    const Char *dir;
113167465Smp    Char    *b;
11459243Sobrien
11559243Sobrien    /*
11659243Sobrien     * kfk - 17 Jan 1984 - stack hack allows user to get at arbitrary dir names
11759243Sobrien     * in stack. PWP: let =foobar pass through (for X windows)
11859243Sobrien     */
11959243Sobrien    if (old[1] == '-' && (old[2] == '\0' || old[2] == '/')) {
12059243Sobrien	/* =- */
121167465Smp	const Char *olddir = varval (STRowd);
122167465Smp
123167465Smp	if (olddir && *olddir &&
124167465Smp	    !dcwd->di_next->di_name && !dcwd->di_prev->di_name)
125167465Smp	    return Strspl(olddir, &old[2]);
12659243Sobrien	dig = -1;
12759243Sobrien	b = &old[2];
12859243Sobrien    }
12959243Sobrien    else if (Isdigit(old[1])) {
13059243Sobrien	/* =<number> */
13159243Sobrien	dig = old[1] - '0';
13259243Sobrien	for (b = &old[2]; Isdigit(*b); b++)
13359243Sobrien	    dig = dig * 10 + (*b - '0');
13459243Sobrien	if (*b != '\0' && *b != '/')
13559243Sobrien	    /* =<number>foobar */
13659243Sobrien	    return old;
13759243Sobrien    }
13859243Sobrien    else
13959243Sobrien	/* =foobar */
14059243Sobrien	return old;
14159243Sobrien
142167465Smp    dir = getstakd(dig);
143167465Smp    if (dir == NULL)
14459243Sobrien	return NULL;
145167465Smp    return Strspl(dir, b);
14659243Sobrien}
14759243Sobrien
14859243Sobrienstatic int
149167465Smpglobbrace(const Char *s, Char ***bl)
15059243Sobrien{
151167465Smp    struct Strbuf gbuf = Strbuf_INIT;
152167465Smp    struct blk_buf bb = BLK_BUF_INIT;
153167465Smp    int     i;
154167465Smp    const Char *p, *pm, *pe, *pl;
155167465Smp    size_t prefix_len;
15659243Sobrien
15759243Sobrien    /* copy part up to the brace */
158167465Smp    for (p = s; *p != LBRC; p++)
159167465Smp	;
160167465Smp    prefix_len = p - s;
16159243Sobrien
16259243Sobrien    /* check for balanced braces */
16359243Sobrien    for (i = 0, pe = ++p; *pe; pe++)
16459243Sobrien	if (*pe == LBRK) {
16559243Sobrien	    /* Ignore everything between [] */
16659243Sobrien	    for (++pe; *pe != RBRK && *pe != EOS; pe++)
16759243Sobrien		continue;
168167465Smp	    if (*pe == EOS)
16959243Sobrien		return (-RBRK);
17059243Sobrien	}
17159243Sobrien	else if (*pe == LBRC)
17259243Sobrien	    i++;
17359243Sobrien	else if (*pe == RBRC) {
17459243Sobrien	    if (i == 0)
17559243Sobrien		break;
17659243Sobrien	    i--;
17759243Sobrien	}
17859243Sobrien
179167465Smp    if (i != 0 || *pe == '\0')
18059243Sobrien	return (-RBRC);
18159243Sobrien
182167465Smp    Strbuf_appendn(&gbuf, s, prefix_len);
183167465Smp
18459243Sobrien    for (i = 0, pl = pm = p; pm <= pe; pm++)
18559243Sobrien	switch (*pm) {
18659243Sobrien	case LBRK:
18759243Sobrien	    for (++pm; *pm != RBRK && *pm != EOS; pm++)
18859243Sobrien		continue;
18959243Sobrien	    if (*pm == EOS) {
190167465Smp		bb_cleanup(&bb);
191167465Smp		xfree(gbuf.s);
19259243Sobrien		return (-RBRK);
19359243Sobrien	    }
19459243Sobrien	    break;
19559243Sobrien	case LBRC:
19659243Sobrien	    i++;
19759243Sobrien	    break;
19859243Sobrien	case RBRC:
19959243Sobrien	    if (i) {
20059243Sobrien		i--;
20159243Sobrien		break;
20259243Sobrien	    }
20359243Sobrien	    /* FALLTHROUGH */
20459243Sobrien	case ',':
20559243Sobrien	    if (i && *pm == ',')
20659243Sobrien		break;
20759243Sobrien	    else {
208167465Smp		gbuf.len = prefix_len;
209167465Smp		Strbuf_appendn(&gbuf, pl, pm - pl);
210167465Smp		Strbuf_append(&gbuf, pe + 1);
211167465Smp		Strbuf_terminate(&gbuf);
212167465Smp		bb_append(&bb, Strsave(gbuf.s));
21359243Sobrien		pl = pm + 1;
21459243Sobrien	    }
21559243Sobrien	    break;
21659243Sobrien	default:
21759243Sobrien	    break;
21859243Sobrien	}
219167465Smp    *bl = bb_finish(&bb);
220167465Smp    xfree(gbuf.s);
221167465Smp    return bb.len;
22259243Sobrien}
22359243Sobrien
22459243Sobrien
22559243Sobrienstatic void
226167465Smpexpbrace(Char ***nvp, Char ***elp, int size)
22759243Sobrien{
22859243Sobrien    Char **vl, **el, **nv, *s;
22959243Sobrien
23059243Sobrien    vl = nv = *nvp;
23159243Sobrien    if (elp != NULL)
23259243Sobrien	el = *elp;
23359243Sobrien    else
234167465Smp	el = vl + blklen(vl);
23559243Sobrien
23659243Sobrien    for (s = *vl; s; s = *++vl) {
23759243Sobrien	Char  **vp, **bp;
23859243Sobrien
23959243Sobrien	/* leave {} untouched for find */
24059243Sobrien	if (s[0] == '{' && (s[1] == '\0' || (s[1] == '}' && s[2] == '\0')))
24159243Sobrien	    continue;
242167465Smp	if (Strchr(s, '{') != NULL) {
243167465Smp	    Char  **bl = NULL;
24459243Sobrien	    int     len;
24559243Sobrien
246167465Smp	    if ((len = globbrace(s, &bl)) < 0)
24759243Sobrien		stderror(ERR_MISSING, -len);
248167465Smp	    xfree(s);
24959243Sobrien	    if (len == 1) {
25059243Sobrien		*vl-- = *bl;
251167465Smp		xfree(bl);
25259243Sobrien		continue;
25359243Sobrien	    }
25459243Sobrien	    if (&el[len] >= &nv[size]) {
255167465Smp		size_t l, e;
256167465Smp		l = &el[len] - &nv[size];
25759243Sobrien		size += GLOBSPACE > l ? GLOBSPACE : l;
258167465Smp		l = vl - nv;
259167465Smp		e = el - nv;
260167465Smp		nv = xrealloc(nv, size * sizeof(Char *));
261167465Smp		*nvp = nv; /* To keep cleanups working */
26259243Sobrien		vl = nv + l;
26359243Sobrien		el = nv + e;
26459243Sobrien	    }
26559243Sobrien	    /* nv vl   el     bl
26659243Sobrien	     * |  |    |      |
26759243Sobrien	     * -.--..--	      x--
26859243Sobrien	     *   |            len
26959243Sobrien	     *   vp
27059243Sobrien	     */
27159243Sobrien	    vp = vl--;
27259243Sobrien	    *vp = *bl;
27359243Sobrien	    len--;
27459243Sobrien	    for (bp = el; bp != vp; bp--)
27559243Sobrien		bp[len] = *bp;
27659243Sobrien	    el += len;
27759243Sobrien	    /* nv vl    el bl
27859243Sobrien	     * |  |     |  |
27959243Sobrien	     * -.-x  ---    --
28059243Sobrien	     *   |len
28159243Sobrien	     *   vp
28259243Sobrien	     */
28359243Sobrien	    vp++;
28459243Sobrien	    for (bp = bl + 1; *bp; *vp++ = *bp++)
28559243Sobrien		continue;
286167465Smp	    xfree(bl);
28759243Sobrien	}
28859243Sobrien
28959243Sobrien    }
29059243Sobrien    if (elp != NULL)
29159243Sobrien	*elp = el;
29259243Sobrien}
29359243Sobrien
29459243Sobrienstatic Char **
295167465Smpglobexpand(Char **v, int noglob)
29659243Sobrien{
29759243Sobrien    Char   *s;
298167465Smp    Char  ***fnv, **vl, **el;
29959243Sobrien    int     size = GLOBSPACE;
30059243Sobrien
30159243Sobrien
302167465Smp    fnv = xmalloc(sizeof(Char ***));
303167465Smp    *fnv = vl = xmalloc(sizeof(Char *) * size);
30459243Sobrien    *vl = NULL;
305167465Smp    cleanup_push(fnv, blk_indirect_cleanup);
30659243Sobrien
30759243Sobrien    /*
30859243Sobrien     * Step 1: expand backquotes.
30959243Sobrien     */
31059243Sobrien    while ((s = *v++) != '\0') {
31159243Sobrien	if (Strchr(s, '`')) {
31259243Sobrien	    int     i;
313167465Smp	    Char **expanded;
31459243Sobrien
315167465Smp	    expanded = dobackp(s, 0);
316167465Smp	    for (i = 0; expanded[i] != NULL; i++) {
317167465Smp		*vl++ = expanded[i];
318167465Smp		if (vl == &(*fnv)[size]) {
31959243Sobrien		    size += GLOBSPACE;
320167465Smp		    *fnv = xrealloc(*fnv, size * sizeof(Char *));
321167465Smp		    vl = &(*fnv)[size - GLOBSPACE];
32259243Sobrien		}
32359243Sobrien	    }
324167465Smp	    xfree(expanded);
32559243Sobrien	}
32659243Sobrien	else {
32759243Sobrien	    *vl++ = Strsave(s);
328167465Smp	    if (vl == &(*fnv)[size]) {
32959243Sobrien		size += GLOBSPACE;
330167465Smp		*fnv = xrealloc(*fnv, size * sizeof(Char *));
331167465Smp		vl = &(*fnv)[size - GLOBSPACE];
33259243Sobrien	    }
33359243Sobrien	}
334167465Smp	*vl = NULL;
33559243Sobrien    }
33659243Sobrien
33759243Sobrien    if (noglob)
338167465Smp	goto done;
33959243Sobrien
34059243Sobrien    /*
34159243Sobrien     * Step 2: expand braces
34259243Sobrien     */
34359243Sobrien    el = vl;
344167465Smp    expbrace(fnv, &el, size);
34559243Sobrien
34659243Sobrien
34759243Sobrien    /*
34859243Sobrien     * Step 3: expand ~ =
34959243Sobrien     */
350167465Smp    vl = *fnv;
35159243Sobrien    for (s = *vl; s; s = *++vl)
35259243Sobrien	switch (*s) {
353167465Smp	    Char *ns;
35459243Sobrien	case '~':
355167465Smp	    *vl = globtilde(s);
35659243Sobrien	    break;
35759243Sobrien	case '=':
358167465Smp	    if ((ns = globequal(s)) == NULL) {
359167465Smp		if (!adrof(STRnonomatch))
360167465Smp		    stderror(ERR_DEEP); /* Error */
36159243Sobrien	    }
36259243Sobrien	    if (ns && ns != s) {
36359243Sobrien		/* Expansion succeeded */
364167465Smp		xfree(s);
365167465Smp		*vl = ns;
36659243Sobrien	    }
36759243Sobrien	    break;
36859243Sobrien	default:
36959243Sobrien	    break;
37059243Sobrien	}
371167465Smp    vl = *fnv;
37259243Sobrien
37359243Sobrien    /*
37459243Sobrien     * Step 4: expand .. if the variable symlinks==expand is set
37559243Sobrien     */
37683098Smp    if (symlinks == SYM_EXPAND) {
37759243Sobrien	for (s = *vl; s; s = *++vl) {
37883098Smp	    *vl = dnormalize(s, 1);
379167465Smp	    xfree(s);
38059243Sobrien	}
38183098Smp    }
38259243Sobrien
383167465Smp done:
384167465Smp    cleanup_ignore(fnv);
385167465Smp    cleanup_until(fnv);
386167465Smp    vl = *fnv;
387167465Smp    xfree(fnv);
388167465Smp    return vl;
38959243Sobrien}
39059243Sobrien
39159243Sobrienstatic Char *
392167465Smphandleone(Char *str, Char **vl, int action)
39359243Sobrien{
394167465Smp    size_t chars;
39559243Sobrien    Char **t, *p, *strp;
39659243Sobrien
39759243Sobrien    switch (action) {
39859243Sobrien    case G_ERROR:
39959243Sobrien	setname(short2str(str));
40059243Sobrien	blkfree(vl);
40159243Sobrien	stderror(ERR_NAME | ERR_AMBIG);
40259243Sobrien	break;
40359243Sobrien    case G_APPEND:
40459243Sobrien	chars = 0;
405167465Smp	for (t = vl; (p = *t++) != NULL; chars++)
406167465Smp	    chars += Strlen(p);
407167465Smp	str = xmalloc(chars * sizeof(Char));
408167465Smp	for (t = vl, strp = str; (p = *t++) != '\0'; chars++) {
40959243Sobrien	    while (*p)
41059243Sobrien		 *strp++ = *p++ & TRIM;
41159243Sobrien	    *strp++ = ' ';
41259243Sobrien	}
41359243Sobrien	*--strp = '\0';
41459243Sobrien	blkfree(vl);
41559243Sobrien	break;
41659243Sobrien    case G_IGNORE:
417167465Smp	str = Strsave(strip(*vl));
41859243Sobrien	blkfree(vl);
41959243Sobrien	break;
42059243Sobrien    default:
42159243Sobrien	break;
42259243Sobrien    }
42359243Sobrien    return (str);
42459243Sobrien}
42559243Sobrien
42659243Sobrienstatic Char **
427167465Smplibglob(Char **vl)
42859243Sobrien{
42959243Sobrien    int     gflgs = GLOB_QUOTE | GLOB_NOMAGIC | GLOB_ALTNOT;
43059243Sobrien    glob_t  globv;
43159243Sobrien    char   *ptr;
43259243Sobrien    int     nonomatch = adrof(STRnonomatch) != 0, magic = 0, match = 0;
43359243Sobrien
43459243Sobrien    if (!vl || !vl[0])
43559243Sobrien	return(vl);
43659243Sobrien
43759243Sobrien    globv.gl_offs = 0;
43859243Sobrien    globv.gl_pathv = 0;
43959243Sobrien    globv.gl_pathc = 0;
44059243Sobrien
44159243Sobrien    if (nonomatch)
44259243Sobrien	gflgs |= GLOB_NOCHECK;
44359243Sobrien
44459243Sobrien    do {
44559243Sobrien	ptr = short2qstr(*vl);
44659243Sobrien	switch (glob(ptr, gflgs, 0, &globv)) {
44759243Sobrien	case GLOB_ABEND:
44859243Sobrien	    globfree(&globv);
44959243Sobrien	    setname(ptr);
45059243Sobrien	    stderror(ERR_NAME | ERR_GLOB);
45159243Sobrien	    /* NOTREACHED */
45259243Sobrien	case GLOB_NOSPACE:
45359243Sobrien	    globfree(&globv);
45459243Sobrien	    stderror(ERR_NOMEM);
45559243Sobrien	    /* NOTREACHED */
45659243Sobrien	default:
45759243Sobrien	    break;
45859243Sobrien	}
45959243Sobrien	if (globv.gl_flags & GLOB_MAGCHAR) {
46059243Sobrien	    match |= (globv.gl_matchc != 0);
46159243Sobrien	    magic = 1;
46259243Sobrien	}
46359243Sobrien	gflgs |= GLOB_APPEND;
46459243Sobrien    }
46559243Sobrien    while (*++vl);
46659243Sobrien    vl = (globv.gl_pathc == 0 || (magic && !match && !nonomatch)) ?
46759243Sobrien	NULL : blk2short(globv.gl_pathv);
46859243Sobrien    globfree(&globv);
46959243Sobrien    return (vl);
47059243Sobrien}
47159243Sobrien
47259243SobrienChar   *
473167465Smpglobone(Char *str, int action)
47459243Sobrien{
47559243Sobrien    Char   *v[2], **vl, **vo;
476167465Smp    int gflg, noglob;
47759243Sobrien
47859243Sobrien    noglob = adrof(STRnoglob) != 0;
47959243Sobrien    v[0] = str;
48059243Sobrien    v[1] = 0;
481167465Smp    gflg = tglob(v);
48259243Sobrien    if (gflg == G_NONE)
48359243Sobrien	return (strip(Strsave(str)));
48459243Sobrien
48559243Sobrien    if (gflg & G_CSH) {
48659243Sobrien	/*
48759243Sobrien	 * Expand back-quote, tilde and brace
48859243Sobrien	 */
489167465Smp	vo = globexpand(v, noglob);
49059243Sobrien	if (noglob || (gflg & G_GLOB) == 0) {
491167465Smp	    vl = vo;
492167465Smp	    goto result;
49359243Sobrien	}
494167465Smp	cleanup_push(vo, blk_cleanup);
49559243Sobrien    }
49659243Sobrien    else if (noglob || (gflg & G_GLOB) == 0)
49759243Sobrien	return (strip(Strsave(str)));
49859243Sobrien    else
49959243Sobrien	vo = v;
50059243Sobrien
50159243Sobrien    vl = libglob(vo);
502167465Smp    if (gflg & G_CSH) {
503167465Smp    	if (vl != vo)
504167465Smp	    cleanup_until(vo);
505167465Smp	else
506167465Smp	    cleanup_ignore(vo);
507167465Smp    }
50859243Sobrien    if (vl == NULL) {
50959243Sobrien	setname(short2str(str));
51059243Sobrien	stderror(ERR_NAME | ERR_NOMATCH);
51159243Sobrien    }
512167465Smp result:
51359243Sobrien    if (vl[0] == NULL) {
514167465Smp	xfree(vl);
51559243Sobrien	return (Strsave(STRNULL));
51659243Sobrien    }
51759243Sobrien    if (vl[1])
51859243Sobrien	return (handleone(str, vl, action));
51959243Sobrien    else {
52059243Sobrien	str = strip(*vl);
521167465Smp	xfree(vl);
52259243Sobrien	return (str);
52359243Sobrien    }
52459243Sobrien}
52559243Sobrien
52659243SobrienChar  **
527167465Smpgloball(Char **v, int gflg)
52859243Sobrien{
52959243Sobrien    Char  **vl, **vo;
530167465Smp    int noglob;
53159243Sobrien
532167465Smp    if (!v || !v[0])
533167465Smp	return saveblk(v);
53459243Sobrien
53559243Sobrien    noglob = adrof(STRnoglob) != 0;
53659243Sobrien
53759243Sobrien    if (gflg & G_CSH)
53859243Sobrien	/*
53959243Sobrien	 * Expand back-quote, tilde and brace
54059243Sobrien	 */
541167465Smp	vl = vo = globexpand(v, noglob);
54259243Sobrien    else
54359243Sobrien	vl = vo = saveblk(v);
54459243Sobrien
54559243Sobrien    if (!noglob && (gflg & G_GLOB)) {
546167465Smp	cleanup_push(vo, blk_cleanup);
54759243Sobrien	vl = libglob(vo);
548167465Smp	if (vl == vo)
549167465Smp	    cleanup_ignore(vo);
550167465Smp	cleanup_until(vo);
55159243Sobrien    }
55259243Sobrien    else
55359243Sobrien	trim(vl);
55459243Sobrien
555167465Smp    return vl;
55659243Sobrien}
55759243Sobrien
558167465SmpChar **
559167465Smpglob_all_or_error(Char **v)
56059243Sobrien{
561167465Smp    int gflag;
562167465Smp
563167465Smp    gflag = tglob(v);
564167465Smp    if (gflag) {
565167465Smp	v = globall(v, gflag);
566167465Smp	if (v == NULL)
567167465Smp	    stderror(ERR_NAME | ERR_NOMATCH);
568167465Smp    } else {
569167465Smp	v = saveblk(v);
570167465Smp	trim(v);
571167465Smp    }
572167465Smp    return v;
57359243Sobrien}
57459243Sobrien
57559243Sobrienvoid
576167465Smprscan(Char **t, void (*f) (Char))
57759243Sobrien{
578145479Smp    Char *p;
57959243Sobrien
58059243Sobrien    while ((p = *t++) != '\0')
58159243Sobrien	while (*p)
58259243Sobrien	    (*f) (*p++);
58359243Sobrien}
58459243Sobrien
58559243Sobrienvoid
586167465Smptrim(Char **t)
58759243Sobrien{
588145479Smp    Char *p;
58959243Sobrien
59059243Sobrien    while ((p = *t++) != '\0')
59159243Sobrien	while (*p)
59259243Sobrien	    *p++ &= TRIM;
59359243Sobrien}
59459243Sobrien
595167465Smpint
596167465Smptglob(Char **t)
59759243Sobrien{
598167465Smp    int gflag;
599167465Smp    const Char *p;
60059243Sobrien
601167465Smp    gflag = 0;
60259243Sobrien    while ((p = *t++) != '\0') {
60359243Sobrien	if (*p == '~' || *p == '=')
60459243Sobrien	    gflag |= G_CSH;
60559243Sobrien	else if (*p == '{' &&
60659243Sobrien		 (p[1] == '\0' || (p[1] == '}' && p[2] == '\0')))
60759243Sobrien	    continue;
608167465Smp	while (*p != '\0') {
609167465Smp	    if (*p == '`') {
61059243Sobrien		gflag |= G_CSH;
61159243Sobrien#ifdef notdef
61259243Sobrien		/*
61359243Sobrien		 * We do want to expand echo `echo '*'`, so we don't\
61459243Sobrien		 * use this piece of code anymore.
61559243Sobrien		 */
616167465Smp		p++;
61759243Sobrien		while (*p && *p != '`')
61859243Sobrien		    if (*p++ == '\\') {
61959243Sobrien			if (*p)		/* Quoted chars */
62059243Sobrien			    p++;
62159243Sobrien			else
62259243Sobrien			    break;
62359243Sobrien		    }
624167465Smp		if (!*p)		/* The matching ` */
62559243Sobrien		    break;
62659243Sobrien#endif
62759243Sobrien	    }
628167465Smp	    else if (*p == '{')
62959243Sobrien		gflag |= G_CSH;
630167465Smp	    else if (isglob(*p))
63159243Sobrien		gflag |= G_GLOB;
63259243Sobrien	    else if (symlinks == SYM_EXPAND &&
633167465Smp		p[1] && ISDOTDOT(p) && (p == *(t-1) || *(p-1) == '/') )
63459243Sobrien	    	gflag |= G_CSH;
635167465Smp	    p++;
63659243Sobrien	}
63759243Sobrien    }
638167465Smp    return gflag;
63959243Sobrien}
64059243Sobrien
64159243Sobrien/*
64259243Sobrien * Command substitute cp.  If literal, then this is a substitution from a
64359243Sobrien * << redirection, and so we should not crunch blanks and tabs, separating
64459243Sobrien * words only at newlines.
64559243Sobrien */
64659243SobrienChar  **
647167465Smpdobackp(Char *cp, int literal)
64859243Sobrien{
649167465Smp    struct Strbuf word = Strbuf_INIT;
650167465Smp    struct blk_buf bb = BLK_BUF_INIT;
651167465Smp    Char *lp, *rp, *ep;
65259243Sobrien
653167465Smp    cleanup_push(&bb, bb_cleanup);
654167465Smp    cleanup_push(&word, Strbuf_cleanup);
65559243Sobrien    for (;;) {
656167465Smp	for (lp = cp; *lp != '\0' && *lp != '`'; lp++)
657167465Smp	    ;
658167465Smp	Strbuf_appendn(&word, cp, lp - cp);
659167465Smp	if (*lp == 0)
660167465Smp	    break;
66159243Sobrien	lp++;
66259243Sobrien	for (rp = lp; *rp && *rp != '`'; rp++)
66359243Sobrien	    if (*rp == '\\') {
66459243Sobrien		rp++;
66559243Sobrien		if (!*rp)
66659243Sobrien		    goto oops;
66759243Sobrien	    }
668167465Smp	if (!*rp) {
669167465Smp	oops:
670167465Smp	    stderror(ERR_UNMATCHED, '`');
671167465Smp	}
672167465Smp	ep = Strnsave(lp, rp - lp);
673167465Smp	cleanup_push(ep, xfree);
674167465Smp	backeval(&bb, &word, ep, literal);
675167465Smp	cleanup_until(ep);
67659243Sobrien	cp = rp + 1;
67759243Sobrien    }
678167465Smp    if (word.len != 0)
679167465Smp	pword(&bb, &word);
680167465Smp    cleanup_ignore(&bb);
681167465Smp    cleanup_until(&bb);
682167465Smp    return bb_finish(&bb);
68359243Sobrien}
68459243Sobrien
68559243Sobrien
68659243Sobrienstatic void
687167465Smpbackeval(struct blk_buf *bb, struct Strbuf *word, Char *cp, int literal)
68859243Sobrien{
689145479Smp    int icnt;
690145479Smp    Char c, *ip;
69159243Sobrien    struct command faket;
692145479Smp    int    hadnl;
69359243Sobrien    int     pvec[2], quoted;
69459243Sobrien    Char   *fakecom[2], ibuf[BUFSIZE];
69559243Sobrien    char    tibuf[BUFSIZE];
69659243Sobrien
69759243Sobrien    hadnl = 0;
69859243Sobrien    icnt = 0;
69959243Sobrien    quoted = (literal || (cp[0] & QUOTE)) ? QUOTE : 0;
70059243Sobrien    faket.t_dtyp = NODE_COMMAND;
70159243Sobrien    faket.t_dflg = F_BACKQ;
70259243Sobrien    faket.t_dlef = 0;
70359243Sobrien    faket.t_drit = 0;
70459243Sobrien    faket.t_dspr = 0;
70559243Sobrien    faket.t_dcom = fakecom;
70659243Sobrien    fakecom[0] = STRfakecom1;
70759243Sobrien    fakecom[1] = 0;
70859243Sobrien
70959243Sobrien    /*
71059243Sobrien     * We do the psave job to temporarily change the current job so that the
71159243Sobrien     * following fork is considered a separate job.  This is so that when
71259243Sobrien     * backquotes are used in a builtin function that calls glob the "current
71359243Sobrien     * job" is not corrupted.  We only need one level of pushed jobs as long as
71459243Sobrien     * we are sure to fork here.
71559243Sobrien     */
71659243Sobrien    psavejob();
717167465Smp    cleanup_push(&faket, psavejob_cleanup); /* faket is only a marker */
71859243Sobrien
71959243Sobrien    /*
72059243Sobrien     * It would be nicer if we could integrate this redirection more with the
72159243Sobrien     * routines in sh.sem.c by doing a fake execute on a builtin function that
72259243Sobrien     * was piped out.
72359243Sobrien     */
72459243Sobrien    mypipe(pvec);
725167465Smp    cleanup_push(&pvec[0], open_cleanup);
726167465Smp    cleanup_push(&pvec[1], open_cleanup);
72759243Sobrien    if (pfork(&faket, -1) == 0) {
728145479Smp	jmp_buf_t osetexit;
729167465Smp	struct command *t;
730167465Smp	size_t omark;
73159243Sobrien
732167465Smp	xclose(pvec[0]);
73359243Sobrien	(void) dmove(pvec[1], 1);
73459243Sobrien	(void) dmove(SHDIAG,  2);
73559243Sobrien	initdesc();
736100616Smp	closem();
73759243Sobrien	arginp = cp;
738100616Smp	for (arginp = cp; *cp; cp++) {
739100616Smp	    *cp &= TRIM;
740145479Smp	    if (is_set(STRcsubstnonl) && (*cp == '\n' || *cp == '\r'))
741100616Smp		*cp = ' ';
742100616Smp	}
74359243Sobrien
74459243Sobrien        /*
74559243Sobrien	 * In the child ``forget'' everything about current aliases or
74659243Sobrien	 * eval vectors.
74759243Sobrien	 */
74859243Sobrien	alvec = NULL;
74959243Sobrien	evalvec = NULL;
75059243Sobrien	alvecp = NULL;
75159243Sobrien	evalp = NULL;
752145479Smp
753167465Smp	omark = cleanup_push_mark();
754145479Smp	getexit(osetexit);
755145479Smp	for (;;) {
756145479Smp	    (void) setexit();
757145479Smp	    justpr = 0;
758145479Smp
759145479Smp	    if (haderr) {
760145479Smp		/* unwind */
761145479Smp		doneinp = 0;
762167465Smp		cleanup_pop_mark(omark);
763145479Smp		resexit(osetexit);
764145479Smp		reset();
765145479Smp	    }
766145479Smp	    if (seterr) {
767167465Smp		xfree(seterr);
768145479Smp		seterr = NULL;
769145479Smp	    }
770145479Smp
771145479Smp	    (void) lex(&paraml);
772167465Smp	    cleanup_push(&paraml, lex_cleanup);
773145479Smp	    if (seterr)
774145479Smp		stderror(ERR_OLD);
775145479Smp	    alias(&paraml);
776145479Smp	    t = syntax(paraml.next, &paraml, 0);
777167465Smp	    cleanup_push(t, syntax_cleanup);
778145479Smp	    if (seterr)
779145479Smp		stderror(ERR_OLD);
78059243Sobrien#ifdef SIGTSTP
781167465Smp	    signal(SIGTSTP, SIG_IGN);
78259243Sobrien#endif
78359243Sobrien#ifdef SIGTTIN
784167465Smp	    signal(SIGTTIN, SIG_IGN);
78559243Sobrien#endif
78659243Sobrien#ifdef SIGTTOU
787167465Smp	    signal(SIGTTOU, SIG_IGN);
78859243Sobrien#endif
789145479Smp	    execute(t, -1, NULL, NULL, TRUE);
790145479Smp
791167465Smp	    cleanup_until(&paraml);
792145479Smp	}
79359243Sobrien    }
794167465Smp    cleanup_until(&pvec[1]);
79559243Sobrien    c = 0;
79659243Sobrien    ip = NULL;
79759243Sobrien    do {
79859243Sobrien	int     cnt = 0;
799145479Smp	char   *tmp;
80059243Sobrien
801145479Smp	tmp = tibuf;
80259243Sobrien	for (;;) {
803145479Smp	    while (icnt == 0) {
804145479Smp		int     i, eof;
80559243Sobrien
80659243Sobrien		ip = ibuf;
807167465Smp		icnt = xread(pvec[0], tmp, tibuf + BUFSIZE - tmp);
808145479Smp		eof = 0;
80959243Sobrien		if (icnt <= 0) {
810145479Smp		    if (tmp == tibuf)
811145479Smp			goto eof;
812145479Smp		    icnt = 0;
813145479Smp		    eof = 1;
81459243Sobrien		}
815145479Smp		icnt += tmp - tibuf;
816145479Smp		i = 0;
817145479Smp		tmp = tibuf;
818145479Smp		while (tmp < tibuf + icnt) {
819145479Smp		    int len;
820145479Smp
821145479Smp		    len = normal_mbtowc(&ip[i], tmp, tibuf + icnt - tmp);
822145479Smp		    if (len == -1) {
823145479Smp		        reset_mbtowc();
824145479Smp		        if (!eof && (size_t)(tibuf + icnt - tmp) < MB_CUR_MAX) {
825145479Smp			    break; /* Maybe a partial character */
826145479Smp			}
827145479Smp			ip[i] = (unsigned char) *tmp | INVALID_BYTE; /* Error */
828145479Smp		    }
829145479Smp		    if (len <= 0)
830145479Smp		        len = 1;
831145479Smp		    i++;
832145479Smp		    tmp += len;
833145479Smp		}
834145479Smp		if (tmp != tibuf)
835145479Smp		    memmove (tibuf, tmp, tibuf + icnt - tmp);
836145479Smp		tmp = tibuf + (tibuf + icnt - tmp);
837145479Smp		icnt = i;
83859243Sobrien	    }
83959243Sobrien	    if (hadnl)
84059243Sobrien		break;
84159243Sobrien	    --icnt;
84259243Sobrien	    c = (*ip++ & TRIM);
84359243Sobrien	    if (c == 0)
84459243Sobrien		break;
84569408Sache#ifdef WINNT_NATIVE
84659243Sobrien	    if (c == '\r')
84759243Sobrien	    	c = ' ';
84869408Sache#endif /* WINNT_NATIVE */
84959243Sobrien	    if (c == '\n') {
85059243Sobrien		/*
85159243Sobrien		 * Continue around the loop one more time, so that we can eat
85259243Sobrien		 * the last newline without terminating this word.
85359243Sobrien		 */
85459243Sobrien		hadnl = 1;
85559243Sobrien		continue;
85659243Sobrien	    }
85759243Sobrien	    if (!quoted && (c == ' ' || c == '\t'))
85859243Sobrien		break;
85959243Sobrien	    cnt++;
860167465Smp	    Strbuf_append1(word, c | quoted);
86159243Sobrien	}
86259243Sobrien	/*
86359243Sobrien	 * Unless at end-of-file, we will form a new word here if there were
86459243Sobrien	 * characters in the word, or in any case when we take text literally.
86559243Sobrien	 * If we didn't make empty words here when literal was set then we
86659243Sobrien	 * would lose blank lines.
86759243Sobrien	 */
868145479Smp	if (c != 0 && (cnt || literal))
869167465Smp	    pword(bb, word);
87059243Sobrien	hadnl = 0;
871145479Smp    } while (c > 0);
872145479Smp eof:
873167465Smp    cleanup_until(&pvec[0]);
87459243Sobrien    pwait();
875167465Smp    cleanup_until(&faket); /* psavejob_cleanup(); */
87659243Sobrien}
87759243Sobrien
87859243Sobrienstatic void
879167465Smppword(struct blk_buf *bb, struct Strbuf *word)
88059243Sobrien{
881167465Smp    Char *s;
88259243Sobrien
883167465Smp    s = Strbuf_finish(word);
884167465Smp    bb_append(bb, s);
885167465Smp    *word = Strbuf_init;
88659243Sobrien}
88759243Sobrien
88859243Sobrienint
889167465SmpGmatch(const Char *string, const Char *pattern)
89059243Sobrien{
89159243Sobrien    return Gnmatch(string, pattern, NULL);
89259243Sobrien}
89359243Sobrien
894167465Smpint
895167465SmpGnmatch(const Char *string, const Char *pattern, const Char **endstr)
89659243Sobrien{
897167465Smp    Char ***fblk, **p;
898167465Smp    const Char *tstring = string;
89959243Sobrien    int	   gpol = 1, gres = 0;
90059243Sobrien
90159243Sobrien    if (*pattern == '^') {
90259243Sobrien	gpol = 0;
90359243Sobrien	pattern++;
90459243Sobrien    }
90559243Sobrien
906167465Smp    fblk = xmalloc(sizeof(Char ***));
907167465Smp    *fblk = xmalloc(GLOBSPACE * sizeof(Char *));
908167465Smp    (*fblk)[0] = Strsave(pattern);
909167465Smp    (*fblk)[1] = NULL;
91059243Sobrien
911167465Smp    cleanup_push(fblk, blk_indirect_cleanup);
912167465Smp    expbrace(fblk, NULL, GLOBSPACE);
91359243Sobrien
91459243Sobrien    if (endstr == NULL)
91559243Sobrien	/* Exact matches only */
916167465Smp	for (p = *fblk; *p; p++)
917145479Smp	    gres |= t_pmatch(string, *p, &tstring, 1) == 2 ? 1 : 0;
91859243Sobrien    else {
919167465Smp	const Char *end;
920167465Smp
92159243Sobrien	/* partial matches */
922167465Smp        end = Strend(string);
923167465Smp	for (p = *fblk; *p; p++)
924145479Smp	    if (t_pmatch(string, *p, &tstring, 1) != 0) {
92559243Sobrien		gres |= 1;
926167465Smp		if (end > tstring)
927167465Smp		    end = tstring;
92859243Sobrien	    }
929167465Smp	*endstr = end;
93059243Sobrien    }
93159243Sobrien
932167465Smp    cleanup_until(fblk);
93359243Sobrien    return(gres == gpol);
93459243Sobrien}
93559243Sobrien
936131962Smp/* t_pmatch():
93759243Sobrien *	Return 2 on exact match,
93859243Sobrien *	Return 1 on substring match.
93959243Sobrien *	Return 0 on no match.
94059243Sobrien *	*estr will point to the end of the longest exact or substring match.
94159243Sobrien */
942131962Smpint
943167465Smpt_pmatch(const Char *string, const Char *pattern, const Char **estr, int cs)
94459243Sobrien{
945167465Smp    Char stringc, patternc, rangec;
94659243Sobrien    int     match, negate_range;
947167465Smp    const Char *pestr, *nstring;
94859243Sobrien
949145479Smp    for (nstring = string;; string = nstring) {
950167465Smp	stringc = *nstring++ & TRIM;
951167465Smp	patternc = *pattern++ & TRIM;
95259243Sobrien	switch (patternc) {
953145479Smp	case '\0':
95459243Sobrien	    *estr = string;
955145479Smp	    return (stringc == '\0' ? 2 : 1);
95659243Sobrien	case '?':
95759243Sobrien	    if (stringc == 0)
95859243Sobrien		return (0);
95959243Sobrien	    break;
96059243Sobrien	case '*':
96159243Sobrien	    if (!*pattern) {
962167465Smp		*estr = Strend(string);
96359243Sobrien		return (2);
96459243Sobrien	    }
96559243Sobrien	    pestr = NULL;
96659243Sobrien
967145479Smp	    for (;;) {
968131962Smp		switch(t_pmatch(string, pattern, estr, cs)) {
96959243Sobrien		case 0:
97059243Sobrien		    break;
97159243Sobrien		case 1:
972167465Smp		    pestr = *estr;/*FIXME: does not guarantee longest match */
97359243Sobrien		    break;
97459243Sobrien		case 2:
97559243Sobrien		    return 2;
97659243Sobrien		default:
97759243Sobrien		    abort();	/* Cannot happen */
97859243Sobrien		}
979167465Smp		stringc = *string++ & TRIM;
980145479Smp		if (!stringc)
981145479Smp		    break;
98259243Sobrien	    }
98359243Sobrien
98459243Sobrien	    if (pestr) {
98559243Sobrien		*estr = pestr;
98659243Sobrien		return 1;
98759243Sobrien	    }
988167465Smp	    else
98959243Sobrien		return 0;
99059243Sobrien
99159243Sobrien	case '[':
99259243Sobrien	    match = 0;
99359243Sobrien	    if ((negate_range = (*pattern == '^')) != 0)
99459243Sobrien		pattern++;
995167465Smp	    while ((rangec = *pattern++ & TRIM) != '\0') {
99659243Sobrien		if (rangec == ']')
99759243Sobrien		    break;
99859243Sobrien		if (match)
99959243Sobrien		    continue;
1000145479Smp		if (*pattern == '-' && pattern[1] != ']') {
1001167465Smp		    Char rangec2;
100259243Sobrien		    pattern++;
1003167465Smp		    rangec2 = *pattern++ & TRIM;
1004145479Smp		    match = (globcharcoll(stringc, rangec2, 0) <= 0 &&
1005145479Smp			globcharcoll(rangec, stringc, 0) <= 0);
100659243Sobrien		}
100759243Sobrien		else
1008145479Smp		    match = (stringc == rangec);
100959243Sobrien	    }
1010145479Smp	    if (rangec == '\0')
101159243Sobrien		stderror(ERR_NAME | ERR_MISSING, ']');
1012145479Smp	    if ((!match) && (stringc == '\0'))
1013145479Smp		return (0);
101459243Sobrien	    if (match == negate_range)
101559243Sobrien		return (0);
101659243Sobrien	    break;
101759243Sobrien	default:
1018145479Smp	    if (cs ? patternc  != stringc
1019145479Smp		: Tolower(patternc) != Tolower(stringc))
102059243Sobrien		return (0);
102159243Sobrien	    break;
102259243Sobrien	}
102359243Sobrien    }
102459243Sobrien}
1025