From: "H.Yamamoto" Date: 2004-04-12T21:23:53+09:00 Subject: [ruby-dev:23376] Dir.glob の '{ }' について 山本です。 Dir.glob の '{ }' で、エスケープと、入れ子の '{ }' が正しく動いてないようです。 E:\ruby-cvs>miniruby.exe -v ruby 1.9.0 (2004-04-08) [i386-bccwin32] E:\ruby-cvs>touch , Touch Version 4.2 Copyright (c) 1998 Borland International E:\ruby-cvs>miniruby.exe -e "puts Dir.glob('{\,}')" E:\ruby-cvs>miniruby.exe -e "puts Dir.glob('{mi{ni{ruby}.e}xe}')" こうなるべきように思います。 E:\ruby-cvs\ruby>touch , Touch Version 4.2 Copyright (c) 1998 Borland International E:\ruby-cvs\ruby>miniruby.exe -e "puts Dir.glob('{\,}')" , E:\ruby-cvs\ruby>miniruby.exe -e "puts Dir.glob('{mi{ni{ruby}.e}xe}')" miniruby.exe この解釈で間違いないでしょうか? まだ十分な検証をしてませんが、一応動いているパッチを添付します。(少しリファクタリングもしました) # あと、rb_glob と File.fnmatch は '{ }' をサポートしていませんが、サポートしたほうがいいでしょうか? Index: dir.c =================================================================== RCS file: /ruby/ruby/dir.c,v retrieving revision 1.117 diff -u -w -b -p -r1.117 dir.c --- dir.c 12 Apr 2004 01:45:08 -0000 1.117 +++ dir.c 12 Apr 2004 10:36:30 -0000 @@ -1392,82 +1392,73 @@ push_pattern(path, ary) } static int -push_globs(ary, s, flags) +push_glob(ary, s, flags) VALUE ary; const char *s; int flags; { - return rb_glob2(s, flags, push_pattern, ary); -} + const int escape = !(flags & FNM_NOESCAPE); -static int -push_braces(ary, s, flags) - VALUE ary; - const char *s; - int flags; -{ - char *buf, *b; - const char *p, *t; - const char *lbrace, *rbrace; + const char *p = s; + const char *lbrace = 0, *rbrace = 0; int nest = 0; int status = 0; - p = s; - lbrace = rbrace = 0; while (*p) { if (*p == '{') { - lbrace = p; - break; - } - Inc(p); + if (!lbrace) lbrace = p; + nest++; } - while (*p) { - if (*p == '{') nest++; - if (*p == '}' && --nest == 0) { + else if (*p == '}') { + if (!lbrace) return status; /* invalid */ + if (--nest == 0) { rbrace = p; break; } + } + else if (*p == '\\' && escape) { + if (!*++p) break; + } Inc(p); } if (lbrace && rbrace) { - int len = strlen(s); - buf = xmalloc(len + 1); + char *buf, *b; + buf = xmalloc(strlen(s) + 1); memcpy(buf, s, lbrace-s); b = buf + (lbrace-s); p = lbrace; - while (*p != '}') { - t = Next(p); - for (p = t; *p!='}' && *p!=','; Inc(p)) { - /* skip inner braces */ - if (*p == '{') while (*p!='}') Inc(p); + while (p < rbrace) { + const char *t = ++p; + nest = 0; + while (p < rbrace && !(nest == 0 && *p == ',')) { + if (*p == '{') nest++; + else if (*p == '}') nest--; + else if (*p == '\\' && escape) { + p++; + } + Inc(p); } memcpy(b, t, p-t); - strcpy(b+(p-t), Next(rbrace)); - status = push_braces(ary, buf, flags); + strcpy(b+(p-t), rbrace + 1); + status = push_glob(ary, buf, flags); if (status) break; } free(buf); } - else { - status = push_globs(ary, s, flags); + else if (!lbrace && !rbrace) { + return rb_glob2(s, flags, push_pattern, ary); } return status; } -#define isdelim(c) ((c)=='\0') static VALUE -rb_push_glob(str, flags) +rb_push_glob(str, flags) /* '\0' is delimiter */ VALUE str; int flags; { const char *p, *pend; - char *buf; - const char *t; - int nest, maxnest; - int status = 0; - int escape = !(flags & FNM_NOESCAPE); VALUE ary; if (rb_block_given_p()) @@ -1476,39 +1467,18 @@ rb_push_glob(str, flags) ary = rb_ary_new(); FilePathValue(str); - buf = xmalloc(RSTRING(str)->len + 1); p = RSTRING(str)->ptr; pend = p + RSTRING(str)->len; while (p < pend) { - nest = maxnest = 0; - while (p < pend && isdelim(*p)) p++; - t = p; - while (p < pend && !isdelim(*p)) { - if (*p == '{') nest++, maxnest++; - if (*p == '}') nest--; - if (escape && *p == '\\') { - p++; - if (p == pend || isdelim(*p)) break; - } - Inc(p); - } - memcpy(buf, t, p - t); - buf[p - t] = '\0'; - if (maxnest == 0) { - status = push_globs(ary, buf, flags); - if (status) break; - } - else if (nest == 0) { - status = push_braces(ary, buf, flags); - if (status) break; - } - /* else unmatched braces */ - } - free(buf); - + const char *t; + int status; + for (t = p; t < pend && !*t; ++t); + for (p = t; p < pend && *p; ++p); + status = push_glob(ary, t, flags); if (status) rb_jump_tag(status); + } return ary; }