1232633Smp/* $Header: /p/tcsh/cvsroot/tcsh/sh.glob.c,v 3.82 2011/02/27 00:15:17 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
35232633SmpRCSID("$tcsh: sh.glob.c,v 3.82 2011/02/27 00:15:17 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
434232633Smp    if (adrof(STRglobdot))
435232633Smp       gflgs |= GLOB_DOT;
436232633Smp
437232633Smp    if (adrof(STRglobstar))
438232633Smp       gflgs |= GLOB_STAR;
439232633Smp
44059243Sobrien    if (!vl || !vl[0])
44159243Sobrien	return(vl);
44259243Sobrien
44359243Sobrien    globv.gl_offs = 0;
44459243Sobrien    globv.gl_pathv = 0;
44559243Sobrien    globv.gl_pathc = 0;
44659243Sobrien
44759243Sobrien    if (nonomatch)
44859243Sobrien	gflgs |= GLOB_NOCHECK;
44959243Sobrien
45059243Sobrien    do {
45159243Sobrien	ptr = short2qstr(*vl);
45259243Sobrien	switch (glob(ptr, gflgs, 0, &globv)) {
45359243Sobrien	case GLOB_ABEND:
45459243Sobrien	    globfree(&globv);
45559243Sobrien	    setname(ptr);
45659243Sobrien	    stderror(ERR_NAME | ERR_GLOB);
45759243Sobrien	    /* NOTREACHED */
45859243Sobrien	case GLOB_NOSPACE:
45959243Sobrien	    globfree(&globv);
46059243Sobrien	    stderror(ERR_NOMEM);
46159243Sobrien	    /* NOTREACHED */
46259243Sobrien	default:
46359243Sobrien	    break;
46459243Sobrien	}
46559243Sobrien	if (globv.gl_flags & GLOB_MAGCHAR) {
46659243Sobrien	    match |= (globv.gl_matchc != 0);
46759243Sobrien	    magic = 1;
46859243Sobrien	}
46959243Sobrien	gflgs |= GLOB_APPEND;
47059243Sobrien    }
47159243Sobrien    while (*++vl);
47259243Sobrien    vl = (globv.gl_pathc == 0 || (magic && !match && !nonomatch)) ?
47359243Sobrien	NULL : blk2short(globv.gl_pathv);
47459243Sobrien    globfree(&globv);
47559243Sobrien    return (vl);
47659243Sobrien}
47759243Sobrien
47859243SobrienChar   *
479167465Smpglobone(Char *str, int action)
48059243Sobrien{
48159243Sobrien    Char   *v[2], **vl, **vo;
482167465Smp    int gflg, noglob;
48359243Sobrien
48459243Sobrien    noglob = adrof(STRnoglob) != 0;
48559243Sobrien    v[0] = str;
48659243Sobrien    v[1] = 0;
487167465Smp    gflg = tglob(v);
48859243Sobrien    if (gflg == G_NONE)
48959243Sobrien	return (strip(Strsave(str)));
49059243Sobrien
49159243Sobrien    if (gflg & G_CSH) {
49259243Sobrien	/*
49359243Sobrien	 * Expand back-quote, tilde and brace
49459243Sobrien	 */
495167465Smp	vo = globexpand(v, noglob);
49659243Sobrien	if (noglob || (gflg & G_GLOB) == 0) {
497167465Smp	    vl = vo;
498167465Smp	    goto result;
49959243Sobrien	}
500167465Smp	cleanup_push(vo, blk_cleanup);
50159243Sobrien    }
50259243Sobrien    else if (noglob || (gflg & G_GLOB) == 0)
50359243Sobrien	return (strip(Strsave(str)));
50459243Sobrien    else
50559243Sobrien	vo = v;
50659243Sobrien
50759243Sobrien    vl = libglob(vo);
508167465Smp    if (gflg & G_CSH) {
509167465Smp    	if (vl != vo)
510167465Smp	    cleanup_until(vo);
511167465Smp	else
512167465Smp	    cleanup_ignore(vo);
513167465Smp    }
51459243Sobrien    if (vl == NULL) {
51559243Sobrien	setname(short2str(str));
51659243Sobrien	stderror(ERR_NAME | ERR_NOMATCH);
51759243Sobrien    }
518167465Smp result:
519232633Smp    if (vl && vl[0] == NULL) {
520167465Smp	xfree(vl);
52159243Sobrien	return (Strsave(STRNULL));
52259243Sobrien    }
523232633Smp    if (vl && vl[1])
52459243Sobrien	return (handleone(str, vl, action));
52559243Sobrien    else {
52659243Sobrien	str = strip(*vl);
527167465Smp	xfree(vl);
52859243Sobrien	return (str);
52959243Sobrien    }
53059243Sobrien}
53159243Sobrien
53259243SobrienChar  **
533167465Smpgloball(Char **v, int gflg)
53459243Sobrien{
53559243Sobrien    Char  **vl, **vo;
536167465Smp    int noglob;
53759243Sobrien
538167465Smp    if (!v || !v[0])
539167465Smp	return saveblk(v);
54059243Sobrien
54159243Sobrien    noglob = adrof(STRnoglob) != 0;
54259243Sobrien
54359243Sobrien    if (gflg & G_CSH)
54459243Sobrien	/*
54559243Sobrien	 * Expand back-quote, tilde and brace
54659243Sobrien	 */
547167465Smp	vl = vo = globexpand(v, noglob);
54859243Sobrien    else
54959243Sobrien	vl = vo = saveblk(v);
55059243Sobrien
55159243Sobrien    if (!noglob && (gflg & G_GLOB)) {
552167465Smp	cleanup_push(vo, blk_cleanup);
55359243Sobrien	vl = libglob(vo);
554167465Smp	if (vl == vo)
555167465Smp	    cleanup_ignore(vo);
556167465Smp	cleanup_until(vo);
55759243Sobrien    }
55859243Sobrien    else
55959243Sobrien	trim(vl);
56059243Sobrien
561167465Smp    return vl;
56259243Sobrien}
56359243Sobrien
564167465SmpChar **
565167465Smpglob_all_or_error(Char **v)
56659243Sobrien{
567167465Smp    int gflag;
568167465Smp
569167465Smp    gflag = tglob(v);
570167465Smp    if (gflag) {
571167465Smp	v = globall(v, gflag);
572167465Smp	if (v == NULL)
573167465Smp	    stderror(ERR_NAME | ERR_NOMATCH);
574167465Smp    } else {
575167465Smp	v = saveblk(v);
576167465Smp	trim(v);
577167465Smp    }
578167465Smp    return v;
57959243Sobrien}
58059243Sobrien
58159243Sobrienvoid
582167465Smprscan(Char **t, void (*f) (Char))
58359243Sobrien{
584145479Smp    Char *p;
58559243Sobrien
58659243Sobrien    while ((p = *t++) != '\0')
58759243Sobrien	while (*p)
58859243Sobrien	    (*f) (*p++);
58959243Sobrien}
59059243Sobrien
59159243Sobrienvoid
592167465Smptrim(Char **t)
59359243Sobrien{
594145479Smp    Char *p;
59559243Sobrien
59659243Sobrien    while ((p = *t++) != '\0')
59759243Sobrien	while (*p)
59859243Sobrien	    *p++ &= TRIM;
59959243Sobrien}
60059243Sobrien
601167465Smpint
602167465Smptglob(Char **t)
60359243Sobrien{
604167465Smp    int gflag;
605167465Smp    const Char *p;
60659243Sobrien
607167465Smp    gflag = 0;
60859243Sobrien    while ((p = *t++) != '\0') {
60959243Sobrien	if (*p == '~' || *p == '=')
61059243Sobrien	    gflag |= G_CSH;
61159243Sobrien	else if (*p == '{' &&
61259243Sobrien		 (p[1] == '\0' || (p[1] == '}' && p[2] == '\0')))
61359243Sobrien	    continue;
614167465Smp	while (*p != '\0') {
615167465Smp	    if (*p == '`') {
61659243Sobrien		gflag |= G_CSH;
61759243Sobrien#ifdef notdef
61859243Sobrien		/*
61959243Sobrien		 * We do want to expand echo `echo '*'`, so we don't\
62059243Sobrien		 * use this piece of code anymore.
62159243Sobrien		 */
622167465Smp		p++;
62359243Sobrien		while (*p && *p != '`')
62459243Sobrien		    if (*p++ == '\\') {
62559243Sobrien			if (*p)		/* Quoted chars */
62659243Sobrien			    p++;
62759243Sobrien			else
62859243Sobrien			    break;
62959243Sobrien		    }
630167465Smp		if (!*p)		/* The matching ` */
63159243Sobrien		    break;
63259243Sobrien#endif
63359243Sobrien	    }
634167465Smp	    else if (*p == '{')
63559243Sobrien		gflag |= G_CSH;
636167465Smp	    else if (isglob(*p))
63759243Sobrien		gflag |= G_GLOB;
63859243Sobrien	    else if (symlinks == SYM_EXPAND &&
639167465Smp		p[1] && ISDOTDOT(p) && (p == *(t-1) || *(p-1) == '/') )
64059243Sobrien	    	gflag |= G_CSH;
641167465Smp	    p++;
64259243Sobrien	}
64359243Sobrien    }
644167465Smp    return gflag;
64559243Sobrien}
64659243Sobrien
64759243Sobrien/*
64859243Sobrien * Command substitute cp.  If literal, then this is a substitution from a
64959243Sobrien * << redirection, and so we should not crunch blanks and tabs, separating
65059243Sobrien * words only at newlines.
65159243Sobrien */
65259243SobrienChar  **
653167465Smpdobackp(Char *cp, int literal)
65459243Sobrien{
655167465Smp    struct Strbuf word = Strbuf_INIT;
656167465Smp    struct blk_buf bb = BLK_BUF_INIT;
657167465Smp    Char *lp, *rp, *ep;
65859243Sobrien
659167465Smp    cleanup_push(&bb, bb_cleanup);
660167465Smp    cleanup_push(&word, Strbuf_cleanup);
66159243Sobrien    for (;;) {
662167465Smp	for (lp = cp; *lp != '\0' && *lp != '`'; lp++)
663167465Smp	    ;
664167465Smp	Strbuf_appendn(&word, cp, lp - cp);
665167465Smp	if (*lp == 0)
666167465Smp	    break;
66759243Sobrien	lp++;
66859243Sobrien	for (rp = lp; *rp && *rp != '`'; rp++)
66959243Sobrien	    if (*rp == '\\') {
67059243Sobrien		rp++;
67159243Sobrien		if (!*rp)
67259243Sobrien		    goto oops;
67359243Sobrien	    }
674167465Smp	if (!*rp) {
675167465Smp	oops:
676195609Smp	    cleanup_until(&bb);
677167465Smp	    stderror(ERR_UNMATCHED, '`');
678167465Smp	}
679167465Smp	ep = Strnsave(lp, rp - lp);
680167465Smp	cleanup_push(ep, xfree);
681167465Smp	backeval(&bb, &word, ep, literal);
682167465Smp	cleanup_until(ep);
68359243Sobrien	cp = rp + 1;
68459243Sobrien    }
685167465Smp    if (word.len != 0)
686167465Smp	pword(&bb, &word);
687167465Smp    cleanup_ignore(&bb);
688167465Smp    cleanup_until(&bb);
689167465Smp    return bb_finish(&bb);
69059243Sobrien}
69159243Sobrien
69259243Sobrien
69359243Sobrienstatic void
694167465Smpbackeval(struct blk_buf *bb, struct Strbuf *word, Char *cp, int literal)
69559243Sobrien{
696232633Smp    ssize_t icnt;
697145479Smp    Char c, *ip;
69859243Sobrien    struct command faket;
699145479Smp    int    hadnl;
70059243Sobrien    int     pvec[2], quoted;
70159243Sobrien    Char   *fakecom[2], ibuf[BUFSIZE];
70259243Sobrien    char    tibuf[BUFSIZE];
70359243Sobrien
70459243Sobrien    hadnl = 0;
70559243Sobrien    icnt = 0;
70659243Sobrien    quoted = (literal || (cp[0] & QUOTE)) ? QUOTE : 0;
70759243Sobrien    faket.t_dtyp = NODE_COMMAND;
70859243Sobrien    faket.t_dflg = F_BACKQ;
70959243Sobrien    faket.t_dlef = 0;
71059243Sobrien    faket.t_drit = 0;
71159243Sobrien    faket.t_dspr = 0;
71259243Sobrien    faket.t_dcom = fakecom;
71359243Sobrien    fakecom[0] = STRfakecom1;
71459243Sobrien    fakecom[1] = 0;
71559243Sobrien
71659243Sobrien    /*
71759243Sobrien     * We do the psave job to temporarily change the current job so that the
71859243Sobrien     * following fork is considered a separate job.  This is so that when
71959243Sobrien     * backquotes are used in a builtin function that calls glob the "current
72059243Sobrien     * job" is not corrupted.  We only need one level of pushed jobs as long as
72159243Sobrien     * we are sure to fork here.
72259243Sobrien     */
72359243Sobrien    psavejob();
724167465Smp    cleanup_push(&faket, psavejob_cleanup); /* faket is only a marker */
72559243Sobrien
72659243Sobrien    /*
72759243Sobrien     * It would be nicer if we could integrate this redirection more with the
72859243Sobrien     * routines in sh.sem.c by doing a fake execute on a builtin function that
72959243Sobrien     * was piped out.
73059243Sobrien     */
73159243Sobrien    mypipe(pvec);
732167465Smp    cleanup_push(&pvec[0], open_cleanup);
733167465Smp    cleanup_push(&pvec[1], open_cleanup);
73459243Sobrien    if (pfork(&faket, -1) == 0) {
735145479Smp	jmp_buf_t osetexit;
736167465Smp	struct command *t;
737167465Smp	size_t omark;
73859243Sobrien
739167465Smp	xclose(pvec[0]);
74059243Sobrien	(void) dmove(pvec[1], 1);
74159243Sobrien	(void) dmove(SHDIAG,  2);
74259243Sobrien	initdesc();
743100616Smp	closem();
74459243Sobrien	arginp = cp;
745100616Smp	for (arginp = cp; *cp; cp++) {
746100616Smp	    *cp &= TRIM;
747145479Smp	    if (is_set(STRcsubstnonl) && (*cp == '\n' || *cp == '\r'))
748100616Smp		*cp = ' ';
749100616Smp	}
75059243Sobrien
75159243Sobrien        /*
75259243Sobrien	 * In the child ``forget'' everything about current aliases or
75359243Sobrien	 * eval vectors.
75459243Sobrien	 */
75559243Sobrien	alvec = NULL;
75659243Sobrien	evalvec = NULL;
75759243Sobrien	alvecp = NULL;
75859243Sobrien	evalp = NULL;
759145479Smp
760167465Smp	omark = cleanup_push_mark();
761145479Smp	getexit(osetexit);
762145479Smp	for (;;) {
763145479Smp	    (void) setexit();
764145479Smp	    justpr = 0;
765145479Smp
766145479Smp	    if (haderr) {
767145479Smp		/* unwind */
768145479Smp		doneinp = 0;
769167465Smp		cleanup_pop_mark(omark);
770145479Smp		resexit(osetexit);
771145479Smp		reset();
772145479Smp	    }
773145479Smp	    if (seterr) {
774167465Smp		xfree(seterr);
775145479Smp		seterr = NULL;
776145479Smp	    }
777145479Smp
778145479Smp	    (void) lex(&paraml);
779167465Smp	    cleanup_push(&paraml, lex_cleanup);
780145479Smp	    if (seterr)
781145479Smp		stderror(ERR_OLD);
782145479Smp	    alias(&paraml);
783145479Smp	    t = syntax(paraml.next, &paraml, 0);
784232633Smp	    if (t == NULL)
785232633Smp		return;
786167465Smp	    cleanup_push(t, syntax_cleanup);
787232633Smp	    /* The F_BACKQ flag must set so the job output is correct if
788232633Smp	     * printexitvalue is set.  If it's not set, the job output
789232633Smp	     * will have "Exit N" appended where N is the exit status. */
790232633Smp	    t->t_dflg = F_BACKQ|F_NOFORK;
791145479Smp	    if (seterr)
792145479Smp		stderror(ERR_OLD);
79359243Sobrien#ifdef SIGTSTP
794167465Smp	    signal(SIGTSTP, SIG_IGN);
79559243Sobrien#endif
79659243Sobrien#ifdef SIGTTIN
797167465Smp	    signal(SIGTTIN, SIG_IGN);
79859243Sobrien#endif
79959243Sobrien#ifdef SIGTTOU
800167465Smp	    signal(SIGTTOU, SIG_IGN);
80159243Sobrien#endif
802145479Smp	    execute(t, -1, NULL, NULL, TRUE);
803145479Smp
804167465Smp	    cleanup_until(&paraml);
805145479Smp	}
80659243Sobrien    }
807167465Smp    cleanup_until(&pvec[1]);
80859243Sobrien    c = 0;
80959243Sobrien    ip = NULL;
81059243Sobrien    do {
811232633Smp	ssize_t     cnt = 0;
812145479Smp	char   *tmp;
81359243Sobrien
814145479Smp	tmp = tibuf;
81559243Sobrien	for (;;) {
816145479Smp	    while (icnt == 0) {
817145479Smp		int     i, eof;
81859243Sobrien
81959243Sobrien		ip = ibuf;
820167465Smp		icnt = xread(pvec[0], tmp, tibuf + BUFSIZE - tmp);
821145479Smp		eof = 0;
82259243Sobrien		if (icnt <= 0) {
823145479Smp		    if (tmp == tibuf)
824145479Smp			goto eof;
825145479Smp		    icnt = 0;
826145479Smp		    eof = 1;
82759243Sobrien		}
828145479Smp		icnt += tmp - tibuf;
829145479Smp		i = 0;
830145479Smp		tmp = tibuf;
831145479Smp		while (tmp < tibuf + icnt) {
832145479Smp		    int len;
833145479Smp
834145479Smp		    len = normal_mbtowc(&ip[i], tmp, tibuf + icnt - tmp);
835145479Smp		    if (len == -1) {
836145479Smp		        reset_mbtowc();
837145479Smp		        if (!eof && (size_t)(tibuf + icnt - tmp) < MB_CUR_MAX) {
838145479Smp			    break; /* Maybe a partial character */
839145479Smp			}
840145479Smp			ip[i] = (unsigned char) *tmp | INVALID_BYTE; /* Error */
841145479Smp		    }
842145479Smp		    if (len <= 0)
843145479Smp		        len = 1;
844145479Smp		    i++;
845145479Smp		    tmp += len;
846145479Smp		}
847145479Smp		if (tmp != tibuf)
848145479Smp		    memmove (tibuf, tmp, tibuf + icnt - tmp);
849145479Smp		tmp = tibuf + (tibuf + icnt - tmp);
850145479Smp		icnt = i;
85159243Sobrien	    }
85259243Sobrien	    if (hadnl)
85359243Sobrien		break;
85459243Sobrien	    --icnt;
85559243Sobrien	    c = (*ip++ & TRIM);
85659243Sobrien	    if (c == 0)
85759243Sobrien		break;
858195609Smp#if defined(WINNT_NATIVE) || defined(__CYGWIN__)
85959243Sobrien	    if (c == '\r')
86059243Sobrien	    	c = ' ';
861195609Smp#endif /* WINNT_NATIVE || __CYGWIN__ */
86259243Sobrien	    if (c == '\n') {
86359243Sobrien		/*
86459243Sobrien		 * Continue around the loop one more time, so that we can eat
86559243Sobrien		 * the last newline without terminating this word.
86659243Sobrien		 */
86759243Sobrien		hadnl = 1;
86859243Sobrien		continue;
86959243Sobrien	    }
87059243Sobrien	    if (!quoted && (c == ' ' || c == '\t'))
87159243Sobrien		break;
87259243Sobrien	    cnt++;
873167465Smp	    Strbuf_append1(word, c | quoted);
87459243Sobrien	}
87559243Sobrien	/*
87659243Sobrien	 * Unless at end-of-file, we will form a new word here if there were
87759243Sobrien	 * characters in the word, or in any case when we take text literally.
87859243Sobrien	 * If we didn't make empty words here when literal was set then we
87959243Sobrien	 * would lose blank lines.
88059243Sobrien	 */
881145479Smp	if (c != 0 && (cnt || literal))
882167465Smp	    pword(bb, word);
88359243Sobrien	hadnl = 0;
884145479Smp    } while (c > 0);
885145479Smp eof:
886167465Smp    cleanup_until(&pvec[0]);
88759243Sobrien    pwait();
888167465Smp    cleanup_until(&faket); /* psavejob_cleanup(); */
88959243Sobrien}
89059243Sobrien
89159243Sobrienstatic void
892167465Smppword(struct blk_buf *bb, struct Strbuf *word)
89359243Sobrien{
894167465Smp    Char *s;
89559243Sobrien
896167465Smp    s = Strbuf_finish(word);
897167465Smp    bb_append(bb, s);
898167465Smp    *word = Strbuf_init;
89959243Sobrien}
90059243Sobrien
90159243Sobrienint
902167465SmpGmatch(const Char *string, const Char *pattern)
90359243Sobrien{
90459243Sobrien    return Gnmatch(string, pattern, NULL);
90559243Sobrien}
90659243Sobrien
907167465Smpint
908167465SmpGnmatch(const Char *string, const Char *pattern, const Char **endstr)
90959243Sobrien{
910167465Smp    Char ***fblk, **p;
911167465Smp    const Char *tstring = string;
91259243Sobrien    int	   gpol = 1, gres = 0;
91359243Sobrien
91459243Sobrien    if (*pattern == '^') {
91559243Sobrien	gpol = 0;
91659243Sobrien	pattern++;
91759243Sobrien    }
91859243Sobrien
919167465Smp    fblk = xmalloc(sizeof(Char ***));
920167465Smp    *fblk = xmalloc(GLOBSPACE * sizeof(Char *));
921167465Smp    (*fblk)[0] = Strsave(pattern);
922167465Smp    (*fblk)[1] = NULL;
92359243Sobrien
924167465Smp    cleanup_push(fblk, blk_indirect_cleanup);
925167465Smp    expbrace(fblk, NULL, GLOBSPACE);
92659243Sobrien
92759243Sobrien    if (endstr == NULL)
92859243Sobrien	/* Exact matches only */
929167465Smp	for (p = *fblk; *p; p++)
930145479Smp	    gres |= t_pmatch(string, *p, &tstring, 1) == 2 ? 1 : 0;
93159243Sobrien    else {
932167465Smp	const Char *end;
933167465Smp
93459243Sobrien	/* partial matches */
935167465Smp        end = Strend(string);
936167465Smp	for (p = *fblk; *p; p++)
937145479Smp	    if (t_pmatch(string, *p, &tstring, 1) != 0) {
93859243Sobrien		gres |= 1;
939167465Smp		if (end > tstring)
940167465Smp		    end = tstring;
94159243Sobrien	    }
942167465Smp	*endstr = end;
94359243Sobrien    }
94459243Sobrien
945167465Smp    cleanup_until(fblk);
94659243Sobrien    return(gres == gpol);
94759243Sobrien}
94859243Sobrien
949131962Smp/* t_pmatch():
95059243Sobrien *	Return 2 on exact match,
95159243Sobrien *	Return 1 on substring match.
95259243Sobrien *	Return 0 on no match.
95359243Sobrien *	*estr will point to the end of the longest exact or substring match.
95459243Sobrien */
955131962Smpint
956167465Smpt_pmatch(const Char *string, const Char *pattern, const Char **estr, int cs)
95759243Sobrien{
958167465Smp    Char stringc, patternc, rangec;
95959243Sobrien    int     match, negate_range;
960167465Smp    const Char *pestr, *nstring;
96159243Sobrien
962145479Smp    for (nstring = string;; string = nstring) {
963167465Smp	stringc = *nstring++ & TRIM;
964167465Smp	patternc = *pattern++ & TRIM;
96559243Sobrien	switch (patternc) {
966145479Smp	case '\0':
96759243Sobrien	    *estr = string;
968145479Smp	    return (stringc == '\0' ? 2 : 1);
96959243Sobrien	case '?':
97059243Sobrien	    if (stringc == 0)
97159243Sobrien		return (0);
97259243Sobrien	    break;
97359243Sobrien	case '*':
97459243Sobrien	    if (!*pattern) {
975167465Smp		*estr = Strend(string);
97659243Sobrien		return (2);
97759243Sobrien	    }
97859243Sobrien	    pestr = NULL;
97959243Sobrien
980145479Smp	    for (;;) {
981131962Smp		switch(t_pmatch(string, pattern, estr, cs)) {
98259243Sobrien		case 0:
98359243Sobrien		    break;
98459243Sobrien		case 1:
985167465Smp		    pestr = *estr;/*FIXME: does not guarantee longest match */
98659243Sobrien		    break;
98759243Sobrien		case 2:
98859243Sobrien		    return 2;
98959243Sobrien		default:
99059243Sobrien		    abort();	/* Cannot happen */
99159243Sobrien		}
992167465Smp		stringc = *string++ & TRIM;
993145479Smp		if (!stringc)
994145479Smp		    break;
99559243Sobrien	    }
99659243Sobrien
99759243Sobrien	    if (pestr) {
99859243Sobrien		*estr = pestr;
99959243Sobrien		return 1;
100059243Sobrien	    }
1001167465Smp	    else
100259243Sobrien		return 0;
100359243Sobrien
100459243Sobrien	case '[':
100559243Sobrien	    match = 0;
100659243Sobrien	    if ((negate_range = (*pattern == '^')) != 0)
100759243Sobrien		pattern++;
1008167465Smp	    while ((rangec = *pattern++ & TRIM) != '\0') {
100959243Sobrien		if (rangec == ']')
101059243Sobrien		    break;
101159243Sobrien		if (match)
101259243Sobrien		    continue;
1013145479Smp		if (*pattern == '-' && pattern[1] != ']') {
1014167465Smp		    Char rangec2;
101559243Sobrien		    pattern++;
1016167465Smp		    rangec2 = *pattern++ & TRIM;
1017145479Smp		    match = (globcharcoll(stringc, rangec2, 0) <= 0 &&
1018145479Smp			globcharcoll(rangec, stringc, 0) <= 0);
101959243Sobrien		}
102059243Sobrien		else
1021145479Smp		    match = (stringc == rangec);
102259243Sobrien	    }
1023145479Smp	    if (rangec == '\0')
102459243Sobrien		stderror(ERR_NAME | ERR_MISSING, ']');
1025145479Smp	    if ((!match) && (stringc == '\0'))
1026145479Smp		return (0);
102759243Sobrien	    if (match == negate_range)
102859243Sobrien		return (0);
102959243Sobrien	    break;
103059243Sobrien	default:
1031145479Smp	    if (cs ? patternc  != stringc
1032145479Smp		: Tolower(patternc) != Tolower(stringc))
103359243Sobrien		return (0);
103459243Sobrien	    break;
103559243Sobrien	}
103659243Sobrien    }
103759243Sobrien}
1038