こんにちは、山本です。

mblen('\0', MB_CUR_MAX) == 1 と仮定して、整理してみました。
ruby1.8.0(Release)に対するパッチです。

正直、これでいいのかまだ自信がありません。とりあえずスクリプトを書いたりして
みようと思います。

--- e:\dir.c Mon Jun 23 17:49:48 2003
+++ dir.c Sun Nov 30 19:52:54 2003
@@ -70,15 +70,87 @@
 #define FNM_NOMATCH 1
 #define FNM_ERROR 2
 
-#define downcase(c) (nocase && ISUPPER(c) ? tolower(c) : (c))
+#define downcase(c) (nocase && ISUPPER(c) ? tolower(c) : (c)) /* use for single byte */
 
-#ifndef CharNext  /* defined as CharNext[AW] on Windows. */
-# if defined(DJGPP)
-#   define CharNext(p) ((p) + mblen(p, MB_CUR_MAX))
-# else
-#   define CharNext(p) ((p) + 1)
-# endif
-#endif
+#if defined(_WIN32)
+#  define Next(p) (*(p) ? CharNext(p) : (p) + 1)
+#elif defined(DJGPP) || defined(__EMX__)
+#  define Next(p) ((p) + mblen(p, MB_CUR_MAX))
+#endif
+
+#ifndef Next /* single byte environment */
+#  define Next(p) ((p) + 1)
+#  define Inc(p) (++(p))
+#  define IncLater(p) ((p)++)
+#  define CopyAndInc(dst, src) (*(dst)++ = *(src)++)
+#  define Compare(p1, p2) (((int)downcase(*(p1))) - ((int)downcase(*(p2))))
+#  define find_char(s, c) strchr(s, c)
+#else /* multi byte environment */
+#  define Inc(p) (p = Next(p))
+
+static char*
+IncLaterImpl(pp)
+ char **pp;
+{
+ char *t = *pp;
+ Inc(*pp);
+ return t;
+}
+
+#  define IncLater(p) (IncLaterImpl(&(p)))
+
+static void
+CopyAndIncImpl(pdst, psrc)
+ char **pdst;
+ const char **psrc;
+{
+ const int len = Next(*psrc) - *psrc;
+ memcpy(*pdst, *psrc, len);
+ (*pdst) += len;
+ (*psrc) += len;
+}
+
+#  define CopyAndInc(dst, src) (CopyAndIncImpl(&(dst), &(src)))
+
+static int
+CompareImpl(p1, p2, nocase)
+ const char* p1;
+ const char* p2;
+ int nocase;
+{
+ const int len1 = Next(p1) - p1;
+ const int len2 = Next(p2) - p2;
+
+ if (len1 < len2) {
+  return -1;
+ }
+ else if (len1 > len2) {
+  return 1;
+ }
+ else if (len1 == 1) {
+  return ((int)downcase(*p1)) - ((int)downcase(*p2));
+ }
+ else {
+  return strncmp(p1, p2, len1);
+ }
+}
+
+#  define Compare(p1, p2) (CompareImpl(p1, p2, nocase))
+
+static const char*
+find_char(s, c)
+ const char* s;
+ char c;
+{
+ while (*s) {
+ if (*s == c)
+  return s;
+ Inc(s);
+ }
+ return 0;
+}
+
+#endif /* environment */
 
 #if defined DOSISH
 #define isdirsep(c) ((c) == '/' || (c) == '\\')
@@ -89,7 +161,7 @@
     while (*s) {
  if (isdirsep(*s))
      return s;
- s = CharNext(s);
+ s = Next(s);
     }
     return 0;
 }
@@ -101,7 +173,7 @@
 static char *
 range(pat, test, flags)
     char *pat;
-    char test;
+    char *test;
     int flags;
 {
     int not, ok = 0;
@@ -110,97 +182,95 @@
 
     not = *pat == '!' || *pat == '^';
     if (not)
- pat++;
-
-    test = downcase(test);
+ Inc(pat);
 
     while (*pat) {
- int cstart, cend;
- cstart = cend = *pat++;
- if (cstart == ']')
+ char *pstart, *pend;
+ pstart = pend = IncLater(pat);
+ if (*pstart == ']')
      return ok == not ? 0 : pat;
-        else if (escape && cstart == '\\')
-     cstart = cend = *pat++;
- if (*pat == '-' && pat[1] != ']') {
-     if (escape && pat[1] == '\\')
-  pat++;
-     cend = pat[1];
-     if (!cend)
+        else if (escape && *pstart == '\\')
+     pstart = pend = IncLater(pat);
+ if (*pat == '-' && *Next(pat) != ']') {
+     if (escape && *Next(pat) == '\\')
+  Inc(pat);
+     pend = Next(pat);
+     if (!*pend)
   return 0;
-     pat += 2;
+     Inc(pat); Inc(pat);
  }
- if (downcase(cstart) <= test && test <= downcase(cend))
+ if (Compare(pstart, test) <= 0 && Compare(test, pend) <= 0)
      ok = 1;
     }
     return 0;
 }
 
 #define ISDIRSEP(c) (pathname && isdirsep(c))
-#define PERIOD(s) (period && *(s) == '.' && \
-    ((s) == string || ISDIRSEP((s)[-1])))
+#define PERIOD_S() (period && *s == '.' && \
+    (s == string || ISDIRSEP(s_prev)))
+#define INC_S() (s = Next(s_prev = s))
 static int
 fnmatch(pat, string, flags)
     const char *pat;
     const char *string;
     int flags;
 {
-    int c;
-    int test;
-    const char *s = string;
+    const char *p;
+    const char *test;
+    const char *s = string, *s_prev;
     int escape = !(flags & FNM_NOESCAPE);
     int pathname = flags & FNM_PATHNAME;
     int period = !(flags & FNM_DOTMATCH);
     int nocase = flags & FNM_CASEFOLD;
 
-    while (c = *pat++) {
- switch (c) {
+    while (*(p = IncLater(pat))) {
+ switch (*p) {
  case '?':
-     if (!*s || ISDIRSEP(*s) || PERIOD(s))
+     if (!*s || ISDIRSEP(*s) || PERIOD_S())
   return FNM_NOMATCH;
-     s++;
+     INC_S();
      break;
  case '*':
-     while ((c = *pat++) == '*')
+     while (*(p = IncLater(pat)) == '*')
   ;
 
-     if (PERIOD(s))
+     if (PERIOD_S())
   return FNM_NOMATCH;
 
-     if (!c) {
+     if (!*p) {
   if (pathname && find_dirsep(s))
       return FNM_NOMATCH;
   else
       return 0;
      }
-     else if (ISDIRSEP(c)) {
+     else if (ISDIRSEP(*p)) {
   s = find_dirsep(s);
   if (s) {
-                    s++;
+                    INC_S();
       break;
                 }
   return FNM_NOMATCH;
      }
 
-     test = escape && c == '\\' ? *pat : c;
-     test = downcase(test);
-     pat--;
+     test = escape && *p == '\\' ? pat : p;
+     pat = p;
      while (*s) {
-  if ((c == '[' || downcase(*s) == test) &&
+  if ((*p == '[' || Compare(s, test) == 0) &&
       !fnmatch(pat, s, flags | FNM_DOTMATCH))
       return 0;
   else if (ISDIRSEP(*s))
       break;
-  s++;
+  INC_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);
+     pat = range(pat, s, flags);
      if (!pat)
   return FNM_NOMATCH;
-     s++;
+     INC_S();
      break;
 
  case '\\':
@@ -209,23 +279,23 @@
   && *pat && strchr("*?[\\", *pat)
 #endif
   ) {
-  c = *pat;
-  if (!c)
-      c = '\\';
+  p = pat;
+  if (!*p)
+      p = "\\"; /* point to embeded string */
   else
-      pat++;
+      Inc(pat);
      }
      /* FALLTHROUGH */
 
  default:
 #if defined DOSISH
-     if (ISDIRSEP(c) && isdirsep(*s))
+     if (ISDIRSEP(*p) && isdirsep(*s))
   ;
      else
 #endif
-     if(downcase(c) != downcase(*s))
+     if(Compare(p, s) != 0)
   return FNM_NOMATCH;
-     s++;
+     INC_S();
      break;
  }
     }
@@ -569,13 +639,12 @@
      char *s, *send;
      int flags;
 {
-    register char *p = s;
-    register char c;
+    char *p;
     int open = 0;
     int escape = !(flags & FNM_NOESCAPE);
 
-    while ((c = *p++) != '\0') {
- switch (c) {
+    while (*(p = IncLater(s)) != '\0') {
+ switch (*p) {
    case '?':
    case '*':
      return Qtrue;
@@ -589,11 +658,11 @@
      continue;
 
    case '\\':
-     if (escape && *p++ == '\0')
+     if (escape && *IncLater(s) == '\0')
   return Qfalse;
  }
 
- if (send && p >= send) break;
+ if (send && s >= send) break;
     }
     return Qfalse;
 }
@@ -605,18 +674,26 @@
     char *alloc;
     int len;
 
+ char *prev2 = 0;
+ char *prev1 = 0;
+ char *cur;
+
     len = pend - p;
     alloc = ALLOC_N(char, len+1);
     memcpy(alloc, p, len);
-    if (len > 1 && pend[-1] == '/'
+ alloc[len] = 0;
+
+ for (cur = alloc; cur != alloc + len; Inc(cur)) {
+  prev2 = prev1;
+  prev1 = cur;
+ }
+
+ if (prev2 && *prev1 == '/'
 #if defined DOSISH_DRIVE_LETTER
-    && pend[-2] != ':'
+ && *prev2 != ':'
 #endif
     ) {
- alloc[len-1] = 0;
-    }
-    else {
- alloc[len] = 0;
+ *prev1 = 0;
     }
 
     return alloc;
@@ -628,7 +705,7 @@
 {
     char *pend;
 
-    pend = strchr(path, '/');
+    pend = find_char(path, '/');
     if (!pend) pend = path + strlen(path);
 
     return extract_path(path, pend);
@@ -643,13 +720,14 @@
 
     while (p < pend) {
  if (*p == '\\') {
-     if (++p == pend) break;
+     if (Inc(p) == pend) break;
  }
- *t++ = *p++;
+ CopyAndInc(t, p);
     }
     *t = '\0';
 }
 
+
 #ifndef S_ISDIR
 #   define S_ISDIR(m) ((m & S_IFMT) == S_IFDIR)
 #endif
@@ -720,8 +798,8 @@
     }
 
     while (p && !status) {
- if (*p == '/') p++;
- m = strchr(p, '/');
+ if (*p == '/') Inc(p);
+ m = find_char(p, '/');
  if (has_magic(p, m, flags)) {
      char *dir, *base, *magic, *buf;
      DIR *dirp;
@@ -769,7 +847,7 @@
      }
 
 #if defined DOSISH_DRIVE_LETTER
-#define BASE (*base && !((isdirsep(*base) && !base[1]) || (base[1] == ':' && isdirsep(base[2]) && !base[3])))
+#define BASE (*base && !((isdirsep(*base) && !base[1]) || (ISALPHA(*base) && base[1] == ':' && isdirsep(base[2]) && !base[3])))
 #else
 #define BASE (*base && !(isdirsep(*base) && !base[1]))
 #endif
@@ -918,7 +996,7 @@
      lbrace = p;
      break;
  }
- p++;
+ Inc(p);
     }
     while (*p) {
  if (*p == '{') nest++;
@@ -926,7 +1004,7 @@
      rbrace = p;
      break;
  }
- p++;
+ Inc(p);
     }
 
     if (lbrace && rbrace) {
@@ -936,13 +1014,13 @@
  b = buf + (lbrace-s);
  p = lbrace;
  while (*p != '}') {
-     t = p + 1;
-     for (p = t; *p!='}' && *p!=','; p++) {
+     t = Next(p);
+     for (p = t; *p!='}' && *p!=','; Inc(p)) {
   /* skip inner braces */
-  if (*p == '{') while (*p!='}') p++;
+  if (*p == '{') while (*p!='}') Inc(p);
      }
      memcpy(b, t, p-t);
-     strcpy(b+(p-t), rbrace+1);
+     strcpy(b+(p-t), Next(rbrace));
      push_braces(ary, buf, flags);
  }
  free(buf);
@@ -980,15 +1058,15 @@
     while (p < pend) {
  t = buf;
  nest = maxnest = 0;
- while (p < pend && isdelim(*p)) p++;
+ while (p < pend && isdelim(*p)) Inc(p);
  while (p < pend && !isdelim(*p)) {
      if (*p == '{') nest++, maxnest++;
      if (*p == '}') nest--;
      if (!noescape && *p == '\\') {
-  *t++ = *p++;
+  CopyAndInc(t, p);
   if (p == pend) break;
      }
-     *t++ = *p++;
+     CopyAndInc(t, p);
  }
  *t = '\0';
  if (maxnest == 0) {