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