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