Home | History | Annotate | Line # | Download | only in csh
glob.c revision 1.1
      1 /*-
      2  * Copyright (c) 1980, 1991 The Regents of the University of California.
      3  * All rights reserved.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions
      7  * are met:
      8  * 1. Redistributions of source code must retain the above copyright
      9  *    notice, this list of conditions and the following disclaimer.
     10  * 2. Redistributions in binary form must reproduce the above copyright
     11  *    notice, this list of conditions and the following disclaimer in the
     12  *    documentation and/or other materials provided with the distribution.
     13  * 3. All advertising materials mentioning features or use of this software
     14  *    must display the following acknowledgement:
     15  *	This product includes software developed by the University of
     16  *	California, Berkeley and its contributors.
     17  * 4. Neither the name of the University nor the names of its contributors
     18  *    may be used to endorse or promote products derived from this software
     19  *    without specific prior written permission.
     20  *
     21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     31  * SUCH DAMAGE.
     32  */
     33 
     34 #ifndef lint
     35 static char sccsid[] = "@(#)glob.c	5.21 (Berkeley) 6/25/91";
     36 #endif /* not lint */
     37 
     38 #include <sys/param.h>
     39 #include <glob.h>
     40 #include <errno.h>
     41 #include <stdlib.h>
     42 #include <string.h>
     43 #include <unistd.h>
     44 #if __STDC__
     45 # include <stdarg.h>
     46 #else
     47 # include <varargs.h>
     48 #endif
     49 
     50 #include "csh.h"
     51 #include "extern.h"
     52 
     53 static int noglob, nonomatch;
     54 static int pargsiz, gargsiz;
     55 
     56 /*
     57  * Values for gflag
     58  */
     59 #define	G_NONE	0		/* No globbing needed			*/
     60 #define	G_GLOB	1		/* string contains *?[] characters	*/
     61 #define	G_CSH	2		/* string contains ~`{ characters	*/
     62 
     63 #define	GLOBSPACE	100	/* Alloc increment			*/
     64 
     65 #define LBRC '{'
     66 #define RBRC '}'
     67 #define LBRK '['
     68 #define RBRK ']'
     69 #define EOS '\0'
     70 
     71 Char  **gargv = NULL;
     72 long    gargc = 0;
     73 Char  **pargv = NULL;
     74 long    pargc = 0;
     75 
     76 /*
     77  * globbing is now done in two stages. In the first pass we expand
     78  * csh globbing idioms ~`{ and then we proceed doing the normal
     79  * globbing if needed ?*[
     80  *
     81  * Csh type globbing is handled in globexpand() and the rest is
     82  * handled in glob() which is part of the 4.4BSD libc.
     83  *
     84  */
     85 static Char	*globtilde __P((Char **, Char *));
     86 static Char	**libglob __P((Char **));
     87 static Char	**globexpand __P((Char **));
     88 static int	globbrace __P((Char *, Char *, Char ***));
     89 static void	pword __P((void));
     90 static void	psave __P((int));
     91 static void	backeval __P((Char *, bool));
     92 
     93 
     94 static Char *
     95 globtilde(nv, s)
     96     Char  **nv, *s;
     97 {
     98     Char    gbuf[MAXPATHLEN], *gstart, *b, *u, *e;
     99 
    100     gstart = gbuf;
    101     *gstart++ = *s++;
    102     u = s;
    103     for (b = gstart, e = &gbuf[MAXPATHLEN - 1]; *s && *s != '/' && b < e;
    104 	 *b++ = *s++);
    105     *b = EOS;
    106     if (gethdir(gstart)) {
    107 	blkfree(nv);
    108 	if (*gstart)
    109 	    stderror(ERR_UNKUSER, short2str(gstart));
    110 	else
    111 	    stderror(ERR_NOHOME);
    112     }
    113     b = &gstart[Strlen(gstart)];
    114     while (*s)
    115 	*b++ = *s++;
    116     *b = EOS;
    117     --u;
    118     xfree((ptr_t) u);
    119     return (Strsave(gstart));
    120 }
    121 
    122 static int
    123 globbrace(s, p, bl)
    124     Char   *s, *p, ***bl;
    125 {
    126     int     i, len;
    127     Char   *pm, *pe, *lm, *pl;
    128     Char  **nv, **vl;
    129     Char    gbuf[MAXPATHLEN];
    130     int     size = GLOBSPACE;
    131 
    132     nv = vl = (Char **) xmalloc((size_t) sizeof(Char *) * size);
    133     *vl = NULL;
    134 
    135     len = 0;
    136     /* copy part up to the brace */
    137     for (lm = gbuf, p = s; *p != LBRC; *lm++ = *p++)
    138 	continue;
    139 
    140     /* check for balanced braces */
    141     for (i = 0, pe = ++p; *pe; pe++)
    142 	if (*pe == LBRK) {
    143 	    /* Ignore everything between [] */
    144 	    for (++pe; *pe != RBRK && *pe != EOS; pe++)
    145 		continue;
    146 	    if (*pe == EOS) {
    147 		blkfree(nv);
    148 		return (-LBRK);
    149 	    }
    150 	}
    151 	else if (*pe == LBRC)
    152 	    i++;
    153 	else if (*pe == RBRC) {
    154 	    if (i == 0)
    155 		break;
    156 	    i--;
    157 	}
    158 
    159     if (i != 0) {
    160 	blkfree(nv);
    161 	return (-LBRC);
    162     }
    163 
    164     for (i = 0, pl = pm = p; pm <= pe; pm++)
    165 	switch (*pm) {
    166 	case LBRK:
    167 	    for (++pm; *pm != RBRK && *pm != EOS; pm++)
    168 		continue;
    169 	    if (*pm == EOS) {
    170 		*vl = NULL;
    171 		blkfree(nv);
    172 		return (-RBRK);
    173 	    }
    174 	    break;
    175 	case LBRC:
    176 	    i++;
    177 	    break;
    178 	case RBRC:
    179 	    if (i) {
    180 		i--;
    181 		break;
    182 	    }
    183 	    /* FALLTHROUGH */
    184 	case ',':
    185 	    if (i && *pm == ',')
    186 		break;
    187 	    else {
    188 		Char    savec = *pm;
    189 
    190 		*pm = EOS;
    191 		(void) Strcpy(lm, pl);
    192 		(void) Strcat(gbuf, pe + 1);
    193 		*pm = savec;
    194 		*vl++ = Strsave(gbuf);
    195 		len++;
    196 		pl = pm + 1;
    197 		if (vl == &nv[size]) {
    198 		    size += GLOBSPACE;
    199 		    nv = (Char **) xrealloc((ptr_t) nv, (size_t)
    200 					    size * sizeof(Char *));
    201 		    vl = &nv[size - GLOBSPACE];
    202 		}
    203 	    }
    204 	    break;
    205 	}
    206     *vl = NULL;
    207     *bl = nv;
    208     return (len);
    209 }
    210 
    211 static Char **
    212 globexpand(v)
    213     Char  **v;
    214 {
    215     Char   *s;
    216     Char  **nv, **vl, **el;
    217     int     size = GLOBSPACE;
    218 
    219 
    220     nv = vl = (Char **) xmalloc((size_t) sizeof(Char *) * size);
    221     *vl = NULL;
    222 
    223     /*
    224      * Step 1: expand backquotes.
    225      */
    226     while (s = *v++) {
    227 	if (Strchr(s, '`')) {
    228 	    int     i;
    229 
    230 	    (void) dobackp(s, 0);
    231 	    for (i = 0; i < pargc; i++) {
    232 		*vl++ = pargv[i];
    233 		if (vl == &nv[size]) {
    234 		    size += GLOBSPACE;
    235 		    nv = (Char **) xrealloc((ptr_t) nv,
    236 					    (size_t) size * sizeof(Char *));
    237 		    vl = &nv[size - GLOBSPACE];
    238 		}
    239 	    }
    240 	    xfree((ptr_t) pargv);
    241 	    pargv = NULL;
    242 	}
    243 	else {
    244 	    *vl++ = Strsave(s);
    245 	    if (vl == &nv[size]) {
    246 		size += GLOBSPACE;
    247 		nv = (Char **) xrealloc((ptr_t) nv, (size_t)
    248 					size * sizeof(Char *));
    249 		vl = &nv[size - GLOBSPACE];
    250 	    }
    251 	}
    252     }
    253     *vl = NULL;
    254 
    255     if (noglob)
    256 	return (nv);
    257 
    258     /*
    259      * Step 2: expand braces
    260      */
    261     el = vl;
    262     vl = nv;
    263     for (s = *vl; s; s = *++vl) {
    264 	Char   *b;
    265 	Char  **vp, **bp;
    266 
    267 	if (b = Strchr(s, LBRC)) {
    268 	    Char  **bl;
    269 	    int     len;
    270 
    271 	    if ((len = globbrace(s, b, &bl)) < 0) {
    272 		blkfree(nv);
    273 		stderror(ERR_MISSING, -len);
    274 	    }
    275 	    xfree((ptr_t) s);
    276 	    if (len == 1) {
    277 		*vl-- = *bl;
    278 		xfree((ptr_t) bl);
    279 		continue;
    280 	    }
    281 	    len = blklen(bl);
    282 	    if (&el[len] >= &nv[size]) {
    283 		int     l, e;
    284 
    285 		l = &el[len] - &nv[size];
    286 		size += GLOBSPACE > l ? GLOBSPACE : l;
    287 		l = vl - nv;
    288 		e = el - nv;
    289 		nv = (Char **) xrealloc((ptr_t) nv, (size_t)
    290 					size * sizeof(Char *));
    291 		vl = nv + l;
    292 		el = nv + e;
    293 	    }
    294 	    vp = vl--;
    295 	    *vp = *bl;
    296 	    len--;
    297 	    for (bp = el; bp != vp; bp--)
    298 		bp[len] = *bp;
    299 	    el += len;
    300 	    vp++;
    301 	    for (bp = bl + 1; *bp; *vp++ = *bp++)
    302 		continue;
    303 	    xfree((ptr_t) bl);
    304 	}
    305 
    306     }
    307 
    308     /*
    309      * Step 3: expand ~
    310      */
    311     vl = nv;
    312     for (s = *vl; s; s = *++vl)
    313 	if (*s == '~')
    314 	    *vl = globtilde(nv, s);
    315     vl = nv;
    316     return (vl);
    317 }
    318 
    319 static Char *
    320 handleone(str, vl, action)
    321     Char   *str, **vl;
    322     int     action;
    323 {
    324 
    325     Char   *cp, **vlp = vl;
    326 
    327     switch (action) {
    328     case G_ERROR:
    329 	setname(short2str(str));
    330 	blkfree(vl);
    331 	stderror(ERR_NAME | ERR_AMBIG);
    332 	break;
    333     case G_APPEND:
    334 	trim(vlp);
    335 	str = Strsave(*vlp++);
    336 	do {
    337 	    cp = Strspl(str, STRspace);
    338 	    xfree((ptr_t) str);
    339 	    str = Strspl(cp, *vlp);
    340 	    xfree((ptr_t) cp);
    341 	}
    342 	while (*++vlp);
    343 	blkfree(vl);
    344 	break;
    345     case G_IGNORE:
    346 	str = Strsave(strip(*vlp));
    347 	blkfree(vl);
    348 	break;
    349     }
    350     return (str);
    351 }
    352 
    353 static Char **
    354 libglob(vl)
    355     Char  **vl;
    356 {
    357     int     gflgs = GLOB_QUOTE | GLOB_NOCHECK;
    358     glob_t  globv;
    359     char   *ptr;
    360 
    361     globv.gl_offs = 0;
    362     globv.gl_pathv = 0;
    363     globv.gl_pathc = 0;
    364     nonomatch = adrof(STRnonomatch) != 0;
    365     do {
    366 	ptr = short2qstr(*vl);
    367 	switch (glob(ptr, gflgs, 0, &globv)) {
    368 	case GLOB_ABEND:
    369 	    setname(ptr);
    370 	    stderror(ERR_NAME | ERR_GLOB);
    371 	    /* NOTREACHED */
    372 	case GLOB_NOSPACE:
    373 	    stderror(ERR_NOMEM);
    374 	    /* NOTREACHED */
    375 	default:
    376 	    break;
    377 	}
    378 	if (!nonomatch && (globv.gl_matchc == 0) &&
    379 	    (globv.gl_flags & GLOB_MAGCHAR)) {
    380 	    globfree(&globv);
    381 	    return (NULL);
    382 	}
    383 	gflgs |= GLOB_APPEND;
    384     }
    385     while (*++vl);
    386     vl = blk2short(globv.gl_pathv);
    387     globfree(&globv);
    388     return (vl);
    389 }
    390 
    391 Char   *
    392 globone(str, action)
    393     Char   *str;
    394     int     action;
    395 {
    396 
    397     Char   *v[2], **vl, **vo;
    398 
    399     noglob = adrof(STRnoglob) != 0;
    400     gflag = 0;
    401     v[0] = str;
    402     v[1] = 0;
    403     tglob(v);
    404     if (gflag == G_NONE)
    405 	return (strip(Strsave(str)));
    406 
    407     if (gflag & G_CSH) {
    408 	/*
    409 	 * Expand back-quote, tilde and brace
    410 	 */
    411 	vo = globexpand(v);
    412 	if (noglob || (gflag & G_GLOB) == 0) {
    413 	    if (vo[0] == NULL) {
    414 		xfree((ptr_t) vo);
    415 		return (Strsave(STRNULL));
    416 	    }
    417 	    if (vo[1] != NULL)
    418 		return (handleone(str, vo, action));
    419 	    else {
    420 		str = strip(vo[0]);
    421 		xfree((ptr_t) vo);
    422 		return (str);
    423 	    }
    424 	}
    425     }
    426     else if (noglob || (gflag & G_GLOB) == 0)
    427 	return (strip(Strsave(str)));
    428     else
    429 	vo = v;
    430 
    431     vl = libglob(vo);
    432     if (gflag & G_CSH)
    433 	blkfree(vo);
    434     if (vl == NULL) {
    435 	setname(short2str(str));
    436 	stderror(ERR_NAME | ERR_NOMATCH);
    437     }
    438     if (vl[0] == NULL) {
    439 	xfree((ptr_t) vl);
    440 	return (Strsave(STRNULL));
    441     }
    442     if (vl[1] != NULL)
    443 	return (handleone(str, vl, action));
    444     else {
    445 	str = strip(*vl);
    446 	xfree((ptr_t) vl);
    447 	return (str);
    448     }
    449 }
    450 
    451 Char  **
    452 globall(v)
    453     Char  **v;
    454 {
    455     Char  **vl, **vo;
    456 
    457     if (!v || !v[0]) {
    458 	gargv = saveblk(v);
    459 	gargc = blklen(gargv);
    460 	return (gargv);
    461     }
    462 
    463     noglob = adrof(STRnoglob) != 0;
    464 
    465     if (gflag & G_CSH)
    466 	/*
    467 	 * Expand back-quote, tilde and brace
    468 	 */
    469 	vl = vo = globexpand(v);
    470     else
    471 	vl = vo = saveblk(v);
    472 
    473     if (!noglob && (gflag & G_GLOB)) {
    474 	vl = libglob(vo);
    475 	if (gflag & G_CSH)
    476 	    blkfree(vo);
    477     }
    478 
    479     gargc = vl ? blklen(vl) : 0;
    480     return (gargv = vl);
    481 }
    482 
    483 void
    484 ginit()
    485 {
    486     gargsiz = GLOBSPACE;
    487     gargv = (Char **) xmalloc((size_t) sizeof(Char *) * gargsiz);
    488     gargv[0] = 0;
    489     gargc = 0;
    490 }
    491 
    492 void
    493 rscan(t, f)
    494     register Char **t;
    495     void    (*f) ();
    496 {
    497     register Char *p;
    498 
    499     while (p = *t++)
    500 	while (*p)
    501 	    (*f) (*p++);
    502 }
    503 
    504 void
    505 trim(t)
    506     register Char **t;
    507 {
    508     register Char *p;
    509 
    510     while (p = *t++)
    511 	while (*p)
    512 	    *p++ &= TRIM;
    513 }
    514 
    515 void
    516 tglob(t)
    517     register Char **t;
    518 {
    519     register Char *p, c;
    520 
    521     while (p = *t++) {
    522 	if (*p == '~' || *p == '=')
    523 	    gflag |= G_CSH;
    524 	else if (*p == '{' &&
    525 		 (p[1] == '\0' || p[1] == '}' && p[2] == '\0'))
    526 	    continue;
    527 	while (c = *p++)
    528 	    if (isglob(c))
    529 		gflag |= (c == '{' || c == '`') ? G_CSH : G_GLOB;
    530     }
    531 }
    532 
    533 /*
    534  * Command substitute cp.  If literal, then this is a substitution from a
    535  * << redirection, and so we should not crunch blanks and tabs, separating
    536  * words only at newlines.
    537  */
    538 Char  **
    539 dobackp(cp, literal)
    540     Char   *cp;
    541     bool    literal;
    542 {
    543     register Char *lp, *rp;
    544     Char   *ep, word[MAXPATHLEN];
    545 
    546     if (pargv) {
    547 	abort();
    548 	blkfree(pargv);
    549     }
    550     pargsiz = GLOBSPACE;
    551     pargv = (Char **) xmalloc((size_t) sizeof(Char *) * pargsiz);
    552     pargv[0] = NULL;
    553     pargcp = pargs = word;
    554     pargc = 0;
    555     pnleft = MAXPATHLEN - 4;
    556     for (;;) {
    557 	for (lp = cp; *lp != '`'; lp++) {
    558 	    if (*lp == 0) {
    559 		if (pargcp != pargs)
    560 		    pword();
    561 		return (pargv);
    562 	    }
    563 	    psave(*lp);
    564 	}
    565 	lp++;
    566 	for (rp = lp; *rp && *rp != '`'; rp++)
    567 	    if (*rp == '\\') {
    568 		rp++;
    569 		if (!*rp)
    570 		    goto oops;
    571 	    }
    572 	if (!*rp)
    573     oops:  stderror(ERR_UNMATCHED, '`');
    574 	ep = Strsave(lp);
    575 	ep[rp - lp] = 0;
    576 	backeval(ep, literal);
    577 	cp = rp + 1;
    578     }
    579 }
    580 
    581 static void
    582 backeval(cp, literal)
    583     Char   *cp;
    584     bool    literal;
    585 {
    586     register int icnt, c;
    587     register Char *ip;
    588     struct command faket;
    589     bool    hadnl;
    590     int     pvec[2], quoted;
    591     Char   *fakecom[2], ibuf[BUFSIZ];
    592     char    tibuf[BUFSIZ];
    593 
    594     hadnl = 0;
    595     icnt = 0;
    596     quoted = (literal || (cp[0] & QUOTE)) ? QUOTE : 0;
    597     faket.t_dtyp = NODE_COMMAND;
    598     faket.t_dflg = 0;
    599     faket.t_dlef = 0;
    600     faket.t_drit = 0;
    601     faket.t_dspr = 0;
    602     faket.t_dcom = fakecom;
    603     fakecom[0] = STRfakecom1;
    604     fakecom[1] = 0;
    605 
    606     /*
    607      * We do the psave job to temporarily change the current job so that the
    608      * following fork is considered a separate job.  This is so that when
    609      * backquotes are used in a builtin function that calls glob the "current
    610      * job" is not corrupted.  We only need one level of pushed jobs as long as
    611      * we are sure to fork here.
    612      */
    613     psavejob();
    614 
    615     /*
    616      * It would be nicer if we could integrate this redirection more with the
    617      * routines in sh.sem.c by doing a fake execute on a builtin function that
    618      * was piped out.
    619      */
    620     mypipe(pvec);
    621     if (pfork(&faket, -1) == 0) {
    622 	struct wordent paraml;
    623 	struct command *t;
    624 
    625 	(void) close(pvec[0]);
    626 	(void) dmove(pvec[1], 1);
    627 	(void) dmove(SHDIAG, 2);
    628 	initdesc();
    629 	/*
    630 	 * Bugfix for nested backquotes by Michael Greim <greim (at) sbsvax.UUCP>,
    631 	 * posted to comp.bugs.4bsd 12 Sep. 1989.
    632 	 */
    633 	if (pargv)		/* mg, 21.dec.88 */
    634 	    blkfree(pargv), pargv = 0, pargsiz = 0;
    635 	/* mg, 21.dec.88 */
    636 	arginp = cp;
    637 	while (*cp)
    638 	    *cp++ &= TRIM;
    639 	(void) lex(&paraml);
    640 	if (seterr)
    641 	    stderror(ERR_OLD);
    642 	alias(&paraml);
    643 	t = syntax(paraml.next, &paraml, 0);
    644 	if (seterr)
    645 	    stderror(ERR_OLD);
    646 	if (t)
    647 	    t->t_dflg |= F_NOFORK;
    648 	(void) signal(SIGTSTP, SIG_IGN);
    649 	(void) signal(SIGTTIN, SIG_IGN);
    650 	(void) signal(SIGTTOU, SIG_IGN);
    651 	execute(t, -1, NULL, NULL);
    652 	exitstat();
    653     }
    654     xfree((ptr_t) cp);
    655     (void) close(pvec[1]);
    656     c = 0;
    657     ip = NULL;
    658     do {
    659 	int     cnt = 0;
    660 
    661 	for (;;) {
    662 	    if (icnt == 0) {
    663 		int     i;
    664 
    665 		ip = ibuf;
    666 		do
    667 		    icnt = read(pvec[0], tibuf, BUFSIZ);
    668 		while (icnt == -1 && errno == EINTR);
    669 		if (icnt <= 0) {
    670 		    c = -1;
    671 		    break;
    672 		}
    673 		for (i = 0; i < icnt; i++)
    674 		    ip[i] = (unsigned char) tibuf[i];
    675 	    }
    676 	    if (hadnl)
    677 		break;
    678 	    --icnt;
    679 	    c = (*ip++ & TRIM);
    680 	    if (c == 0)
    681 		break;
    682 	    if (c == '\n') {
    683 		/*
    684 		 * Continue around the loop one more time, so that we can eat
    685 		 * the last newline without terminating this word.
    686 		 */
    687 		hadnl = 1;
    688 		continue;
    689 	    }
    690 	    if (!quoted && (c == ' ' || c == '\t'))
    691 		break;
    692 	    cnt++;
    693 	    psave(c | quoted);
    694 	}
    695 	/*
    696 	 * Unless at end-of-file, we will form a new word here if there were
    697 	 * characters in the word, or in any case when we take text literally.
    698 	 * If we didn't make empty words here when literal was set then we
    699 	 * would lose blank lines.
    700 	 */
    701 	if (c != -1 && (cnt || literal))
    702 	    pword();
    703 	hadnl = 0;
    704     } while (c >= 0);
    705     (void) close(pvec[0]);
    706     pwait();
    707     prestjob();
    708 }
    709 
    710 static void
    711 psave(c)
    712     int    c;
    713 {
    714     if (--pnleft <= 0)
    715 	stderror(ERR_WTOOLONG);
    716     *pargcp++ = c;
    717 }
    718 
    719 static void
    720 pword()
    721 {
    722     psave(0);
    723     if (pargc == pargsiz - 1) {
    724 	pargsiz += GLOBSPACE;
    725 	pargv = (Char **) xrealloc((ptr_t) pargv,
    726 				   (size_t) pargsiz * sizeof(Char *));
    727     }
    728     pargv[pargc++] = Strsave(pargs);
    729     pargv[pargc] = NULL;
    730     pargcp = pargs;
    731     pnleft = MAXPATHLEN - 4;
    732 }
    733 
    734 int
    735 Gmatch(string, pattern)
    736     register Char *string, *pattern;
    737 {
    738     register Char stringc, patternc;
    739     int     match;
    740     Char    rangec;
    741 
    742     for (;; ++string) {
    743 	stringc = *string & TRIM;
    744 	patternc = *pattern++;
    745 	switch (patternc) {
    746 	case 0:
    747 	    return (stringc == 0);
    748 	case '?':
    749 	    if (stringc == 0)
    750 		return (0);
    751 	    break;
    752 	case '*':
    753 	    if (!*pattern)
    754 		return (1);
    755 	    while (*string)
    756 		if (Gmatch(string++, pattern))
    757 		    return (1);
    758 	    return (0);
    759 	case '[':
    760 	    match = 0;
    761 	    while (rangec = *pattern++) {
    762 		if (rangec == ']')
    763 		    if (match)
    764 			break;
    765 		    else
    766 			return (0);
    767 		if (match)
    768 		    continue;
    769 		if (rangec == '-' && *(pattern - 2) != '[' && *pattern != ']') {
    770 		    match = (stringc <= (*pattern & TRIM) &&
    771 			     (*(pattern - 2) & TRIM) <= stringc);
    772 		    pattern++;
    773 		}
    774 		else
    775 		    match = (stringc == rangec);
    776 	    }
    777 	    if (rangec == 0)
    778 		stderror(ERR_NAME | ERR_MISSING, ']');
    779 	    break;
    780 	default:
    781 	    if ((patternc & TRIM) != stringc)
    782 		return (0);
    783 	    break;
    784 
    785 	}
    786     }
    787 }
    788 
    789 void
    790 Gcat(s1, s2)
    791     Char   *s1, *s2;
    792 {
    793     register Char *p, *q;
    794     int     n;
    795 
    796     for (p = s1; *p++;);
    797     for (q = s2; *q++;);
    798     n = (p - s1) + (q - s2) - 1;
    799     if (++gargc >= gargsiz) {
    800 	gargsiz += GLOBSPACE;
    801 	gargv = (Char **) xrealloc((ptr_t) gargv,
    802 				   (size_t) gargsiz * sizeof(Char *));
    803     }
    804     gargv[gargc] = 0;
    805     p = gargv[gargc - 1] = (Char *) xmalloc((size_t) n * sizeof(Char));
    806     for (q = s1; *p++ = *q++;);
    807     for (p--, q = s2; *p++ = *q++;);
    808 }
    809 
    810 #ifdef FILEC
    811 int
    812 sortscmp(a, b)
    813     register Char **a, **b;
    814 {
    815 #if defined(NLS) && !defined(NOSTRCOLL)
    816     char    buf[2048];
    817 
    818 #endif
    819 
    820     if (!a)			/* check for NULL */
    821 	return (b ? 1 : 0);
    822     if (!b)
    823 	return (-1);
    824 
    825     if (!*a)			/* check for NULL */
    826 	return (*b ? 1 : 0);
    827     if (!*b)
    828 	return (-1);
    829 
    830 #if defined(NLS) && !defined(NOSTRCOLL)
    831     (void) strcpy(buf, short2str(*a));
    832     return ((int) strcoll(buf, short2str(*b)));
    833 #else
    834     return ((int) Strcmp(*a, *b));
    835 #endif
    836 }
    837 #endif /* FILEC */
    838