usr.sbin/makefs: Add -o c|C option to specify comp|check type
[dragonfly.git] / contrib / tcsh-6 / sh.glob.c
blob992f5e47362d4067ecdda1220ac248b5ab4f8ea4
1 /*
2 * sh.glob.c: Regular expression expansion
3 */
4 /*-
5 * Copyright (c) 1980, 1991 The Regents of the University of California.
6 * All rights reserved.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of the University nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
32 #include "sh.h"
33 #include "tc.h"
34 #include "tw.h"
36 #include "glob.h"
39 * Values for gflag
41 #define G_NONE 0 /* No globbing needed */
42 #define G_GLOB 1 /* string contains *?[] characters */
43 #define G_CSH 2 /* string contains ~`{ characters */
45 #define GLOBSPACE 100 /* Alloc increment */
48 #define LBRC '{'
49 #define RBRC '}'
50 #define LBRK '['
51 #define RBRK ']'
52 #define EOS '\0'
55 * globbing is now done in two stages. In the first pass we expand
56 * csh globbing idioms ~`{ and then we proceed doing the normal
57 * globbing if needed ?*[
59 * Csh type globbing is handled in globexpand() and the rest is
60 * handled in glob() which is part of the 4.4BSD libc.
63 static Char *globtilde (Char *);
64 static Char *handleone (Char *, Char **, int);
65 static Char **libglob (Char **);
66 static Char **globexpand (Char **, int);
67 static int globbrace (const Char *, Char ***);
68 static void expbrace (Char ***, Char ***, int);
69 static void pword (struct blk_buf *, struct Strbuf *);
70 static void backeval (struct blk_buf *, struct Strbuf *, Char *,
71 int);
72 static Char *
73 globtilde(Char *s)
75 Char *name, *u, *home, *res;
77 u = s;
79 if (s[1] == '~')
80 return Strsave(s);
82 for (s++; *s && *s != '/' && *s != ':'; s++)
83 continue;
85 name = Strnsave(u + 1, s - (u + 1));
86 cleanup_push(name, xfree);
87 home = gethdir(name);
88 if (home == NULL) {
89 if (adrof(STRnonomatch)) {
90 cleanup_until(name);
91 return u;
93 if (*name)
94 stderror(ERR_UNKUSER, short2str(name));
95 else
96 stderror(ERR_NOHOME);
98 cleanup_until(name);
99 if (home[0] == '/' && home[1] == '\0' && s[0] == '/')
100 res = Strsave(s);
101 else
102 res = Strspl(home, s);
103 xfree(home);
104 xfree(u);
105 return res;
108 /* Returns a newly allocated string, old or NULL */
109 Char *
110 globequal(Char *old)
112 int dig;
113 const Char *dir;
114 Char *b;
117 * kfk - 17 Jan 1984 - stack hack allows user to get at arbitrary dir names
118 * in stack. PWP: let =foobar pass through (for X windows)
120 if (old[1] == '-' && (old[2] == '\0' || old[2] == '/')) {
121 /* =- */
122 const Char *olddir = varval (STRowd);
124 if (olddir && *olddir &&
125 !dcwd->di_next->di_name && !dcwd->di_prev->di_name)
126 return Strspl(olddir, &old[2]);
127 dig = -1;
128 b = &old[2];
130 else if (Isdigit(old[1])) {
131 /* =<number> */
132 dig = old[1] - '0';
133 for (b = &old[2]; Isdigit(*b); b++)
134 dig = dig * 10 + (*b - '0');
135 if (*b != '\0' && *b != '/')
136 /* =<number>foobar */
137 return old;
139 else
140 /* =foobar */
141 return old;
143 dir = getstakd(dig);
144 if (dir == NULL)
145 return NULL;
146 return Strspl(dir, b);
149 static int
150 globbrace(const Char *s, Char ***bl)
152 struct Strbuf gbuf = Strbuf_INIT;
153 struct blk_buf bb = BLK_BUF_INIT;
154 int i;
155 const Char *p, *pm, *pe, *pl;
156 size_t prefix_len;
158 /* copy part up to the brace */
159 for (p = s; *p != LBRC; p++)
161 prefix_len = p - s;
163 /* check for balanced braces */
164 for (i = 0, pe = ++p; *pe; pe++)
165 if (*pe == LBRK) {
166 /* Ignore everything between [] */
167 for (++pe; *pe != RBRK && *pe != EOS; pe++)
168 continue;
169 if (*pe == EOS)
170 return (-RBRK);
172 else if (*pe == LBRC)
173 i++;
174 else if (*pe == RBRC) {
175 if (i == 0)
176 break;
177 i--;
180 if (i != 0 || *pe == '\0')
181 return (-RBRC);
183 Strbuf_appendn(&gbuf, s, prefix_len);
185 for (i = 0, pl = pm = p; pm <= pe; pm++)
186 switch (*pm) {
187 case LBRK:
188 for (++pm; *pm != RBRK && *pm != EOS; pm++)
189 continue;
190 if (*pm == EOS) {
191 bb_cleanup(&bb);
192 xfree(gbuf.s);
193 return (-RBRK);
195 break;
196 case LBRC:
197 i++;
198 break;
199 case RBRC:
200 if (i) {
201 i--;
202 break;
204 /* FALLTHROUGH */
205 case ',':
206 if (i && *pm == ',')
207 break;
208 else {
209 gbuf.len = prefix_len;
210 Strbuf_appendn(&gbuf, pl, pm - pl);
211 Strbuf_append(&gbuf, pe + 1);
212 Strbuf_terminate(&gbuf);
213 bb_append(&bb, Strsave(gbuf.s));
214 pl = pm + 1;
216 break;
217 default:
218 break;
220 *bl = bb_finish(&bb);
221 xfree(gbuf.s);
222 return bb.len;
226 static void
227 expbrace(Char ***nvp, Char ***elp, int size)
229 Char **vl, **el, **nv, *s;
231 vl = nv = *nvp;
232 if (elp != NULL)
233 el = *elp;
234 else
235 el = vl + blklen(vl);
237 for (s = *vl; s; s = *++vl) {
238 Char **vp, **bp;
240 /* leave {} untouched for find */
241 if (s[0] == '{' && (s[1] == '\0' || (s[1] == '}' && s[2] == '\0')))
242 continue;
243 if (Strchr(s, '{') != NULL) {
244 Char **bl = NULL;
245 int len;
247 if ((len = globbrace(s, &bl)) < 0)
248 stderror(ERR_MISSING, -len);
249 xfree(s);
250 if (len == 1) {
251 *vl-- = *bl;
252 xfree(bl);
253 continue;
255 if (&el[len] >= &nv[size]) {
256 size_t l, e;
257 l = &el[len] - &nv[size];
258 size += GLOBSPACE > l ? GLOBSPACE : l;
259 l = vl - nv;
260 e = el - nv;
261 nv = xrealloc(nv, size * sizeof(Char *));
262 *nvp = nv; /* To keep cleanups working */
263 vl = nv + l;
264 el = nv + e;
266 /* nv vl el bl
267 * | | | |
268 * -.--..-- x--
269 * | len
270 * vp
272 vp = vl--;
273 *vp = *bl;
274 len--;
275 for (bp = el; bp != vp; bp--)
276 bp[len] = *bp;
277 el += len;
278 /* nv vl el bl
279 * | | | |
280 * -.-x --- --
281 * |len
282 * vp
284 vp++;
285 for (bp = bl + 1; *bp; *vp++ = *bp++)
286 continue;
287 xfree(bl);
291 if (elp != NULL)
292 *elp = el;
295 static Char **
296 globexpand(Char **v, int noglob)
298 Char *s;
299 Char ***fnv, **vl, **el;
300 int size = GLOBSPACE;
303 fnv = xmalloc(sizeof(Char ***));
304 *fnv = vl = xmalloc(sizeof(Char *) * size);
305 *vl = NULL;
306 cleanup_push(fnv, blk_indirect_cleanup);
309 * Step 1: expand backquotes.
311 while ((s = *v++) != NULL) {
312 if (Strchr(s, '`')) {
313 int i;
314 Char **expanded;
316 expanded = dobackp(s, 0);
317 for (i = 0; expanded[i] != NULL; i++) {
318 *vl++ = expanded[i];
319 if (vl == &(*fnv)[size]) {
320 size += GLOBSPACE;
321 *fnv = xrealloc(*fnv, size * sizeof(Char *));
322 vl = &(*fnv)[size - GLOBSPACE];
325 xfree(expanded);
327 else {
328 *vl++ = Strsave(s);
329 if (vl == &(*fnv)[size]) {
330 size += GLOBSPACE;
331 *fnv = xrealloc(*fnv, size * sizeof(Char *));
332 vl = &(*fnv)[size - GLOBSPACE];
335 *vl = NULL;
338 if (noglob)
339 goto done;
342 * Step 2: expand braces
344 el = vl;
345 expbrace(fnv, &el, size);
349 * Step 3: expand ~ =
351 vl = *fnv;
352 for (s = *vl; s; s = *++vl)
353 switch (*s) {
354 Char *ns;
355 case '~':
356 *vl = globtilde(s);
357 break;
358 case '=':
359 if ((ns = globequal(s)) == NULL) {
360 if (!adrof(STRnonomatch))
361 stderror(ERR_DEEP); /* Error */
363 if (ns && ns != s) {
364 /* Expansion succeeded */
365 xfree(s);
366 *vl = ns;
368 break;
369 default:
370 break;
372 vl = *fnv;
375 * Step 4: expand .. if the variable symlinks==expand is set
377 if (symlinks == SYM_EXPAND) {
378 for (s = *vl; s; s = *++vl) {
379 *vl = dnormalize(s, 1);
380 xfree(s);
384 done:
385 cleanup_ignore(fnv);
386 cleanup_until(fnv);
387 vl = *fnv;
388 xfree(fnv);
389 return vl;
392 static Char *
393 handleone(Char *str, Char **vl, int action)
395 size_t chars;
396 Char **t, *p, *strp;
398 switch (action) {
399 case G_ERROR:
400 setname(short2str(str));
401 blkfree(vl);
402 stderror(ERR_NAME | ERR_AMBIG);
403 break;
404 case G_APPEND:
405 chars = 0;
406 for (t = vl; (p = *t++) != NULL; chars++)
407 chars += Strlen(p);
408 str = xmalloc(chars * sizeof(Char));
409 for (t = vl, strp = str; (p = *t++) != NULL; chars++) {
410 while (*p)
411 *strp++ = *p++ & TRIM;
412 *strp++ = ' ';
414 *--strp = '\0';
415 blkfree(vl);
416 break;
417 case G_IGNORE:
418 str = Strsave(strip(*vl));
419 blkfree(vl);
420 break;
421 default:
422 break;
424 return (str);
427 static Char **
428 libglob(Char **vl)
430 int gflgs = GLOB_QUOTE | GLOB_NOMAGIC | GLOB_ALTNOT;
431 glob_t globv;
432 char *ptr;
433 int nonomatch = adrof(STRnonomatch) != 0, magic = 0, match = 0;
435 if (adrof(STRglobdot))
436 gflgs |= GLOB_DOT;
438 if (adrof(STRglobstar))
439 gflgs |= GLOB_STAR;
441 if (!vl || !vl[0])
442 return(vl);
444 globv.gl_offs = 0;
445 globv.gl_pathv = 0;
446 globv.gl_pathc = 0;
448 if (nonomatch)
449 gflgs |= GLOB_NOCHECK;
451 do {
452 ptr = short2qstr(*vl);
453 switch (glob(ptr, gflgs, 0, &globv)) {
454 case GLOB_ABEND:
455 globfree(&globv);
456 setname(ptr);
457 stderror(ERR_NAME | ERR_GLOB);
458 /* NOTREACHED */
459 case GLOB_NOSPACE:
460 globfree(&globv);
461 stderror(ERR_NOMEM);
462 /* NOTREACHED */
463 default:
464 break;
466 if (globv.gl_flags & GLOB_MAGCHAR) {
467 match |= (globv.gl_matchc != 0);
468 magic = 1;
470 gflgs |= GLOB_APPEND;
472 while (*++vl);
473 vl = (globv.gl_pathc == 0 || (magic && !match && !nonomatch)) ?
474 NULL : blk2short(globv.gl_pathv);
475 globfree(&globv);
476 return (vl);
479 Char *
480 globone(Char *str, int action)
482 Char *v[2], **vl, **vo;
483 int gflg, noglob;
485 noglob = adrof(STRnoglob) != 0;
486 v[0] = str;
487 v[1] = 0;
488 gflg = tglob(v);
489 if (gflg == G_NONE)
490 return (strip(Strsave(str)));
492 if (gflg & G_CSH) {
494 * Expand back-quote, tilde and brace
496 vo = globexpand(v, noglob);
497 if (noglob || (gflg & G_GLOB) == 0) {
498 vl = vo;
499 goto result;
501 cleanup_push(vo, blk_cleanup);
503 else if (noglob || (gflg & G_GLOB) == 0)
504 return (strip(Strsave(str)));
505 else
506 vo = v;
508 vl = libglob(vo);
509 if (gflg & G_CSH) {
510 if (vl != vo)
511 cleanup_until(vo);
512 else
513 cleanup_ignore(vo);
515 if (vl == NULL) {
516 setname(short2str(str));
517 stderror(ERR_NAME | ERR_NOMATCH);
519 result:
520 if (vl && vl[0] == NULL) {
521 if (vl != v)
522 xfree(vl);
523 return (Strsave(STRNULL));
525 if (vl && vl[1])
526 return (handleone(str, vl, action));
527 else {
528 str = strip(*vl);
529 if (vl != v)
530 xfree(vl);
531 return (str);
535 Char **
536 globall(Char **v, int gflg)
538 Char **vl, **vo;
539 int noglob;
541 if (!v || !v[0])
542 return saveblk(v);
544 noglob = adrof(STRnoglob) != 0;
546 if (gflg & G_CSH)
548 * Expand back-quote, tilde and brace
550 vl = vo = globexpand(v, noglob);
551 else
552 vl = vo = saveblk(v);
554 if (!noglob && (gflg & G_GLOB)) {
555 cleanup_push(vo, blk_cleanup);
556 vl = libglob(vo);
557 if (vl == vo)
558 cleanup_ignore(vo);
559 cleanup_until(vo);
561 else
562 trim(vl);
564 return vl;
567 Char **
568 glob_all_or_error(Char **v)
570 int gflag;
572 gflag = tglob(v);
573 if (gflag) {
574 v = globall(v, gflag);
575 if (v == NULL)
576 stderror(ERR_NAME | ERR_NOMATCH);
577 } else {
578 v = saveblk(v);
579 trim(v);
581 return v;
584 void
585 rscan(Char **t, void (*f) (Char))
587 Char *p;
589 while ((p = *t++) != NULL)
590 while (*p)
591 (*f) (*p++);
594 void
595 trim(Char **t)
597 Char *p;
599 while ((p = *t++) != NULL)
600 while (*p) {
601 #if INVALID_BYTE != 0
602 if ((*p & INVALID_BYTE) != INVALID_BYTE) /* *p < INVALID_BYTE */
603 #endif
604 *p &= TRIM;
605 p++;
610 tglob(Char **t)
612 int gflag;
613 const Char *p;
615 gflag = 0;
616 while ((p = *t++) != NULL) {
617 if (*p == '~' || *p == '=')
618 gflag |= G_CSH;
619 else if (*p == '{' &&
620 (p[1] == '\0' || (p[1] == '}' && p[2] == '\0')))
621 continue;
622 while (*p != '\0') {
623 if (*p == '`') {
624 gflag |= G_CSH;
625 #ifdef notdef
627 * We do want to expand echo `echo '*'`, so we don't\
628 * use this piece of code anymore.
630 p++;
631 while (*p && *p != '`')
632 if (*p++ == '\\') {
633 if (*p) /* Quoted chars */
634 p++;
635 else
636 break;
638 if (!*p) /* The matching ` */
639 break;
640 #endif
642 else if (*p == '{')
643 gflag |= G_CSH;
644 else if (isglob(*p))
645 gflag |= G_GLOB;
646 else if (symlinks == SYM_EXPAND &&
647 p[1] && ISDOTDOT(p) && (p == *(t-1) || *(p-1) == '/') )
648 gflag |= G_CSH;
649 p++;
652 return gflag;
656 * Command substitute cp. If literal, then this is a substitution from a
657 * << redirection, and so we should not crunch blanks and tabs, separating
658 * words only at newlines.
660 Char **
661 dobackp(Char *cp, int literal)
663 struct Strbuf word = Strbuf_INIT;
664 struct blk_buf bb = BLK_BUF_INIT;
665 Char *lp, *rp, *ep;
667 cleanup_push(&bb, bb_cleanup);
668 cleanup_push(&word, Strbuf_cleanup);
669 for (;;) {
670 for (lp = cp; *lp != '\0' && *lp != '`'; lp++)
672 Strbuf_appendn(&word, cp, lp - cp);
673 if (*lp == 0)
674 break;
675 lp++;
676 for (rp = lp; *rp && *rp != '`'; rp++)
677 if (*rp == '\\') {
678 rp++;
679 if (!*rp)
680 goto oops;
682 if (!*rp) {
683 oops:
684 cleanup_until(&bb);
685 stderror(ERR_UNMATCHED, '`');
687 ep = Strnsave(lp, rp - lp);
688 cleanup_push(ep, xfree);
689 backeval(&bb, &word, ep, literal);
690 cleanup_until(ep);
691 cp = rp + 1;
693 if (word.len != 0)
694 pword(&bb, &word);
695 cleanup_ignore(&bb);
696 cleanup_until(&bb);
697 return bb_finish(&bb);
701 static void
702 backeval(struct blk_buf *bb, struct Strbuf *word, Char *cp, int literal)
704 ssize_t icnt;
705 Char c, *ip;
706 struct command faket;
707 int hadnl;
708 int pvec[2], quoted;
709 Char *fakecom[2], ibuf[BUFSIZE];
711 hadnl = 0;
712 icnt = 0;
713 if (!literal) {
714 for (ip = cp; (*ip & QUOTE) != 0; ip++)
715 continue;
716 quoted = *ip == '\0';
717 } else
718 quoted = literal;
719 faket.t_dtyp = NODE_COMMAND;
720 faket.t_dflg = F_BACKQ;
721 faket.t_dlef = 0;
722 faket.t_drit = 0;
723 faket.t_dspr = 0;
724 faket.t_dcom = fakecom;
725 fakecom[0] = STRfakecom1;
726 fakecom[1] = 0;
729 * We do the psave job to temporarily change the current job so that the
730 * following fork is considered a separate job. This is so that when
731 * backquotes are used in a builtin function that calls glob the "current
732 * job" is not corrupted. We only need one level of pushed jobs as long as
733 * we are sure to fork here.
735 psavejob();
736 cleanup_push(&faket, psavejob_cleanup); /* faket is only a marker */
739 * It would be nicer if we could integrate this redirection more with the
740 * routines in sh.sem.c by doing a fake execute on a builtin function that
741 * was piped out.
743 mypipe(pvec);
744 cleanup_push(&pvec[0], open_cleanup);
745 cleanup_push(&pvec[1], open_cleanup);
746 if (pfork(&faket, -1) == 0) {
747 jmp_buf_t osetexit;
748 struct command *t;
749 size_t omark;
751 xclose(pvec[0]);
752 (void) dmove(pvec[1], 1);
753 (void) dmove(SHDIAG, 2);
754 initdesc();
755 closem();
756 arginp = cp;
757 for (arginp = cp; *cp; cp++) {
758 *cp &= TRIM;
759 if (is_set(STRcsubstnonl) && (*cp == '\n' || *cp == '\r'))
760 *cp = ' ';
764 * In the child ``forget'' everything about current aliases or
765 * eval vectors.
767 alvec = NULL;
768 evalvec = NULL;
769 alvecp = NULL;
770 evalp = NULL;
772 omark = cleanup_push_mark();
773 getexit(osetexit);
774 for (;;) {
775 struct wordent paraml1;
776 initlex(&paraml1);
778 (void) setexit();
779 justpr = 0;
781 if (haderr) {
782 /* unwind */
783 doneinp = 0;
784 cleanup_pop_mark(omark);
785 resexit(osetexit);
786 reset();
788 if (seterr) {
789 xfree(seterr);
790 seterr = NULL;
793 freelex(&paraml1);
794 (void) lex(&paraml1);
795 cleanup_push(&paraml1, lex_cleanup);
796 if (seterr)
797 stderror(ERR_OLD);
798 alias(&paraml1);
799 t = syntax(paraml1.next, &paraml1, 0);
800 cleanup_push(t, syntax_cleanup);
801 /* The F_BACKQ flag must set so the job output is correct if
802 * printexitvalue is set. If it's not set, the job output
803 * will have "Exit N" appended where N is the exit status. */
804 if (t)
805 t->t_dflg = F_BACKQ|F_NOFORK;
806 if (seterr)
807 stderror(ERR_OLD);
808 #ifdef SIGTSTP
809 signal(SIGTSTP, SIG_IGN);
810 #endif
811 #ifdef SIGTTIN
812 signal(SIGTTIN, SIG_IGN);
813 #endif
814 #ifdef SIGTTOU
815 signal(SIGTTOU, SIG_IGN);
816 #endif
817 execute(t, -1, NULL, NULL, TRUE);
819 cleanup_until(&paraml1);
822 cleanup_until(&pvec[1]);
823 c = 0;
824 ip = NULL;
825 do {
826 ssize_t cnt = 0;
828 for (;;) {
829 if (icnt == 0) {
830 ip = ibuf;
831 icnt = wide_read(pvec[0], ibuf, BUFSIZE, 0);
832 if (icnt <= 0)
833 goto eof;
835 if (hadnl)
836 break;
837 --icnt;
838 c = (*ip++ & TRIM);
839 if (c == 0)
840 break;
841 #if defined(WINNT_NATIVE) || defined(__CYGWIN__)
842 if (c == '\r')
843 c = ' ';
844 #endif /* WINNT_NATIVE || __CYGWIN__ */
845 if (c == '\n') {
847 * Continue around the loop one more time, so that we can eat
848 * the last newline without terminating this word.
850 hadnl = 1;
851 continue;
853 if (!quoted && (c == ' ' || c == '\t'))
854 break;
855 cnt++;
856 if (c == '\\' || quoted)
857 c |= QUOTE;
858 Strbuf_append1(word, c);
861 * Unless at end-of-file, we will form a new word here if there were
862 * characters in the word, or in any case when we take text literally.
863 * If we didn't make empty words here when literal was set then we
864 * would lose blank lines.
866 if (c != 0 && (cnt || literal))
867 pword(bb, word);
868 hadnl = 0;
869 } while (c > 0);
870 eof:
871 cleanup_until(&pvec[0]);
872 pwait();
873 cleanup_until(&faket); /* psavejob_cleanup(); */
876 static void
877 pword(struct blk_buf *bb, struct Strbuf *word)
879 Char *s;
881 s = Strbuf_finish(word);
882 bb_append(bb, s);
883 *word = Strbuf_init;
887 Gmatch(const Char *string, const Char *pattern)
889 return Gnmatch(string, pattern, NULL);
893 Gnmatch(const Char *string, const Char *pattern, const Char **endstr)
895 Char ***fblk, **p;
896 const Char *tstring = string;
897 int gpol = 1, gres = 0;
899 if (*pattern == '^') {
900 gpol = 0;
901 pattern++;
904 fblk = xmalloc(sizeof(Char ***));
905 *fblk = xmalloc(GLOBSPACE * sizeof(Char *));
906 (*fblk)[0] = Strsave(pattern);
907 (*fblk)[1] = NULL;
909 cleanup_push(fblk, blk_indirect_cleanup);
910 expbrace(fblk, NULL, GLOBSPACE);
912 if (endstr == NULL)
913 /* Exact matches only */
914 for (p = *fblk; *p; p++)
915 gres |= t_pmatch(string, *p, &tstring, 1) == 2 ? 1 : 0;
916 else {
917 const Char *end;
919 /* partial matches */
920 end = Strend(string);
921 for (p = *fblk; *p; p++)
922 if (t_pmatch(string, *p, &tstring, 1) != 0) {
923 gres |= 1;
924 if (end > tstring)
925 end = tstring;
927 *endstr = end;
930 cleanup_until(fblk);
931 return(gres == gpol);
934 /* t_pmatch():
935 * Return 2 on exact match,
936 * Return 1 on substring match.
937 * Return 0 on no match.
938 * *estr will point to the end of the longest exact or substring match.
941 t_pmatch(const Char *string, const Char *pattern, const Char **estr, int cs)
943 Char stringc, patternc, rangec;
944 int match, negate_range;
945 const Char *pestr, *nstring;
947 for (nstring = string;; string = nstring) {
948 stringc = *nstring++ & TRIM;
949 patternc = *pattern++ & TRIM;
950 switch (patternc) {
951 case '\0':
952 *estr = string;
953 return (stringc == '\0' ? 2 : 1);
954 case '?':
955 if (stringc == 0)
956 return (0);
957 break;
958 case '*':
959 if (!*pattern) {
960 *estr = Strend(string);
961 return (2);
963 pestr = NULL;
965 for (;;) {
966 switch(t_pmatch(string, pattern, estr, cs)) {
967 case 0:
968 break;
969 case 1:
970 pestr = *estr;/*FIXME: does not guarantee longest match */
971 break;
972 case 2:
973 return 2;
974 default:
975 abort(); /* Cannot happen */
977 stringc = *string++ & TRIM;
978 if (!stringc)
979 break;
982 if (pestr) {
983 *estr = pestr;
984 return 1;
986 else
987 return 0;
989 case '[':
990 match = 0;
991 if ((negate_range = (*pattern == '^')) != 0)
992 pattern++;
993 while ((rangec = *pattern++ & TRIM) != '\0') {
994 if (rangec == ']')
995 break;
996 if (match)
997 continue;
998 if (*pattern == '-' && pattern[1] != ']') {
999 Char rangec2;
1000 pattern++;
1001 rangec2 = *pattern++ & TRIM;
1002 match = (globcharcoll(stringc, rangec2, 0) <= 0 &&
1003 globcharcoll(rangec, stringc, 0) <= 0);
1005 else
1006 match = (stringc == rangec);
1008 if (rangec == '\0')
1009 stderror(ERR_NAME | ERR_MISSING, ']');
1010 if ((!match) && (stringc == '\0'))
1011 return (0);
1012 if (match == negate_range)
1013 return (0);
1014 break;
1015 default:
1016 if (cs ? patternc != stringc
1017 : Tolower(patternc) != Tolower(stringc))
1018 return (0);
1019 break;