From: "H.Yamamoto" Date: 2003-11-28T22:32:10+09:00 Subject: [ruby-dev:22071] Dir.glob と Shjift_JIS について はじめまして。山本といいます。 長いこと未解決だった問題に対し恐れ多いのですが、*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)) {