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