implement FNM_LEADING_DIR extension flag in fnmatch

previously this flag was defined and accepted as a no-op, possibly
breaking some software that uses it. given the choice to remove the
definition and possibly break applications that were already working,
or simply implement the feature, the latter turned out to be easy
enough to make the decision easy.

in the case where the FNM_PATHNAME flag is also set, this
implementation is clean and essentially optimal. otherwise, it's an
inefficient "brute force" implementation. at some point, when cleaning
up and refactoring this code, I may add a more direct code path for
handling FNM_LEADING_DIR in the non-FNM_PATHNAME case, but at this
point my main interest is avoiding introducing new bugs in the code
that implements the standard fnmatch features specified by POSIX.
This commit is contained in:
Rich Felker 2013-12-02 02:08:41 -05:00
parent a223175704
commit a4e10e304d
1 changed files with 9 additions and 2 deletions

View File

@ -288,12 +288,19 @@ int fnmatch(const char *pat, const char *str, int flags)
if (flags & FNM_PATHNAME) for (;;) { if (flags & FNM_PATHNAME) for (;;) {
for (s=str; *s && *s!='/'; s++); for (s=str; *s && *s!='/'; s++);
for (p=pat; (c=pat_next(p, -1, &inc, flags))!=END && c!='/'; p+=inc); for (p=pat; (c=pat_next(p, -1, &inc, flags))!=END && c!='/'; p+=inc);
if (c!=*s) return FNM_NOMATCH; if (c!=*s && (!*s || !(flags & FNM_LEADING_DIR)))
return FNM_NOMATCH;
if (fnmatch_internal(pat, p-pat, str, s-str, flags)) if (fnmatch_internal(pat, p-pat, str, s-str, flags))
return FNM_NOMATCH; return FNM_NOMATCH;
if (!*s) return 0; if (!c) return 0;
str = s+1; str = s+1;
pat = p+inc; pat = p+inc;
} else if (flags & FNM_LEADING_DIR) {
for (s=str; *s; s++) {
if (*s != '/') continue;
if (!fnmatch_internal(pat, -1, str, s-str, flags))
return 0;
}
} }
return fnmatch_internal(pat, -1, str, -1, flags); return fnmatch_internal(pat, -1, str, -1, flags);
} }