こんにちは、山本です。 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) {