From: Akinori MUSHA Date: 2002-03-08T17:10:39+09:00 Subject: [ruby-dev:16277] Dir::glob(pattern, flags = 0)  しばらく放置していた、 「Dir::glob() にも FNM_* フラグを指定できるようにしたい」 の件ですが、以下の仕様でいけそうなので、改めて提案します。 - Dir::[] と Dir::glob は同一仕様で、 Dir::[](pattern, flags = 0) Dir::glob(pattern, flags = 0) とする。複数パターンは { , } を使えば書けるので、 pattern は 一つだけ受け付ければ十分。 - File::(Constants::)FNM_PERIOD についてはこれを廃止し、正反対の 意味を持つフラグとして File::FNM_DOTMATCH を導入する。 理由は、 * はドットファイルにマッチさせたくないのが通例なので、 それをデフォルトにしたいからです。現に Dir::glob() はそういう 仕様なので、互換性維持の面からも重要。 仮に File::fnmatch(pattern, flags = File::FNM_PERIOD) Dir::glob(pattern, flags = File::FNM_PERIOD) としてしまうと、マッチさせたいときは 0 を指定するとか、他に フラグを指定したいときには |File::FNM_PERIOD を追加する必要が あるとか、分かりにくくなってしまいます。 また、「. を特別扱いしない」という機能に対して FNM_PERIOD という 名前は誤解を招きやすいという点も挙げられます。伝統を重んじるので あれば FNM_NOPERIOD という手もあるが、ますます分かりにくい。 ;) - fnmatch() や FNM_* の外部公開についてはペンディング。コスト高 だが、正規表現で代用したり rb_cDir に対し rb_funcall することも できる。  差分は以下のように簡単で、他の部分にも互換性にも影響ありません。 よければ 1.7 に入れたいと思うので、意見を募集します。 -- / /__ __ Akinori.org / MUSHA.org / ) ) ) ) / FreeBSD.org / Ruby-lang.org Akinori MUSHA aka / (_ / ( (__( @ iDaemons.org / and.or.jp "Somewhere out of a memory.. of lighted streets on quiet nights.." Index: dir.c =================================================================== RCS file: /src/ruby/dir.c,v retrieving revision 1.60 diff -u -u -r1.60 dir.c --- dir.c 2002/02/18 09:52:45 1.60 +++ dir.c 2002/03/08 07:43:29 @@ -69,7 +69,7 @@ #define FNM_NOESCAPE 0x01 #define FNM_PATHNAME 0x02 -#define FNM_PERIOD 0x04 +#define FNM_DOTMATCH 0x04 #define FNM_CASEFOLD 0x08 #define FNM_NOMATCH 1 @@ -153,7 +153,7 @@ const char *s = string; int escape = !(flags & FNM_NOESCAPE); int pathname = flags & FNM_PATHNAME; - int period = flags & FNM_PERIOD; + int period = !(flags & FNM_DOTMATCH); int nocase = flags & FNM_CASEFOLD; while (c = *pat++) { @@ -188,7 +188,7 @@ pat--; while (*s) { if ((c == '[' || downcase(*s) == test) && - !fnmatch(pat, s, flags & ~FNM_PERIOD)) + !fnmatch(pat, s, flags | FNM_DOTMATCH)) return 0; else if (ISDIRSEP(*s)) break; @@ -793,13 +793,23 @@ } } +static void +rb_glob2(path, flags, func, arg) + char *path; + int flags; + void (*func) _((const char*, VALUE)); + VALUE arg; +{ + glob_helper(path, 0, flags, func, arg); +} + void rb_glob(path, func, arg) char *path; void (*func) _((const char*, VALUE)); VALUE arg; { - glob_helper(path, 0, FNM_PERIOD, func, arg); + rb_glob2(path, 0, func, arg); } void @@ -808,11 +818,9 @@ void (*func) _((const char*, VALUE)); VALUE arg; { - glob_helper(path, 0, FNM_PERIOD|FNM_CASEFOLD, func, arg); + rb_glob2(path, FNM_CASEFOLD, func, arg); } -static void push_pattern _((const char *path, VALUE ary)); - static void push_pattern(path, ary) const char *path; @@ -829,17 +837,19 @@ } static void -push_globs(ary, s) +push_globs(ary, s, flags) VALUE ary; char *s; + int flags; { - rb_glob(s, push_pattern, ary); + rb_glob2(s, flags, push_pattern, ary); } static void -push_braces(ary, s) +push_braces(ary, s, flags) VALUE ary; char *s; + int flags; { char *buf; char *p, *t, *b; @@ -878,26 +888,34 @@ } memcpy(b, t, p-t); strcpy(b+(p-t), rbrace+1); - push_braces(ary, buf); + push_braces(ary, buf, flags); } free(buf); } else { - push_globs(ary, s); + push_globs(ary, s, flags); } } #define isdelim(c) ((c)=='\0') static VALUE -dir_s_glob(dir, str) - VALUE dir, str; +dir_s_glob(argc, argv, obj) + int argc; + VALUE *argv; + VALUE obj; { char *p, *pend; char *buf; char *t; - int nest; + int nest, maxnest; VALUE ary = 0; + VALUE str, rflags; + int flags = 0; + int noescape = flags & FNM_NOESCAPE; + + if (rb_scan_args(argc, argv, "11", &str, &rflags) == 2) + flags = NUM2INT(rflags); SafeStringValue(str); if (!rb_block_given_p()) { @@ -913,20 +931,20 @@ nest = 0; while (p < pend && isdelim(*p)) p++; while (p < pend && !isdelim(*p)) { - if (*p == '{') nest+=2; - if (*p == '}') nest+=3; - if (*p == '\\') { + if (*p == '{') nest++, maxnest++; + if (*p == '}') nest--; + if (!noescape && *p == '\\') { *t++ = *p++; if (p == pend) break; } *t++ = *p++; } *t = '\0'; - if (nest == 0) { - push_globs(ary, buf); + if (maxnest == 0) { + push_globs(ary, buf, flags); } - else if (nest % 5 == 0) { - push_braces(ary, buf); + else if (nest == 0) { + push_braces(ary, buf, flags); } /* else unmatched braces */ } @@ -1014,14 +1032,14 @@ rb_define_singleton_method(rb_cDir,"delete", dir_s_rmdir, 1); rb_define_singleton_method(rb_cDir,"unlink", dir_s_rmdir, 1); - rb_define_singleton_method(rb_cDir,"glob", dir_s_glob, 1); - rb_define_singleton_method(rb_cDir,"[]", dir_s_glob, 1); + rb_define_singleton_method(rb_cDir,"glob", dir_s_glob, -1); + rb_define_singleton_method(rb_cDir,"[]", dir_s_glob, -1); rb_define_singleton_method(rb_cFile,"fnmatch", file_s_fnmatch, -1); rb_define_singleton_method(rb_cFile,"fnmatch?", file_s_fnmatch, -1); rb_file_const("FNM_NOESCAPE", INT2FIX(FNM_NOESCAPE)); rb_file_const("FNM_PATHNAME", INT2FIX(FNM_PATHNAME)); - rb_file_const("FNM_PERIOD", INT2FIX(FNM_PERIOD)); + rb_file_const("FNM_DOTMATCH", INT2FIX(FNM_DOTMATCH)); rb_file_const("FNM_CASEFOLD", INT2FIX(FNM_CASEFOLD)); }