山本です。

File.fnmatch で、* のあとに ? が続く場合のマッチが正しくないようなので、
修正してみました。File.fnmatch は把握しきれてないのですが、こんな感じで
いいでしょうか?

# 修正前

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

# 修正後

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

fnmatch 以外の部分は、コメントの修正とか、見栄えの修正とかです。
動作にはまったく影響ありません。


cvs diff -u -wb -p 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 -p -r1.100 dir.c
--- dir.c	29 Jan 2004 11:59:55 -0000	1.100
+++ dir.c	6 Feb 2004 15:30:10 -0000
@@ -267,7 +267,7 @@ fnmatch(pat, string, flags)
 
 	    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))
@@ -884,6 +884,7 @@ do_stat(path, pst)
     int ret = stat(path, pst);
     if (ret < 0 && errno != ENOENT)
 	rb_sys_warning(path);
+
     return ret;
 }
 
@@ -895,6 +896,7 @@ do_lstat(path, pst)
     int ret = lstat(path, pst);
     if (ret < 0 && errno != ENOENT)
 	rb_sys_warning(path);
+
     return ret;
 }
 
@@ -905,6 +907,7 @@ do_opendir(path)
     DIR *dirp = opendir(path);
     if (dirp == NULL && errno != ENOENT && errno != ENOTDIR)
 	rb_sys_warning(path);
+
     return dirp;
 }
 
@@ -971,7 +974,13 @@ remove_backslashes(p)
 }
 
 /* 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 +994,14 @@ glob_make_pattern(p, flags)
     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;
@@ -1046,7 +1056,6 @@ join_path(path, dirsep, name)
     const char *name;
 {
     const int len = strlen(path);
-
     char *buf = ALLOC_N(char, len+1+strlen(name)+1);
     strcpy(buf, path);
     if (dirsep) {
@@ -1056,11 +1065,14 @@ join_path(path, dirsep, name)
     else {
 	strcpy(buf+len, name);
     }
-
     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 +1123,9 @@ glob_call_func(func, path, arg)
 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 +1133,23 @@ glob_helper(path, dirsep, exist, isdir, 
     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 +1184,25 @@ glob_helper(path, dirsep, exist, isdir, 
 
     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 +1220,11 @@ glob_helper(path, dirsep, exist, isdir, 
 
 	    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 +1241,7 @@ glob_helper(path, dirsep, exist, isdir, 
 
 	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 +1250,8 @@ glob_helper(path, dirsep, exist, isdir, 
 	    *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 +1259,6 @@ glob_helper(path, dirsep, exist, isdir, 
 		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 +1276,6 @@ glob_helper(path, dirsep, exist, isdir, 
 
 		if (status) break;
 	    }
-
 	}
 
 	free(copy_beg);