なかだです。

At Sat, 13 Dec 2003 12:22:11 +0900,
H.Yamamoto wrote:
> 山本です。glob_helperをリファクタリングしてみました。

お疲れ様です。大作ですね。

> 次の点以外は、仕様は変化していないはずです。
> # DOSISHな環境で、Dir.glob("e:*") が動作するようになった。(eドライブのカレントを列挙)
> # 以前は、Dir.glob("e:./*") とする必要があった。
> 依存個所は、glob_helperの中の char *dir の初期化部分と、
> rb_glob2の中のmagic探索開始ポインタ設定部分です。

これは気づきませんでした。
# たまにWindows使っても、全ドライブ一つにつなげちゃうしなぁ。

> 今までと違って大きくいじったので、ちょっと怖いです。
> いちおう自分のスクリプトは動作していますが・・・

File.fnmatch("[a]", "a") がfalseになるのはまずいと思います。

# ついでにまとめて
At Sat, 13 Dec 2003 13:22:18 +0900,
H.Yamamoto wrote:
> やはり、DOSISHの場合は rb_glob2 でフラグに
> File::FNM_CASEFOLD を付加したいのですが、問題ないでしょうか?

どっちかというとそのほうが自然な気はしますが…。

> それとも、statから返されたファイル名もCaseCmpすべきでしょうか。
> それだと、"e:/hoge/hoge/hoge" を一気に stat に渡せず、
> "e:/" "e:/hoge" "e:/hoge/hoge" ... と elem ごとに stat を
> 呼び出し比較する必要がありそうですが・・・

メタキャラクタを含まない部分については一気にstat()できるような
気がするんですが、よく分かりません。

ちょっといじってみました。[ruby-dev:22258]からの差分ですが、-w
オプション付きなので、インデントは適当に直してください。

* single byteに決定しているところではNext()/Inc()を使わない。
* 一文字ずつでは効率が悪そうに見えるので、CopyAndInc()は削除。


--- dir.c-22258 2003-12-13 12:30:05.000000000 +0900 +++ dir.c 2003-12-13 15:24:28.000000000 +0900 @@ -79,16 +79,20 @@ char *strchr _((char*,char)); #define compare(c1, c2) (((unsigned char)(c1)) - ((unsigned char)(c2))) -static char * -greater(p1, p2) - const char *p1; - const char *p2; +#if defined(CharNext) +# define Next(p) CharNext(p) /* faster */ +# define MBLEN(p) (CharNext(p)-(p)) +#elif defined(DJGPP) +# define Next(p) ((p) + MBLEN(p)) +# define MBLEN(p) mblen(p, MB_CUR_MAX) +#elif defined(__EMX__) +# define Next(p) ((p) + MBLEN(p)) +static inline int +MBLEN(p) + const char *p; { - return p1 > p2 ? (char *)p1 : (char *)p2; + int n = mblen(p, INT_MAX); + if (n <= 0) n = 1; + return n; } - -#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 @@ -96,21 +100,8 @@ greater(p1, p2) # define Next(p) ((p) + 1) # define Inc(p) (++(p)) -# define CopyAndInc(dst, src) (*(dst)++ = *(src)++) # define Compare(p1, p2) (compare(downcase(*(p1)), downcase(*(p2)))) #else /* multi byte environment */ # define Inc(p) ((p) = Next(p)) -# define CopyAndInc(dst, src) (CopyAndIncImpl(&(dst), &(src))) # define Compare(p1, p2) (CompareImpl(p1, p2, nocase)) -static void -CopyAndIncImpl(pdst, psrc) - char **pdst; - const char **psrc; -{ - const int len = Next(*psrc) - *psrc; - memcpy(*pdst, *psrc, len); - (*pdst) += len; - (*psrc) += len; -} - static int CompareImpl(p1, p2, nocase) @@ -119,6 +110,6 @@ CompareImpl(p1, p2, nocase) int nocase; { - const int len1 = Next(p1) - p1; - const int len2 = Next(p2) - p2; + const int len1 = MBLEN(p1); + const int len2 = MBLEN(p2); if (len1 == 1) @@ -172,20 +163,21 @@ range(pat, test, flags) not = *pat == '!' || *pat == '^'; if (not) - Inc(pat); + pat++; while (*pat) { char *pstart, *pend; - pstart = pend = pat; Inc(pat); + pstart = pend = pat; if (*pstart == ']') - return ok == not ? 0 : pat; + return ok == not ? 0 : ++pat; else if (escape && *pstart == '\\') - pstart = pend = pat; Inc(pat); - if (*pat == '-' && *Next(pat) != ']') { - if (escape && *Next(pat) == '\\') + pstart = pend = ++pat; Inc(pat); - pend = Next(pat); + if (*pat == '-' && pat[1] != ']') { + if (escape && pat[1] == '\\') + pat++; + pend = pat+1; if (!*pend) return 0; - Inc(pat); Inc(pat); + pat = Next(pend); } if (Compare(pstart, test) <= 0 && Compare(test, pend) <= 0) @@ -205,5 +197,5 @@ fnmatch(pat, string, flags) int flags; { - const char *p; + int c; const char *test; const char *s = string, *s_prev; @@ -213,13 +205,14 @@ fnmatch(pat, string, flags) int nocase = flags & FNM_CASEFOLD; - while (p = pat, Inc(pat), *p) { - switch (*p) { + while (c = *pat) { + switch (c) { case '?': if (!*s || ISDIRSEP(*s) || PERIOD_S()) return FNM_NOMATCH; INC_S(); + ++pat; break; case '*': - while (p = pat, Inc(pat), *p == '*') + while ((c = *++pat) == '*') ; @@ -227,5 +220,5 @@ fnmatch(pat, string, flags) return FNM_NOMATCH; - if (!*p) { + if (!c) { if (pathname && find_dirsep(s)) return FNM_NOMATCH; @@ -233,5 +226,5 @@ fnmatch(pat, string, flags) return 0; } - else if (ISDIRSEP(*p)) { + else if (ISDIRSEP(c)) { s = find_dirsep(s); if (s) { @@ -242,8 +235,7 @@ fnmatch(pat, string, flags) } - test = escape && *p == '\\' ? pat : p; - pat = p; + test = escape && c == '\\' ? pat+1 : pat; while (*s) { - if ((*p == '[' || Compare(s, test) == 0) && + if ((c == '[' || Compare(s, test) == 0) && !fnmatch(pat, s, flags | FNM_DOTMATCH)) return 0; @@ -257,5 +249,5 @@ fnmatch(pat, string, flags) if (!*s || ISDIRSEP(*s) || PERIOD_S()) return FNM_NOMATCH; - pat = range(pat, s, flags); + pat = range(pat+1, s, flags); if (!pat) return FNM_NOMATCH; @@ -264,14 +256,10 @@ fnmatch(pat, string, flags) case '\\': - if (escape + if (escape && pat[1] #if defined DOSISH - && *pat && strchr("*?[\\", *pat) + && strchr("*?[\\", pat[1]) #endif ) { - p = pat; - if (!*p) - p = "\\"; /* point to embeded string */ - else - Inc(pat); + c = *++pat; } /* FALLTHROUGH */ @@ -279,11 +267,12 @@ fnmatch(pat, string, flags) default: #if defined DOSISH - if (ISDIRSEP(*p) && isdirsep(*s)) + if (ISDIRSEP(c) && isdirsep(*s)) ; else #endif - if(Compare(p, s) != 0) + if(Compare(pat, s) != 0) return FNM_NOMATCH; INC_S(); + Inc(pat); break; } @@ -624,5 +613,5 @@ dir_s_rmdir(obj, dir) /* difference from find_dirsep: if not found, return pointer to '\0' */ -static char * +static void find_magic(s, flags, pbeg, pend) char *s; @@ -631,5 +620,6 @@ find_magic(s, flags, pbeg, pend) char **pend; { - char *p; + register char *p = s; + register char c; int open = 0; int escape = !(flags & FNM_NOESCAPE); @@ -637,8 +627,8 @@ find_magic(s, flags, pbeg, pend) *pbeg = s; - while (p = s, Inc(s), *p != '\0') { - switch (*p) { + while ((c = *p++) != '\0') { + switch (c) { case '/': - *pbeg = s; + *pbeg = s = p; continue; @@ -656,19 +646,19 @@ find_magic(s, flags, pbeg, pend) case '\\': - if (escape && (p = s, Inc(s), *p == '\0')) + if (escape && *p++ == '\0') goto miss; + continue; } + + p = Next(p - 1); } miss: - *pbeg = *pend = p; + *pbeg = *pend = --p; return; found: - while (*s) { - if (*s == '/') - break; + while (*s && *s != '/') Inc(s); - } *pend = s; } @@ -697,10 +687,20 @@ remove_backslashes(p) char *pend = p + strlen(p); char *t = p; + char *s = p; while (p < pend) { if (*p == '\\') { + if (p > s) { + if (s > t) memcpy(t, s, p - s); + t += p - s; + s = p; + } if (++p == pend) break; } - CopyAndInc(t, p); + p = Next(p); + } + if (p > s) { + if (s > t) memcpy(t, s, p - s); + t += p - s; } *t = '\0'; @@ -880,9 +880,9 @@ glob_helper(path, sub, flags, func, arg) if (stat(link->path, &st) == 0) { if (S_ISDIR(st.st_mode)) { - int n = strlen(link->path); - buf = ALLOC_N(char, n+strlen(end)+1); - memcpy(buf, link->path, n); - strcpy(buf+n, end); - status = glob_helper(buf, buf+n, flags, func, arg); + int len = strlen(link->path); + buf = ALLOC_N(char, len+strlen(end)+1); + memcpy(buf, link->path, len); + strcpy(buf+len, end); + status = glob_helper(buf, buf+len, flags, func, arg); free(buf); } @@ -1039,17 +1039,18 @@ rb_push_glob(str, flags) while (p < pend) { - t = buf; nest = maxnest = 0; - while (p < pend && isdelim(*p)) Inc(p); + while (p < pend && isdelim(*p)) p++; + t = p; while (p < pend && !isdelim(*p)) { if (*p == '{') nest++, maxnest++; if (*p == '}') nest--; if (!noescape && *p == '\\') { - CopyAndInc(t, p); - if (p == pend) break; + p++; + if (p == pend || isdelim(*p)) break; } - CopyAndInc(t, p); + p = Next(p); } - *t = '\0'; + memcpy(buf, t, p - t); + buf[p - t] = '\0'; if (maxnest == 0) { push_globs(ary, buf, flags);
-- --- 僕の前にBugはない。 --- 僕の後ろにBugはできる。 中田 伸悦