From: "H.Yamamoto" Date: 2003-12-03T23:53:27+09:00 Subject: [ruby-dev:22126] Re: Dir.glob と Shjift_JIS について 山本です。 新しいパッチができました。[ruby-dev:22104] からの変更点は、 1.文字の比較方法を String#<=> や RegExp に合わせた。 2.Next(p)をより安全にして、必ず+1以上するようにした。 3.Win32用 CompareImpl を実装した。(特に自信なし) 4.find_dirsep の関数形式を find_char と同じにした。 です。 --- dir.c Sat Nov 22 12:59:18 2003 +++ dir.c Wed Dec 3 22:08:54 2003 @@ -77,15 +77,121 @@ char *strchr _((char*,char)); -#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) +static int compare(c1, c2) + unsigned char c1; + unsigned char c2; +{ + return c1 < c2 ? -1 : c1 > c2 ? 1 : 0; +} + +#define GREATER(p1, p2) ((p1) > (p2) ? (p1) : (p2)) + +#if defined(_WIN32) +# define Next(p) (GREATER((p) + 1, CharNext(p))) /* faster */ +#elif defined(DJGPP) || defined(__EMX__) +# define Next(p) (GREATER((p) + 1, (p) + mblen(p, INT_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) (compare(downcase(*(p1)), downcase(*(p2)))) +# define find_char(s, c) strchr(s, c) +#else /* multi byte environment */ +# define Inc(p) ((p) = Next(p)) +# define IncLater(p) (IncLaterImpl(&(p))) +# define CopyAndInc(dst, src) (CopyAndIncImpl(&(dst), &(src))) +# define Compare(p1, p2) (CompareImpl(p1, p2, nocase)) +static char * +IncLaterImpl(pp) + char **pp; +{ + char *t = *pp; + Inc(*pp); + return t; +} + +static void +CopyAndIncImpl(pdst, psrc) + char **pdst; + const char **psrc; +{ + const int len = Next(*psrc) - *psrc; + memcpy(*pdst, *psrc, len); + (*pdst) += len; + (*psrc) += len; +} + +#ifndef _WIN32 +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 == 1) + if (len2 == 1) { + return compare(downcase(*p1), downcase(*p2)); + } + else { + int ret = compare(downcase(*p1), *p2); + return ret ? ret : -1; + } + else + if (len2 == 1) { + int ret = compare(*p1, downcase(*p2)); + return ret ? ret : 1; + } + else { + int ret = memcmp(p1, p2, len1 < len2 ? len1 : len2); + return ret ? ret : len1 - len2; + } +} +#else +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; + + int ret = ::CompareString(LOCALE_SYSTEM_DEFAULT, + (nocase ? NORM_IGNORECASE : 0) | SORT_STRINGSORT, + p1, len1, + p2, len2); + + if (ret) { + return ret - 2; + } + else { /* failed */ + ret = memcmp(p1, p2, len1 < len2 ? len1 : len2); + return ret ? ret : len1 - len2; + } +} #endif +static char * +find_char(s, c) + const char *s; + char c; +{ + while (*s) { + if (*s == c) + return (char *)s; + Inc(s); + } + return 0; +} +#endif /* environment */ + #if defined DOSISH #define isdirsep(c) ((c) == '/' || (c) == '\\') -static const char * +static char * find_dirsep(s) @@ -95,4 +201,4 @@ find_dirsep(s) if (isdirsep(*s)) - return s; - s = CharNext(s); + return (char *)s; + Inc(s); } @@ -108,3 +214,3 @@ range(pat, test, flags) char *pat; - char test; + char *test; int flags; @@ -117,22 +223,20 @@ range(pat, test, flags) 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; @@ -143,4 +247,5 @@ range(pat, test, flags) #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 @@ -151,5 +256,5 @@ fnmatch(pat, string, 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); @@ -159,17 +264,17 @@ fnmatch(pat, string, flags) - 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)) @@ -179,6 +284,6 @@ fnmatch(pat, string, flags) } - else if (ISDIRSEP(c)) { + else if (ISDIRSEP(*p)) { s = find_dirsep(s); if (s) { - s++; + INC_S(); break; @@ -188,7 +293,6 @@ fnmatch(pat, string, flags) - 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)) @@ -197,3 +301,3 @@ fnmatch(pat, string, flags) break; - s++; + INC_S(); } @@ -202,8 +306,8 @@ fnmatch(pat, string, flags) 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; @@ -216,7 +320,7 @@ fnmatch(pat, string, flags) ) { - c = *pat; - if (!c) - c = '\\'; + p = pat; + if (!*p) + p = "\\"; /* point to embeded string */ else - pat++; + Inc(pat); } @@ -226,3 +330,3 @@ fnmatch(pat, string, flags) #if defined DOSISH - if (ISDIRSEP(c) && isdirsep(*s)) + if (ISDIRSEP(*p) && isdirsep(*s)) ; @@ -230,5 +334,5 @@ fnmatch(pat, string, flags) #endif - if(downcase(c) != downcase(*s)) + if(Compare(p, s) != 0) return FNM_NOMATCH; - s++; + INC_S(); break; @@ -576,4 +680,3 @@ has_magic(s, send, flags) { - register char *p = s; - register char c; + char *p; int open = 0; @@ -581,4 +684,4 @@ has_magic(s, send, flags) - while ((c = *p++) != '\0') { - switch (c) { + while (*(p = IncLater(s)) != '\0') { + switch (*p) { case '?': @@ -596,3 +699,3 @@ has_magic(s, send, flags) case '\\': - if (escape && *p++ == '\0') + if (escape && *IncLater(s) == '\0') return Qfalse; @@ -600,3 +703,3 @@ has_magic(s, send, flags) - if (send && p >= send) break; + if (send && s >= send) break; } @@ -612,2 +715,6 @@ extract_path(p, pend) + char *prev2 = 0; + char *prev1 = 0; + char *cur; + len = pend - p; @@ -615,11 +722,15 @@ extract_path(p, pend) 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; } @@ -635,3 +746,3 @@ extract_elem(path) - pend = strchr(path, '/'); + pend = find_char(path, '/'); if (!pend) pend = path + strlen(path); @@ -650,5 +761,5 @@ remove_backslashes(p) if (*p == '\\') { - if (++p == pend) break; + if (Inc(p) == pend) break; } - *t++ = *p++; + CopyAndInc(t, p); } @@ -657,2 +768,3 @@ remove_backslashes(p) + #ifndef S_ISDIR @@ -727,4 +839,4 @@ glob_helper(path, sub, flags, func, arg) while (p && !status) { - if (*p == '/') p++; - m = strchr(p, '/'); + if (*p == '/') Inc(p); + m = find_char(p, '/'); if (has_magic(p, m, flags)) { @@ -776,3 +888,3 @@ glob_helper(path, sub, flags, func, arg) #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 @@ -926,3 +1038,3 @@ push_braces(ary, s, flags) } - p++; + Inc(p); } @@ -934,3 +1046,3 @@ push_braces(ary, s, flags) } - p++; + Inc(p); } @@ -944,9 +1056,9 @@ push_braces(ary, s, flags) 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); @@ -988,3 +1100,3 @@ rb_push_glob(str, flags) nest = maxnest = 0; - while (p < pend && isdelim(*p)) p++; + while (p < pend && isdelim(*p)) Inc(p); while (p < pend && !isdelim(*p)) { @@ -993,6 +1105,6 @@ rb_push_glob(str, flags) if (!noescape && *p == '\\') { - *t++ = *p++; + CopyAndInc(t, p); if (p == pend) break; } - *t++ = *p++; + CopyAndInc(t, p); }