1316958Sdchagin/* $Header: /p/tcsh/cvsroot/tcsh/sh.glob.c,v 3.95 2016/08/01 16:21:09 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
35316958SdchaginRCSID("$tcsh: sh.glob.c,v 3.95 2016/08/01 16:21:09 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
434231990Smp    if (adrof(STRglobdot))
435231990Smp       gflgs |= GLOB_DOT;
436231990Smp
437231990Smp    if (adrof(STRglobstar))
438231990Smp       gflgs |= GLOB_STAR;
439231990Smp
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:
519231990Smp    if (vl && vl[0] == NULL) {
520167465Smp	xfree(vl);
52159243Sobrien	return (Strsave(STRNULL));
52259243Sobrien    }
523231990Smp    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')
597316958Sdchagin	while (*p) {
598316958Sdchagin#if INVALID_BYTE != 0
599316958Sdchagin	    if ((*p & INVALID_BYTE) != INVALID_BYTE)	/* *p < INVALID_BYTE */
600316958Sdchagin#endif
601316958Sdchagin		*p &= TRIM;
602316958Sdchagin	    p++;
603316958Sdchagin	}
60459243Sobrien}
60559243Sobrien
606167465Smpint
607167465Smptglob(Char **t)
60859243Sobrien{
609167465Smp    int gflag;
610167465Smp    const Char *p;
61159243Sobrien
612167465Smp    gflag = 0;
61359243Sobrien    while ((p = *t++) != '\0') {
61459243Sobrien	if (*p == '~' || *p == '=')
61559243Sobrien	    gflag |= G_CSH;
61659243Sobrien	else if (*p == '{' &&
61759243Sobrien		 (p[1] == '\0' || (p[1] == '}' && p[2] == '\0')))
61859243Sobrien	    continue;
619167465Smp	while (*p != '\0') {
620167465Smp	    if (*p == '`') {
62159243Sobrien		gflag |= G_CSH;
62259243Sobrien#ifdef notdef
62359243Sobrien		/*
62459243Sobrien		 * We do want to expand echo `echo '*'`, so we don't\
62559243Sobrien		 * use this piece of code anymore.
62659243Sobrien		 */
627167465Smp		p++;
62859243Sobrien		while (*p && *p != '`')
62959243Sobrien		    if (*p++ == '\\') {
63059243Sobrien			if (*p)		/* Quoted chars */
63159243Sobrien			    p++;
63259243Sobrien			else
63359243Sobrien			    break;
63459243Sobrien		    }
635167465Smp		if (!*p)		/* The matching ` */
63659243Sobrien		    break;
63759243Sobrien#endif
63859243Sobrien	    }
639167465Smp	    else if (*p == '{')
64059243Sobrien		gflag |= G_CSH;
641167465Smp	    else if (isglob(*p))
64259243Sobrien		gflag |= G_GLOB;
64359243Sobrien	    else if (symlinks == SYM_EXPAND &&
644167465Smp		p[1] && ISDOTDOT(p) && (p == *(t-1) || *(p-1) == '/') )
64559243Sobrien	    	gflag |= G_CSH;
646167465Smp	    p++;
64759243Sobrien	}
64859243Sobrien    }
649167465Smp    return gflag;
65059243Sobrien}
65159243Sobrien
65259243Sobrien/*
65359243Sobrien * Command substitute cp.  If literal, then this is a substitution from a
65459243Sobrien * << redirection, and so we should not crunch blanks and tabs, separating
65559243Sobrien * words only at newlines.
65659243Sobrien */
65759243SobrienChar  **
658167465Smpdobackp(Char *cp, int literal)
65959243Sobrien{
660167465Smp    struct Strbuf word = Strbuf_INIT;
661167465Smp    struct blk_buf bb = BLK_BUF_INIT;
662167465Smp    Char *lp, *rp, *ep;
66359243Sobrien
664167465Smp    cleanup_push(&bb, bb_cleanup);
665167465Smp    cleanup_push(&word, Strbuf_cleanup);
66659243Sobrien    for (;;) {
667167465Smp	for (lp = cp; *lp != '\0' && *lp != '`'; lp++)
668167465Smp	    ;
669167465Smp	Strbuf_appendn(&word, cp, lp - cp);
670167465Smp	if (*lp == 0)
671167465Smp	    break;
67259243Sobrien	lp++;
67359243Sobrien	for (rp = lp; *rp && *rp != '`'; rp++)
67459243Sobrien	    if (*rp == '\\') {
67559243Sobrien		rp++;
67659243Sobrien		if (!*rp)
67759243Sobrien		    goto oops;
67859243Sobrien	    }
679167465Smp	if (!*rp) {
680167465Smp	oops:
681195609Smp	    cleanup_until(&bb);
682167465Smp	    stderror(ERR_UNMATCHED, '`');
683167465Smp	}
684167465Smp	ep = Strnsave(lp, rp - lp);
685167465Smp	cleanup_push(ep, xfree);
686167465Smp	backeval(&bb, &word, ep, literal);
687167465Smp	cleanup_until(ep);
68859243Sobrien	cp = rp + 1;
68959243Sobrien    }
690167465Smp    if (word.len != 0)
691167465Smp	pword(&bb, &word);
692167465Smp    cleanup_ignore(&bb);
693167465Smp    cleanup_until(&bb);
694167465Smp    return bb_finish(&bb);
69559243Sobrien}
69659243Sobrien
69759243Sobrien
69859243Sobrienstatic void
699167465Smpbackeval(struct blk_buf *bb, struct Strbuf *word, Char *cp, int literal)
70059243Sobrien{
701231990Smp    ssize_t icnt;
702145479Smp    Char c, *ip;
70359243Sobrien    struct command faket;
704145479Smp    int    hadnl;
70559243Sobrien    int     pvec[2], quoted;
70659243Sobrien    Char   *fakecom[2], ibuf[BUFSIZE];
70759243Sobrien
70859243Sobrien    hadnl = 0;
70959243Sobrien    icnt = 0;
710316958Sdchagin    if (!literal) {
711316958Sdchagin	for (ip = cp; (*ip & QUOTE) != 0; ip++)
712316958Sdchagin		continue;
713316958Sdchagin	quoted = *ip == '\0';
714316958Sdchagin    } else
715316958Sdchagin	quoted = literal;
71659243Sobrien    faket.t_dtyp = NODE_COMMAND;
71759243Sobrien    faket.t_dflg = F_BACKQ;
71859243Sobrien    faket.t_dlef = 0;
71959243Sobrien    faket.t_drit = 0;
72059243Sobrien    faket.t_dspr = 0;
72159243Sobrien    faket.t_dcom = fakecom;
72259243Sobrien    fakecom[0] = STRfakecom1;
72359243Sobrien    fakecom[1] = 0;
72459243Sobrien
72559243Sobrien    /*
72659243Sobrien     * We do the psave job to temporarily change the current job so that the
72759243Sobrien     * following fork is considered a separate job.  This is so that when
72859243Sobrien     * backquotes are used in a builtin function that calls glob the "current
72959243Sobrien     * job" is not corrupted.  We only need one level of pushed jobs as long as
73059243Sobrien     * we are sure to fork here.
73159243Sobrien     */
73259243Sobrien    psavejob();
733167465Smp    cleanup_push(&faket, psavejob_cleanup); /* faket is only a marker */
73459243Sobrien
73559243Sobrien    /*
73659243Sobrien     * It would be nicer if we could integrate this redirection more with the
73759243Sobrien     * routines in sh.sem.c by doing a fake execute on a builtin function that
73859243Sobrien     * was piped out.
73959243Sobrien     */
74059243Sobrien    mypipe(pvec);
741167465Smp    cleanup_push(&pvec[0], open_cleanup);
742167465Smp    cleanup_push(&pvec[1], open_cleanup);
74359243Sobrien    if (pfork(&faket, -1) == 0) {
744145479Smp	jmp_buf_t osetexit;
745167465Smp	struct command *t;
746167465Smp	size_t omark;
74759243Sobrien
748167465Smp	xclose(pvec[0]);
74959243Sobrien	(void) dmove(pvec[1], 1);
75059243Sobrien	(void) dmove(SHDIAG,  2);
75159243Sobrien	initdesc();
752100616Smp	closem();
75359243Sobrien	arginp = cp;
754100616Smp	for (arginp = cp; *cp; cp++) {
755100616Smp	    *cp &= TRIM;
756145479Smp	    if (is_set(STRcsubstnonl) && (*cp == '\n' || *cp == '\r'))
757100616Smp		*cp = ' ';
758100616Smp	}
75959243Sobrien
76059243Sobrien        /*
76159243Sobrien	 * In the child ``forget'' everything about current aliases or
76259243Sobrien	 * eval vectors.
76359243Sobrien	 */
76459243Sobrien	alvec = NULL;
76559243Sobrien	evalvec = NULL;
76659243Sobrien	alvecp = NULL;
76759243Sobrien	evalp = NULL;
768145479Smp
769167465Smp	omark = cleanup_push_mark();
770145479Smp	getexit(osetexit);
771145479Smp	for (;;) {
772316958Sdchagin	    struct wordent paraml1;
773316958Sdchagin	    initlex(&paraml1);
774316958Sdchagin
775145479Smp	    (void) setexit();
776145479Smp	    justpr = 0;
777145479Smp
778145479Smp	    if (haderr) {
779145479Smp		/* unwind */
780145479Smp		doneinp = 0;
781167465Smp		cleanup_pop_mark(omark);
782145479Smp		resexit(osetexit);
783145479Smp		reset();
784145479Smp	    }
785145479Smp	    if (seterr) {
786167465Smp		xfree(seterr);
787145479Smp		seterr = NULL;
788145479Smp	    }
789145479Smp
790316958Sdchagin	    freelex(&paraml1);
791316958Sdchagin	    (void) lex(&paraml1);
792316958Sdchagin	    cleanup_push(&paraml1, lex_cleanup);
793145479Smp	    if (seterr)
794145479Smp		stderror(ERR_OLD);
795316958Sdchagin	    alias(&paraml1);
796316958Sdchagin	    t = syntax(paraml1.next, &paraml1, 0);
797167465Smp	    cleanup_push(t, syntax_cleanup);
798231990Smp	    /* The F_BACKQ flag must set so the job output is correct if
799231990Smp	     * printexitvalue is set.  If it's not set, the job output
800231990Smp	     * will have "Exit N" appended where N is the exit status. */
801316958Sdchagin	    if (t)
802316958Sdchagin		    t->t_dflg = F_BACKQ|F_NOFORK;
803145479Smp	    if (seterr)
804145479Smp		stderror(ERR_OLD);
80559243Sobrien#ifdef SIGTSTP
806167465Smp	    signal(SIGTSTP, SIG_IGN);
80759243Sobrien#endif
80859243Sobrien#ifdef SIGTTIN
809167465Smp	    signal(SIGTTIN, SIG_IGN);
81059243Sobrien#endif
81159243Sobrien#ifdef SIGTTOU
812167465Smp	    signal(SIGTTOU, SIG_IGN);
81359243Sobrien#endif
814145479Smp	    execute(t, -1, NULL, NULL, TRUE);
815145479Smp
816316958Sdchagin	    cleanup_until(&paraml1);
817145479Smp	}
81859243Sobrien    }
819167465Smp    cleanup_until(&pvec[1]);
82059243Sobrien    c = 0;
82159243Sobrien    ip = NULL;
82259243Sobrien    do {
823231990Smp	ssize_t     cnt = 0;
82459243Sobrien
82559243Sobrien	for (;;) {
826316958Sdchagin	    if (icnt == 0) {
82759243Sobrien		ip = ibuf;
828316958Sdchagin		icnt = wide_read(pvec[0], ibuf, BUFSIZE, 0);
829316958Sdchagin		if (icnt <= 0)
830316958Sdchagin		    goto eof;
83159243Sobrien	    }
83259243Sobrien	    if (hadnl)
83359243Sobrien		break;
83459243Sobrien	    --icnt;
83559243Sobrien	    c = (*ip++ & TRIM);
83659243Sobrien	    if (c == 0)
83759243Sobrien		break;
838195609Smp#if defined(WINNT_NATIVE) || defined(__CYGWIN__)
83959243Sobrien	    if (c == '\r')
84059243Sobrien	    	c = ' ';
841195609Smp#endif /* WINNT_NATIVE || __CYGWIN__ */
84259243Sobrien	    if (c == '\n') {
84359243Sobrien		/*
84459243Sobrien		 * Continue around the loop one more time, so that we can eat
84559243Sobrien		 * the last newline without terminating this word.
84659243Sobrien		 */
84759243Sobrien		hadnl = 1;
84859243Sobrien		continue;
84959243Sobrien	    }
85059243Sobrien	    if (!quoted && (c == ' ' || c == '\t'))
85159243Sobrien		break;
85259243Sobrien	    cnt++;
853316958Sdchagin	    if (c == '\\' || quoted)
854316958Sdchagin		c |= QUOTE;
855316958Sdchagin	    Strbuf_append1(word, c);
85659243Sobrien	}
85759243Sobrien	/*
85859243Sobrien	 * Unless at end-of-file, we will form a new word here if there were
85959243Sobrien	 * characters in the word, or in any case when we take text literally.
86059243Sobrien	 * If we didn't make empty words here when literal was set then we
86159243Sobrien	 * would lose blank lines.
86259243Sobrien	 */
863145479Smp	if (c != 0 && (cnt || literal))
864167465Smp	    pword(bb, word);
86559243Sobrien	hadnl = 0;
866145479Smp    } while (c > 0);
867145479Smp eof:
868167465Smp    cleanup_until(&pvec[0]);
86959243Sobrien    pwait();
870167465Smp    cleanup_until(&faket); /* psavejob_cleanup(); */
87159243Sobrien}
87259243Sobrien
87359243Sobrienstatic void
874167465Smppword(struct blk_buf *bb, struct Strbuf *word)
87559243Sobrien{
876167465Smp    Char *s;
87759243Sobrien
878167465Smp    s = Strbuf_finish(word);
879167465Smp    bb_append(bb, s);
880167465Smp    *word = Strbuf_init;
88159243Sobrien}
88259243Sobrien
88359243Sobrienint
884167465SmpGmatch(const Char *string, const Char *pattern)
88559243Sobrien{
88659243Sobrien    return Gnmatch(string, pattern, NULL);
88759243Sobrien}
88859243Sobrien
889167465Smpint
890167465SmpGnmatch(const Char *string, const Char *pattern, const Char **endstr)
89159243Sobrien{
892167465Smp    Char ***fblk, **p;
893167465Smp    const Char *tstring = string;
89459243Sobrien    int	   gpol = 1, gres = 0;
89559243Sobrien
89659243Sobrien    if (*pattern == '^') {
89759243Sobrien	gpol = 0;
89859243Sobrien	pattern++;
89959243Sobrien    }
90059243Sobrien
901167465Smp    fblk = xmalloc(sizeof(Char ***));
902167465Smp    *fblk = xmalloc(GLOBSPACE * sizeof(Char *));
903167465Smp    (*fblk)[0] = Strsave(pattern);
904167465Smp    (*fblk)[1] = NULL;
90559243Sobrien
906167465Smp    cleanup_push(fblk, blk_indirect_cleanup);
907167465Smp    expbrace(fblk, NULL, GLOBSPACE);
90859243Sobrien
90959243Sobrien    if (endstr == NULL)
91059243Sobrien	/* Exact matches only */
911167465Smp	for (p = *fblk; *p; p++)
912145479Smp	    gres |= t_pmatch(string, *p, &tstring, 1) == 2 ? 1 : 0;
91359243Sobrien    else {
914167465Smp	const Char *end;
915167465Smp
91659243Sobrien	/* partial matches */
917167465Smp        end = Strend(string);
918167465Smp	for (p = *fblk; *p; p++)
919145479Smp	    if (t_pmatch(string, *p, &tstring, 1) != 0) {
92059243Sobrien		gres |= 1;
921167465Smp		if (end > tstring)
922167465Smp		    end = tstring;
92359243Sobrien	    }
924167465Smp	*endstr = end;
92559243Sobrien    }
92659243Sobrien
927167465Smp    cleanup_until(fblk);
92859243Sobrien    return(gres == gpol);
92959243Sobrien}
93059243Sobrien
931131962Smp/* t_pmatch():
93259243Sobrien *	Return 2 on exact match,
93359243Sobrien *	Return 1 on substring match.
93459243Sobrien *	Return 0 on no match.
93559243Sobrien *	*estr will point to the end of the longest exact or substring match.
93659243Sobrien */
937131962Smpint
938167465Smpt_pmatch(const Char *string, const Char *pattern, const Char **estr, int cs)
93959243Sobrien{
940167465Smp    Char stringc, patternc, rangec;
94159243Sobrien    int     match, negate_range;
942167465Smp    const Char *pestr, *nstring;
94359243Sobrien
944145479Smp    for (nstring = string;; string = nstring) {
945167465Smp	stringc = *nstring++ & TRIM;
946167465Smp	patternc = *pattern++ & TRIM;
94759243Sobrien	switch (patternc) {
948145479Smp	case '\0':
94959243Sobrien	    *estr = string;
950145479Smp	    return (stringc == '\0' ? 2 : 1);
95159243Sobrien	case '?':
95259243Sobrien	    if (stringc == 0)
95359243Sobrien		return (0);
95459243Sobrien	    break;
95559243Sobrien	case '*':
95659243Sobrien	    if (!*pattern) {
957167465Smp		*estr = Strend(string);
95859243Sobrien		return (2);
95959243Sobrien	    }
96059243Sobrien	    pestr = NULL;
96159243Sobrien
962145479Smp	    for (;;) {
963131962Smp		switch(t_pmatch(string, pattern, estr, cs)) {
96459243Sobrien		case 0:
96559243Sobrien		    break;
96659243Sobrien		case 1:
967167465Smp		    pestr = *estr;/*FIXME: does not guarantee longest match */
96859243Sobrien		    break;
96959243Sobrien		case 2:
97059243Sobrien		    return 2;
97159243Sobrien		default:
97259243Sobrien		    abort();	/* Cannot happen */
97359243Sobrien		}
974167465Smp		stringc = *string++ & TRIM;
975145479Smp		if (!stringc)
976145479Smp		    break;
97759243Sobrien	    }
97859243Sobrien
97959243Sobrien	    if (pestr) {
98059243Sobrien		*estr = pestr;
98159243Sobrien		return 1;
98259243Sobrien	    }
983167465Smp	    else
98459243Sobrien		return 0;
98559243Sobrien
98659243Sobrien	case '[':
98759243Sobrien	    match = 0;
98859243Sobrien	    if ((negate_range = (*pattern == '^')) != 0)
98959243Sobrien		pattern++;
990167465Smp	    while ((rangec = *pattern++ & TRIM) != '\0') {
99159243Sobrien		if (rangec == ']')
99259243Sobrien		    break;
99359243Sobrien		if (match)
99459243Sobrien		    continue;
995145479Smp		if (*pattern == '-' && pattern[1] != ']') {
996167465Smp		    Char rangec2;
99759243Sobrien		    pattern++;
998167465Smp		    rangec2 = *pattern++ & TRIM;
999145479Smp		    match = (globcharcoll(stringc, rangec2, 0) <= 0 &&
1000145479Smp			globcharcoll(rangec, stringc, 0) <= 0);
100159243Sobrien		}
100259243Sobrien		else
1003145479Smp		    match = (stringc == rangec);
100459243Sobrien	    }
1005145479Smp	    if (rangec == '\0')
100659243Sobrien		stderror(ERR_NAME | ERR_MISSING, ']');
1007145479Smp	    if ((!match) && (stringc == '\0'))
1008145479Smp		return (0);
100959243Sobrien	    if (match == negate_range)
101059243Sobrien		return (0);
101159243Sobrien	    break;
101259243Sobrien	default:
1013145479Smp	    if (cs ? patternc  != stringc
1014145479Smp		: Tolower(patternc) != Tolower(stringc))
101559243Sobrien		return (0);
101659243Sobrien	    break;
101759243Sobrien	}
101859243Sobrien    }
101959243Sobrien}
1020