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