sh.glob.c revision 59243
159243Sobrien/* $Header: /src/pub/tcsh/sh.glob.c,v 3.43 1998/10/25 15:10:14 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.
1759243Sobrien * 3. All advertising materials mentioning features or use of this software
1859243Sobrien *    must display the following acknowledgement:
1959243Sobrien *	This product includes software developed by the University of
2059243Sobrien *	California, Berkeley and its contributors.
2159243Sobrien * 4. Neither the name of the University nor the names of its contributors
2259243Sobrien *    may be used to endorse or promote products derived from this software
2359243Sobrien *    without specific prior written permission.
2459243Sobrien *
2559243Sobrien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2659243Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2759243Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2859243Sobrien * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2959243Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
3059243Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3159243Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3259243Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3359243Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3459243Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3559243Sobrien * SUCH DAMAGE.
3659243Sobrien */
3759243Sobrien#include "sh.h"
3859243Sobrien
3959243SobrienRCSID("$Id: sh.glob.c,v 3.43 1998/10/25 15:10:14 christos Exp $")
4059243Sobrien
4159243Sobrien#include "tc.h"
4259243Sobrien
4359243Sobrien#include "glob.h"
4459243Sobrien
4559243Sobrienstatic int noglob;
4659243Sobrienstatic int pargsiz, gargsiz;
4759243Sobrien
4859243Sobrien/*
4959243Sobrien * Values for gflag
5059243Sobrien */
5159243Sobrien#define	G_NONE	0		/* No globbing needed			*/
5259243Sobrien#define	G_GLOB	1		/* string contains *?[] characters	*/
5359243Sobrien#define	G_CSH	2		/* string contains ~`{ characters	*/
5459243Sobrien
5559243Sobrien#define	GLOBSPACE	100	/* Alloc increment			*/
5659243Sobrien#define LONGBSIZE	10240	/* Backquote expansion buffer size	*/
5759243Sobrien
5859243Sobrien
5959243Sobrien#define LBRC '{'
6059243Sobrien#define RBRC '}'
6159243Sobrien#define LBRK '['
6259243Sobrien#define RBRK ']'
6359243Sobrien#define EOS '\0'
6459243Sobrien
6559243SobrienChar  **gargv = NULL;
6659243Sobrienint     gargc = 0;
6759243SobrienChar  **pargv = NULL;
6859243Sobrienstatic int pargc = 0;
6959243Sobrien
7059243Sobrien/*
7159243Sobrien * globbing is now done in two stages. In the first pass we expand
7259243Sobrien * csh globbing idioms ~`{ and then we proceed doing the normal
7359243Sobrien * globbing if needed ?*[
7459243Sobrien *
7559243Sobrien * Csh type globbing is handled in globexpand() and the rest is
7659243Sobrien * handled in glob() which is part of the 4.4BSD libc.
7759243Sobrien *
7859243Sobrien */
7959243Sobrienstatic	Char	 *globtilde	__P((Char **, Char *));
8059243Sobrienstatic	Char     *handleone	__P((Char *, Char **, int));
8159243Sobrienstatic	Char	**libglob	__P((Char **));
8259243Sobrienstatic	Char	**globexpand	__P((Char **));
8359243Sobrienstatic	int	  globbrace	__P((Char *, Char *, Char ***));
8459243Sobrienstatic  void	  expbrace	__P((Char ***, Char ***, int));
8559243Sobrienstatic  int	  pmatch	__P((Char *, Char *, Char **));
8659243Sobrienstatic	void	  pword		__P((int));
8759243Sobrienstatic	void	  psave		__P((int));
8859243Sobrienstatic	void	  backeval	__P((Char *, bool));
8959243Sobrien
9059243Sobrienstatic Char *
9159243Sobrienglobtilde(nv, s)
9259243Sobrien    Char  **nv, *s;
9359243Sobrien{
9459243Sobrien    Char    gbuf[BUFSIZE], *gstart, *b, *u, *e;
9559243Sobrien#ifdef apollo
9659243Sobrien    int slash;
9759243Sobrien#endif
9859243Sobrien
9959243Sobrien    gstart = gbuf;
10059243Sobrien    *gstart++ = *s++;
10159243Sobrien    u = s;
10259243Sobrien    for (b = gstart, e = &gbuf[BUFSIZE - 1];
10359243Sobrien	 *s && *s != '/' && *s != ':' && b < e;
10459243Sobrien	 *b++ = *s++)
10559243Sobrien	continue;
10659243Sobrien    *b = EOS;
10759243Sobrien    if (gethdir(gstart)) {
10859243Sobrien	if (adrof(STRnonomatch))
10959243Sobrien	    return (--u);
11059243Sobrien	blkfree(nv);
11159243Sobrien	if (*gstart)
11259243Sobrien	    stderror(ERR_UNKUSER, short2str(gstart));
11359243Sobrien	else
11459243Sobrien	    stderror(ERR_NOHOME);
11559243Sobrien    }
11659243Sobrien    b = &gstart[Strlen(gstart)];
11759243Sobrien#ifdef apollo
11859243Sobrien    slash = gstart[0] == '/' && gstart[1] == '\0';
11959243Sobrien#endif
12059243Sobrien    while (*s)
12159243Sobrien	*b++ = *s++;
12259243Sobrien    *b = EOS;
12359243Sobrien    --u;
12459243Sobrien    xfree((ptr_t) u);
12559243Sobrien#ifdef apollo
12659243Sobrien    if (slash && gstart[1] == '/')
12759243Sobrien	gstart++;
12859243Sobrien#endif
12959243Sobrien    return (Strsave(gstart));
13059243Sobrien}
13159243Sobrien
13259243SobrienChar *
13359243Sobrienglobequal(new, old)
13459243Sobrien    Char *new, *old;
13559243Sobrien{
13659243Sobrien    int     dig;
13759243Sobrien    Char    *b, *d;
13859243Sobrien
13959243Sobrien    /*
14059243Sobrien     * kfk - 17 Jan 1984 - stack hack allows user to get at arbitrary dir names
14159243Sobrien     * in stack. PWP: let =foobar pass through (for X windows)
14259243Sobrien     */
14359243Sobrien    if (old[1] == '-' && (old[2] == '\0' || old[2] == '/')) {
14459243Sobrien	/* =- */
14559243Sobrien	dig = -1;
14659243Sobrien	b = &old[2];
14759243Sobrien    }
14859243Sobrien    else if (Isdigit(old[1])) {
14959243Sobrien	/* =<number> */
15059243Sobrien	dig = old[1] - '0';
15159243Sobrien	for (b = &old[2]; Isdigit(*b); b++)
15259243Sobrien	    dig = dig * 10 + (*b - '0');
15359243Sobrien	if (*b != '\0' && *b != '/')
15459243Sobrien	    /* =<number>foobar */
15559243Sobrien	    return old;
15659243Sobrien    }
15759243Sobrien    else
15859243Sobrien	/* =foobar */
15959243Sobrien	return old;
16059243Sobrien
16159243Sobrien    if (!getstakd(new, dig))
16259243Sobrien	return NULL;
16359243Sobrien
16459243Sobrien    /* Copy the rest of the string */
16559243Sobrien    for (d = &new[Strlen(new)];
16659243Sobrien	 d < &new[BUFSIZE - 1] && (*d++ = *b++) != '\0';)
16759243Sobrien	continue;
16859243Sobrien    *d = '\0';
16959243Sobrien
17059243Sobrien    return new;
17159243Sobrien}
17259243Sobrien
17359243Sobrienstatic int
17459243Sobrienglobbrace(s, p, bl)
17559243Sobrien    Char   *s, *p, ***bl;
17659243Sobrien{
17759243Sobrien    int     i, len;
17859243Sobrien    Char   *pm, *pe, *lm, *pl;
17959243Sobrien    Char  **nv, **vl;
18059243Sobrien    Char    gbuf[BUFSIZE];
18159243Sobrien    int     size = GLOBSPACE;
18259243Sobrien
18359243Sobrien    nv = vl = (Char **) xmalloc((size_t) (sizeof(Char *) * size));
18459243Sobrien    *vl = NULL;
18559243Sobrien
18659243Sobrien    len = 0;
18759243Sobrien    /* copy part up to the brace */
18859243Sobrien    for (lm = gbuf, p = s; *p != LBRC; *lm++ = *p++)
18959243Sobrien	continue;
19059243Sobrien
19159243Sobrien    /* check for balanced braces */
19259243Sobrien    for (i = 0, pe = ++p; *pe; pe++)
19359243Sobrien	if (*pe == LBRK) {
19459243Sobrien	    /* Ignore everything between [] */
19559243Sobrien	    for (++pe; *pe != RBRK && *pe != EOS; pe++)
19659243Sobrien		continue;
19759243Sobrien	    if (*pe == EOS) {
19859243Sobrien		blkfree(nv);
19959243Sobrien		return (-RBRK);
20059243Sobrien	    }
20159243Sobrien	}
20259243Sobrien	else if (*pe == LBRC)
20359243Sobrien	    i++;
20459243Sobrien	else if (*pe == RBRC) {
20559243Sobrien	    if (i == 0)
20659243Sobrien		break;
20759243Sobrien	    i--;
20859243Sobrien	}
20959243Sobrien
21059243Sobrien    if (i != 0 || *pe == '\0') {
21159243Sobrien	blkfree(nv);
21259243Sobrien	return (-RBRC);
21359243Sobrien    }
21459243Sobrien
21559243Sobrien    for (i = 0, pl = pm = p; pm <= pe; pm++)
21659243Sobrien	switch (*pm) {
21759243Sobrien	case LBRK:
21859243Sobrien	    for (++pm; *pm != RBRK && *pm != EOS; pm++)
21959243Sobrien		continue;
22059243Sobrien	    if (*pm == EOS) {
22159243Sobrien		*vl = NULL;
22259243Sobrien		blkfree(nv);
22359243Sobrien		return (-RBRK);
22459243Sobrien	    }
22559243Sobrien	    break;
22659243Sobrien	case LBRC:
22759243Sobrien	    i++;
22859243Sobrien	    break;
22959243Sobrien	case RBRC:
23059243Sobrien	    if (i) {
23159243Sobrien		i--;
23259243Sobrien		break;
23359243Sobrien	    }
23459243Sobrien	    /* FALLTHROUGH */
23559243Sobrien	case ',':
23659243Sobrien	    if (i && *pm == ',')
23759243Sobrien		break;
23859243Sobrien	    else {
23959243Sobrien		Char    savec = *pm;
24059243Sobrien
24159243Sobrien		*pm = EOS;
24259243Sobrien		(void) Strcpy(lm, pl);
24359243Sobrien		(void) Strcat(gbuf, pe + 1);
24459243Sobrien		*pm = savec;
24559243Sobrien		*vl++ = Strsave(gbuf);
24659243Sobrien		len++;
24759243Sobrien		pl = pm + 1;
24859243Sobrien		if (vl == &nv[size]) {
24959243Sobrien		    size += GLOBSPACE;
25059243Sobrien		    nv = (Char **) xrealloc((ptr_t) nv,
25159243Sobrien					    (size_t) (size * sizeof(Char *)));
25259243Sobrien		    vl = &nv[size - GLOBSPACE];
25359243Sobrien		}
25459243Sobrien	    }
25559243Sobrien	    break;
25659243Sobrien	default:
25759243Sobrien	    break;
25859243Sobrien	}
25959243Sobrien    *vl = NULL;
26059243Sobrien    *bl = nv;
26159243Sobrien    return (len);
26259243Sobrien}
26359243Sobrien
26459243Sobrien
26559243Sobrienstatic void
26659243Sobrienexpbrace(nvp, elp, size)
26759243Sobrien    Char ***nvp, ***elp;
26859243Sobrien    int size;
26959243Sobrien{
27059243Sobrien    Char **vl, **el, **nv, *s;
27159243Sobrien
27259243Sobrien    vl = nv = *nvp;
27359243Sobrien    if (elp != NULL)
27459243Sobrien	el = *elp;
27559243Sobrien    else
27659243Sobrien	for (el = vl; *el; el++)
27759243Sobrien	    continue;
27859243Sobrien
27959243Sobrien    for (s = *vl; s; s = *++vl) {
28059243Sobrien	Char   *b;
28159243Sobrien	Char  **vp, **bp;
28259243Sobrien
28359243Sobrien	/* leave {} untouched for find */
28459243Sobrien	if (s[0] == '{' && (s[1] == '\0' || (s[1] == '}' && s[2] == '\0')))
28559243Sobrien	    continue;
28659243Sobrien	if ((b = Strchr(s, '{')) != NULL) {
28759243Sobrien	    Char  **bl;
28859243Sobrien	    int     len;
28959243Sobrien
29059243Sobrien	    if ((len = globbrace(s, b, &bl)) < 0) {
29159243Sobrien		xfree((ptr_t) nv);
29259243Sobrien		stderror(ERR_MISSING, -len);
29359243Sobrien	    }
29459243Sobrien	    xfree((ptr_t) s);
29559243Sobrien	    if (len == 1) {
29659243Sobrien		*vl-- = *bl;
29759243Sobrien		xfree((ptr_t) bl);
29859243Sobrien		continue;
29959243Sobrien	    }
30059243Sobrien	    if (&el[len] >= &nv[size]) {
30159243Sobrien		int     l, e;
30259243Sobrien		l = (int) (&el[len] - &nv[size]);
30359243Sobrien		size += GLOBSPACE > l ? GLOBSPACE : l;
30459243Sobrien		l = (int) (vl - nv);
30559243Sobrien		e = (int) (el - nv);
30659243Sobrien		nv = (Char **) xrealloc((ptr_t) nv,
30759243Sobrien					(size_t) (size * sizeof(Char *)));
30859243Sobrien		vl = nv + l;
30959243Sobrien		el = nv + e;
31059243Sobrien	    }
31159243Sobrien	    /* nv vl   el     bl
31259243Sobrien	     * |  |    |      |
31359243Sobrien	     * -.--..--	      x--
31459243Sobrien	     *   |            len
31559243Sobrien	     *   vp
31659243Sobrien	     */
31759243Sobrien	    vp = vl--;
31859243Sobrien	    *vp = *bl;
31959243Sobrien	    len--;
32059243Sobrien	    for (bp = el; bp != vp; bp--)
32159243Sobrien		bp[len] = *bp;
32259243Sobrien	    el += len;
32359243Sobrien	    /* nv vl    el bl
32459243Sobrien	     * |  |     |  |
32559243Sobrien	     * -.-x  ---    --
32659243Sobrien	     *   |len
32759243Sobrien	     *   vp
32859243Sobrien	     */
32959243Sobrien	    vp++;
33059243Sobrien	    for (bp = bl + 1; *bp; *vp++ = *bp++)
33159243Sobrien		continue;
33259243Sobrien	    xfree((ptr_t) bl);
33359243Sobrien	}
33459243Sobrien
33559243Sobrien    }
33659243Sobrien    if (elp != NULL)
33759243Sobrien	*elp = el;
33859243Sobrien    *nvp = nv;
33959243Sobrien}
34059243Sobrien
34159243Sobrienstatic Char **
34259243Sobrienglobexpand(v)
34359243Sobrien    Char  **v;
34459243Sobrien{
34559243Sobrien    Char   *s;
34659243Sobrien    Char  **nv, **vl, **el;
34759243Sobrien    int     size = GLOBSPACE;
34859243Sobrien
34959243Sobrien
35059243Sobrien    nv = vl = (Char **) xmalloc((size_t) (sizeof(Char *) * size));
35159243Sobrien    *vl = NULL;
35259243Sobrien
35359243Sobrien    /*
35459243Sobrien     * Step 1: expand backquotes.
35559243Sobrien     */
35659243Sobrien    while ((s = *v++) != '\0') {
35759243Sobrien	if (Strchr(s, '`')) {
35859243Sobrien	    int     i;
35959243Sobrien
36059243Sobrien	    (void) dobackp(s, 0);
36159243Sobrien	    for (i = 0; i < pargc; i++) {
36259243Sobrien		*vl++ = pargv[i];
36359243Sobrien		if (vl == &nv[size]) {
36459243Sobrien		    size += GLOBSPACE;
36559243Sobrien		    nv = (Char **) xrealloc((ptr_t) nv,
36659243Sobrien					    (size_t) (size * sizeof(Char *)));
36759243Sobrien		    vl = &nv[size - GLOBSPACE];
36859243Sobrien		}
36959243Sobrien	    }
37059243Sobrien	    xfree((ptr_t) pargv);
37159243Sobrien	    pargv = NULL;
37259243Sobrien	}
37359243Sobrien	else {
37459243Sobrien	    *vl++ = Strsave(s);
37559243Sobrien	    if (vl == &nv[size]) {
37659243Sobrien		size += GLOBSPACE;
37759243Sobrien		nv = (Char **) xrealloc((ptr_t) nv,
37859243Sobrien					(size_t) (size * sizeof(Char *)));
37959243Sobrien		vl = &nv[size - GLOBSPACE];
38059243Sobrien	    }
38159243Sobrien	}
38259243Sobrien    }
38359243Sobrien    *vl = NULL;
38459243Sobrien
38559243Sobrien    if (noglob)
38659243Sobrien	return (nv);
38759243Sobrien
38859243Sobrien    /*
38959243Sobrien     * Step 2: expand braces
39059243Sobrien     */
39159243Sobrien    el = vl;
39259243Sobrien    expbrace(&nv, &el, size);
39359243Sobrien
39459243Sobrien
39559243Sobrien    /*
39659243Sobrien     * Step 3: expand ~ =
39759243Sobrien     */
39859243Sobrien    vl = nv;
39959243Sobrien    for (s = *vl; s; s = *++vl)
40059243Sobrien	switch (*s) {
40159243Sobrien	    Char gp[BUFSIZE], *ns;
40259243Sobrien	case '~':
40359243Sobrien	    *vl = globtilde(nv, s);
40459243Sobrien	    break;
40559243Sobrien	case '=':
40659243Sobrien	    if ((ns = globequal(gp, s)) == NULL) {
40759243Sobrien		if (!adrof(STRnonomatch)) {
40859243Sobrien		    /* Error */
40959243Sobrien		    blkfree(nv);
41059243Sobrien		    stderror(ERR_DEEP);
41159243Sobrien		}
41259243Sobrien	    }
41359243Sobrien	    if (ns && ns != s) {
41459243Sobrien		/* Expansion succeeded */
41559243Sobrien		xfree((ptr_t) s);
41659243Sobrien		*vl = Strsave(gp);
41759243Sobrien	    }
41859243Sobrien	    break;
41959243Sobrien	default:
42059243Sobrien	    break;
42159243Sobrien	}
42259243Sobrien    vl = nv;
42359243Sobrien
42459243Sobrien    /*
42559243Sobrien     * Step 4: expand .. if the variable symlinks==expand is set
42659243Sobrien     */
42759243Sobrien    if ( symlinks == SYM_EXPAND )
42859243Sobrien	for (s = *vl; s; s = *++vl) {
42959243Sobrien	    *vl = dnormalize(s, 1);
43059243Sobrien	    xfree((ptr_t) s);
43159243Sobrien	}
43259243Sobrien    vl = nv;
43359243Sobrien
43459243Sobrien    return (vl);
43559243Sobrien}
43659243Sobrien
43759243Sobrienstatic Char *
43859243Sobrienhandleone(str, vl, action)
43959243Sobrien    Char   *str, **vl;
44059243Sobrien    int     action;
44159243Sobrien{
44259243Sobrien
44359243Sobrien    Char   **vlp = vl;
44459243Sobrien    int chars;
44559243Sobrien    Char **t, *p, *strp;
44659243Sobrien
44759243Sobrien    switch (action) {
44859243Sobrien    case G_ERROR:
44959243Sobrien	setname(short2str(str));
45059243Sobrien	blkfree(vl);
45159243Sobrien	stderror(ERR_NAME | ERR_AMBIG);
45259243Sobrien	break;
45359243Sobrien    case G_APPEND:
45459243Sobrien	chars = 0;
45559243Sobrien	for (t = vlp; (p = *t++) != '\0'; chars++)
45659243Sobrien	    while (*p++)
45759243Sobrien		chars++;
45859243Sobrien	str = (Char *)xmalloc((size_t)(chars * sizeof(Char)));
45959243Sobrien	for (t = vlp, strp = str; (p = *t++) != '\0'; chars++) {
46059243Sobrien	    while (*p)
46159243Sobrien		 *strp++ = *p++ & TRIM;
46259243Sobrien	    *strp++ = ' ';
46359243Sobrien	}
46459243Sobrien	*--strp = '\0';
46559243Sobrien	blkfree(vl);
46659243Sobrien	break;
46759243Sobrien    case G_IGNORE:
46859243Sobrien	str = Strsave(strip(*vlp));
46959243Sobrien	blkfree(vl);
47059243Sobrien	break;
47159243Sobrien    default:
47259243Sobrien	break;
47359243Sobrien    }
47459243Sobrien    return (str);
47559243Sobrien}
47659243Sobrien
47759243Sobrienstatic Char **
47859243Sobrienlibglob(vl)
47959243Sobrien    Char  **vl;
48059243Sobrien{
48159243Sobrien    int     gflgs = GLOB_QUOTE | GLOB_NOMAGIC | GLOB_ALTNOT;
48259243Sobrien    glob_t  globv;
48359243Sobrien    char   *ptr;
48459243Sobrien    int     nonomatch = adrof(STRnonomatch) != 0, magic = 0, match = 0;
48559243Sobrien
48659243Sobrien    if (!vl || !vl[0])
48759243Sobrien	return(vl);
48859243Sobrien
48959243Sobrien    globv.gl_offs = 0;
49059243Sobrien    globv.gl_pathv = 0;
49159243Sobrien    globv.gl_pathc = 0;
49259243Sobrien
49359243Sobrien    if (nonomatch)
49459243Sobrien	gflgs |= GLOB_NOCHECK;
49559243Sobrien
49659243Sobrien    do {
49759243Sobrien	ptr = short2qstr(*vl);
49859243Sobrien	switch (glob(ptr, gflgs, 0, &globv)) {
49959243Sobrien	case GLOB_ABEND:
50059243Sobrien	    globfree(&globv);
50159243Sobrien	    setname(ptr);
50259243Sobrien	    stderror(ERR_NAME | ERR_GLOB);
50359243Sobrien	    /* NOTREACHED */
50459243Sobrien	case GLOB_NOSPACE:
50559243Sobrien	    globfree(&globv);
50659243Sobrien	    stderror(ERR_NOMEM);
50759243Sobrien	    /* NOTREACHED */
50859243Sobrien	default:
50959243Sobrien	    break;
51059243Sobrien	}
51159243Sobrien	if (globv.gl_flags & GLOB_MAGCHAR) {
51259243Sobrien	    match |= (globv.gl_matchc != 0);
51359243Sobrien	    magic = 1;
51459243Sobrien	}
51559243Sobrien	gflgs |= GLOB_APPEND;
51659243Sobrien    }
51759243Sobrien    while (*++vl);
51859243Sobrien    vl = (globv.gl_pathc == 0 || (magic && !match && !nonomatch)) ?
51959243Sobrien	NULL : blk2short(globv.gl_pathv);
52059243Sobrien    globfree(&globv);
52159243Sobrien    return (vl);
52259243Sobrien}
52359243Sobrien
52459243SobrienChar   *
52559243Sobrienglobone(str, action)
52659243Sobrien    Char   *str;
52759243Sobrien    int     action;
52859243Sobrien{
52959243Sobrien
53059243Sobrien    Char   *v[2], **vl, **vo;
53159243Sobrien    int gflg;
53259243Sobrien
53359243Sobrien    noglob = adrof(STRnoglob) != 0;
53459243Sobrien    gflag = 0;
53559243Sobrien    v[0] = str;
53659243Sobrien    v[1] = 0;
53759243Sobrien    tglob(v);
53859243Sobrien    gflg = gflag;
53959243Sobrien    if (gflg == G_NONE)
54059243Sobrien	return (strip(Strsave(str)));
54159243Sobrien
54259243Sobrien    if (gflg & G_CSH) {
54359243Sobrien	/*
54459243Sobrien	 * Expand back-quote, tilde and brace
54559243Sobrien	 */
54659243Sobrien	vo = globexpand(v);
54759243Sobrien	if (noglob || (gflg & G_GLOB) == 0) {
54859243Sobrien	    if (vo[0] == NULL) {
54959243Sobrien		xfree((ptr_t) vo);
55059243Sobrien		return (Strsave(STRNULL));
55159243Sobrien	    }
55259243Sobrien	    if (vo[1] != NULL)
55359243Sobrien		return (handleone(str, vo, action));
55459243Sobrien	    else {
55559243Sobrien		str = strip(vo[0]);
55659243Sobrien		xfree((ptr_t) vo);
55759243Sobrien		return (str);
55859243Sobrien	    }
55959243Sobrien	}
56059243Sobrien    }
56159243Sobrien    else if (noglob || (gflg & G_GLOB) == 0)
56259243Sobrien	return (strip(Strsave(str)));
56359243Sobrien    else
56459243Sobrien	vo = v;
56559243Sobrien
56659243Sobrien    vl = libglob(vo);
56759243Sobrien    if ((gflg & G_CSH) && vl != vo)
56859243Sobrien	blkfree(vo);
56959243Sobrien    if (vl == NULL) {
57059243Sobrien	setname(short2str(str));
57159243Sobrien	stderror(ERR_NAME | ERR_NOMATCH);
57259243Sobrien    }
57359243Sobrien    if (vl[0] == NULL) {
57459243Sobrien	xfree((ptr_t) vl);
57559243Sobrien	return (Strsave(STRNULL));
57659243Sobrien    }
57759243Sobrien    if (vl[1])
57859243Sobrien	return (handleone(str, vl, action));
57959243Sobrien    else {
58059243Sobrien	str = strip(*vl);
58159243Sobrien	xfree((ptr_t) vl);
58259243Sobrien	return (str);
58359243Sobrien    }
58459243Sobrien}
58559243Sobrien
58659243SobrienChar  **
58759243Sobriengloball(v)
58859243Sobrien    Char  **v;
58959243Sobrien{
59059243Sobrien    Char  **vl, **vo;
59159243Sobrien    int gflg = gflag;
59259243Sobrien
59359243Sobrien    if (!v || !v[0]) {
59459243Sobrien	gargv = saveblk(v);
59559243Sobrien	gargc = blklen(gargv);
59659243Sobrien	return (gargv);
59759243Sobrien    }
59859243Sobrien
59959243Sobrien    noglob = adrof(STRnoglob) != 0;
60059243Sobrien
60159243Sobrien    if (gflg & G_CSH)
60259243Sobrien	/*
60359243Sobrien	 * Expand back-quote, tilde and brace
60459243Sobrien	 */
60559243Sobrien	vl = vo = globexpand(v);
60659243Sobrien    else
60759243Sobrien	vl = vo = saveblk(v);
60859243Sobrien
60959243Sobrien    if (!noglob && (gflg & G_GLOB)) {
61059243Sobrien	vl = libglob(vo);
61159243Sobrien	if (vl != vo)
61259243Sobrien	    blkfree(vo);
61359243Sobrien    }
61459243Sobrien    else
61559243Sobrien	trim(vl);
61659243Sobrien
61759243Sobrien    gargc = vl ? blklen(vl) : 0;
61859243Sobrien    return (gargv = vl);
61959243Sobrien}
62059243Sobrien
62159243Sobrienvoid
62259243Sobrienginit()
62359243Sobrien{
62459243Sobrien    gargsiz = GLOBSPACE;
62559243Sobrien    gargv = (Char **) xmalloc((size_t) (sizeof(Char *) * gargsiz));
62659243Sobrien    gargv[0] = 0;
62759243Sobrien    gargc = 0;
62859243Sobrien}
62959243Sobrien
63059243Sobrienvoid
63159243Sobrienrscan(t, f)
63259243Sobrien    register Char **t;
63359243Sobrien    void    (*f) __P((int));
63459243Sobrien{
63559243Sobrien    register Char *p;
63659243Sobrien
63759243Sobrien    while ((p = *t++) != '\0')
63859243Sobrien	while (*p)
63959243Sobrien	    (*f) (*p++);
64059243Sobrien}
64159243Sobrien
64259243Sobrienvoid
64359243Sobrientrim(t)
64459243Sobrien    register Char **t;
64559243Sobrien{
64659243Sobrien    register Char *p;
64759243Sobrien
64859243Sobrien    while ((p = *t++) != '\0')
64959243Sobrien	while (*p)
65059243Sobrien	    *p++ &= TRIM;
65159243Sobrien}
65259243Sobrien
65359243Sobrienvoid
65459243Sobrientglob(t)
65559243Sobrien    register Char **t;
65659243Sobrien{
65759243Sobrien    register Char *p, *c;
65859243Sobrien
65959243Sobrien    while ((p = *t++) != '\0') {
66059243Sobrien	if (*p == '~' || *p == '=')
66159243Sobrien	    gflag |= G_CSH;
66259243Sobrien	else if (*p == '{' &&
66359243Sobrien		 (p[1] == '\0' || (p[1] == '}' && p[2] == '\0')))
66459243Sobrien	    continue;
66559243Sobrien	/*
66659243Sobrien	 * The following line used to be *(c = p++), but hp broke their
66759243Sobrien	 * optimizer in 9.01, so we break the assignment into two pieces
66859243Sobrien	 * The careful reader here will note that *most* compiler workarounds
66959243Sobrien	 * in tcsh are either for apollo/DomainOS or hpux. Is it a coincidence?
67059243Sobrien	 */
67159243Sobrien	while ( *(c = p) != '\0') {
67259243Sobrien	    p++;
67359243Sobrien	    if (*c == '`') {
67459243Sobrien		gflag |= G_CSH;
67559243Sobrien#ifdef notdef
67659243Sobrien		/*
67759243Sobrien		 * We do want to expand echo `echo '*'`, so we don't\
67859243Sobrien		 * use this piece of code anymore.
67959243Sobrien		 */
68059243Sobrien		while (*p && *p != '`')
68159243Sobrien		    if (*p++ == '\\') {
68259243Sobrien			if (*p)		/* Quoted chars */
68359243Sobrien			    p++;
68459243Sobrien			else
68559243Sobrien			    break;
68659243Sobrien		    }
68759243Sobrien		if (*p)			/* The matching ` */
68859243Sobrien		    p++;
68959243Sobrien		else
69059243Sobrien		    break;
69159243Sobrien#endif
69259243Sobrien	    }
69359243Sobrien	    else if (*c == '{')
69459243Sobrien		gflag |= G_CSH;
69559243Sobrien	    else if (isglob(*c))
69659243Sobrien		gflag |= G_GLOB;
69759243Sobrien	    else if (symlinks == SYM_EXPAND &&
69859243Sobrien		*p && ISDOTDOT(c) && (c == *(t-1) || *(c-1) == '/') )
69959243Sobrien	    	gflag |= G_CSH;
70059243Sobrien	}
70159243Sobrien    }
70259243Sobrien}
70359243Sobrien
70459243Sobrien/*
70559243Sobrien * Command substitute cp.  If literal, then this is a substitution from a
70659243Sobrien * << redirection, and so we should not crunch blanks and tabs, separating
70759243Sobrien * words only at newlines.
70859243Sobrien */
70959243SobrienChar  **
71059243Sobriendobackp(cp, literal)
71159243Sobrien    Char   *cp;
71259243Sobrien    bool    literal;
71359243Sobrien{
71459243Sobrien    register Char *lp, *rp;
71559243Sobrien    Char   *ep, word[LONGBSIZE];
71659243Sobrien
71759243Sobrien    if (pargv) {
71859243Sobrien#ifdef notdef
71959243Sobrien	abort();
72059243Sobrien#endif
72159243Sobrien	blkfree(pargv);
72259243Sobrien    }
72359243Sobrien    pargsiz = GLOBSPACE;
72459243Sobrien    pargv = (Char **) xmalloc((size_t) (sizeof(Char *) * pargsiz));
72559243Sobrien    pargv[0] = NULL;
72659243Sobrien    pargcp = pargs = word;
72759243Sobrien    pargc = 0;
72859243Sobrien    pnleft = LONGBSIZE - 4;
72959243Sobrien    for (;;) {
73059243Sobrien	for (lp = cp; *lp != '`'; lp++) {
73159243Sobrien	    if (*lp == 0) {
73259243Sobrien		if (pargcp != pargs)
73359243Sobrien		    pword(LONGBSIZE);
73459243Sobrien		return (pargv);
73559243Sobrien	    }
73659243Sobrien	    psave(*lp);
73759243Sobrien	}
73859243Sobrien	lp++;
73959243Sobrien	for (rp = lp; *rp && *rp != '`'; rp++)
74059243Sobrien	    if (*rp == '\\') {
74159243Sobrien		rp++;
74259243Sobrien		if (!*rp)
74359243Sobrien		    goto oops;
74459243Sobrien	    }
74559243Sobrien	if (!*rp)
74659243Sobrien    oops:  stderror(ERR_UNMATCHED, '`');
74759243Sobrien	ep = Strsave(lp);
74859243Sobrien	ep[rp - lp] = 0;
74959243Sobrien	backeval(ep, literal);
75059243Sobrien	cp = rp + 1;
75159243Sobrien    }
75259243Sobrien}
75359243Sobrien
75459243Sobrien
75559243Sobrienstatic void
75659243Sobrienbackeval(cp, literal)
75759243Sobrien    Char   *cp;
75859243Sobrien    bool    literal;
75959243Sobrien{
76059243Sobrien    register int icnt, c;
76159243Sobrien    register Char *ip;
76259243Sobrien    struct command faket;
76359243Sobrien    bool    hadnl;
76459243Sobrien    int     pvec[2], quoted;
76559243Sobrien    Char   *fakecom[2], ibuf[BUFSIZE];
76659243Sobrien    char    tibuf[BUFSIZE];
76759243Sobrien
76859243Sobrien    hadnl = 0;
76959243Sobrien    icnt = 0;
77059243Sobrien    quoted = (literal || (cp[0] & QUOTE)) ? QUOTE : 0;
77159243Sobrien    faket.t_dtyp = NODE_COMMAND;
77259243Sobrien    faket.t_dflg = F_BACKQ;
77359243Sobrien    faket.t_dlef = 0;
77459243Sobrien    faket.t_drit = 0;
77559243Sobrien    faket.t_dspr = 0;
77659243Sobrien    faket.t_dcom = fakecom;
77759243Sobrien    fakecom[0] = STRfakecom1;
77859243Sobrien    fakecom[1] = 0;
77959243Sobrien
78059243Sobrien    /*
78159243Sobrien     * We do the psave job to temporarily change the current job so that the
78259243Sobrien     * following fork is considered a separate job.  This is so that when
78359243Sobrien     * backquotes are used in a builtin function that calls glob the "current
78459243Sobrien     * job" is not corrupted.  We only need one level of pushed jobs as long as
78559243Sobrien     * we are sure to fork here.
78659243Sobrien     */
78759243Sobrien    psavejob();
78859243Sobrien
78959243Sobrien    /*
79059243Sobrien     * It would be nicer if we could integrate this redirection more with the
79159243Sobrien     * routines in sh.sem.c by doing a fake execute on a builtin function that
79259243Sobrien     * was piped out.
79359243Sobrien     */
79459243Sobrien    mypipe(pvec);
79559243Sobrien    if (pfork(&faket, -1) == 0) {
79659243Sobrien	struct command *t;
79759243Sobrien
79859243Sobrien	(void) close(pvec[0]);
79959243Sobrien	(void) dmove(pvec[1], 1);
80059243Sobrien	(void) dmove(SHDIAG,  2);
80159243Sobrien	initdesc();
80259243Sobrien	/*
80359243Sobrien	 * Bugfix for nested backquotes by Michael Greim <greim@sbsvax.UUCP>,
80459243Sobrien	 * posted to comp.bugs.4bsd 12 Sep. 1989.
80559243Sobrien	 */
80659243Sobrien	if (pargv)		/* mg, 21.dec.88 */
80759243Sobrien	    blkfree(pargv), pargv = 0, pargsiz = 0;
80859243Sobrien	/* mg, 21.dec.88 */
80959243Sobrien	arginp = cp;
81059243Sobrien	while (*cp)
81159243Sobrien	    *cp++ &= TRIM;
81259243Sobrien
81359243Sobrien        /*
81459243Sobrien	 * In the child ``forget'' everything about current aliases or
81559243Sobrien	 * eval vectors.
81659243Sobrien	 */
81759243Sobrien	alvec = NULL;
81859243Sobrien	evalvec = NULL;
81959243Sobrien	alvecp = NULL;
82059243Sobrien	evalp = NULL;
82159243Sobrien	(void) lex(&paraml);
82259243Sobrien	if (seterr)
82359243Sobrien	    stderror(ERR_OLD);
82459243Sobrien	alias(&paraml);
82559243Sobrien	t = syntax(paraml.next, &paraml, 0);
82659243Sobrien	if (seterr)
82759243Sobrien	    stderror(ERR_OLD);
82859243Sobrien	if (t)
82959243Sobrien	    t->t_dflg |= F_NOFORK;
83059243Sobrien#ifdef SIGTSTP
83159243Sobrien	(void) sigignore(SIGTSTP);
83259243Sobrien#endif
83359243Sobrien#ifdef SIGTTIN
83459243Sobrien	(void) sigignore(SIGTTIN);
83559243Sobrien#endif
83659243Sobrien#ifdef SIGTTOU
83759243Sobrien	(void) sigignore(SIGTTOU);
83859243Sobrien#endif
83959243Sobrien	execute(t, -1, NULL, NULL);
84059243Sobrien	exitstat();
84159243Sobrien    }
84259243Sobrien    xfree((ptr_t) cp);
84359243Sobrien    (void) close(pvec[1]);
84459243Sobrien    c = 0;
84559243Sobrien    ip = NULL;
84659243Sobrien    do {
84759243Sobrien	int     cnt = 0;
84859243Sobrien
84959243Sobrien	for (;;) {
85059243Sobrien	    if (icnt == 0) {
85159243Sobrien		int     i;
85259243Sobrien
85359243Sobrien		ip = ibuf;
85459243Sobrien		do
85559243Sobrien		    icnt = read(pvec[0], tibuf, BUFSIZE);
85659243Sobrien		while (icnt == -1 && errno == EINTR);
85759243Sobrien		if (icnt <= 0) {
85859243Sobrien		    c = -1;
85959243Sobrien		    break;
86059243Sobrien		}
86159243Sobrien		for (i = 0; i < icnt; i++)
86259243Sobrien		    ip[i] = (unsigned char) tibuf[i];
86359243Sobrien	    }
86459243Sobrien	    if (hadnl)
86559243Sobrien		break;
86659243Sobrien	    --icnt;
86759243Sobrien	    c = (*ip++ & TRIM);
86859243Sobrien	    if (c == 0)
86959243Sobrien		break;
87059243Sobrien#ifdef WINNT
87159243Sobrien	    if (c == '\r')
87259243Sobrien	    	c = ' ';
87359243Sobrien#endif /* WINNT */
87459243Sobrien	    if (c == '\n') {
87559243Sobrien		/*
87659243Sobrien		 * Continue around the loop one more time, so that we can eat
87759243Sobrien		 * the last newline without terminating this word.
87859243Sobrien		 */
87959243Sobrien		hadnl = 1;
88059243Sobrien		continue;
88159243Sobrien	    }
88259243Sobrien	    if (!quoted && (c == ' ' || c == '\t'))
88359243Sobrien		break;
88459243Sobrien	    cnt++;
88559243Sobrien	    psave(c | quoted);
88659243Sobrien	}
88759243Sobrien	/*
88859243Sobrien	 * Unless at end-of-file, we will form a new word here if there were
88959243Sobrien	 * characters in the word, or in any case when we take text literally.
89059243Sobrien	 * If we didn't make empty words here when literal was set then we
89159243Sobrien	 * would lose blank lines.
89259243Sobrien	 */
89359243Sobrien	if (c != -1 && (cnt || literal))
89459243Sobrien	    pword(BUFSIZE);
89559243Sobrien	hadnl = 0;
89659243Sobrien    } while (c >= 0);
89759243Sobrien    (void) close(pvec[0]);
89859243Sobrien    pwait();
89959243Sobrien    prestjob();
90059243Sobrien}
90159243Sobrien
90259243Sobrienstatic void
90359243Sobrienpsave(c)
90459243Sobrien    int    c;
90559243Sobrien{
90659243Sobrien    if (--pnleft <= 0)
90759243Sobrien	stderror(ERR_WTOOLONG);
90859243Sobrien    *pargcp++ = (Char) c;
90959243Sobrien}
91059243Sobrien
91159243Sobrienstatic void
91259243Sobrienpword(bufsiz)
91359243Sobrien    int    bufsiz;
91459243Sobrien{
91559243Sobrien    psave(0);
91659243Sobrien    if (pargc == pargsiz - 1) {
91759243Sobrien	pargsiz += GLOBSPACE;
91859243Sobrien	pargv = (Char **) xrealloc((ptr_t) pargv,
91959243Sobrien				   (size_t) (pargsiz * sizeof(Char *)));
92059243Sobrien    }
92159243Sobrien    pargv[pargc++] = Strsave(pargs);
92259243Sobrien    pargv[pargc] = NULL;
92359243Sobrien    pargcp = pargs;
92459243Sobrien    pnleft = bufsiz - 4;
92559243Sobrien}
92659243Sobrien
92759243Sobrienint
92859243SobrienGmatch(string, pattern)
92959243Sobrien    Char *string, *pattern;
93059243Sobrien{
93159243Sobrien    return Gnmatch(string, pattern, NULL);
93259243Sobrien}
93359243Sobrien
93459243Sobrienint
93559243SobrienGnmatch(string, pattern, endstr)
93659243Sobrien    Char *string, *pattern, **endstr;
93759243Sobrien{
93859243Sobrien    Char **blk, **p, *tstring = string;
93959243Sobrien    int	   gpol = 1, gres = 0;
94059243Sobrien
94159243Sobrien    if (*pattern == '^') {
94259243Sobrien	gpol = 0;
94359243Sobrien	pattern++;
94459243Sobrien    }
94559243Sobrien
94659243Sobrien    blk = (Char **) xmalloc((size_t) (GLOBSPACE * sizeof(Char *)));
94759243Sobrien    blk[0] = Strsave(pattern);
94859243Sobrien    blk[1] = NULL;
94959243Sobrien
95059243Sobrien    expbrace(&blk, NULL, GLOBSPACE);
95159243Sobrien
95259243Sobrien    if (endstr == NULL)
95359243Sobrien	/* Exact matches only */
95459243Sobrien	for (p = blk; *p; p++)
95559243Sobrien	    gres |= pmatch(string, *p, &tstring) == 2 ? 1 : 0;
95659243Sobrien    else {
95759243Sobrien	/* partial matches */
95859243Sobrien	int minc = 0x7fffffff;
95959243Sobrien	for (p = blk; *p; p++)
96059243Sobrien	    if (pmatch(string, *p, &tstring) != 0) {
96159243Sobrien		int t = (int) (tstring - string);
96259243Sobrien		gres |= 1;
96359243Sobrien		if (minc == -1 || minc > t)
96459243Sobrien		    minc = t;
96559243Sobrien	    }
96659243Sobrien	*endstr = string + minc;
96759243Sobrien    }
96859243Sobrien
96959243Sobrien    blkfree(blk);
97059243Sobrien    return(gres == gpol);
97159243Sobrien}
97259243Sobrien
97359243Sobrien/* pmatch():
97459243Sobrien *	Return 2 on exact match,
97559243Sobrien *	Return 1 on substring match.
97659243Sobrien *	Return 0 on no match.
97759243Sobrien *	*estr will point to the end of the longest exact or substring match.
97859243Sobrien */
97959243Sobrienstatic int
98059243Sobrienpmatch(string, pattern, estr)
98159243Sobrien    register Char *string, *pattern, **estr;
98259243Sobrien{
98359243Sobrien    register Char stringc, patternc;
98459243Sobrien    int     match, negate_range;
98559243Sobrien    Char    rangec, *oestr, *pestr;
98659243Sobrien
98759243Sobrien    for (;; ++string) {
98859243Sobrien	stringc = *string & TRIM;
98959243Sobrien	/*
99059243Sobrien	 * apollo compiler bug: switch (patternc = *pattern++) dies
99159243Sobrien	 */
99259243Sobrien	patternc = *pattern++;
99359243Sobrien	switch (patternc) {
99459243Sobrien	case 0:
99559243Sobrien	    *estr = string;
99659243Sobrien	    return (stringc == 0 ? 2 : 1);
99759243Sobrien	case '?':
99859243Sobrien	    if (stringc == 0)
99959243Sobrien		return (0);
100059243Sobrien	    *estr = string;
100159243Sobrien	    break;
100259243Sobrien	case '*':
100359243Sobrien	    if (!*pattern) {
100459243Sobrien		while (*string) string++;
100559243Sobrien		*estr = string;
100659243Sobrien		return (2);
100759243Sobrien	    }
100859243Sobrien	    oestr = *estr;
100959243Sobrien	    pestr = NULL;
101059243Sobrien
101159243Sobrien	    do {
101259243Sobrien		switch(pmatch(string, pattern, estr)) {
101359243Sobrien		case 0:
101459243Sobrien		    break;
101559243Sobrien		case 1:
101659243Sobrien		    pestr = *estr;
101759243Sobrien		    break;
101859243Sobrien		case 2:
101959243Sobrien		    return 2;
102059243Sobrien		default:
102159243Sobrien		    abort();	/* Cannot happen */
102259243Sobrien		}
102359243Sobrien		*estr = string;
102459243Sobrien	    }
102559243Sobrien	    while (*string++);
102659243Sobrien
102759243Sobrien	    if (pestr) {
102859243Sobrien		*estr = pestr;
102959243Sobrien		return 1;
103059243Sobrien	    }
103159243Sobrien	    else {
103259243Sobrien		*estr = oestr;
103359243Sobrien		return 0;
103459243Sobrien	    }
103559243Sobrien
103659243Sobrien	case '[':
103759243Sobrien	    match = 0;
103859243Sobrien	    if ((negate_range = (*pattern == '^')) != 0)
103959243Sobrien		pattern++;
104059243Sobrien	    while ((rangec = *pattern++) != '\0') {
104159243Sobrien		if (rangec == ']')
104259243Sobrien		    break;
104359243Sobrien		if (match)
104459243Sobrien		    continue;
104559243Sobrien		if (rangec == '-' && *(pattern-2) != '[' && *pattern  != ']') {
104659243Sobrien		    match = (globcharcoll(stringc, *pattern & TRIM) <= 0 &&
104759243Sobrien		    globcharcoll(*(pattern-2) & TRIM, stringc) <= 0);
104859243Sobrien		    pattern++;
104959243Sobrien		}
105059243Sobrien		else
105159243Sobrien		    match = (stringc == (rangec & TRIM));
105259243Sobrien	    }
105359243Sobrien	    if (rangec == 0)
105459243Sobrien		stderror(ERR_NAME | ERR_MISSING, ']');
105559243Sobrien	    if (match == negate_range)
105659243Sobrien		return (0);
105759243Sobrien	    *estr = string;
105859243Sobrien	    break;
105959243Sobrien	default:
106059243Sobrien	    if ((patternc & TRIM) != stringc)
106159243Sobrien		return (0);
106259243Sobrien	    *estr = string;
106359243Sobrien	    break;
106459243Sobrien	}
106559243Sobrien    }
106659243Sobrien}
106759243Sobrien
106859243Sobrienvoid
106959243SobrienGcat(s1, s2)
107059243Sobrien    Char   *s1, *s2;
107159243Sobrien{
107259243Sobrien    register Char *p, *q;
107359243Sobrien    int     n;
107459243Sobrien
107559243Sobrien    for (p = s1; *p++;)
107659243Sobrien	continue;
107759243Sobrien    for (q = s2; *q++;)
107859243Sobrien	continue;
107959243Sobrien    n = (int) ((p - s1) + (q - s2) - 1);
108059243Sobrien    if (++gargc >= gargsiz) {
108159243Sobrien	gargsiz += GLOBSPACE;
108259243Sobrien	gargv = (Char **) xrealloc((ptr_t) gargv,
108359243Sobrien				   (size_t) (gargsiz * sizeof(Char *)));
108459243Sobrien    }
108559243Sobrien    gargv[gargc] = 0;
108659243Sobrien    p = gargv[gargc - 1] = (Char *) xmalloc((size_t) (n * sizeof(Char)));
108759243Sobrien    for (q = s1; (*p++ = *q++) != '\0';)
108859243Sobrien	continue;
108959243Sobrien    for (p--, q = s2; (*p++ = *q++) != '\0';)
109059243Sobrien	continue;
109159243Sobrien}
109259243Sobrien
109359243Sobrien#ifdef FILEC
109459243Sobrienint
109559243Sobriensortscmp(a, b)
109659243Sobrien    register Char **a, **b;
109759243Sobrien{
109859243Sobrien    if (!a)			/* check for NULL */
109959243Sobrien	return (b ? 1 : 0);
110059243Sobrien    if (!b)
110159243Sobrien	return (-1);
110259243Sobrien
110359243Sobrien    if (!*a)			/* check for NULL */
110459243Sobrien	return (*b ? 1 : 0);
110559243Sobrien    if (!*b)
110659243Sobrien	return (-1);
110759243Sobrien
110859243Sobrien    return (int) collate(*a, *b);
110959243Sobrien}
111059243Sobrien
111159243Sobrien#endif
1112