diff options
author | obrien <obrien@FreeBSD.org> | 2000-04-15 04:41:27 +0000 |
---|---|---|
committer | obrien <obrien@FreeBSD.org> | 2000-04-15 04:41:27 +0000 |
commit | 4ad28cefef28ce6bdb44a0532cfe20a2076bc694 (patch) | |
tree | 7679c440a91912ee9586cee3ebab24596c0fe1c4 /contrib/tcsh/sh.glob.c | |
download | FreeBSD-src-4ad28cefef28ce6bdb44a0532cfe20a2076bc694.zip FreeBSD-src-4ad28cefef28ce6bdb44a0532cfe20a2076bc694.tar.gz |
Import the latest version of the 44BSD C-shell -- tcsh-6.09.
Diffstat (limited to 'contrib/tcsh/sh.glob.c')
-rw-r--r-- | contrib/tcsh/sh.glob.c | 1111 |
1 files changed, 1111 insertions, 0 deletions
diff --git a/contrib/tcsh/sh.glob.c b/contrib/tcsh/sh.glob.c new file mode 100644 index 0000000..20faaee --- /dev/null +++ b/contrib/tcsh/sh.glob.c @@ -0,0 +1,1111 @@ +/* $Header: /src/pub/tcsh/sh.glob.c,v 3.43 1998/10/25 15:10:14 christos Exp $ */ +/* + * sh.glob.c: Regular expression expansion + */ +/*- + * Copyright (c) 1980, 1991 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +#include "sh.h" + +RCSID("$Id: sh.glob.c,v 3.43 1998/10/25 15:10:14 christos Exp $") + +#include "tc.h" + +#include "glob.h" + +static int noglob; +static int pargsiz, gargsiz; + +/* + * Values for gflag + */ +#define G_NONE 0 /* No globbing needed */ +#define G_GLOB 1 /* string contains *?[] characters */ +#define G_CSH 2 /* string contains ~`{ characters */ + +#define GLOBSPACE 100 /* Alloc increment */ +#define LONGBSIZE 10240 /* Backquote expansion buffer size */ + + +#define LBRC '{' +#define RBRC '}' +#define LBRK '[' +#define RBRK ']' +#define EOS '\0' + +Char **gargv = NULL; +int gargc = 0; +Char **pargv = NULL; +static int pargc = 0; + +/* + * globbing is now done in two stages. In the first pass we expand + * csh globbing idioms ~`{ and then we proceed doing the normal + * globbing if needed ?*[ + * + * Csh type globbing is handled in globexpand() and the rest is + * handled in glob() which is part of the 4.4BSD libc. + * + */ +static Char *globtilde __P((Char **, Char *)); +static Char *handleone __P((Char *, Char **, int)); +static Char **libglob __P((Char **)); +static Char **globexpand __P((Char **)); +static int globbrace __P((Char *, Char *, Char ***)); +static void expbrace __P((Char ***, Char ***, int)); +static int pmatch __P((Char *, Char *, Char **)); +static void pword __P((int)); +static void psave __P((int)); +static void backeval __P((Char *, bool)); + +static Char * +globtilde(nv, s) + Char **nv, *s; +{ + Char gbuf[BUFSIZE], *gstart, *b, *u, *e; +#ifdef apollo + int slash; +#endif + + gstart = gbuf; + *gstart++ = *s++; + u = s; + for (b = gstart, e = &gbuf[BUFSIZE - 1]; + *s && *s != '/' && *s != ':' && b < e; + *b++ = *s++) + continue; + *b = EOS; + if (gethdir(gstart)) { + if (adrof(STRnonomatch)) + return (--u); + blkfree(nv); + if (*gstart) + stderror(ERR_UNKUSER, short2str(gstart)); + else + stderror(ERR_NOHOME); + } + b = &gstart[Strlen(gstart)]; +#ifdef apollo + slash = gstart[0] == '/' && gstart[1] == '\0'; +#endif + while (*s) + *b++ = *s++; + *b = EOS; + --u; + xfree((ptr_t) u); +#ifdef apollo + if (slash && gstart[1] == '/') + gstart++; +#endif + return (Strsave(gstart)); +} + +Char * +globequal(new, old) + Char *new, *old; +{ + int dig; + Char *b, *d; + + /* + * kfk - 17 Jan 1984 - stack hack allows user to get at arbitrary dir names + * in stack. PWP: let =foobar pass through (for X windows) + */ + if (old[1] == '-' && (old[2] == '\0' || old[2] == '/')) { + /* =- */ + dig = -1; + b = &old[2]; + } + else if (Isdigit(old[1])) { + /* =<number> */ + dig = old[1] - '0'; + for (b = &old[2]; Isdigit(*b); b++) + dig = dig * 10 + (*b - '0'); + if (*b != '\0' && *b != '/') + /* =<number>foobar */ + return old; + } + else + /* =foobar */ + return old; + + if (!getstakd(new, dig)) + return NULL; + + /* Copy the rest of the string */ + for (d = &new[Strlen(new)]; + d < &new[BUFSIZE - 1] && (*d++ = *b++) != '\0';) + continue; + *d = '\0'; + + return new; +} + +static int +globbrace(s, p, bl) + Char *s, *p, ***bl; +{ + int i, len; + Char *pm, *pe, *lm, *pl; + Char **nv, **vl; + Char gbuf[BUFSIZE]; + int size = GLOBSPACE; + + nv = vl = (Char **) xmalloc((size_t) (sizeof(Char *) * size)); + *vl = NULL; + + len = 0; + /* copy part up to the brace */ + for (lm = gbuf, p = s; *p != LBRC; *lm++ = *p++) + continue; + + /* check for balanced braces */ + for (i = 0, pe = ++p; *pe; pe++) + if (*pe == LBRK) { + /* Ignore everything between [] */ + for (++pe; *pe != RBRK && *pe != EOS; pe++) + continue; + if (*pe == EOS) { + blkfree(nv); + return (-RBRK); + } + } + else if (*pe == LBRC) + i++; + else if (*pe == RBRC) { + if (i == 0) + break; + i--; + } + + if (i != 0 || *pe == '\0') { + blkfree(nv); + return (-RBRC); + } + + for (i = 0, pl = pm = p; pm <= pe; pm++) + switch (*pm) { + case LBRK: + for (++pm; *pm != RBRK && *pm != EOS; pm++) + continue; + if (*pm == EOS) { + *vl = NULL; + blkfree(nv); + return (-RBRK); + } + break; + case LBRC: + i++; + break; + case RBRC: + if (i) { + i--; + break; + } + /* FALLTHROUGH */ + case ',': + if (i && *pm == ',') + break; + else { + Char savec = *pm; + + *pm = EOS; + (void) Strcpy(lm, pl); + (void) Strcat(gbuf, pe + 1); + *pm = savec; + *vl++ = Strsave(gbuf); + len++; + pl = pm + 1; + if (vl == &nv[size]) { + size += GLOBSPACE; + nv = (Char **) xrealloc((ptr_t) nv, + (size_t) (size * sizeof(Char *))); + vl = &nv[size - GLOBSPACE]; + } + } + break; + default: + break; + } + *vl = NULL; + *bl = nv; + return (len); +} + + +static void +expbrace(nvp, elp, size) + Char ***nvp, ***elp; + int size; +{ + Char **vl, **el, **nv, *s; + + vl = nv = *nvp; + if (elp != NULL) + el = *elp; + else + for (el = vl; *el; el++) + continue; + + for (s = *vl; s; s = *++vl) { + Char *b; + Char **vp, **bp; + + /* leave {} untouched for find */ + if (s[0] == '{' && (s[1] == '\0' || (s[1] == '}' && s[2] == '\0'))) + continue; + if ((b = Strchr(s, '{')) != NULL) { + Char **bl; + int len; + + if ((len = globbrace(s, b, &bl)) < 0) { + xfree((ptr_t) nv); + stderror(ERR_MISSING, -len); + } + xfree((ptr_t) s); + if (len == 1) { + *vl-- = *bl; + xfree((ptr_t) bl); + continue; + } + if (&el[len] >= &nv[size]) { + int l, e; + l = (int) (&el[len] - &nv[size]); + size += GLOBSPACE > l ? GLOBSPACE : l; + l = (int) (vl - nv); + e = (int) (el - nv); + nv = (Char **) xrealloc((ptr_t) nv, + (size_t) (size * sizeof(Char *))); + vl = nv + l; + el = nv + e; + } + /* nv vl el bl + * | | | | + * -.--..-- x-- + * | len + * vp + */ + vp = vl--; + *vp = *bl; + len--; + for (bp = el; bp != vp; bp--) + bp[len] = *bp; + el += len; + /* nv vl el bl + * | | | | + * -.-x --- -- + * |len + * vp + */ + vp++; + for (bp = bl + 1; *bp; *vp++ = *bp++) + continue; + xfree((ptr_t) bl); + } + + } + if (elp != NULL) + *elp = el; + *nvp = nv; +} + +static Char ** +globexpand(v) + Char **v; +{ + Char *s; + Char **nv, **vl, **el; + int size = GLOBSPACE; + + + nv = vl = (Char **) xmalloc((size_t) (sizeof(Char *) * size)); + *vl = NULL; + + /* + * Step 1: expand backquotes. + */ + while ((s = *v++) != '\0') { + if (Strchr(s, '`')) { + int i; + + (void) dobackp(s, 0); + for (i = 0; i < pargc; i++) { + *vl++ = pargv[i]; + if (vl == &nv[size]) { + size += GLOBSPACE; + nv = (Char **) xrealloc((ptr_t) nv, + (size_t) (size * sizeof(Char *))); + vl = &nv[size - GLOBSPACE]; + } + } + xfree((ptr_t) pargv); + pargv = NULL; + } + else { + *vl++ = Strsave(s); + if (vl == &nv[size]) { + size += GLOBSPACE; + nv = (Char **) xrealloc((ptr_t) nv, + (size_t) (size * sizeof(Char *))); + vl = &nv[size - GLOBSPACE]; + } + } + } + *vl = NULL; + + if (noglob) + return (nv); + + /* + * Step 2: expand braces + */ + el = vl; + expbrace(&nv, &el, size); + + + /* + * Step 3: expand ~ = + */ + vl = nv; + for (s = *vl; s; s = *++vl) + switch (*s) { + Char gp[BUFSIZE], *ns; + case '~': + *vl = globtilde(nv, s); + break; + case '=': + if ((ns = globequal(gp, s)) == NULL) { + if (!adrof(STRnonomatch)) { + /* Error */ + blkfree(nv); + stderror(ERR_DEEP); + } + } + if (ns && ns != s) { + /* Expansion succeeded */ + xfree((ptr_t) s); + *vl = Strsave(gp); + } + break; + default: + break; + } + vl = nv; + + /* + * Step 4: expand .. if the variable symlinks==expand is set + */ + if ( symlinks == SYM_EXPAND ) + for (s = *vl; s; s = *++vl) { + *vl = dnormalize(s, 1); + xfree((ptr_t) s); + } + vl = nv; + + return (vl); +} + +static Char * +handleone(str, vl, action) + Char *str, **vl; + int action; +{ + + Char **vlp = vl; + int chars; + Char **t, *p, *strp; + + switch (action) { + case G_ERROR: + setname(short2str(str)); + blkfree(vl); + stderror(ERR_NAME | ERR_AMBIG); + break; + case G_APPEND: + chars = 0; + for (t = vlp; (p = *t++) != '\0'; chars++) + while (*p++) + chars++; + str = (Char *)xmalloc((size_t)(chars * sizeof(Char))); + for (t = vlp, strp = str; (p = *t++) != '\0'; chars++) { + while (*p) + *strp++ = *p++ & TRIM; + *strp++ = ' '; + } + *--strp = '\0'; + blkfree(vl); + break; + case G_IGNORE: + str = Strsave(strip(*vlp)); + blkfree(vl); + break; + default: + break; + } + return (str); +} + +static Char ** +libglob(vl) + Char **vl; +{ + int gflgs = GLOB_QUOTE | GLOB_NOMAGIC | GLOB_ALTNOT; + glob_t globv; + char *ptr; + int nonomatch = adrof(STRnonomatch) != 0, magic = 0, match = 0; + + if (!vl || !vl[0]) + return(vl); + + globv.gl_offs = 0; + globv.gl_pathv = 0; + globv.gl_pathc = 0; + + if (nonomatch) + gflgs |= GLOB_NOCHECK; + + do { + ptr = short2qstr(*vl); + switch (glob(ptr, gflgs, 0, &globv)) { + case GLOB_ABEND: + globfree(&globv); + setname(ptr); + stderror(ERR_NAME | ERR_GLOB); + /* NOTREACHED */ + case GLOB_NOSPACE: + globfree(&globv); + stderror(ERR_NOMEM); + /* NOTREACHED */ + default: + break; + } + if (globv.gl_flags & GLOB_MAGCHAR) { + match |= (globv.gl_matchc != 0); + magic = 1; + } + gflgs |= GLOB_APPEND; + } + while (*++vl); + vl = (globv.gl_pathc == 0 || (magic && !match && !nonomatch)) ? + NULL : blk2short(globv.gl_pathv); + globfree(&globv); + return (vl); +} + +Char * +globone(str, action) + Char *str; + int action; +{ + + Char *v[2], **vl, **vo; + int gflg; + + noglob = adrof(STRnoglob) != 0; + gflag = 0; + v[0] = str; + v[1] = 0; + tglob(v); + gflg = gflag; + if (gflg == G_NONE) + return (strip(Strsave(str))); + + if (gflg & G_CSH) { + /* + * Expand back-quote, tilde and brace + */ + vo = globexpand(v); + if (noglob || (gflg & G_GLOB) == 0) { + if (vo[0] == NULL) { + xfree((ptr_t) vo); + return (Strsave(STRNULL)); + } + if (vo[1] != NULL) + return (handleone(str, vo, action)); + else { + str = strip(vo[0]); + xfree((ptr_t) vo); + return (str); + } + } + } + else if (noglob || (gflg & G_GLOB) == 0) + return (strip(Strsave(str))); + else + vo = v; + + vl = libglob(vo); + if ((gflg & G_CSH) && vl != vo) + blkfree(vo); + if (vl == NULL) { + setname(short2str(str)); + stderror(ERR_NAME | ERR_NOMATCH); + } + if (vl[0] == NULL) { + xfree((ptr_t) vl); + return (Strsave(STRNULL)); + } + if (vl[1]) + return (handleone(str, vl, action)); + else { + str = strip(*vl); + xfree((ptr_t) vl); + return (str); + } +} + +Char ** +globall(v) + Char **v; +{ + Char **vl, **vo; + int gflg = gflag; + + if (!v || !v[0]) { + gargv = saveblk(v); + gargc = blklen(gargv); + return (gargv); + } + + noglob = adrof(STRnoglob) != 0; + + if (gflg & G_CSH) + /* + * Expand back-quote, tilde and brace + */ + vl = vo = globexpand(v); + else + vl = vo = saveblk(v); + + if (!noglob && (gflg & G_GLOB)) { + vl = libglob(vo); + if (vl != vo) + blkfree(vo); + } + else + trim(vl); + + gargc = vl ? blklen(vl) : 0; + return (gargv = vl); +} + +void +ginit() +{ + gargsiz = GLOBSPACE; + gargv = (Char **) xmalloc((size_t) (sizeof(Char *) * gargsiz)); + gargv[0] = 0; + gargc = 0; +} + +void +rscan(t, f) + register Char **t; + void (*f) __P((int)); +{ + register Char *p; + + while ((p = *t++) != '\0') + while (*p) + (*f) (*p++); +} + +void +trim(t) + register Char **t; +{ + register Char *p; + + while ((p = *t++) != '\0') + while (*p) + *p++ &= TRIM; +} + +void +tglob(t) + register Char **t; +{ + register Char *p, *c; + + while ((p = *t++) != '\0') { + if (*p == '~' || *p == '=') + gflag |= G_CSH; + else if (*p == '{' && + (p[1] == '\0' || (p[1] == '}' && p[2] == '\0'))) + continue; + /* + * The following line used to be *(c = p++), but hp broke their + * optimizer in 9.01, so we break the assignment into two pieces + * The careful reader here will note that *most* compiler workarounds + * in tcsh are either for apollo/DomainOS or hpux. Is it a coincidence? + */ + while ( *(c = p) != '\0') { + p++; + if (*c == '`') { + gflag |= G_CSH; +#ifdef notdef + /* + * We do want to expand echo `echo '*'`, so we don't\ + * use this piece of code anymore. + */ + while (*p && *p != '`') + if (*p++ == '\\') { + if (*p) /* Quoted chars */ + p++; + else + break; + } + if (*p) /* The matching ` */ + p++; + else + break; +#endif + } + else if (*c == '{') + gflag |= G_CSH; + else if (isglob(*c)) + gflag |= G_GLOB; + else if (symlinks == SYM_EXPAND && + *p && ISDOTDOT(c) && (c == *(t-1) || *(c-1) == '/') ) + gflag |= G_CSH; + } + } +} + +/* + * Command substitute cp. If literal, then this is a substitution from a + * << redirection, and so we should not crunch blanks and tabs, separating + * words only at newlines. + */ +Char ** +dobackp(cp, literal) + Char *cp; + bool literal; +{ + register Char *lp, *rp; + Char *ep, word[LONGBSIZE]; + + if (pargv) { +#ifdef notdef + abort(); +#endif + blkfree(pargv); + } + pargsiz = GLOBSPACE; + pargv = (Char **) xmalloc((size_t) (sizeof(Char *) * pargsiz)); + pargv[0] = NULL; + pargcp = pargs = word; + pargc = 0; + pnleft = LONGBSIZE - 4; + for (;;) { + for (lp = cp; *lp != '`'; lp++) { + if (*lp == 0) { + if (pargcp != pargs) + pword(LONGBSIZE); + return (pargv); + } + psave(*lp); + } + lp++; + for (rp = lp; *rp && *rp != '`'; rp++) + if (*rp == '\\') { + rp++; + if (!*rp) + goto oops; + } + if (!*rp) + oops: stderror(ERR_UNMATCHED, '`'); + ep = Strsave(lp); + ep[rp - lp] = 0; + backeval(ep, literal); + cp = rp + 1; + } +} + + +static void +backeval(cp, literal) + Char *cp; + bool literal; +{ + register int icnt, c; + register Char *ip; + struct command faket; + bool hadnl; + int pvec[2], quoted; + Char *fakecom[2], ibuf[BUFSIZE]; + char tibuf[BUFSIZE]; + + hadnl = 0; + icnt = 0; + quoted = (literal || (cp[0] & QUOTE)) ? QUOTE : 0; + faket.t_dtyp = NODE_COMMAND; + faket.t_dflg = F_BACKQ; + faket.t_dlef = 0; + faket.t_drit = 0; + faket.t_dspr = 0; + faket.t_dcom = fakecom; + fakecom[0] = STRfakecom1; + fakecom[1] = 0; + + /* + * We do the psave job to temporarily change the current job so that the + * following fork is considered a separate job. This is so that when + * backquotes are used in a builtin function that calls glob the "current + * job" is not corrupted. We only need one level of pushed jobs as long as + * we are sure to fork here. + */ + psavejob(); + + /* + * It would be nicer if we could integrate this redirection more with the + * routines in sh.sem.c by doing a fake execute on a builtin function that + * was piped out. + */ + mypipe(pvec); + if (pfork(&faket, -1) == 0) { + struct command *t; + + (void) close(pvec[0]); + (void) dmove(pvec[1], 1); + (void) dmove(SHDIAG, 2); + initdesc(); + /* + * Bugfix for nested backquotes by Michael Greim <greim@sbsvax.UUCP>, + * posted to comp.bugs.4bsd 12 Sep. 1989. + */ + if (pargv) /* mg, 21.dec.88 */ + blkfree(pargv), pargv = 0, pargsiz = 0; + /* mg, 21.dec.88 */ + arginp = cp; + while (*cp) + *cp++ &= TRIM; + + /* + * In the child ``forget'' everything about current aliases or + * eval vectors. + */ + alvec = NULL; + evalvec = NULL; + alvecp = NULL; + evalp = NULL; + (void) lex(¶ml); + if (seterr) + stderror(ERR_OLD); + alias(¶ml); + t = syntax(paraml.next, ¶ml, 0); + if (seterr) + stderror(ERR_OLD); + if (t) + t->t_dflg |= F_NOFORK; +#ifdef SIGTSTP + (void) sigignore(SIGTSTP); +#endif +#ifdef SIGTTIN + (void) sigignore(SIGTTIN); +#endif +#ifdef SIGTTOU + (void) sigignore(SIGTTOU); +#endif + execute(t, -1, NULL, NULL); + exitstat(); + } + xfree((ptr_t) cp); + (void) close(pvec[1]); + c = 0; + ip = NULL; + do { + int cnt = 0; + + for (;;) { + if (icnt == 0) { + int i; + + ip = ibuf; + do + icnt = read(pvec[0], tibuf, BUFSIZE); + while (icnt == -1 && errno == EINTR); + if (icnt <= 0) { + c = -1; + break; + } + for (i = 0; i < icnt; i++) + ip[i] = (unsigned char) tibuf[i]; + } + if (hadnl) + break; + --icnt; + c = (*ip++ & TRIM); + if (c == 0) + break; +#ifdef WINNT + if (c == '\r') + c = ' '; +#endif /* WINNT */ + if (c == '\n') { + /* + * Continue around the loop one more time, so that we can eat + * the last newline without terminating this word. + */ + hadnl = 1; + continue; + } + if (!quoted && (c == ' ' || c == '\t')) + break; + cnt++; + psave(c | quoted); + } + /* + * Unless at end-of-file, we will form a new word here if there were + * characters in the word, or in any case when we take text literally. + * If we didn't make empty words here when literal was set then we + * would lose blank lines. + */ + if (c != -1 && (cnt || literal)) + pword(BUFSIZE); + hadnl = 0; + } while (c >= 0); + (void) close(pvec[0]); + pwait(); + prestjob(); +} + +static void +psave(c) + int c; +{ + if (--pnleft <= 0) + stderror(ERR_WTOOLONG); + *pargcp++ = (Char) c; +} + +static void +pword(bufsiz) + int bufsiz; +{ + psave(0); + if (pargc == pargsiz - 1) { + pargsiz += GLOBSPACE; + pargv = (Char **) xrealloc((ptr_t) pargv, + (size_t) (pargsiz * sizeof(Char *))); + } + pargv[pargc++] = Strsave(pargs); + pargv[pargc] = NULL; + pargcp = pargs; + pnleft = bufsiz - 4; +} + +int +Gmatch(string, pattern) + Char *string, *pattern; +{ + return Gnmatch(string, pattern, NULL); +} + +int +Gnmatch(string, pattern, endstr) + Char *string, *pattern, **endstr; +{ + Char **blk, **p, *tstring = string; + int gpol = 1, gres = 0; + + if (*pattern == '^') { + gpol = 0; + pattern++; + } + + blk = (Char **) xmalloc((size_t) (GLOBSPACE * sizeof(Char *))); + blk[0] = Strsave(pattern); + blk[1] = NULL; + + expbrace(&blk, NULL, GLOBSPACE); + + if (endstr == NULL) + /* Exact matches only */ + for (p = blk; *p; p++) + gres |= pmatch(string, *p, &tstring) == 2 ? 1 : 0; + else { + /* partial matches */ + int minc = 0x7fffffff; + for (p = blk; *p; p++) + if (pmatch(string, *p, &tstring) != 0) { + int t = (int) (tstring - string); + gres |= 1; + if (minc == -1 || minc > t) + minc = t; + } + *endstr = string + minc; + } + + blkfree(blk); + return(gres == gpol); +} + +/* pmatch(): + * Return 2 on exact match, + * Return 1 on substring match. + * Return 0 on no match. + * *estr will point to the end of the longest exact or substring match. + */ +static int +pmatch(string, pattern, estr) + register Char *string, *pattern, **estr; +{ + register Char stringc, patternc; + int match, negate_range; + Char rangec, *oestr, *pestr; + + for (;; ++string) { + stringc = *string & TRIM; + /* + * apollo compiler bug: switch (patternc = *pattern++) dies + */ + patternc = *pattern++; + switch (patternc) { + case 0: + *estr = string; + return (stringc == 0 ? 2 : 1); + case '?': + if (stringc == 0) + return (0); + *estr = string; + break; + case '*': + if (!*pattern) { + while (*string) string++; + *estr = string; + return (2); + } + oestr = *estr; + pestr = NULL; + + do { + switch(pmatch(string, pattern, estr)) { + case 0: + break; + case 1: + pestr = *estr; + break; + case 2: + return 2; + default: + abort(); /* Cannot happen */ + } + *estr = string; + } + while (*string++); + + if (pestr) { + *estr = pestr; + return 1; + } + else { + *estr = oestr; + return 0; + } + + case '[': + match = 0; + if ((negate_range = (*pattern == '^')) != 0) + pattern++; + while ((rangec = *pattern++) != '\0') { + if (rangec == ']') + break; + if (match) + continue; + if (rangec == '-' && *(pattern-2) != '[' && *pattern != ']') { + match = (globcharcoll(stringc, *pattern & TRIM) <= 0 && + globcharcoll(*(pattern-2) & TRIM, stringc) <= 0); + pattern++; + } + else + match = (stringc == (rangec & TRIM)); + } + if (rangec == 0) + stderror(ERR_NAME | ERR_MISSING, ']'); + if (match == negate_range) + return (0); + *estr = string; + break; + default: + if ((patternc & TRIM) != stringc) + return (0); + *estr = string; + break; + } + } +} + +void +Gcat(s1, s2) + Char *s1, *s2; +{ + register Char *p, *q; + int n; + + for (p = s1; *p++;) + continue; + for (q = s2; *q++;) + continue; + n = (int) ((p - s1) + (q - s2) - 1); + if (++gargc >= gargsiz) { + gargsiz += GLOBSPACE; + gargv = (Char **) xrealloc((ptr_t) gargv, + (size_t) (gargsiz * sizeof(Char *))); + } + gargv[gargc] = 0; + p = gargv[gargc - 1] = (Char *) xmalloc((size_t) (n * sizeof(Char))); + for (q = s1; (*p++ = *q++) != '\0';) + continue; + for (p--, q = s2; (*p++ = *q++) != '\0';) + continue; +} + +#ifdef FILEC +int +sortscmp(a, b) + register Char **a, **b; +{ + if (!a) /* check for NULL */ + return (b ? 1 : 0); + if (!b) + return (-1); + + if (!*a) /* check for NULL */ + return (*b ? 1 : 0); + if (!*b) + return (-1); + + return (int) collate(*a, *b); +} + +#endif |