山本です。

>File.fnmatch で、* のあとに ? が続く場合のマッチが正しくないようなので、
>修正してみました。

もうひとつ忘れてました。']'もエスケープ対象文字だと思うので、以下のように
修正しました。これは Unix のシェルでもそうなのか自信がありません。
BeOS(bash) では「修正後」のように動作しました。

# 修正前

E:\ruby-cvs\ruby>..\miniruby -Ks -ve "puts File.fnmatch('\[1\]', '[1]')"
ruby 1.9.0 (2004-01-31) [i386-bccwin32]
false

# 修正後

E:\ruby-cvs\ruby>miniruby -Ks -ve "puts File.fnmatch('\[1\]', '[1]')"
ruby 1.9.0 (2004-01-31) [i386-bccwin32]
true

前回同様、fnmatch以外の部分は、コメントや長すぎる行の修正などで、
動作に変更はありません。


cvs diff -u -wb dir.c (in directory E:\ruby-cvs\ruby\)
Index: dir.c
===================================================================
RCS file: /ruby/ruby/dir.c,v
retrieving revision 1.100
diff -u -w -b -r1.100 dir.c
--- dir.c	29 Jan 2004 11:59:55 -0000	1.100
+++ dir.c	7 Feb 2004 02:20:01 -0000
@@ -267,7 +267,7 @@
 
 	    test = escape && c == '\\' ? pat+1 : pat;
 	    while (*s) {
-		if ((c == '[' || Compare(s, test) == 0) &&
+		if ((c == '?' || c == '[' || Compare(s, test) == 0) &&
 		    !fnmatch(pat, s, flags | FNM_DOTMATCH))
 		    return 0;
 		else if (ISDIRSEP(*s))
@@ -288,7 +288,7 @@
 	  case '\\':
 	    if (escape && pat[1]
 #if defined DOSISH
-		&& strchr("*?[\\", pat[1])
+		&& strchr("*?[]\\", pat[1])
 #endif
 		) {
 		c = *++pat;
@@ -971,7 +971,13 @@
 }
 
 /* Globing pattern */
-enum glob_pattern_type { PLAIN, MAGICAL, RECURSIVE, MATCH_ALL, MATCH_DIR };
+enum glob_pattern_type {
+    PLAIN,
+    MAGICAL,
+    RECURSIVE,
+    MATCH_ALL,
+    MATCH_DIR
+};
 
 struct glob_pattern {
     char *str;
@@ -985,13 +991,14 @@
     int flags;
 {
     char *buf;
-    int dirsep = 0; /* pattern terminates with '/' */
+    int dirsep = 0;
     struct glob_pattern *list, *tmp, **tail = &list;
 
     while (*p) {
 	tmp = ALLOC(struct glob_pattern);
 	if (p[0] == '*' && p[1] == '*' && p[2] == '/') {
-	    do { p += 3; } while (p[0] == '*' && p[1] == '*' && p[2] == '/'); /* fold continuous RECURSIVEs */
+	    /* fold continuous recursive patterns */
+	    do { p += 3; } while (p[0] == '*' && p[1] == '*' && p[2] == '/');
 	    tmp->type = RECURSIVE;
 	    tmp->str = 0;
 	    dirsep = 1;
@@ -1060,7 +1067,11 @@
     return buf;
 }
 
-enum answer { YES, NO, UNKNOWN };
+enum answer {
+    YES,
+    NO,
+    UNKNOWN
+};
 
 #ifndef S_ISDIR
 #   define S_ISDIR(m) ((m & S_IFMT) == S_IFDIR)
@@ -1111,9 +1122,9 @@
 static int
 glob_helper(path, dirsep, exist, isdir, beg, end, flags, func, arg)
     const char *path;
-    int dirsep; /* '/' should be placed before appending child entry's name to 'path'. */
-    enum answer exist; /* exist? */
-    enum answer isdir; /* a directory or a symlink to a directory? */
+    int dirsep; /* '/' is needed before appending name to 'path' */
+    enum answer exist; /* Does 'path' indicates an existing entry? */
+    enum answer isdir; /* Does 'path' indicates a directory or a symlink to a directory? */
     struct glob_pattern **beg;
     struct glob_pattern **end;
     int flags;
@@ -1121,24 +1132,23 @@
     VALUE arg;
 {
     struct stat st;
-    int status = 0;
     struct glob_pattern **cur, **new_beg, **new_end;
-    int recursive = 0, need_readdir = 0, need_plain = 0, match_all = 0, match_dir = 0;
-    const int escape = !(flags & FNM_NOESCAPE);
+    int plain = 0, magical = 0, recursive = 0, match_all = 0, match_dir = 0;
+    int status = 0;
+    int escape = !(flags & FNM_NOESCAPE);
 
     for (cur = beg; cur < end; ++cur) {
 	struct glob_pattern *p = *cur;
 	if (p->type == RECURSIVE) {
 	    recursive = 1;
-	    need_readdir = 1;
 	    p = p->next;
 	}
 	switch (p->type) {
 	case PLAIN:
-	    need_plain = 1; /* ignored if need_readdir is set */
+	    plain = 1;
 	    break;
 	case MAGICAL:
-	    need_readdir = 1;
+	    magical = 1;
 	    break;
 	case MATCH_ALL:
 	    match_all = 1;
@@ -1173,29 +1183,25 @@
 
     if (match_all && exist == YES) {
 	status = glob_call_func(func, path, arg);
+	if (status) return status;
     }
 
     if (match_dir && isdir == YES) {
 	char *buf = join_path(path, dirsep, "");
 	status = glob_call_func(func, buf, arg);
 	free(buf);
-    }
-
     if (status) return status;
+    }
 
     if (exist == NO || isdir == NO) return 0;
 
-    if (need_readdir) {
-
+    if (magical || recursive) {
 	struct dirent *dp;
-
 	DIR *dirp = do_opendir(*path ? path : ".");
 	if (dirp == NULL) return 0;
 
 	for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) {
-
 	    char *buf = join_path(path, dirsep, dp->d_name);
-
 	    enum answer new_isdir = UNKNOWN;
 
 	    if (recursive && strcmp(dp->d_name, ".") != 0 && strcmp(dp->d_name, "..") != 0) {
@@ -1213,13 +1219,11 @@
 
 	    for (cur = beg; cur < end; ++cur) {
 		struct glob_pattern *p = *cur;
-
 		if (p->type == RECURSIVE) {
 		    if (new_isdir == YES) /* not symlink but real directory */
 			*new_end++ = p; /* append recursive pattern */
 		    p = p->next; /* 0 times recursion */
 		}
-
 		if (p->type == PLAIN || p->type == MAGICAL) {
 		    if (fnmatch(p->str, dp->d_name, flags) == 0)
 			*new_end++ = p->next;
@@ -1236,8 +1240,7 @@
 
 	closedir(dirp);
     }
-    else if (need_plain) {
-
+    else if (plain) {
 	struct glob_pattern **copy_beg, **copy_end, **cur2;
 
 	copy_beg = copy_end = ALLOC_N(struct glob_pattern *, end - beg);
@@ -1246,11 +1249,8 @@
 	    *copy_end++ = (*cur)->type == PLAIN ? *cur : 0;
 
 	for (cur = copy_beg; cur < copy_end; ++cur) {
-
 	    if (*cur) {
-
-		char *buf, *name;
-
+		char *name, *buf;
 		name = ALLOC_N(char, strlen((*cur)->str) + 1);
 		strcpy(name, (*cur)->str);
 		if (escape) remove_backslashes(name);
@@ -1258,7 +1258,6 @@
 		new_beg = new_end = ALLOC_N(struct glob_pattern *, end - beg);
 
 		*new_end++ = (*cur)->next;
-
 		for (cur2 = cur + 1; cur2 < copy_end; ++cur2) {
 		    if (*cur2 && fnmatch((*cur2)->str, name, flags) == 0) {
 			*new_end++ = (*cur2)->next;
@@ -1276,7 +1275,6 @@
 
 		if (status) break;
 	    }
-
 	}
 
 	free(copy_beg);