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