xref: /netbsd-src/bin/csh/glob.c (revision 76dfffe33547c37f8bdd446e3e4ab0f3c16cea4b)
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@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