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