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