xref: /netbsd-src/bin/csh/glob.c (revision 5f7096188587a2c7c95fa3c69b78e1ec9c7923d0)
1 /*-
2  * Copyright (c) 1980, 1991 The Regents of the University of California.
3  * 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	5.21 (Berkeley) 6/25/91";*/
36 static char rcsid[] = "$Id: glob.c,v 1.5 1993/11/03 18:02:57 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, nonomatch;
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	pword __P((void));
91 static void	psave __P((int));
92 static void	backeval __P((Char *, bool));
93 
94 
95 static Char *
96 globtilde(nv, s)
97     Char  **nv, *s;
98 {
99     Char    gbuf[MAXPATHLEN], *gstart, *b, *u, *e;
100 
101     gstart = gbuf;
102     *gstart++ = *s++;
103     u = s;
104     for (b = gstart, e = &gbuf[MAXPATHLEN - 1]; *s && *s != '/' && b < e;
105 	 *b++ = *s++);
106     *b = EOS;
107     if (gethdir(gstart)) {
108 	blkfree(nv);
109 	if (*gstart)
110 	    stderror(ERR_UNKUSER, short2str(gstart));
111 	else
112 	    stderror(ERR_NOHOME);
113     }
114     b = &gstart[Strlen(gstart)];
115     while (*s)
116 	*b++ = *s++;
117     *b = EOS;
118     --u;
119     xfree((ptr_t) u);
120     return (Strsave(gstart));
121 }
122 
123 static int
124 globbrace(s, p, bl)
125     Char   *s, *p, ***bl;
126 {
127     int     i, len;
128     Char   *pm, *pe, *lm, *pl;
129     Char  **nv, **vl;
130     Char    gbuf[MAXPATHLEN];
131     int     size = GLOBSPACE;
132 
133     nv = vl = (Char **) xmalloc((size_t) sizeof(Char *) * size);
134     *vl = NULL;
135 
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 (-LBRK);
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) {
161 	blkfree(nv);
162 	return (-LBRC);
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 = (Char **) xrealloc((ptr_t) nv, (size_t)
201 					    size * sizeof(Char *));
202 		    vl = &nv[size - GLOBSPACE];
203 		}
204 	    }
205 	    break;
206 	}
207     *vl = NULL;
208     *bl = nv;
209     return (len);
210 }
211 
212 static Char **
213 globexpand(v)
214     Char  **v;
215 {
216     Char   *s;
217     Char  **nv, **vl, **el;
218     int     size = GLOBSPACE;
219 
220 
221     nv = vl = (Char **) xmalloc((size_t) sizeof(Char *) * size);
222     *vl = NULL;
223 
224     /*
225      * Step 1: expand backquotes.
226      */
227     while (s = *v++) {
228 	if (Strchr(s, '`')) {
229 	    int     i;
230 
231 	    (void) dobackp(s, 0);
232 	    for (i = 0; i < pargc; i++) {
233 		*vl++ = pargv[i];
234 		if (vl == &nv[size]) {
235 		    size += GLOBSPACE;
236 		    nv = (Char **) xrealloc((ptr_t) nv,
237 					    (size_t) size * sizeof(Char *));
238 		    vl = &nv[size - GLOBSPACE];
239 		}
240 	    }
241 	    xfree((ptr_t) pargv);
242 	    pargv = NULL;
243 	}
244 	else {
245 	    *vl++ = Strsave(s);
246 	    if (vl == &nv[size]) {
247 		size += GLOBSPACE;
248 		nv = (Char **) xrealloc((ptr_t) nv, (size_t)
249 					size * sizeof(Char *));
250 		vl = &nv[size - GLOBSPACE];
251 	    }
252 	}
253     }
254     *vl = NULL;
255 
256     if (noglob)
257 	return (nv);
258 
259     /*
260      * Step 2: expand braces
261      */
262     el = vl;
263     vl = nv;
264     for (s = *vl; s; s = *++vl) {
265 	Char   *b;
266 	Char  **vp, **bp;
267 
268 	if (b = Strchr(s, LBRC)) {
269 	    Char  **bl;
270 	    int     len;
271 
272 	    if ((len = globbrace(s, b, &bl)) < 0) {
273 		blkfree(nv);
274 		stderror(ERR_MISSING, -len);
275 	    }
276 	    xfree((ptr_t) s);
277 	    if (len == 1) {
278 		*vl-- = *bl;
279 		xfree((ptr_t) bl);
280 		continue;
281 	    }
282 	    len = blklen(bl);
283 	    if (&el[len] >= &nv[size]) {
284 		int     l, e;
285 
286 		l = &el[len] - &nv[size];
287 		size += GLOBSPACE > l ? GLOBSPACE : l;
288 		l = vl - nv;
289 		e = el - nv;
290 		nv = (Char **) xrealloc((ptr_t) nv, (size_t)
291 					size * sizeof(Char *));
292 		vl = nv + l;
293 		el = nv + e;
294 	    }
295 	    vp = vl--;
296 	    *vp = *bl;
297 	    len--;
298 	    for (bp = el; bp != vp; bp--)
299 		bp[len] = *bp;
300 	    el += len;
301 	    vp++;
302 	    for (bp = bl + 1; *bp; *vp++ = *bp++)
303 		continue;
304 	    xfree((ptr_t) bl);
305 	}
306 
307     }
308 
309     /*
310      * Step 3: expand ~
311      */
312     vl = nv;
313     for (s = *vl; s; s = *++vl)
314 	if (*s == '~')
315 	    *vl = globtilde(nv, s);
316     vl = nv;
317     return (vl);
318 }
319 
320 static Char *
321 handleone(str, vl, action)
322     Char   *str, **vl;
323     int     action;
324 {
325 
326     Char   *cp, **vlp = vl;
327 
328     switch (action) {
329     case G_ERROR:
330 	setname(short2str(str));
331 	blkfree(vl);
332 	stderror(ERR_NAME | ERR_AMBIG);
333 	break;
334     case G_APPEND:
335 	trim(vlp);
336 	str = Strsave(*vlp++);
337 	do {
338 	    cp = Strspl(str, STRspace);
339 	    xfree((ptr_t) str);
340 	    str = Strspl(cp, *vlp);
341 	    xfree((ptr_t) cp);
342 	}
343 	while (*++vlp);
344 	blkfree(vl);
345 	break;
346     case G_IGNORE:
347 	str = Strsave(strip(*vlp));
348 	blkfree(vl);
349 	break;
350     }
351     return (str);
352 }
353 
354 static Char **
355 libglob(vl)
356     Char  **vl;
357 {
358     int     gflgs = GLOB_QUOTE | GLOB_NOCHECK, badmagic = 0, goodmagic = 0;
359     glob_t  globv;
360     char   *ptr;
361 
362     globv.gl_offs = 0;
363     globv.gl_pathv = 0;
364     globv.gl_pathc = 0;
365     nonomatch = adrof(STRnonomatch) != 0;
366     do {
367 	ptr = short2qstr(*vl);
368 	switch (glob(ptr, gflgs, 0, &globv)) {
369 	case GLOB_ABEND:
370 	    setname(ptr);
371 	    stderror(ERR_NAME | ERR_GLOB);
372 	    /* NOTREACHED */
373 	case GLOB_NOSPACE:
374 	    stderror(ERR_NOMEM);
375 	    /* NOTREACHED */
376 	default:
377 	    break;
378 	}
379 	if (!nonomatch && (globv.gl_matchc == 0) &&
380 	    (globv.gl_flags & GLOB_MAGCHAR)) {
381 	    badmagic = 1;
382 	    globv.gl_pathc--;
383 	    free(globv.gl_pathv[globv.gl_pathc]);
384 	    globv.gl_pathv[globv.gl_pathc] = (char *)0;
385 	} else
386 	    if (!nonomatch && (globv.gl_matchc > 0) &&
387 		(globv.gl_flags & GLOB_MAGCHAR))
388 		goodmagic = 1;
389 	gflgs |= GLOB_APPEND;
390     }
391     while (*++vl);
392     if (badmagic && !goodmagic) {
393 	globfree(&globv);
394 	return (NULL);
395     }
396     vl = blk2short(globv.gl_pathv);
397     globfree(&globv);
398     return (vl);
399 }
400 
401 Char   *
402 globone(str, action)
403     Char   *str;
404     int     action;
405 {
406 
407     Char   *v[2], **vl, **vo;
408 
409     noglob = adrof(STRnoglob) != 0;
410     gflag = 0;
411     v[0] = str;
412     v[1] = 0;
413     tglob(v);
414     if (gflag == G_NONE)
415 	return (strip(Strsave(str)));
416 
417     if (gflag & G_CSH) {
418 	/*
419 	 * Expand back-quote, tilde and brace
420 	 */
421 	vo = globexpand(v);
422 	if (noglob || (gflag & G_GLOB) == 0) {
423 	    if (vo[0] == NULL) {
424 		xfree((ptr_t) vo);
425 		return (Strsave(STRNULL));
426 	    }
427 	    if (vo[1] != NULL)
428 		return (handleone(str, vo, action));
429 	    else {
430 		str = strip(vo[0]);
431 		xfree((ptr_t) vo);
432 		return (str);
433 	    }
434 	}
435     }
436     else if (noglob || (gflag & G_GLOB) == 0)
437 	return (strip(Strsave(str)));
438     else
439 	vo = v;
440 
441     vl = libglob(vo);
442     if (gflag & G_CSH)
443 	blkfree(vo);
444     if (vl == NULL) {
445 	setname(short2str(str));
446 	stderror(ERR_NAME | ERR_NOMATCH);
447     }
448     if (vl[0] == NULL) {
449 	xfree((ptr_t) vl);
450 	return (Strsave(STRNULL));
451     }
452     if (vl[1] != NULL)
453 	return (handleone(str, vl, action));
454     else {
455 	str = strip(*vl);
456 	xfree((ptr_t) vl);
457 	return (str);
458     }
459 }
460 
461 Char  **
462 globall(v)
463     Char  **v;
464 {
465     Char  **vl, **vo;
466 
467     if (!v || !v[0]) {
468 	gargv = saveblk(v);
469 	gargc = blklen(gargv);
470 	return (gargv);
471     }
472 
473     noglob = adrof(STRnoglob) != 0;
474 
475     if (gflag & G_CSH)
476 	/*
477 	 * Expand back-quote, tilde and brace
478 	 */
479 	vl = vo = globexpand(v);
480     else
481 	vl = vo = saveblk(v);
482 
483     if (!noglob && (gflag & G_GLOB)) {
484 	vl = libglob(vo);
485 	if (gflag & G_CSH)
486 	    blkfree(vo);
487     }
488 
489     gargc = vl ? blklen(vl) : 0;
490     return (gargv = vl);
491 }
492 
493 void
494 ginit()
495 {
496     gargsiz = GLOBSPACE;
497     gargv = (Char **) xmalloc((size_t) sizeof(Char *) * gargsiz);
498     gargv[0] = 0;
499     gargc = 0;
500 }
501 
502 void
503 rscan(t, f)
504     register Char **t;
505     void    (*f) ();
506 {
507     register Char *p;
508 
509     while (p = *t++)
510 	while (*p)
511 	    (*f) (*p++);
512 }
513 
514 void
515 trim(t)
516     register Char **t;
517 {
518     register Char *p;
519 
520     while (p = *t++)
521 	while (*p)
522 	    *p++ &= TRIM;
523 }
524 
525 void
526 tglob(t)
527     register Char **t;
528 {
529     register Char *p, c;
530 
531     while (p = *t++) {
532 	if (*p == '~' || *p == '=')
533 	    gflag |= G_CSH;
534 	else if (*p == '{' &&
535 		 (p[1] == '\0' || p[1] == '}' && p[2] == '\0'))
536 	    continue;
537 	while (c = *p++)
538 	    if (isglob(c))
539 		gflag |= (c == '{' || c == '`') ? G_CSH : G_GLOB;
540     }
541 }
542 
543 /*
544  * Command substitute cp.  If literal, then this is a substitution from a
545  * << redirection, and so we should not crunch blanks and tabs, separating
546  * words only at newlines.
547  */
548 Char  **
549 dobackp(cp, literal)
550     Char   *cp;
551     bool    literal;
552 {
553     register Char *lp, *rp;
554     Char   *ep, word[MAXPATHLEN];
555 
556     if (pargv) {
557 	abort();
558 	blkfree(pargv);
559     }
560     pargsiz = GLOBSPACE;
561     pargv = (Char **) xmalloc((size_t) sizeof(Char *) * pargsiz);
562     pargv[0] = NULL;
563     pargcp = pargs = word;
564     pargc = 0;
565     pnleft = MAXPATHLEN - 4;
566     for (;;) {
567 	for (lp = cp; *lp != '`'; lp++) {
568 	    if (*lp == 0) {
569 		if (pargcp != pargs)
570 		    pword();
571 		return (pargv);
572 	    }
573 	    psave(*lp);
574 	}
575 	lp++;
576 	for (rp = lp; *rp && *rp != '`'; rp++)
577 	    if (*rp == '\\') {
578 		rp++;
579 		if (!*rp)
580 		    goto oops;
581 	    }
582 	if (!*rp)
583     oops:  stderror(ERR_UNMATCHED, '`');
584 	ep = Strsave(lp);
585 	ep[rp - lp] = 0;
586 	backeval(ep, literal);
587 	cp = rp + 1;
588     }
589 }
590 
591 static void
592 backeval(cp, literal)
593     Char   *cp;
594     bool    literal;
595 {
596     register int icnt, c;
597     register Char *ip;
598     struct command faket;
599     bool    hadnl;
600     int     pvec[2], quoted;
601     Char   *fakecom[2], ibuf[BUFSIZ];
602     char    tibuf[BUFSIZ];
603 
604     hadnl = 0;
605     icnt = 0;
606     quoted = (literal || (cp[0] & QUOTE)) ? QUOTE : 0;
607     faket.t_dtyp = NODE_COMMAND;
608     faket.t_dflg = 0;
609     faket.t_dlef = 0;
610     faket.t_drit = 0;
611     faket.t_dspr = 0;
612     faket.t_dcom = fakecom;
613     fakecom[0] = STRfakecom1;
614     fakecom[1] = 0;
615 
616     /*
617      * We do the psave job to temporarily change the current job so that the
618      * following fork is considered a separate job.  This is so that when
619      * backquotes are used in a builtin function that calls glob the "current
620      * job" is not corrupted.  We only need one level of pushed jobs as long as
621      * we are sure to fork here.
622      */
623     psavejob();
624 
625     /*
626      * It would be nicer if we could integrate this redirection more with the
627      * routines in sh.sem.c by doing a fake execute on a builtin function that
628      * was piped out.
629      */
630     mypipe(pvec);
631     if (pfork(&faket, -1) == 0) {
632 	struct wordent paraml;
633 	struct command *t;
634 
635 	(void) close(pvec[0]);
636 	(void) dmove(pvec[1], 1);
637 	(void) dmove(SHDIAG, 2);
638 	initdesc();
639 	/*
640 	 * Bugfix for nested backquotes by Michael Greim <greim@sbsvax.UUCP>,
641 	 * posted to comp.bugs.4bsd 12 Sep. 1989.
642 	 */
643 	if (pargv)		/* mg, 21.dec.88 */
644 	    blkfree(pargv), pargv = 0, pargsiz = 0;
645 	/* mg, 21.dec.88 */
646 	arginp = cp;
647 	while (*cp)
648 	    *cp++ &= TRIM;
649 	(void) lex(&paraml);
650 	if (seterr)
651 	    stderror(ERR_OLD);
652 	alias(&paraml);
653 	t = syntax(paraml.next, &paraml, 0);
654 	if (seterr)
655 	    stderror(ERR_OLD);
656 	if (t)
657 	    t->t_dflg |= F_NOFORK;
658 	(void) signal(SIGTSTP, SIG_IGN);
659 	(void) signal(SIGTTIN, SIG_IGN);
660 	(void) signal(SIGTTOU, SIG_IGN);
661 	execute(t, -1, NULL, NULL);
662 	exitstat();
663     }
664     xfree((ptr_t) cp);
665     (void) close(pvec[1]);
666     c = 0;
667     ip = NULL;
668     do {
669 	int     cnt = 0;
670 
671 	for (;;) {
672 	    if (icnt == 0) {
673 		int     i;
674 
675 		ip = ibuf;
676 		do
677 		    icnt = read(pvec[0], tibuf, BUFSIZ);
678 		while (icnt == -1 && errno == EINTR);
679 		if (icnt <= 0) {
680 		    c = -1;
681 		    break;
682 		}
683 		for (i = 0; i < icnt; i++)
684 		    ip[i] = (unsigned char) tibuf[i];
685 	    }
686 	    if (hadnl)
687 		break;
688 	    --icnt;
689 	    c = (*ip++ & TRIM);
690 	    if (c == 0)
691 		break;
692 	    if (c == '\n') {
693 		/*
694 		 * Continue around the loop one more time, so that we can eat
695 		 * the last newline without terminating this word.
696 		 */
697 		hadnl = 1;
698 		continue;
699 	    }
700 	    if (!quoted && (c == ' ' || c == '\t'))
701 		break;
702 	    cnt++;
703 	    psave(c | quoted);
704 	}
705 	/*
706 	 * Unless at end-of-file, we will form a new word here if there were
707 	 * characters in the word, or in any case when we take text literally.
708 	 * If we didn't make empty words here when literal was set then we
709 	 * would lose blank lines.
710 	 */
711 	if (c != -1 && (cnt || literal))
712 	    pword();
713 	hadnl = 0;
714     } while (c >= 0);
715     (void) close(pvec[0]);
716     pwait();
717     prestjob();
718 }
719 
720 static void
721 psave(c)
722     int    c;
723 {
724     if (--pnleft <= 0)
725 	stderror(ERR_WTOOLONG);
726     *pargcp++ = c;
727 }
728 
729 static void
730 pword()
731 {
732     psave(0);
733     if (pargc == pargsiz - 1) {
734 	pargsiz += GLOBSPACE;
735 	pargv = (Char **) xrealloc((ptr_t) pargv,
736 				   (size_t) pargsiz * sizeof(Char *));
737     }
738     pargv[pargc++] = Strsave(pargs);
739     pargv[pargc] = NULL;
740     pargcp = pargs;
741     pnleft = MAXPATHLEN - 4;
742 }
743 
744 int
745 Gmatch(string, pattern)
746     register Char *string, *pattern;
747 {
748     register Char stringc, patternc;
749     int     match;
750     Char    rangec;
751 
752     for (;; ++string) {
753 	stringc = *string & TRIM;
754 	patternc = *pattern++;
755 	switch (patternc) {
756 	case 0:
757 	    return (stringc == 0);
758 	case '?':
759 	    if (stringc == 0)
760 		return (0);
761 	    break;
762 	case '*':
763 	    if (!*pattern)
764 		return (1);
765 	    while (*string)
766 		if (Gmatch(string++, pattern))
767 		    return (1);
768 	    return (0);
769 	case '[':
770 	    match = 0;
771 	    while (rangec = *pattern++) {
772 		if (rangec == ']')
773 		    if (match)
774 			break;
775 		    else
776 			return (0);
777 		if (match)
778 		    continue;
779 		if (rangec == '-' && *(pattern - 2) != '[' && *pattern != ']') {
780 		    match = (stringc <= (*pattern & TRIM) &&
781 			     (*(pattern - 2) & TRIM) <= stringc);
782 		    pattern++;
783 		}
784 		else
785 		    match = (stringc == rangec);
786 	    }
787 	    if (rangec == 0)
788 		stderror(ERR_NAME | ERR_MISSING, ']');
789 	    break;
790 	default:
791 	    if ((patternc & TRIM) != stringc)
792 		return (0);
793 	    break;
794 
795 	}
796     }
797 }
798 
799 void
800 Gcat(s1, s2)
801     Char   *s1, *s2;
802 {
803     register Char *p, *q;
804     int     n;
805 
806     for (p = s1; *p++;);
807     for (q = s2; *q++;);
808     n = (p - s1) + (q - s2) - 1;
809     if (++gargc >= gargsiz) {
810 	gargsiz += GLOBSPACE;
811 	gargv = (Char **) xrealloc((ptr_t) gargv,
812 				   (size_t) gargsiz * sizeof(Char *));
813     }
814     gargv[gargc] = 0;
815     p = gargv[gargc - 1] = (Char *) xmalloc((size_t) n * sizeof(Char));
816     for (q = s1; *p++ = *q++;);
817     for (p--, q = s2; *p++ = *q++;);
818 }
819 
820 #ifdef FILEC
821 int
822 sortscmp(a, b)
823     register Char **a, **b;
824 {
825 #if defined(NLS) && !defined(NOSTRCOLL)
826     char    buf[2048];
827 
828 #endif
829 
830     if (!a)			/* check for NULL */
831 	return (b ? 1 : 0);
832     if (!b)
833 	return (-1);
834 
835     if (!*a)			/* check for NULL */
836 	return (*b ? 1 : 0);
837     if (!*b)
838 	return (-1);
839 
840 #if defined(NLS) && !defined(NOSTRCOLL)
841     (void) strcpy(buf, short2str(*a));
842     return ((int) strcoll(buf, short2str(*b)));
843 #else
844     return ((int) Strcmp(*a, *b));
845 #endif
846 }
847 #endif /* FILEC */
848