* dir.c (fnmatch):
directory recursion '**/' can be used with File::FNM_PATHNAME. [ruby-dev:22901] * dir.c (fnmatch_helper): only '/' is accepted as path separator even in DOSISH environment. [ruby-dev:22974] [ruby-list:39337] * dir.c (fnmatch_helper): faster '*' matching. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@5944 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
e8ec668627
commit
c6e5374aae
13
ChangeLog
13
ChangeLog
@ -1,3 +1,16 @@
|
|||||||
|
Fri Mar 12 23:52:56 Hirokazu Yamamoto <ocean@m2.ccsnet.ne.jp>
|
||||||
|
|
||||||
|
* dir.c (fnmatch):
|
||||||
|
directory recursion '**/' can be used with File::FNM_PATHNAME.
|
||||||
|
[ruby-dev:22901]
|
||||||
|
|
||||||
|
* dir.c (fnmatch_helper):
|
||||||
|
only '/' is accepted as path separator even in DOSISH environment.
|
||||||
|
[ruby-dev:22974] [ruby-list:39337]
|
||||||
|
|
||||||
|
* dir.c (fnmatch_helper):
|
||||||
|
faster '*' matching.
|
||||||
|
|
||||||
Fri Mar 12 20:19:16 2004 Nobuyoshi Nakada <nobu@ruby-lang.org>
|
Fri Mar 12 20:19:16 2004 Nobuyoshi Nakada <nobu@ruby-lang.org>
|
||||||
|
|
||||||
* configure.in (rb_cv_noreturn): default for platforms not support
|
* configure.in (rb_cv_noreturn): default for platforms not support
|
||||||
|
246
dir.c
246
dir.c
@ -164,150 +164,174 @@ CompareImpl(p1, p2, nocase)
|
|||||||
}
|
}
|
||||||
#endif /* environment */
|
#endif /* environment */
|
||||||
|
|
||||||
#if defined DOSISH
|
static char *
|
||||||
#define isdirsep(c) ((c) == '/' || (c) == '\\')
|
bracket(p, s, flags)
|
||||||
#else
|
const char *p; /* pattern (next to '[') */
|
||||||
#define isdirsep(c) ((c) == '/')
|
const char *s; /* string */
|
||||||
#endif
|
int flags;
|
||||||
|
|
||||||
static const char *
|
|
||||||
range(
|
|
||||||
const char *p, /* pattern */
|
|
||||||
const char *test,
|
|
||||||
int flags)
|
|
||||||
{
|
{
|
||||||
int not = 0, ok = 0;
|
|
||||||
const char *t1, *t2;
|
|
||||||
const int nocase = flags & FNM_CASEFOLD;
|
const int nocase = flags & FNM_CASEFOLD;
|
||||||
const int escape = !(flags & FNM_NOESCAPE);
|
const int escape = !(flags & FNM_NOESCAPE);
|
||||||
|
|
||||||
|
int ok = 0, not = 0;
|
||||||
|
|
||||||
if (*p == '!' || *p == '^') {
|
if (*p == '!' || *p == '^') {
|
||||||
not = 1;
|
not = 1;
|
||||||
p++;
|
p++;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (*p) {
|
while (*p != ']') {
|
||||||
if (*p == ']')
|
const char *t1 = p;
|
||||||
return ok == not ? 0 : p + 1;
|
|
||||||
t1 = p;
|
|
||||||
if (escape && *t1 == '\\')
|
if (escape && *t1 == '\\')
|
||||||
t1++;
|
t1++;
|
||||||
if (!*t1)
|
if (!*t1)
|
||||||
break;
|
return 0;
|
||||||
p = Next(t1);
|
p = Next(t1);
|
||||||
if (*p == '-' && p[1] != ']') {
|
if (p[0] == '-' && p[1] != ']') {
|
||||||
t2 = p + 1;
|
const char *t2 = p + 1;
|
||||||
if (escape && *t2 == '\\')
|
if (escape && *t2 == '\\')
|
||||||
t2++;
|
t2++;
|
||||||
if (!*t2)
|
if (!*t2)
|
||||||
break;
|
|
||||||
p = Next(t2);
|
|
||||||
if (!ok && Compare(t1, test) <= 0 && Compare(test, t2) <= 0)
|
|
||||||
ok = 1;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (!ok && Compare(t1, test) == 0)
|
|
||||||
ok = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
p = Next(t2);
|
||||||
|
if (!ok && Compare(t1, s) <= 0 && Compare(s, t2) <= 0)
|
||||||
|
ok = 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if (!ok && Compare(t1, s) == 0)
|
||||||
|
ok = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define ISDIRSEP(c) (pathname && isdirsep(c))
|
return ok == not ? 0 : (char *)p + 1;
|
||||||
#define PERIOD_S() (period && *s == '.' && \
|
}
|
||||||
(!s_prev || ISDIRSEP(*s_prev)))
|
|
||||||
#define INC_S() (s = Next(s_prev = s))
|
/* If FNM_PATHNAME is set, only path element will be matched. (upto '/' or '\0')
|
||||||
|
Otherwise, entire string will be matched.
|
||||||
|
End marker itself won't be compared.
|
||||||
|
And if function succeeds, *pcur reaches end marker.
|
||||||
|
*/
|
||||||
|
#define ISEND(c) (!(c) || (pathname && (c) == '/'))
|
||||||
|
#define RETURN(val) return *pcur = p, *scur = s, (val);
|
||||||
|
|
||||||
static int
|
static int
|
||||||
fnmatch(pat, string, flags)
|
fnmatch_helper(pcur, scur, flags)
|
||||||
const char *pat;
|
const char **pcur; /* pattern */
|
||||||
const char *string;
|
const char **scur; /* string */
|
||||||
int flags;
|
int flags;
|
||||||
{
|
{
|
||||||
int c;
|
const int period = !(flags & FNM_DOTMATCH);
|
||||||
const char *test;
|
const int escape = !(flags & FNM_NOESCAPE);
|
||||||
const char *s = string, *s_prev = 0;
|
const int nocase = flags & FNM_CASEFOLD;
|
||||||
int escape = !(flags & FNM_NOESCAPE);
|
const int pathname = flags & FNM_PATHNAME;
|
||||||
int pathname = flags & FNM_PATHNAME;
|
|
||||||
int period = !(flags & FNM_DOTMATCH);
|
|
||||||
int nocase = flags & FNM_CASEFOLD;
|
|
||||||
|
|
||||||
while (c = *pat) {
|
const char *ptmp = 0;
|
||||||
switch (c) {
|
const char *stmp = 0;
|
||||||
|
|
||||||
|
const char *p = *pcur;
|
||||||
|
const char *s = *scur;
|
||||||
|
|
||||||
|
if (period && *s == '.' && *p != '.') /* leading period */
|
||||||
|
RETURN(FNM_NOMATCH);
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
if (*p == '*') {
|
||||||
|
do { p++; } while (*p == '*');
|
||||||
|
if (ISEND(*p))
|
||||||
|
RETURN(0);
|
||||||
|
ptmp = p;
|
||||||
|
stmp = s;
|
||||||
|
}
|
||||||
|
if (ISEND(*s)) {
|
||||||
|
RETURN(ISEND(*p) ? 0 : FNM_NOMATCH);
|
||||||
|
}
|
||||||
|
if (ISEND(*p)) {
|
||||||
|
goto failed;
|
||||||
|
}
|
||||||
|
switch (*p) {
|
||||||
case '?':
|
case '?':
|
||||||
if (!*s || ISDIRSEP(*s) || PERIOD_S())
|
p++;
|
||||||
return FNM_NOMATCH;
|
Inc(s);
|
||||||
INC_S();
|
continue;
|
||||||
++pat;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case '*':
|
case '[': {
|
||||||
while ((c = *++pat) == '*')
|
const char *t = bracket(p + 1, s, flags);
|
||||||
;
|
if (t) {
|
||||||
|
p = t;
|
||||||
if (PERIOD_S())
|
Inc(s);
|
||||||
return FNM_NOMATCH;
|
continue;
|
||||||
|
|
||||||
if (!c) {
|
|
||||||
if (pathname && *rb_path_next(s))
|
|
||||||
return FNM_NOMATCH;
|
|
||||||
else
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
else if (ISDIRSEP(c)) {
|
goto failed;
|
||||||
s = rb_path_next(s);
|
|
||||||
if (*s) {
|
|
||||||
INC_S();
|
|
||||||
++pat;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
return FNM_NOMATCH;
|
|
||||||
}
|
|
||||||
|
|
||||||
test = escape && c == '\\' ? pat+1 : pat;
|
|
||||||
while (*s) {
|
|
||||||
if ((c == '?' || c == '[' || Compare(s, test) == 0) &&
|
|
||||||
!fnmatch(pat, s, flags | FNM_DOTMATCH))
|
|
||||||
return 0;
|
|
||||||
else if (ISDIRSEP(*s))
|
|
||||||
break;
|
|
||||||
INC_S();
|
|
||||||
}
|
|
||||||
return FNM_NOMATCH;
|
|
||||||
|
|
||||||
case '[':
|
|
||||||
if (!*s || ISDIRSEP(*s) || PERIOD_S())
|
|
||||||
return FNM_NOMATCH;
|
|
||||||
pat = range(pat+1, s, flags);
|
|
||||||
if (!pat)
|
|
||||||
return FNM_NOMATCH;
|
|
||||||
INC_S();
|
|
||||||
break;
|
|
||||||
|
|
||||||
case '\\':
|
case '\\':
|
||||||
if (escape && pat[1]
|
if (escape && p[1])
|
||||||
#if defined DOSISH
|
p++;
|
||||||
&& strchr("*?[]\\", pat[1])
|
break; /* goto ordinary */
|
||||||
#endif
|
|
||||||
) {
|
|
||||||
c = *++pat;
|
|
||||||
}
|
}
|
||||||
/* FALLTHROUGH */
|
|
||||||
|
|
||||||
default:
|
/* ordinary */
|
||||||
#if defined DOSISH
|
if (Compare(p, s) != 0) {
|
||||||
if (ISDIRSEP(c) && isdirsep(*s))
|
goto failed;
|
||||||
;
|
}
|
||||||
else
|
Inc(p);
|
||||||
#endif
|
Inc(s);
|
||||||
if (Compare(pat, s) != 0)
|
continue;
|
||||||
|
|
||||||
|
failed: /* try next '*' position */
|
||||||
|
if (ptmp && stmp) {
|
||||||
|
p = ptmp;
|
||||||
|
Inc(stmp); /* !ISEND(*stmp) */
|
||||||
|
s = stmp;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
RETURN(FNM_NOMATCH);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
fnmatch(p, s, flags)
|
||||||
|
const char *p; /* pattern */
|
||||||
|
const char *s; /* string */
|
||||||
|
int flags;
|
||||||
|
{
|
||||||
|
const int period = !(flags & FNM_DOTMATCH);
|
||||||
|
const int pathname = flags & FNM_PATHNAME;
|
||||||
|
|
||||||
|
const char *ptmp = 0;
|
||||||
|
const char *stmp = 0;
|
||||||
|
|
||||||
|
if (pathname) {
|
||||||
|
while (1) {
|
||||||
|
if (p[0] == '*' && p[1] == '*' && p[2] == '/') {
|
||||||
|
do { p += 3; } while (p[0] == '*' && p[1] == '*' && p[2] == '/');
|
||||||
|
ptmp = p;
|
||||||
|
stmp = s;
|
||||||
|
}
|
||||||
|
if (fnmatch_helper(&p, &s, flags) == 0) {
|
||||||
|
while (*s && *s != '/') Inc(s);
|
||||||
|
if (*p && *s) {
|
||||||
|
p++;
|
||||||
|
s++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!*p && !*s)
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/* failed : try next recursion */
|
||||||
|
if (ptmp && stmp && !(period && *stmp == '.' && *ptmp != '.')) {
|
||||||
|
while (*stmp && *stmp != '/') Inc(stmp);
|
||||||
|
if (*stmp) {
|
||||||
|
p = ptmp;
|
||||||
|
stmp++;
|
||||||
|
s = stmp;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
return FNM_NOMATCH;
|
return FNM_NOMATCH;
|
||||||
INC_S();
|
|
||||||
Inc(pat);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return !*s ? 0 : FNM_NOMATCH;
|
else
|
||||||
|
return fnmatch_helper(&p, &s, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
VALUE rb_cDir;
|
VALUE rb_cDir;
|
||||||
@ -1586,6 +1610,8 @@ dir_entries(io, dirname)
|
|||||||
* File.fnmatch('* / FIXME *', 'dave/.profile', File::FNM_PATHNAME) #=> false
|
* File.fnmatch('* / FIXME *', 'dave/.profile', File::FNM_PATHNAME) #=> false
|
||||||
* STRICT = File::FNM_PATHNAME | File::FNM_DOTMATCH
|
* STRICT = File::FNM_PATHNAME | File::FNM_DOTMATCH
|
||||||
* File.fnmatch('* / FIXME *', 'dave/.profile', STRICT) #=> true
|
* File.fnmatch('* / FIXME *', 'dave/.profile', STRICT) #=> true
|
||||||
|
*
|
||||||
|
* File.fnmatch('** ERASEME /t', 'c/a/b/c/t', File::FNM_PATHNAME) #=> true
|
||||||
*/
|
*/
|
||||||
static VALUE
|
static VALUE
|
||||||
file_s_fnmatch(argc, argv, obj)
|
file_s_fnmatch(argc, argv, obj)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user