xref: /csrg-svn/bin/csh/glob.c (revision 60765)
147823Sbostic /*-
2*60765Sbostic  * Copyright (c) 1980, 1991, 1993
3*60765Sbostic  *	The Regents of the University of California.  All rights reserved.
447823Sbostic  *
547823Sbostic  * %sccs.include.redist.c%
621934Sdist  */
721934Sdist 
817514Sedward #ifndef lint
9*60765Sbostic static char sccsid[] = "@(#)glob.c	8.1 (Berkeley) 05/31/93";
1047823Sbostic #endif /* not lint */
115774Smckusic 
1250028Sbostic #include <sys/param.h>
1350028Sbostic #include <glob.h>
1450028Sbostic #include <errno.h>
1550028Sbostic #include <stdlib.h>
1650028Sbostic #include <string.h>
1750028Sbostic #include <unistd.h>
1850033Schristos #if __STDC__
1950033Schristos # include <stdarg.h>
2050033Schristos #else
2150033Schristos # include <varargs.h>
2250033Schristos #endif
2350033Schristos 
2450023Sbostic #include "csh.h"
2550023Sbostic #include "extern.h"
261295Sbill 
2750439Schristos static int noglob;
2849992Sbostic static int pargsiz, gargsiz;
2947414Sbostic 
301295Sbill /*
3147414Sbostic  * Values for gflag
321295Sbill  */
3349992Sbostic #define	G_NONE	0		/* No globbing needed			*/
3449992Sbostic #define	G_GLOB	1		/* string contains *?[] characters	*/
3549992Sbostic #define	G_CSH	2		/* string contains ~`{ characters	*/
361295Sbill 
3749992Sbostic #define	GLOBSPACE	100	/* Alloc increment			*/
3849992Sbostic 
3947414Sbostic #define LBRC '{'
4047414Sbostic #define RBRC '}'
4147414Sbostic #define LBRK '['
4247414Sbostic #define RBRK ']'
4347414Sbostic #define EOS '\0'
441295Sbill 
4550024Schristos Char  **gargv = NULL;
4649992Sbostic long    gargc = 0;
4750024Schristos Char  **pargv = NULL;
4849992Sbostic long    pargc = 0;
4949992Sbostic 
5028055Slepreau /*
5147414Sbostic  * globbing is now done in two stages. In the first pass we expand
5249992Sbostic  * csh globbing idioms ~`{ and then we proceed doing the normal
5347414Sbostic  * globbing if needed ?*[
5447414Sbostic  *
5547414Sbostic  * Csh type globbing is handled in globexpand() and the rest is
5648513Sbostic  * handled in glob() which is part of the 4.4BSD libc.
5749992Sbostic  *
5828055Slepreau  */
5950024Schristos static Char	*globtilde __P((Char **, Char *));
6050024Schristos static Char	**libglob __P((Char **));
6150024Schristos static Char	**globexpand __P((Char **));
6250024Schristos static int	globbrace __P((Char *, Char *, Char ***));
6352372Schristos static void	expbrace __P((Char ***, Char ***, int));
6452375Schristos static int	pmatch __P((Char *, Char *));
6550024Schristos static void	pword __P((void));
6650024Schristos static void	psave __P((int));
6750024Schristos static void	backeval __P((Char *, bool));
681295Sbill 
691295Sbill 
7049992Sbostic static Char *
globtilde(nv,s)7148513Sbostic globtilde(nv, s)
7249992Sbostic     Char  **nv, *s;
731295Sbill {
7449992Sbostic     Char    gbuf[MAXPATHLEN], *gstart, *b, *u, *e;
751295Sbill 
7649992Sbostic     gstart = gbuf;
7749992Sbostic     *gstart++ = *s++;
7849992Sbostic     u = s;
7951437Sleres     for (b = gstart, e = &gbuf[MAXPATHLEN - 1];
8051357Schristos 	 *s && *s != '/' && *s != ':' && b < e;
8151437Sleres 	 *b++ = *s++)
8251437Sleres 	 continue;
8349992Sbostic     *b = EOS;
8449992Sbostic     if (gethdir(gstart)) {
8549992Sbostic 	blkfree(nv);
8649992Sbostic 	if (*gstart)
8751589Schristos 	    stderror(ERR_UNKUSER, vis_str(gstart));
8849992Sbostic 	else
8949992Sbostic 	    stderror(ERR_NOHOME);
9049992Sbostic     }
9149992Sbostic     b = &gstart[Strlen(gstart)];
9249992Sbostic     while (*s)
9349992Sbostic 	*b++ = *s++;
9449992Sbostic     *b = EOS;
9549992Sbostic     --u;
9649992Sbostic     xfree((ptr_t) u);
9749992Sbostic     return (Strsave(gstart));
981295Sbill }
991295Sbill 
10047414Sbostic static int
globbrace(s,p,bl)10147414Sbostic globbrace(s, p, bl)
10249992Sbostic     Char   *s, *p, ***bl;
1031295Sbill {
10449992Sbostic     int     i, len;
10549992Sbostic     Char   *pm, *pe, *lm, *pl;
10649992Sbostic     Char  **nv, **vl;
10749992Sbostic     Char    gbuf[MAXPATHLEN];
10849992Sbostic     int     size = GLOBSPACE;
1091295Sbill 
11049992Sbostic     nv = vl = (Char **) xmalloc((size_t) sizeof(Char *) * size);
11150024Schristos     *vl = NULL;
1121295Sbill 
11349992Sbostic     len = 0;
11449992Sbostic     /* copy part up to the brace */
11549992Sbostic     for (lm = gbuf, p = s; *p != LBRC; *lm++ = *p++)
11649992Sbostic 	continue;
11749992Sbostic 
11849992Sbostic     /* check for balanced braces */
11949992Sbostic     for (i = 0, pe = ++p; *pe; pe++)
12049992Sbostic 	if (*pe == LBRK) {
12149992Sbostic 	    /* Ignore everything between [] */
12249992Sbostic 	    for (++pe; *pe != RBRK && *pe != EOS; pe++)
1231295Sbill 		continue;
12449992Sbostic 	    if (*pe == EOS) {
12547414Sbostic 		blkfree(nv);
12652372Schristos 		return (-RBRK);
12749992Sbostic 	    }
1281295Sbill 	}
12949992Sbostic 	else if (*pe == LBRC)
13049992Sbostic 	    i++;
13149992Sbostic 	else if (*pe == RBRC) {
13249992Sbostic 	    if (i == 0)
13349992Sbostic 		break;
13449992Sbostic 	    i--;
13549992Sbostic 	}
1361295Sbill 
13750386Schristos     if (i != 0 || *pe == '\0') {
13849992Sbostic 	blkfree(nv);
13950386Schristos 	return (-RBRC);
14049992Sbostic     }
14149992Sbostic 
14249992Sbostic     for (i = 0, pl = pm = p; pm <= pe; pm++)
14347414Sbostic 	switch (*pm) {
14447414Sbostic 	case LBRK:
14549992Sbostic 	    for (++pm; *pm != RBRK && *pm != EOS; pm++)
14649992Sbostic 		continue;
14749992Sbostic 	    if (*pm == EOS) {
14850024Schristos 		*vl = NULL;
14949992Sbostic 		blkfree(nv);
15049992Sbostic 		return (-RBRK);
15149992Sbostic 	    }
15249992Sbostic 	    break;
15347414Sbostic 	case LBRC:
15449992Sbostic 	    i++;
15549992Sbostic 	    break;
15649992Sbostic 	case RBRC:
15749992Sbostic 	    if (i) {
15849992Sbostic 		i--;
15947414Sbostic 		break;
16049992Sbostic 	    }
16149992Sbostic 	    /* FALLTHROUGH */
1621295Sbill 	case ',':
16349992Sbostic 	    if (i && *pm == ',')
16449992Sbostic 		break;
16549992Sbostic 	    else {
16649992Sbostic 		Char    savec = *pm;
16749992Sbostic 
16849992Sbostic 		*pm = EOS;
16949992Sbostic 		(void) Strcpy(lm, pl);
17049992Sbostic 		(void) Strcat(gbuf, pe + 1);
17149992Sbostic 		*pm = savec;
17249992Sbostic 		*vl++ = Strsave(gbuf);
17349992Sbostic 		len++;
17449992Sbostic 		pl = pm + 1;
17549992Sbostic 		if (vl == &nv[size]) {
17649992Sbostic 		    size += GLOBSPACE;
17749992Sbostic 		    nv = (Char **) xrealloc((ptr_t) nv, (size_t)
17849992Sbostic 					    size * sizeof(Char *));
17949992Sbostic 		    vl = &nv[size - GLOBSPACE];
18047414Sbostic 		}
18149992Sbostic 	    }
18249992Sbostic 	    break;
18352372Schristos 	default:
18452372Schristos 	    break;
1851295Sbill 	}
18650024Schristos     *vl = NULL;
18749992Sbostic     *bl = nv;
18849992Sbostic     return (len);
1891295Sbill }
1901295Sbill 
19152372Schristos 
19252372Schristos static void
expbrace(nvp,elp,size)19352372Schristos expbrace(nvp, elp, size)
19452372Schristos     Char ***nvp, ***elp;
19552372Schristos     int size;
19652372Schristos {
19752372Schristos     Char **vl, **el, **nv, *s;
19852372Schristos 
19952372Schristos     vl = nv = *nvp;
20052372Schristos     if (elp != NULL)
20152372Schristos 	el = *elp;
20252372Schristos     else
20352372Schristos 	for (el = vl; *el; el++)
20452372Schristos 	    continue;
20552372Schristos 
20652372Schristos     for (s = *vl; s; s = *++vl) {
20752372Schristos 	Char   *b;
20852372Schristos 	Char  **vp, **bp;
20952372Schristos 
21052372Schristos 	/* leave {} untouched for find */
21152372Schristos 	if (s[0] == '{' && (s[1] == '\0' || (s[1] == '}' && s[2] == '\0')))
21252372Schristos 	    continue;
21360237Schristos 	if ((b = Strchr(s, '{')) != NULL) {
21452372Schristos 	    Char  **bl;
21552372Schristos 	    int     len;
21652372Schristos 
21752372Schristos 	    if ((len = globbrace(s, b, &bl)) < 0) {
21852372Schristos 		xfree((ptr_t) nv);
21952372Schristos 		stderror(ERR_MISSING, -len);
22052372Schristos 	    }
22152372Schristos 	    xfree((ptr_t) s);
22252372Schristos 	    if (len == 1) {
22352372Schristos 		*vl-- = *bl;
22452372Schristos 		xfree((ptr_t) bl);
22552372Schristos 		continue;
22652372Schristos 	    }
22752372Schristos 	    len = blklen(bl);
22852372Schristos 	    if (&el[len] >= &nv[size]) {
22952372Schristos 		int     l, e;
23052372Schristos 
23152372Schristos 		l = &el[len] - &nv[size];
23252372Schristos 		size += GLOBSPACE > l ? GLOBSPACE : l;
23352372Schristos 		l = vl - nv;
23452372Schristos 		e = el - nv;
23552372Schristos 		nv = (Char **) xrealloc((ptr_t) nv, (size_t)
23652372Schristos 					size * sizeof(Char *));
23752372Schristos 		vl = nv + l;
23852372Schristos 		el = nv + e;
23952372Schristos 	    }
24052372Schristos 	    vp = vl--;
24152372Schristos 	    *vp = *bl;
24252372Schristos 	    len--;
24352372Schristos 	    for (bp = el; bp != vp; bp--)
24452372Schristos 		bp[len] = *bp;
24552372Schristos 	    el += len;
24652372Schristos 	    vp++;
24752372Schristos 	    for (bp = bl + 1; *bp; *vp++ = *bp++)
24852372Schristos 		continue;
24952372Schristos 	    xfree((ptr_t) bl);
25052372Schristos 	}
25152372Schristos 
25252372Schristos     }
25352372Schristos     if (elp != NULL)
25452372Schristos 	*elp = el;
25552372Schristos     *nvp = nv;
25652372Schristos }
25752372Schristos 
25849992Sbostic static Char **
globexpand(v)25947414Sbostic globexpand(v)
26049992Sbostic     Char  **v;
2611295Sbill {
26249992Sbostic     Char   *s;
26349992Sbostic     Char  **nv, **vl, **el;
26449992Sbostic     int     size = GLOBSPACE;
2651295Sbill 
2661295Sbill 
26749992Sbostic     nv = vl = (Char **) xmalloc((size_t) sizeof(Char *) * size);
26850024Schristos     *vl = NULL;
2691295Sbill 
27049992Sbostic     /*
27149992Sbostic      * Step 1: expand backquotes.
27249992Sbostic      */
27360237Schristos     while ((s = *v++) != NULL) {
27449992Sbostic 	if (Strchr(s, '`')) {
27549992Sbostic 	    int     i;
2761295Sbill 
27749992Sbostic 	    (void) dobackp(s, 0);
27849992Sbostic 	    for (i = 0; i < pargc; i++) {
27949992Sbostic 		*vl++ = pargv[i];
28049992Sbostic 		if (vl == &nv[size]) {
28149992Sbostic 		    size += GLOBSPACE;
28249992Sbostic 		    nv = (Char **) xrealloc((ptr_t) nv,
28349992Sbostic 					    (size_t) size * sizeof(Char *));
28449992Sbostic 		    vl = &nv[size - GLOBSPACE];
28547414Sbostic 		}
28649992Sbostic 	    }
28749992Sbostic 	    xfree((ptr_t) pargv);
28850024Schristos 	    pargv = NULL;
28947414Sbostic 	}
29049992Sbostic 	else {
29149992Sbostic 	    *vl++ = Strsave(s);
29249992Sbostic 	    if (vl == &nv[size]) {
29349992Sbostic 		size += GLOBSPACE;
29449992Sbostic 		nv = (Char **) xrealloc((ptr_t) nv, (size_t)
29549992Sbostic 					size * sizeof(Char *));
29649992Sbostic 		vl = &nv[size - GLOBSPACE];
29749992Sbostic 	    }
29849992Sbostic 	}
29949992Sbostic     }
30050024Schristos     *vl = NULL;
3011295Sbill 
30249992Sbostic     if (noglob)
30349992Sbostic 	return (nv);
3041295Sbill 
30549992Sbostic     /*
30649992Sbostic      * Step 2: expand braces
30749992Sbostic      */
30849992Sbostic     el = vl;
30954017Schristos     expbrace(&nv, &el, size);
31049992Sbostic 
31149992Sbostic     /*
31249992Sbostic      * Step 3: expand ~
31349992Sbostic      */
31449992Sbostic     vl = nv;
31549992Sbostic     for (s = *vl; s; s = *++vl)
31649992Sbostic 	if (*s == '~')
31749992Sbostic 	    *vl = globtilde(nv, s);
31849992Sbostic     vl = nv;
31949992Sbostic     return (vl);
3201295Sbill }
3211295Sbill 
32249992Sbostic static Char *
handleone(str,vl,action)32349992Sbostic handleone(str, vl, action)
32449992Sbostic     Char   *str, **vl;
32549992Sbostic     int     action;
3261295Sbill {
3271295Sbill 
32849992Sbostic     Char   *cp, **vlp = vl;
3291295Sbill 
33049992Sbostic     switch (action) {
33149992Sbostic     case G_ERROR:
33251589Schristos 	setname(vis_str(str));
33349992Sbostic 	blkfree(vl);
33449992Sbostic 	stderror(ERR_NAME | ERR_AMBIG);
33549992Sbostic 	break;
33649992Sbostic     case G_APPEND:
33749992Sbostic 	trim(vlp);
33849992Sbostic 	str = Strsave(*vlp++);
33949992Sbostic 	do {
34049992Sbostic 	    cp = Strspl(str, STRspace);
34149992Sbostic 	    xfree((ptr_t) str);
34249992Sbostic 	    str = Strspl(cp, *vlp);
34349992Sbostic 	    xfree((ptr_t) cp);
34449992Sbostic 	}
34549992Sbostic 	while (*++vlp);
34649992Sbostic 	blkfree(vl);
34749992Sbostic 	break;
34849992Sbostic     case G_IGNORE:
34949992Sbostic 	str = Strsave(strip(*vlp));
35049992Sbostic 	blkfree(vl);
35149992Sbostic 	break;
35252372Schristos     default:
35352372Schristos 	break;
35449992Sbostic     }
35549992Sbostic     return (str);
35649992Sbostic }
3571295Sbill 
35849992Sbostic static Char **
libglob(vl)35949992Sbostic libglob(vl)
36049992Sbostic     Char  **vl;
36149992Sbostic {
36250439Schristos     int     gflgs = GLOB_QUOTE | GLOB_NOMAGIC;
36349992Sbostic     glob_t  globv;
36449992Sbostic     char   *ptr;
36550439Schristos     int     nonomatch = adrof(STRnonomatch) != 0, magic = 0, match = 0;
36649992Sbostic 
36750738Schristos     if (!vl || !vl[0])
36850738Schristos 	return (vl);
36950738Schristos 
37049992Sbostic     globv.gl_offs = 0;
37149992Sbostic     globv.gl_pathv = 0;
37249992Sbostic     globv.gl_pathc = 0;
37350439Schristos 
37450439Schristos     if (nonomatch)
37550439Schristos 	gflgs |= GLOB_NOCHECK;
37650439Schristos 
37749992Sbostic     do {
37849992Sbostic 	ptr = short2qstr(*vl);
37949992Sbostic 	switch (glob(ptr, gflgs, 0, &globv)) {
38049992Sbostic 	case GLOB_ABEND:
38151589Schristos 	    setname(vis_str(*vl));
38249992Sbostic 	    stderror(ERR_NAME | ERR_GLOB);
38349992Sbostic 	    /* NOTREACHED */
38449992Sbostic 	case GLOB_NOSPACE:
38549992Sbostic 	    stderror(ERR_NOMEM);
38649992Sbostic 	    /* NOTREACHED */
38749992Sbostic 	default:
38849992Sbostic 	    break;
38947414Sbostic 	}
39050439Schristos 	if (globv.gl_flags & GLOB_MAGCHAR) {
39150439Schristos 	    match |= (globv.gl_matchc != 0);
39250439Schristos 	    magic = 1;
39349992Sbostic 	}
39449992Sbostic 	gflgs |= GLOB_APPEND;
39549992Sbostic     }
39649992Sbostic     while (*++vl);
39751437Sleres     vl = (globv.gl_pathc == 0 || (magic && !match && !nonomatch)) ?
39850439Schristos 	NULL : blk2short(globv.gl_pathv);
39949992Sbostic     globfree(&globv);
40049992Sbostic     return (vl);
40149992Sbostic }
4021295Sbill 
40349992Sbostic Char   *
globone(str,action)40449992Sbostic globone(str, action)
40549992Sbostic     Char   *str;
40649992Sbostic     int     action;
40749992Sbostic {
40849992Sbostic     Char   *v[2], **vl, **vo;
40950558Schristos     int    gflg;
41049992Sbostic 
41149992Sbostic     noglob = adrof(STRnoglob) != 0;
41249992Sbostic     gflag = 0;
41349992Sbostic     v[0] = str;
41449992Sbostic     v[1] = 0;
41549992Sbostic     tglob(v);
41650558Schristos     gflg = gflag;
41750558Schristos     if (gflg == G_NONE)
41849992Sbostic 	return (strip(Strsave(str)));
41949992Sbostic 
42050558Schristos     if (gflg & G_CSH) {
42149992Sbostic 	/*
42249992Sbostic 	 * Expand back-quote, tilde and brace
42349992Sbostic 	 */
42449992Sbostic 	vo = globexpand(v);
42550558Schristos 	if (noglob || (gflg & G_GLOB) == 0) {
42650048Schristos 	    if (vo[0] == NULL) {
42750048Schristos 		xfree((ptr_t) vo);
42850048Schristos 		return (Strsave(STRNULL));
42950048Schristos 	    }
43050024Schristos 	    if (vo[1] != NULL)
43149992Sbostic 		return (handleone(str, vo, action));
43249992Sbostic 	    else {
43349992Sbostic 		str = strip(vo[0]);
43449992Sbostic 		xfree((ptr_t) vo);
43549992Sbostic 		return (str);
43649992Sbostic 	    }
4371295Sbill 	}
43849992Sbostic     }
43950558Schristos     else if (noglob || (gflg & G_GLOB) == 0)
44049992Sbostic 	return (strip(Strsave(str)));
44149992Sbostic     else
44249992Sbostic 	vo = v;
44349992Sbostic 
44449992Sbostic     vl = libglob(vo);
44550745Schristos     if ((gflg & G_CSH) && vl != vo)
44649992Sbostic 	blkfree(vo);
44750024Schristos     if (vl == NULL) {
44851589Schristos 	setname(vis_str(str));
44949992Sbostic 	stderror(ERR_NAME | ERR_NOMATCH);
45049992Sbostic     }
45150048Schristos     if (vl[0] == NULL) {
45250048Schristos 	xfree((ptr_t) vl);
45350048Schristos 	return (Strsave(STRNULL));
45450048Schristos     }
45550048Schristos     if (vl[1] != NULL)
45649992Sbostic 	return (handleone(str, vl, action));
45749992Sbostic     else {
45849992Sbostic 	str = strip(*vl);
45949992Sbostic 	xfree((ptr_t) vl);
46050048Schristos 	return (str);
46149992Sbostic     }
4621295Sbill }
4631295Sbill 
46449992Sbostic Char  **
globall(v)46547414Sbostic globall(v)
46649992Sbostic     Char  **v;
4671295Sbill {
46849992Sbostic     Char  **vl, **vo;
46950558Schristos     int   gflg = gflag;
4701295Sbill 
47149992Sbostic     if (!v || !v[0]) {
47249992Sbostic 	gargv = saveblk(v);
47349992Sbostic 	gargc = blklen(gargv);
47449992Sbostic 	return (gargv);
47549992Sbostic     }
4761295Sbill 
47749992Sbostic     noglob = adrof(STRnoglob) != 0;
4781295Sbill 
47950558Schristos     if (gflg & G_CSH)
48049992Sbostic 	/*
48149992Sbostic 	 * Expand back-quote, tilde and brace
48249992Sbostic 	 */
48349992Sbostic 	vl = vo = globexpand(v);
48449992Sbostic     else
48549992Sbostic 	vl = vo = saveblk(v);
48647596Sbostic 
48750558Schristos     if (!noglob && (gflg & G_GLOB)) {
48849992Sbostic 	vl = libglob(vo);
48950745Schristos 	if ((gflg & G_CSH) && vl != vo)
49049992Sbostic 	    blkfree(vo);
49149992Sbostic     }
49250806Schristos     else
49350806Schristos 	trim(vl);
49447414Sbostic 
49549992Sbostic     gargc = vl ? blklen(vl) : 0;
49649992Sbostic     return (gargv = vl);
4971295Sbill }
49849992Sbostic 
49949992Sbostic void
ginit()50047414Sbostic ginit()
50147414Sbostic {
50249992Sbostic     gargsiz = GLOBSPACE;
50349992Sbostic     gargv = (Char **) xmalloc((size_t) sizeof(Char *) * gargsiz);
50449992Sbostic     gargv[0] = 0;
50549992Sbostic     gargc = 0;
50647414Sbostic }
5071295Sbill 
50849992Sbostic void
rscan(t,f)5091295Sbill rscan(t, f)
51049992Sbostic     register Char **t;
51149992Sbostic     void    (*f) ();
5121295Sbill {
51349992Sbostic     register Char *p;
5141295Sbill 
51560237Schristos     while ((p = *t++) != NULL)
51649992Sbostic 	while (*p)
51749992Sbostic 	    (*f) (*p++);
5181295Sbill }
5191295Sbill 
52049992Sbostic void
trim(t)52117514Sedward trim(t)
52249992Sbostic     register Char **t;
5231295Sbill {
52449992Sbostic     register Char *p;
5251295Sbill 
52660237Schristos     while ((p = *t++) != NULL)
52749992Sbostic 	while (*p)
52849992Sbostic 	    *p++ &= TRIM;
5291295Sbill }
5301295Sbill 
53149992Sbostic void
tglob(t)53217514Sedward tglob(t)
53349992Sbostic     register Char **t;
5341295Sbill {
53549992Sbostic     register Char *p, c;
5361295Sbill 
53760237Schristos     while ((p = *t++) != NULL) {
53849992Sbostic 	if (*p == '~' || *p == '=')
53949992Sbostic 	    gflag |= G_CSH;
54049992Sbostic 	else if (*p == '{' &&
54152372Schristos 		 (p[1] == '\0' || (p[1] == '}' && p[2] == '\0')))
54249992Sbostic 	    continue;
54360237Schristos 	while ((c = *p++) != '\0') {
54452372Schristos 	    /*
54552372Schristos 	     * eat everything inside the matching backquotes
54652372Schristos 	     */
54752372Schristos 	    if (c == '`') {
54852372Schristos 		gflag |= G_CSH;
54952372Schristos 		while (*p && *p != '`')
55052372Schristos 		    if (*p++ == '\\') {
55152372Schristos 			if (*p)		/* Quoted chars */
55252372Schristos 			    p++;
55352372Schristos 			else
55452372Schristos 			    break;
55552372Schristos 		    }
55652372Schristos 		if (*p)			/* The matching ` */
55752372Schristos 		    p++;
55852372Schristos 		else
55952372Schristos 		    break;
56052372Schristos 	    }
56152372Schristos 	    else if (c == '{')
56252372Schristos 		gflag |= G_CSH;
56352372Schristos 	    else if (isglob(c))
56452372Schristos 		gflag |= G_GLOB;
56552372Schristos 	}
56649992Sbostic     }
5671295Sbill }
5681295Sbill 
5691295Sbill /*
57047414Sbostic  * Command substitute cp.  If literal, then this is a substitution from a
57147414Sbostic  * << redirection, and so we should not crunch blanks and tabs, separating
57247414Sbostic  * words only at newlines.
5731295Sbill  */
57449992Sbostic Char  **
dobackp(cp,literal)5751295Sbill dobackp(cp, literal)
57649992Sbostic     Char   *cp;
57749992Sbostic     bool    literal;
5781295Sbill {
57949992Sbostic     register Char *lp, *rp;
58049992Sbostic     Char   *ep, word[MAXPATHLEN];
5811295Sbill 
58249992Sbostic     if (pargv) {
58352372Schristos #ifdef notdef
58449992Sbostic 	abort();
58552372Schristos #endif
58649992Sbostic 	blkfree(pargv);
58749992Sbostic     }
58849992Sbostic     pargsiz = GLOBSPACE;
58949992Sbostic     pargv = (Char **) xmalloc((size_t) sizeof(Char *) * pargsiz);
59049992Sbostic     pargv[0] = NULL;
59149992Sbostic     pargcp = pargs = word;
59249992Sbostic     pargc = 0;
59349992Sbostic     pnleft = MAXPATHLEN - 4;
59449992Sbostic     for (;;) {
59549992Sbostic 	for (lp = cp; *lp != '`'; lp++) {
59649992Sbostic 	    if (*lp == 0) {
59749992Sbostic 		if (pargcp != pargs)
59849992Sbostic 		    pword();
59949992Sbostic 		return (pargv);
60049992Sbostic 	    }
60149992Sbostic 	    psave(*lp);
6021295Sbill 	}
60349992Sbostic 	lp++;
60449992Sbostic 	for (rp = lp; *rp && *rp != '`'; rp++)
60549992Sbostic 	    if (*rp == '\\') {
60649992Sbostic 		rp++;
6071295Sbill 		if (!*rp)
60849992Sbostic 		    goto oops;
60949992Sbostic 	    }
61049992Sbostic 	if (!*rp)
61149992Sbostic     oops:  stderror(ERR_UNMATCHED, '`');
61249992Sbostic 	ep = Strsave(lp);
61349992Sbostic 	ep[rp - lp] = 0;
61449992Sbostic 	backeval(ep, literal);
61549992Sbostic 	cp = rp + 1;
61649992Sbostic     }
6171295Sbill }
6181295Sbill 
61949992Sbostic static void
backeval(cp,literal)6201295Sbill backeval(cp, literal)
62149992Sbostic     Char   *cp;
62249992Sbostic     bool    literal;
6231295Sbill {
62449992Sbostic     register int icnt, c;
62549992Sbostic     register Char *ip;
62649992Sbostic     struct command faket;
62749992Sbostic     bool    hadnl;
62849992Sbostic     int     pvec[2], quoted;
62949992Sbostic     Char   *fakecom[2], ibuf[BUFSIZ];
63049992Sbostic     char    tibuf[BUFSIZ];
6311295Sbill 
63249992Sbostic     hadnl = 0;
63349992Sbostic     icnt = 0;
63449992Sbostic     quoted = (literal || (cp[0] & QUOTE)) ? QUOTE : 0;
63549992Sbostic     faket.t_dtyp = NODE_COMMAND;
63649992Sbostic     faket.t_dflg = 0;
63749992Sbostic     faket.t_dlef = 0;
63849992Sbostic     faket.t_drit = 0;
63949992Sbostic     faket.t_dspr = 0;
64049992Sbostic     faket.t_dcom = fakecom;
64149992Sbostic     fakecom[0] = STRfakecom1;
64249992Sbostic     fakecom[1] = 0;
64347414Sbostic 
64449992Sbostic     /*
64549992Sbostic      * We do the psave job to temporarily change the current job so that the
64649992Sbostic      * following fork is considered a separate job.  This is so that when
64749992Sbostic      * backquotes are used in a builtin function that calls glob the "current
64849992Sbostic      * job" is not corrupted.  We only need one level of pushed jobs as long as
64949992Sbostic      * we are sure to fork here.
65049992Sbostic      */
65149992Sbostic     psavejob();
65247414Sbostic 
65349992Sbostic     /*
65449992Sbostic      * It would be nicer if we could integrate this redirection more with the
65549992Sbostic      * routines in sh.sem.c by doing a fake execute on a builtin function that
65649992Sbostic      * was piped out.
65749992Sbostic      */
65849992Sbostic     mypipe(pvec);
65949992Sbostic     if (pfork(&faket, -1) == 0) {
66049992Sbostic 	struct wordent paraml;
66149992Sbostic 	struct command *t;
66249992Sbostic 
66349992Sbostic 	(void) close(pvec[0]);
66449992Sbostic 	(void) dmove(pvec[1], 1);
66550439Schristos 	(void) dmove(SHERR, 2);
66649992Sbostic 	initdesc();
6671295Sbill 	/*
66849992Sbostic 	 * Bugfix for nested backquotes by Michael Greim <greim@sbsvax.UUCP>,
66949992Sbostic 	 * posted to comp.bugs.4bsd 12 Sep. 1989.
6701295Sbill 	 */
67149992Sbostic 	if (pargv)		/* mg, 21.dec.88 */
67249992Sbostic 	    blkfree(pargv), pargv = 0, pargsiz = 0;
67349992Sbostic 	/* mg, 21.dec.88 */
67449992Sbostic 	arginp = cp;
67549992Sbostic 	while (*cp)
67649992Sbostic 	    *cp++ &= TRIM;
67751528Schristos 
67851528Schristos         /*
67951528Schristos 	 * In the child ``forget'' everything about current aliases or
68051528Schristos 	 * eval vectors.
68151528Schristos 	 */
68251528Schristos 	alvec = NULL;
68351528Schristos 	evalvec = NULL;
68451528Schristos 	alvecp = NULL;
68551528Schristos 	evalp = NULL;
68649992Sbostic 	(void) lex(&paraml);
68749992Sbostic 	if (seterr)
68849992Sbostic 	    stderror(ERR_OLD);
68949992Sbostic 	alias(&paraml);
69049992Sbostic 	t = syntax(paraml.next, &paraml, 0);
69149992Sbostic 	if (seterr)
69249992Sbostic 	    stderror(ERR_OLD);
69349992Sbostic 	if (t)
69449992Sbostic 	    t->t_dflg |= F_NOFORK;
69549992Sbostic 	(void) signal(SIGTSTP, SIG_IGN);
69649992Sbostic 	(void) signal(SIGTTIN, SIG_IGN);
69749992Sbostic 	(void) signal(SIGTTOU, SIG_IGN);
69850023Sbostic 	execute(t, -1, NULL, NULL);
69949992Sbostic 	exitstat();
70049992Sbostic     }
70149992Sbostic     xfree((ptr_t) cp);
70249992Sbostic     (void) close(pvec[1]);
70349992Sbostic     c = 0;
70450024Schristos     ip = NULL;
70549992Sbostic     do {
70649992Sbostic 	int     cnt = 0;
7071295Sbill 
70849992Sbostic 	for (;;) {
70949992Sbostic 	    if (icnt == 0) {
71049992Sbostic 		int     i;
71149992Sbostic 
71249992Sbostic 		ip = ibuf;
71349992Sbostic 		do
71449992Sbostic 		    icnt = read(pvec[0], tibuf, BUFSIZ);
71549992Sbostic 		while (icnt == -1 && errno == EINTR);
71649992Sbostic 		if (icnt <= 0) {
71749992Sbostic 		    c = -1;
71849992Sbostic 		    break;
7191295Sbill 		}
72049992Sbostic 		for (i = 0; i < icnt; i++)
72149992Sbostic 		    ip[i] = (unsigned char) tibuf[i];
72249992Sbostic 	    }
72349992Sbostic 	    if (hadnl)
72449992Sbostic 		break;
72549992Sbostic 	    --icnt;
72649992Sbostic 	    c = (*ip++ & TRIM);
72749992Sbostic 	    if (c == 0)
72849992Sbostic 		break;
72949992Sbostic 	    if (c == '\n') {
7301295Sbill 		/*
73149992Sbostic 		 * Continue around the loop one more time, so that we can eat
73249992Sbostic 		 * the last newline without terminating this word.
7331295Sbill 		 */
73449992Sbostic 		hadnl = 1;
73549992Sbostic 		continue;
73649992Sbostic 	    }
73749992Sbostic 	    if (!quoted && (c == ' ' || c == '\t'))
73849992Sbostic 		break;
73949992Sbostic 	    cnt++;
74049992Sbostic 	    psave(c | quoted);
74149992Sbostic 	}
74249992Sbostic 	/*
74349992Sbostic 	 * Unless at end-of-file, we will form a new word here if there were
74449992Sbostic 	 * characters in the word, or in any case when we take text literally.
74549992Sbostic 	 * If we didn't make empty words here when literal was set then we
74649992Sbostic 	 * would lose blank lines.
74749992Sbostic 	 */
74849992Sbostic 	if (c != -1 && (cnt || literal))
74949992Sbostic 	    pword();
75049992Sbostic 	hadnl = 0;
75149992Sbostic     } while (c >= 0);
75249992Sbostic     (void) close(pvec[0]);
75349992Sbostic     pwait();
75449992Sbostic     prestjob();
7551295Sbill }
7561295Sbill 
75749992Sbostic static void
psave(c)7581295Sbill psave(c)
75950024Schristos     int    c;
7601295Sbill {
76149992Sbostic     if (--pnleft <= 0)
76249992Sbostic 	stderror(ERR_WTOOLONG);
76349992Sbostic     *pargcp++ = c;
7641295Sbill }
7651295Sbill 
76649992Sbostic static void
pword()7671295Sbill pword()
7681295Sbill {
76949992Sbostic     psave(0);
77049992Sbostic     if (pargc == pargsiz - 1) {
77149992Sbostic 	pargsiz += GLOBSPACE;
77249992Sbostic 	pargv = (Char **) xrealloc((ptr_t) pargv,
77349992Sbostic 				   (size_t) pargsiz * sizeof(Char *));
77449992Sbostic     }
77549992Sbostic     pargv[pargc++] = Strsave(pargs);
77649992Sbostic     pargv[pargc] = NULL;
77749992Sbostic     pargcp = pargs;
77849992Sbostic     pnleft = MAXPATHLEN - 4;
7791295Sbill }
78047414Sbostic 
78152372Schristos int
Gmatch(string,pattern)78252372Schristos Gmatch(string, pattern)
78352372Schristos     Char *string, *pattern;
78452372Schristos {
78552372Schristos     Char **blk, **p;
78652372Schristos     int	   gpol = 1, gres = 0;
78752372Schristos 
78852372Schristos     if (*pattern == '^') {
78952372Schristos 	gpol = 0;
79052372Schristos 	pattern++;
79152372Schristos     }
79252372Schristos 
79352372Schristos     blk = (Char **) xmalloc(GLOBSPACE * sizeof(Char *));
79452372Schristos     blk[0] = Strsave(pattern);
79552372Schristos     blk[1] = NULL;
79652372Schristos 
79752372Schristos     expbrace(&blk, NULL, GLOBSPACE);
79852372Schristos 
79952372Schristos     for (p = blk; *p; p++)
80052372Schristos 	gres |= pmatch(string, *p);
80152372Schristos 
80252372Schristos     blkfree(blk);
80352372Schristos     return(gres == gpol);
80452372Schristos }
80552372Schristos 
80652375Schristos static int
pmatch(string,pattern)80752372Schristos pmatch(string, pattern)
80849992Sbostic     register Char *string, *pattern;
80947414Sbostic {
81049992Sbostic     register Char stringc, patternc;
81152372Schristos     int     match, negate_range;
81249992Sbostic     Char    rangec;
81347414Sbostic 
81449992Sbostic     for (;; ++string) {
81549992Sbostic 	stringc = *string & TRIM;
81649992Sbostic 	patternc = *pattern++;
81749992Sbostic 	switch (patternc) {
81849992Sbostic 	case 0:
81949992Sbostic 	    return (stringc == 0);
82049992Sbostic 	case '?':
82149992Sbostic 	    if (stringc == 0)
82249992Sbostic 		return (0);
82349992Sbostic 	    break;
82449992Sbostic 	case '*':
82549992Sbostic 	    if (!*pattern)
82649992Sbostic 		return (1);
82749992Sbostic 	    while (*string)
82849992Sbostic 		if (Gmatch(string++, pattern))
82949992Sbostic 		    return (1);
83049992Sbostic 	    return (0);
83149992Sbostic 	case '[':
83249992Sbostic 	    match = 0;
83360237Schristos 	    if ((negate_range = (*pattern == '^')) != 0)
83452372Schristos 		pattern++;
83560237Schristos 	    while ((rangec = *pattern++) != '\0') {
83649992Sbostic 		if (rangec == ']')
83752372Schristos 		    break;
83849992Sbostic 		if (match)
83949992Sbostic 		    continue;
84052372Schristos 		if (rangec == '-' && *(pattern-2) != '[' && *pattern  != ']') {
84150126Schristos 		    match = (stringc <= (*pattern & TRIM) &&
84252372Schristos 			      (*(pattern-2) & TRIM) <= stringc);
84349992Sbostic 		    pattern++;
84449992Sbostic 		}
84552372Schristos 		else
84652372Schristos 		    match = (stringc == (rangec & TRIM));
84749992Sbostic 	    }
84849992Sbostic 	    if (rangec == 0)
84949992Sbostic 		stderror(ERR_NAME | ERR_MISSING, ']');
85052372Schristos 	    if (match == negate_range)
85152372Schristos 		return (0);
85249992Sbostic 	    break;
85349992Sbostic 	default:
85449992Sbostic 	    if ((patternc & TRIM) != stringc)
85549992Sbostic 		return (0);
85649992Sbostic 	    break;
85747414Sbostic 
85847414Sbostic 	}
85949992Sbostic     }
86047414Sbostic }
86147414Sbostic 
86249992Sbostic void
Gcat(s1,s2)86347414Sbostic Gcat(s1, s2)
86449992Sbostic     Char   *s1, *s2;
86547414Sbostic {
86649992Sbostic     register Char *p, *q;
86749992Sbostic     int     n;
86847414Sbostic 
86951437Sleres     for (p = s1; *p++;)
87051437Sleres 	continue;
87151437Sleres     for (q = s2; *q++;)
87251437Sleres 	continue;
87349992Sbostic     n = (p - s1) + (q - s2) - 1;
87449992Sbostic     if (++gargc >= gargsiz) {
87549992Sbostic 	gargsiz += GLOBSPACE;
87649992Sbostic 	gargv = (Char **) xrealloc((ptr_t) gargv,
87749992Sbostic 				   (size_t) gargsiz * sizeof(Char *));
87849992Sbostic     }
87949992Sbostic     gargv[gargc] = 0;
88049992Sbostic     p = gargv[gargc - 1] = (Char *) xmalloc((size_t) n * sizeof(Char));
88160237Schristos     for (q = s1; (*p++ = *q++) != '\0';)
88251437Sleres 	continue;
88360237Schristos     for (p--, q = s2; (*p++ = *q++) != '\0';)
88451437Sleres 	continue;
88547414Sbostic }
88647414Sbostic 
88749992Sbostic #ifdef FILEC
88847414Sbostic int
sortscmp(a,b)88949992Sbostic sortscmp(a, b)
89052372Schristos     register const ptr_t a, b;
89147414Sbostic {
89249992Sbostic #if defined(NLS) && !defined(NOSTRCOLL)
89349992Sbostic     char    buf[2048];
89449992Sbostic #endif
89549992Sbostic 
89657937Schristos     if (!a)			/* check for NULL */
89749992Sbostic 	return (b ? 1 : 0);
89849992Sbostic     if (!b)
89949992Sbostic 	return (-1);
90049992Sbostic 
90151665Sbostic     if (!*(Char **)a)			/* check for NULL */
90251665Sbostic 	return (*(Char **)b ? 1 : 0);
90351665Sbostic     if (!*(Char **)b)
90449992Sbostic 	return (-1);
90549992Sbostic 
90649992Sbostic #if defined(NLS) && !defined(NOSTRCOLL)
90751665Sbostic     (void) strcpy(buf, short2str(*(Char **)a));
90851665Sbostic     return ((int) strcoll(buf, short2str(*(Char **)b)));
90949992Sbostic #else
91051665Sbostic     return ((int) Strcmp(*(Char **)a, *(Char **)b));
91149992Sbostic #endif
91247414Sbostic }
91349992Sbostic #endif /* FILEC */
914