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