なかだです。 At Thu, 1 Sep 2005 21:42:00 +0900, U.Nakamura wrote in [ruby-dev:26940]: > (1) 元々、glob はインタプリタから独立して動くようになっていて、 > (2) それがインタプリタに依存するようになって、 > (3) win32 で glob を呼ぶタイミングを ruby_init の後にしたら、 > (4) ruby を組み込む人たちからいろいろ問題が報告されて、 > (5) 仕方がないので ruby_init の前に戻したら、 > (6) いつの間にかまた glob が動かなくなっていた。 > > ということだと思うんですが、(2)の変更の理由は覚えてないし、(6) > がなぜ起こったのかも把握してません。 (2)は、Dir.globのブロックの中で例外が起きたりしたときのために、 リソースをVALUEで管理しようとしたためです。 > とりあえず、(6)はなんでなのかご存知のひとー? rb_protect()内部のコンテキストをcallccで外部から呼び出せないよ うにするために、オブジェクトをマークとして割り当てるようにしま した。これがruby_init前に起きるとGCが呼ばれることになります。 それともう一つ、(5)のときの修正漏れですが、rb_glob_caller()の引 数が呼び出し側とあっていないために、ここでもエラーになるか正し くない結果になります。 たしかにfnmatch()とは無関係なので、名前を変えて外部からは指定で きないようにしました。
Index: dir.c =================================================================== RCS file: /cvs/ruby/src/ruby/dir.c,v retrieving revision 1.144 diff -U2 -p -u -r1.144 dir.c --- dir.c 12 Sep 2005 10:44:19 -0000 1.144 +++ dir.c 14 Sep 2005 04:41:27 -0000 @@ -891,10 +891,13 @@ dir_s_rmdir(VALUE obj, VALUE dir) } +#define GLOB_VERBOSE (1 << (sizeof(int) * CHAR_BIT - 1)) + /* System call with warning */ static int -do_stat(const char *path, struct stat *pst) +do_stat(const char *path, struct stat *pst, int flags) + { int ret = stat(path, pst); - if (ret < 0 && errno != ENOENT) + if (ret < 0 && (flags & GLOB_VERBOSE) && errno != ENOENT) rb_protect((VALUE (*)_((VALUE)))rb_sys_warning, (VALUE)path, 0); @@ -903,8 +906,8 @@ do_stat(const char *path, struct stat *p static int -do_lstat(const char *path, struct stat *pst) +do_lstat(const char *path, struct stat *pst, int flags) { int ret = lstat(path, pst); - if (ret < 0 && errno != ENOENT) + if (ret < 0 && (flags & GLOB_VERBOSE) && errno != ENOENT) rb_protect((VALUE (*)_((VALUE)))rb_sys_warning, (VALUE)path, 0); @@ -913,8 +916,8 @@ do_lstat(const char *path, struct stat * static DIR * -do_opendir(const char *path) +do_opendir(const char *path, int flags) { DIR *dirp = opendir(path); - if (dirp == NULL && errno != ENOENT && errno != ENOTDIR) + if (!dirp && (flags & GLOB_VERBOSE) && errno != ENOENT && errno != ENOTDIR) rb_protect((VALUE (*)_((VALUE)))rb_sys_warning, (VALUE)path, 0); @@ -1119,17 +1122,5 @@ glob_func_caller(VALUE val) } -static int -glob_call_func(void (*func) (const char *, VALUE), const char *path, VALUE arg) -{ - int status; - struct glob_args args; - - args.func = func; - args.c = path; - args.v = arg; - - rb_protect(glob_func_caller, (VALUE)&args, &status); - return status; -} +#define glob_call_func(func, path, arg) (*func)(path, arg) static int @@ -1142,5 +1133,5 @@ glob_helper( struct glob_pattern **end, int flags, - void (*func) (const char *, VALUE), + int (*func)(const char *, VALUE), VALUE arg) { @@ -1177,5 +1168,5 @@ glob_helper( if (*path) { if (match_all && exist == UNKNOWN) { - if (do_lstat(path, &st) == 0) { + if (do_lstat(path, &st, flags) == 0) { exist = YES; isdir = S_ISDIR(st.st_mode) ? YES : S_ISLNK(st.st_mode) ? UNKNOWN : NO; @@ -1187,5 +1178,5 @@ glob_helper( } if (match_dir && isdir == UNKNOWN) { - if (do_stat(path, &st) == 0) { + if (do_stat(path, &st, flags) == 0) { exist = YES; isdir = S_ISDIR(st.st_mode) ? YES : NO; @@ -1212,5 +1203,5 @@ glob_helper( if (magical || recursive) { struct dirent *dp; - DIR *dirp = do_opendir(*path ? path : "."); + DIR *dirp = do_opendir(*path ? path : ".", flags); if (dirp == NULL) return 0; @@ -1222,5 +1213,5 @@ glob_helper( && fnmatch("*", dp->d_name, flags) == 0) { #ifndef _WIN32 - if (do_lstat(buf, &st) == 0) + if (do_lstat(buf, &st, flags) == 0) new_isdir = S_ISDIR(st.st_mode) ? YES : S_ISLNK(st.st_mode) ? UNKNOWN : NO; else @@ -1294,5 +1285,5 @@ glob_helper( static int -rb_glob2(const char *path, int flags, void (*func) (const char *, VALUE), VALUE arg) +ruby_glob0(const char *path, int flags, int (*func)(const char *, VALUE), VALUE arg) { struct glob_pattern *list; @@ -1302,8 +1293,4 @@ rb_glob2(const char *path, int flags, vo int status; - if (flags & FNM_CASEFOLD) { - rb_warn("Dir.glob() ignores File::FNM_CASEFOLD"); - } - start = root = path; #if defined DOSISH @@ -1329,26 +1316,41 @@ rb_glob2(const char *path, int flags, vo } -struct rb_glob_args { - void (*func) _((const char*, VALUE)); - VALUE arg; -}; +int +ruby_glob(const char *path, int flags, int (*func)(const char *, VALUE), VALUE arg) +{ + return ruby_glob0(path, flags & ~GLOB_VERBOSE, func, arg); +} -static void +static int rb_glob_caller(const char *path, VALUE a) { - struct rb_glob_args *args = (struct rb_glob_args *)a; - (*args->func)(path, args->arg); + int status; + struct glob_args *args = (struct glob_args *)a; + + args->c = path; + rb_protect(glob_func_caller, a, &status); + return status; } -void -rb_glob(const char *path, void (*func) (const char *, VALUE), VALUE arg) +static int +rb_glob2(const char *path, int flags, void (*func)(const char *, VALUE), VALUE arg) { - struct rb_glob_args args; + struct glob_args args; int status; args.func = func; - args.arg = arg; - status = rb_glob2(path, 0, rb_glob_caller, (VALUE)&args); + args.v = arg; + if (flags & FNM_CASEFOLD) { + rb_warn("Dir.glob() ignores File::FNM_CASEFOLD"); + } + + return ruby_glob0(path, flags | GLOB_VERBOSE, rb_glob_caller, (VALUE)&args); +} + +void +rb_glob(const char *path, void (*func) (const char *, VALUE), VALUE arg) +{ + int status = rb_glob2(path, 0, func, arg); if (status) rb_jump_tag(status); }
-- --- 僕の前にBugはない。 --- 僕の後ろにBugはできる。 中田 伸悦