しばらく放置していた、

	「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));
 }