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