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