はじめまして。山本といいます。

長いこと未解決だった問題に対し恐れ多いのですが、*p++ などを CharNext() に置
き換えれば
マルチバイトでも動くのではないかと思って、組んでみました。仕様がよくわからな
いので、
ロジックは変更しないようにしています。リリース版のruby1.8.0に対するパッチで
す。

私の環境は、Win2000SP4、BCB5SP1、です。いちおう動いているようですが、
ご意見をお聞きしたくメールしました。

--- e:\dir.c Mon Jun 23 17:49:48 2003
+++ dir.c Fri Nov 28 19:01:22 2003
@@ -80,23 +80,43 @@
 # endif
 #endif

+static inline char
+CharNextLater(pp) /* *p++ for multi byte */
+    const char** pp;
+{
+    const char* t = *pp;
+    *pp = CharNext(*pp);
+    return *t;
+}
+
 #if defined DOSISH
 #define isdirsep(c) ((c) == '/' || (c) == '\\')
+#else
+#define isdirsep(c) ((c) == '/')
+#endif
+
 static const char *
 find_dirsep(s)
     const char *s;
 {
-    while (*s) {
+    for ( ; *s; s = CharNext(s)) {
  if (isdirsep(*s))
      return s;
- s = CharNext(s);
     }
     return 0;
 }
-#else
-#define isdirsep(c) ((c) == '/')
-#define find_dirsep(s) strchr(s, '/')
-#endif
+
+static const char *
+find_char(s, c)
+    const char *s;
+    char c;
+{
+    for ( ; *s; s = CharNext(s)) {
+        if (*s == c)
+            return s;
+    }
+    return 0;
+}

 static char *
 range(pat, test, flags)
@@ -110,24 +130,24 @@

     not = *pat == '!' || *pat == '^';
     if (not)
- pat++;
+    pat = CharNext(pat);

     test = downcase(test);

     while (*pat) {
  int cstart, cend;
- cstart = cend = *pat++;
+    cstart = cend = CharNextLater(&pat);
  if (cstart == ']')
      return ok == not ? 0 : pat;
         else if (escape && cstart == '\\')
-     cstart = cend = *pat++;
- if (*pat == '-' && pat[1] != ']') {
-     if (escape && pat[1] == '\\')
+        cstart = cend = CharNextLater(pat);
+    if (*pat == '-' && *CharNext(pat) != ']') {
+        if (escape && *CharNext(pat) == '\\')
   pat++;
-     cend = pat[1];
+        cend = *CharNext(pat);
      if (!cend)
   return 0;
-     pat += 2;
+        pat = CharNext(CharNext(pat));
  }
  if (downcase(cstart) <= test && test <= downcase(cend))
      ok = 1;
@@ -136,8 +156,9 @@
 }

 #define ISDIRSEP(c) (pathname && isdirsep(c))
-#define PERIOD(s) (period && *(s) == '.' && \
-    ((s) == string || ISDIRSEP((s)[-1])))
+#define PERIOD_S() (period && *s == '.' && (s == string ||
ISDIRSEP(*sprev)))
+#define NEXT_S() (s = CharNext(sprev = s))
+
 static int
 fnmatch(pat, string, flags)
     const char *pat;
@@ -146,24 +167,25 @@
 {
     int c;
     int test;
-    const char *s = string;
+    const char *s = string, *sprev;
+    const char *t;
     int escape = !(flags & FNM_NOESCAPE);
     int pathname = flags & FNM_PATHNAME;
     int period = !(flags & FNM_DOTMATCH);
     int nocase = flags & FNM_CASEFOLD;

-    while (c = *pat++) {
+    while (c = CharNextLater(&pat)) {
  switch (c) {
  case '?':
-     if (!*s || ISDIRSEP(*s) || PERIOD(s))
+        if (!*s || ISDIRSEP(*s) || PERIOD_S())
   return FNM_NOMATCH;
-     s++;
+        NEXT_S();
      break;
  case '*':
-     while ((c = *pat++) == '*')
+        while (t = pat, (c = CharNextLater(&pat)) == '*')
   ;

-     if (PERIOD(s))
+        if (PERIOD_S())
   return FNM_NOMATCH;

      if (!c) {
@@ -175,7 +197,7 @@
      else if (ISDIRSEP(c)) {
   s = find_dirsep(s);
   if (s) {
-                    s++;
+                    NEXT_S();
       break;
                 }
   return FNM_NOMATCH;
@@ -183,24 +205,24 @@

      test = escape && c == '\\' ? *pat : c;
      test = downcase(test);
-     pat--;
+        pat = t;
      while (*s) {
   if ((c == '[' || downcase(*s) == test) &&
       !fnmatch(pat, s, flags | FNM_DOTMATCH))
       return 0;
   else if (ISDIRSEP(*s))
       break;
-  s++;
+        NEXT_S();
      }
      return FNM_NOMATCH;

  case '[':
-     if (!*s || ISDIRSEP(*s) || PERIOD(s))
+        if (!*s || ISDIRSEP(*s) || PERIOD_S())
   return FNM_NOMATCH;
      pat = range(pat, *s, flags);
      if (!pat)
   return FNM_NOMATCH;
-     s++;
+        NEXT_S();
      break;

  case '\\':
@@ -213,7 +235,7 @@
   if (!c)
       c = '\\';
   else
-      pat++;
+            pat = CharNext(pat);
      }
      /* FALLTHROUGH */

@@ -225,13 +247,17 @@
 #endif
      if(downcase(c) != downcase(*s))
   return FNM_NOMATCH;
-     s++;
+        NEXT_S();
      break;
  }
     }
     return !*s ? 0 : FNM_NOMATCH;
 }

+#undef NEXT_S
+#undef PERIOD_S
+#undef ISDIRSEP
+
 VALUE rb_cDir;

 struct dir_data {
@@ -569,12 +595,12 @@
      char *s, *send;
      int flags;
 {
-    register char *p = s;
-    register char c;
+    char *p = s;
+    char c;
     int open = 0;
     int escape = !(flags & FNM_NOESCAPE);

-    while ((c = *p++) != '\0') {
+    while ((c = CharNextLater(&p)) != '\0') {
  switch (c) {
    case '?':
    case '*':
@@ -589,7 +615,7 @@
      continue;

    case '\\':
-     if (escape && *p++ == '\0')
+        if (escape && CharNextLater(&p) == '\0')
   return Qfalse;
  }

@@ -599,24 +625,36 @@
 }

 static char*
-extract_path(p, pend)
-    char *p, *pend;
+extract_path(src_beg, src_end)
+    char *src_beg, *src_end;
 {
-    char *alloc;
-    int len;
+    int len = src_end - src_beg;
+    char* alloc = ALLOC_N(char, len + 1);
+    char* cur = alloc;
+    char* prev1 = 0;
+#ifdef DOSISH_DRIVE_LETTER
+    char* prev2 = 0;
+#endif

-    len = pend - p;
-    alloc = ALLOC_N(char, len+1);
-    memcpy(alloc, p, len);
-    if (len > 1 && pend[-1] == '/'
-#if defined DOSISH_DRIVE_LETTER
-    && pend[-2] != ':'
+    memcpy(alloc, src_beg, len);
+
+    while (cur != alloc + len) {
+#ifdef DOSISH_DRIVE_LETTER
+        prev2 = prev1;
+#endif
+        prev1 = cur;
+        cur = CharNext(cur);
+    }
+
+    if (prev1 && *prev1 == '/'
+#ifdef DOSISH_DRIVE_LETTER
+    && (!(prev2 && *prev2 == ':'))
 #endif
     ) {
- alloc[len-1] = 0;
+        *prev1 = '\0';
     }
     else {
- alloc[len] = 0;
+        *cur = '\0';
     }

     return alloc;
@@ -628,7 +666,7 @@
 {
     char *pend;

-    pend = strchr(path, '/');
+    pend = find_char(path, '/');
     if (!pend) pend = path + strlen(path);

     return extract_path(path, pend);
@@ -638,14 +676,17 @@
 remove_backslashes(p)
     char *p;
 {
-    char *pend = p + strlen(p);
-    char *t = p;
-
-    while (p < pend) {
+    char* t = p;
+    while (*p != '\0') {
  if (*p == '\\') {
-     if (++p == pend) break;
+            p = CharNext(p);
+            if (*p == '\0') {
+                break;
  }
- *t++ = *p++;
+        }
+        *t = *p;
+        t = CharNext(t);
+        p = CharNext(p);
     }
     *t = '\0';
 }
@@ -721,7 +762,7 @@

     while (p && !status) {
  if (*p == '/') p++;
- m = strchr(p, '/');
+        m = find_char(p, '/');
  if (has_magic(p, m, flags)) {
      char *dir, *base, *magic, *buf;
      DIR *dirp;
@@ -769,9 +810,9 @@
      }

 #if defined DOSISH_DRIVE_LETTER
-#define BASE (*base && !((isdirsep(*base) && !base[1]) || (base[1] == ':'
&& isdirsep(base[2]) && !base[3])))
+#define BASE (*base && CharNext(base) == base + 1 && !((isdirsep(*base) &&
!base[1]) || (base[1] == ':' && isdirsep(base[2]) && !base[3])))
 #else
-#define BASE (*base && !(isdirsep(*base) && !base[1]))
+#define BASE (*base && CharNext(base) == base + 1 && !(isdirsep(*base) &&
!base[1]))
 #endif

      for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) {