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