diff options
author | mp <mp@FreeBSD.org> | 2012-02-22 03:36:15 +0000 |
---|---|---|
committer | mp <mp@FreeBSD.org> | 2012-02-22 03:36:15 +0000 |
commit | 3ee51a00f36c11a6172d08d787943dfc63f66110 (patch) | |
tree | 522fd2d4d27770566e466a79d636194e5743d94a /contrib/tcsh/glob.c | |
parent | d177303078ee8f6069218009d6c3c2b6d9d9ca97 (diff) | |
parent | 54c5644df8eb87e7a5b1c4c411e349ac329ee04b (diff) | |
download | FreeBSD-src-3ee51a00f36c11a6172d08d787943dfc63f66110.zip FreeBSD-src-3ee51a00f36c11a6172d08d787943dfc63f66110.tar.gz |
Update to tcsh 6.18.01.
Diffstat (limited to 'contrib/tcsh/glob.c')
-rw-r--r-- | contrib/tcsh/glob.c | 141 |
1 files changed, 97 insertions, 44 deletions
diff --git a/contrib/tcsh/glob.c b/contrib/tcsh/glob.c index a828f63..3680403 100644 --- a/contrib/tcsh/glob.c +++ b/contrib/tcsh/glob.c @@ -83,7 +83,7 @@ typedef unsigned short Char; static int glob1 (Char *, glob_t *, int); static int glob2 (struct strbuf *, const Char *, glob_t *, int); static int glob3 (struct strbuf *, const Char *, const Char *, - glob_t *, int); + const Char *, glob_t *, int); static void globextend (const char *, glob_t *); static int match (const char *, const Char *, const Char *, int); @@ -329,7 +329,7 @@ glob(const char *pattern, int flags, int (*errfunc) (const char *, int), len = mblen((const char *)(patnext - 1), MB_LEN_MAX); if (len == -1) - (void)mblen(NULL, 0); + TCSH_IGNORE(mblen(NULL, 0)); else if (len > 1) { *bufnext++ = (Char) c; while (--len != 0) @@ -389,10 +389,13 @@ glob(const char *pattern, int flags, int (*errfunc) (const char *, int), break; case STAR: pglob->gl_flags |= GLOB_MAGCHAR; - /* collapse adjacent stars to one, to avoid - * exponential behavior + /* collapse adjacent stars to one [or three if globstar], + * to avoid exponential behavior */ - if (bufnext == patbuf || bufnext[-1] != M_ALL) + if (bufnext == patbuf || bufnext[-1] != M_ALL || + ((flags & GLOB_STAR) != 0 && + (bufnext - 1 == patbuf || bufnext[-2] != M_ALL || + bufnext - 2 == patbuf || bufnext[-3] != M_ALL))) *bufnext++ = M_ALL; break; default: @@ -524,25 +527,79 @@ glob2(struct strbuf *pathbuf, const Char *pattern, glob_t *pglob, int no_match) } else { /* need expansion, recurse */ pathbuf->len = orig_len; - return (glob3(pathbuf, pattern, p, pglob, no_match)); + return (glob3(pathbuf, pattern, p, pattern, pglob, no_match)); } } /* NOTREACHED */ } +static size_t +One_Char_mbtowc(__Char *pwc, const Char *s, size_t n) +{ +#ifdef WIDE_STRINGS + char buf[MB_LEN_MAX], *p; + if (n > MB_LEN_MAX) + n = MB_LEN_MAX; + p = buf; + while (p < buf + n && (*p++ = LCHAR(*s++)) != 0) + ; + return one_mbtowc(pwc, buf, n); +#else + *pwc = *s & CHAR; + return 1; +#endif +} + static int glob3(struct strbuf *pathbuf, const Char *pattern, const Char *restpattern, - glob_t *pglob, int no_match) + const Char *pglobstar, glob_t *pglob, int no_match) { DIR *dirp; struct dirent *dp; + struct stat sbuf; int err; Char m_not = (pglob->gl_flags & GLOB_ALTNOT) ? M_ALTNOT : M_NOT; size_t orig_len; + int globstar = 0; + int chase_symlinks = 0; + const Char *termstar = NULL; strbuf_terminate(pathbuf); - errno = 0; + orig_len = pathbuf->len; + errno = err = 0; + + while (pglobstar < restpattern) { + __Char wc; + size_t width = One_Char_mbtowc(&wc, pglobstar, MB_LEN_MAX); + if ((pglobstar[0] & M_MASK) == M_ALL && + (pglobstar[width] & M_MASK) == M_ALL) { + globstar = 1; + chase_symlinks = (pglobstar[2 * width] & M_MASK) == M_ALL; + termstar = pglobstar + (2 + chase_symlinks) * width; + break; + } + pglobstar += width; + } + + if (globstar) { + err = pglobstar==pattern && termstar==restpattern ? + *restpattern == EOS ? + glob2(pathbuf, restpattern - 1, pglob, no_match) : + glob2(pathbuf, restpattern + 1, pglob, no_match) : + glob3(pathbuf, pattern, restpattern, termstar, pglob, no_match); + if (err) + return err; + pathbuf->len = orig_len; + strbuf_terminate(pathbuf); + } + + if (*pathbuf->s && (Lstat(pathbuf->s, &sbuf) || !S_ISDIR(sbuf.st_mode) +#ifdef S_IFLINK + && ((globstar && !chase_symlinks) || !S_ISLNK(sbuf.st_mode)) +#endif + )) + return 0; if (!(dirp = Opendir(pathbuf->s))) { /* todo: don't call for ENOENT or ENOTDIR? */ @@ -553,23 +610,37 @@ glob3(struct strbuf *pathbuf, const Char *pattern, const Char *restpattern, return (0); } - err = 0; - - orig_len = pathbuf->len; /* search directory for matching names */ while ((dp = readdir(dirp)) != NULL) { /* initial DOT must be matched literally */ if (dp->d_name[0] == DOT && *pattern != DOT) - continue; + if (!(pglob->gl_flags & GLOB_DOT) || !dp->d_name[1] || + (dp->d_name[1] == DOT && !dp->d_name[2])) + continue; /*unless globdot and not . or .. */ pathbuf->len = orig_len; strbuf_append(pathbuf, dp->d_name); strbuf_terminate(pathbuf); - if (match(pathbuf->s + orig_len, pattern, restpattern, (int) m_not) - == no_match) - continue; - err = glob2(pathbuf, restpattern, pglob, no_match); - if (err) - break; + + if (globstar) { +#ifdef S_IFLNK + if (!chase_symlinks && + (Lstat(pathbuf->s, &sbuf) || S_ISLNK(sbuf.st_mode))) + continue; +#endif + if (match(pathbuf->s + orig_len, pattern, termstar, + (int)m_not) == no_match) + continue; + strbuf_append1(pathbuf, SEP); + strbuf_terminate(pathbuf); + if ((err = glob2(pathbuf, pglobstar, pglob, no_match)) != 0) + break; + } else { + if (match(pathbuf->s + orig_len, pattern, restpattern, + (int) m_not) == no_match) + continue; + if ((err = glob2(pathbuf, restpattern, pglob, no_match)) != 0) + break; + } } /* todo: check error from readdir? */ closedir(dirp); @@ -613,24 +684,6 @@ globextend(const char *path, glob_t *pglob) pathv[pglob->gl_offs + pglob->gl_pathc] = NULL; } -static size_t -One_Char_mbtowc(__Char *pwc, const Char *s, size_t n) -{ -#ifdef WIDE_STRINGS - char buf[MB_LEN_MAX], *p; - - if (n > MB_LEN_MAX) - n = MB_LEN_MAX; - p = buf; - while (p < buf + n && (*p++ = LCHAR(*s++)) != 0) - ; - return one_mbtowc(pwc, buf, n); -#else - *pwc = *s & CHAR; - return 1; -#endif -} - /* * pattern matching function for filenames. Each occurrence of the * * pattern causes a recursion level. @@ -650,17 +703,17 @@ match(const char *name, const Char *pat, const Char *patend, int m_not) lwk = one_mbtowc(&wk, name, MB_LEN_MAX); switch (c & M_MASK) { case M_ALL: + while (pat < patend && (*pat & M_MASK) == M_ALL) /* eat consecutive '*' */ + pat += One_Char_mbtowc(&wc, pat, MB_LEN_MAX); if (pat == patend) - return (1); - for (;;) { - if (match(name, pat, patend, m_not)) - return (1); + return (1); + while (!match(name, pat, patend, m_not)) { if (*name == EOS) - break; + return (0); name += lwk; lwk = one_mbtowc(&wk, name, MB_LEN_MAX); } - return (0); + return (1); case M_ONE: if (*name == EOS) return (0); @@ -691,9 +744,9 @@ match(const char *name, const Char *pat, const Char *patend, int m_not) return (0); break; default: - name += lwk; - if (samecase(wk) != samecase(wc)) + if (*name == EOS || samecase(wk) != samecase(wc)) return (0); + name += lwk; break; } } |