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