glob.c revision 1.17 1 /* $NetBSD: glob.c,v 1.17 2000/05/31 22:48:45 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. 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.17 2000/05/31 22:48:45 christos 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 /* NOTREACHED */
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_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:
646 stderror(ERR_UNMATCHED, '`');
647 }
648 ep = Strsave(lp);
649 ep[rp - lp] = 0;
650 backeval(ep, literal);
651 cp = rp + 1;
652 }
653 }
654
655 static void
656 backeval(cp, literal)
657 Char *cp;
658 bool literal;
659 {
660 int icnt, c;
661 Char *ip;
662 struct command faket;
663 bool hadnl;
664 int pvec[2], quoted;
665 Char *fakecom[2], ibuf[BUFSIZE];
666 char tibuf[BUFSIZE];
667
668 hadnl = 0;
669 icnt = 0;
670 quoted = (literal || (cp[0] & QUOTE)) ? QUOTE : 0;
671 faket.t_dtyp = NODE_COMMAND;
672 faket.t_dflg = 0;
673 faket.t_dlef = 0;
674 faket.t_drit = 0;
675 faket.t_dspr = 0;
676 faket.t_dcom = fakecom;
677 fakecom[0] = STRfakecom1;
678 fakecom[1] = 0;
679
680 /*
681 * We do the psave job to temporarily change the current job so that the
682 * following fork is considered a separate job. This is so that when
683 * backquotes are used in a builtin function that calls glob the "current
684 * job" is not corrupted. We only need one level of pushed jobs as long as
685 * we are sure to fork here.
686 */
687 psavejob();
688
689 /*
690 * It would be nicer if we could integrate this redirection more with the
691 * routines in sh.sem.c by doing a fake execute on a builtin function that
692 * was piped out.
693 */
694 mypipe(pvec);
695 if (pfork(&faket, -1) == 0) {
696 struct wordent paraml;
697 struct command *t;
698
699 (void) close(pvec[0]);
700 (void) dmove(pvec[1], 1);
701 (void) dmove(SHERR, 2);
702 initdesc();
703 /*
704 * Bugfix for nested backquotes by Michael Greim <greim (at) sbsvax.UUCP>,
705 * posted to comp.bugs.4bsd 12 Sep. 1989.
706 */
707 if (pargv) /* mg, 21.dec.88 */
708 blkfree(pargv), pargv = 0, pargsiz = 0;
709 /* mg, 21.dec.88 */
710 arginp = cp;
711 while (*cp)
712 *cp++ &= TRIM;
713
714 /*
715 * In the child ``forget'' everything about current aliases or
716 * eval vectors.
717 */
718 alvec = NULL;
719 evalvec = NULL;
720 alvecp = NULL;
721 evalp = NULL;
722 (void) lex(¶ml);
723 if (seterr)
724 stderror(ERR_OLD);
725 alias(¶ml);
726 t = syntax(paraml.next, ¶ml, 0);
727 if (seterr)
728 stderror(ERR_OLD);
729 if (t)
730 t->t_dflg |= F_NOFORK;
731 (void) signal(SIGTSTP, SIG_IGN);
732 (void) signal(SIGTTIN, SIG_IGN);
733 (void) signal(SIGTTOU, SIG_IGN);
734 execute(t, -1, NULL, NULL);
735 exitstat();
736 }
737 xfree((ptr_t) cp);
738 (void) close(pvec[1]);
739 c = 0;
740 ip = NULL;
741 do {
742 int cnt = 0;
743
744 for (;;) {
745 if (icnt == 0) {
746 int i;
747
748 ip = ibuf;
749 do
750 icnt = read(pvec[0], tibuf, BUFSIZE);
751 while (icnt == -1 && errno == EINTR);
752 if (icnt <= 0) {
753 c = -1;
754 break;
755 }
756 for (i = 0; i < icnt; i++)
757 ip[i] = (unsigned char) tibuf[i];
758 }
759 if (hadnl)
760 break;
761 --icnt;
762 c = (*ip++ & TRIM);
763 if (c == 0)
764 break;
765 if (c == '\n') {
766 /*
767 * Continue around the loop one more time, so that we can eat
768 * the last newline without terminating this word.
769 */
770 hadnl = 1;
771 continue;
772 }
773 if (!quoted && (c == ' ' || c == '\t'))
774 break;
775 cnt++;
776 psave(c | quoted);
777 }
778 /*
779 * Unless at end-of-file, we will form a new word here if there were
780 * characters in the word, or in any case when we take text literally.
781 * If we didn't make empty words here when literal was set then we
782 * would lose blank lines.
783 */
784 if (c != -1 && (cnt || literal))
785 pword();
786 hadnl = 0;
787 } while (c >= 0);
788 (void) close(pvec[0]);
789 pwait();
790 prestjob();
791 }
792
793 static void
794 psave(c)
795 int c;
796 {
797 if (--pnleft <= 0)
798 stderror(ERR_WTOOLONG);
799 *pargcp++ = c;
800 }
801
802 static void
803 pword()
804 {
805 psave(0);
806 if (pargc == pargsiz - 1) {
807 pargsiz += GLOBSPACE;
808 pargv = (Char **) xrealloc((ptr_t) pargv,
809 (size_t) pargsiz * sizeof(Char *));
810 }
811 pargv[pargc++] = Strsave(pargs);
812 pargv[pargc] = NULL;
813 pargcp = pargs;
814 pnleft = MAXPATHLEN - 4;
815 }
816
817 int
818 Gmatch(string, pattern)
819 Char *string, *pattern;
820 {
821 Char **blk, **p;
822 int gpol = 1, gres = 0;
823
824 if (*pattern == '^') {
825 gpol = 0;
826 pattern++;
827 }
828
829 blk = (Char **) xmalloc(GLOBSPACE * sizeof(Char *));
830 blk[0] = Strsave(pattern);
831 blk[1] = NULL;
832
833 expbrace(&blk, NULL, GLOBSPACE);
834
835 for (p = blk; *p; p++)
836 gres |= pmatch(string, *p);
837
838 blkfree(blk);
839 return(gres == gpol);
840 }
841
842 static int
843 pmatch(string, pattern)
844 Char *string, *pattern;
845 {
846 Char stringc, patternc;
847 int match, negate_range;
848 Char rangec;
849
850 for (;; ++string) {
851 stringc = *string & TRIM;
852 patternc = *pattern++;
853 switch (patternc) {
854 case 0:
855 return (stringc == 0);
856 case '?':
857 if (stringc == 0)
858 return (0);
859 break;
860 case '*':
861 if (!*pattern)
862 return (1);
863 while (*string)
864 if (Gmatch(string++, pattern))
865 return (1);
866 return (0);
867 case '[':
868 match = 0;
869 if ((negate_range = (*pattern == '^')) != 0)
870 pattern++;
871 while ((rangec = *pattern++) != '\0') {
872 if (rangec == ']')
873 break;
874 if (match)
875 continue;
876 if (rangec == '-' && *(pattern-2) != '[' && *pattern != ']') {
877 match = (stringc <= (*pattern & TRIM) &&
878 (*(pattern-2) & TRIM) <= stringc);
879 pattern++;
880 }
881 else
882 match = (stringc == (rangec & TRIM));
883 }
884 if (rangec == 0)
885 stderror(ERR_NAME | ERR_MISSING, ']');
886 if (match == negate_range)
887 return (0);
888 break;
889 default:
890 if ((patternc & TRIM) != stringc)
891 return (0);
892 break;
893
894 }
895 }
896 }
897
898 void
899 Gcat(s1, s2)
900 Char *s1, *s2;
901 {
902 Char *p, *q;
903 int n;
904
905 for (p = s1; *p++;)
906 continue;
907 for (q = s2; *q++;)
908 continue;
909 n = (p - s1) + (q - s2) - 1;
910 if (++gargc >= gargsiz) {
911 gargsiz += GLOBSPACE;
912 gargv = (Char **) xrealloc((ptr_t) gargv,
913 (size_t) gargsiz * sizeof(Char *));
914 }
915 gargv[gargc] = 0;
916 p = gargv[gargc - 1] = (Char *) xmalloc((size_t) n * sizeof(Char));
917 for (q = s1; (*p++ = *q++) != '\0';)
918 continue;
919 for (p--, q = s2; (*p++ = *q++) != '\0';)
920 continue;
921 }
922
923 #ifdef FILEC
924 int
925 sortscmp(a, b)
926 const ptr_t a, b;
927 {
928 #if defined(NLS) && !defined(NOSTRCOLL)
929 char buf[2048];
930 #endif
931
932 if (!a) /* check for NULL */
933 return (b ? 1 : 0);
934 if (!b)
935 return (-1);
936
937 if (!*(Char **)a) /* check for NULL */
938 return (*(Char **)b ? 1 : 0);
939 if (!*(Char **)b)
940 return (-1);
941
942 #if defined(NLS) && !defined(NOSTRCOLL)
943 (void) strcpy(buf, short2str(*(Char **)a));
944 return ((int) strcoll(buf, short2str(*(Char **)b)));
945 #else
946 return ((int) Strcmp(*(Char **)a, *(Char **)b));
947 #endif
948 }
949 #endif /* FILEC */
950