From: Minero Aoki Date: 2007-01-07T10:34:15+09:00 Subject: [ruby-dev:30101] Re: StringScanner#scan BUG? 青木です。すみません、すっかり見落としてました。 In mail "[ruby-dev:29914] StringScanner#scan BUG?" とみたまさひろ wrote: > とみたです。 > > Ruby 1.8.5 で次のコードを実行すると、$KCODE="NONE" かつ正規表現のフラ > グが e, s, u の場合に、"a:b" を返します。 > > require "strscan" > str = "a:b" > ["NONE", "EUC", "SJIS", "UTF8"].each do |code| > p code > $KCODE = code > p StringScanner.new(str).scan(/[^\x01\:]+/n) > p StringScanner.new(str).scan(/[^\x01\:]+/e) > p StringScanner.new(str).scan(/[^\x01\:]+/s) > p StringScanner.new(str).scan(/[^\x01\:]+/u) > end > > [^\x01\:] を [^\:\x01] にすると発生しません。期待どおり "a" を返します。 > > はじめは Ruby 本体の正規表現のバグかと思ったのですが、StringScanner 以 > 外では発生しないようです。 strscan.c で kcode_set_option を呼んでなかったのが原因でした。 以下のパッチで修正できるのですが、1.8 ブランチにコミットしてよいでしょうか? extern 関数が 2 つ増えます。 Index: intern.h =================================================================== RCS file: /var/cvs/src/ruby/intern.h,v retrieving revision 1.139.2.21 diff -u -r1.139.2.21 intern.h --- intern.h 30 Oct 2006 02:24:08 -0000 1.139.2.21 +++ intern.h 7 Jan 2007 01:33:27 -0000 @@ -370,6 +370,8 @@ int rb_reg_options _((VALUE)); void rb_set_kcode _((const char*)); const char* rb_get_kcode _((void)); +void rb_kcode_set_option _((VALUE)); +void rb_kcode_reset_option _((void)); /* ruby.c */ RUBY_EXTERN VALUE rb_argv; RUBY_EXTERN VALUE rb_argv0; Index: re.c =================================================================== RCS file: /var/cvs/src/ruby/re.c,v retrieving revision 1.114.2.20 diff -u -r1.114.2.20 re.c --- re.c 20 Jul 2006 07:04:17 -0000 1.114.2.20 +++ re.c 7 Jan 2007 01:31:23 -0000 @@ -200,8 +200,8 @@ static int curr_kcode; -static void -kcode_set_option(re) +void +rb_kcode_set_option(re) VALUE re; { if (!FL_TEST(re, KCODE_FIXED)) return; @@ -224,8 +224,8 @@ } } -static void -kcode_reset_option() +void +rb_kcode_reset_option() { if (reg_kcode == curr_kcode) return; switch (reg_kcode) { @@ -253,9 +253,9 @@ if (!FL_TEST(re, KCODE_FIXED)) return mbclen(c); - kcode_set_option(re); + rb_kcode_set_option(re); len = mbclen(c); - kcode_reset_option(); + rb_kcode_reset_option(); return len; } @@ -486,11 +486,11 @@ } if (*ptr == ':' && ptr[len-1] == ')') { Regexp *rp; - kcode_set_option(re); + rb_kcode_set_option(re); rp = ALLOC(Regexp); MEMZERO((char *)rp, Regexp, 1); err = re_compile_pattern(++ptr, len -= 2, rp) != 0; - kcode_reset_option(); + rb_kcode_reset_option(); re_free_pattern(rp); } if (err) { @@ -849,7 +849,7 @@ char *err; if (FL_TEST(re, KCODE_FIXED)) - kcode_set_option(re); + rb_kcode_set_option(re); rb_reg_check(re); RREGEXP(re)->ptr->fastmap_accurate = 0; err = re_compile_pattern(RREGEXP(re)->str, RREGEXP(re)->len, RREGEXP(re)->ptr); @@ -870,9 +870,9 @@ if (may_need_recompile) rb_reg_prepare_re(re); if (FL_TEST(re, KCODE_FIXED)) - kcode_set_option(re); + rb_kcode_set_option(re); else if (reg_kcode != curr_kcode) - kcode_reset_option(); + rb_kcode_reset_option(); if (reverse) { range = -pos; @@ -904,9 +904,9 @@ if (may_need_recompile) rb_reg_prepare_re(re); if (FL_TEST(re, KCODE_FIXED)) - kcode_set_option(re); + rb_kcode_set_option(re); else if (reg_kcode != curr_kcode) - kcode_reset_option(); + rb_kcode_reset_option(); if (reverse) { range = -pos; @@ -918,7 +918,7 @@ pos, range, ®s); if (FL_TEST(re, KCODE_FIXED)) - kcode_reset_option(); + rb_kcode_reset_option(); if (result == -2) { rb_reg_raise(RREGEXP(re)->str, RREGEXP(re)->len, @@ -1364,7 +1364,7 @@ } if (options & ~0xf) { - kcode_set_option((VALUE)re); + rb_kcode_set_option((VALUE)re); } if (ruby_ignorecase) { options |= RE_OPTION_IGNORECASE; @@ -1376,7 +1376,7 @@ re->str[len] = '\0'; re->len = len; if (options & ~0xf) { - kcode_reset_option(); + rb_kcode_reset_option(); } if (ruby_in_compile) FL_SET(obj, REG_LITERAL); } @@ -1839,7 +1839,7 @@ } StringValue(str); str = rb_reg_quote(str); - kcode_reset_option(); + rb_kcode_reset_option(); return str; } Index: ext/strscan/strscan.c =================================================================== RCS file: /var/cvs/src/ruby/ext/strscan/strscan.c,v retrieving revision 1.7.2.8 diff -u -r1.7.2.8 strscan.c --- ext/strscan/strscan.c 26 Jul 2006 09:37:00 -0000 1.7.2.8 +++ ext/strscan/strscan.c 7 Jan 2007 01:31:23 -0000 @@ -403,6 +403,7 @@ if (S_RESTLEN(p) < 0) { return Qnil; } + rb_kcode_set_option(regex); if (headonly) { ret = re_match(RREGEXP(regex)->ptr, CURPTR(p), S_RESTLEN(p), @@ -416,6 +417,7 @@ S_RESTLEN(p), &(p->regs)); } + rb_kcode_reset_option(); if (ret == -2) rb_raise(ScanError, "regexp buffer overflow"); if (ret < 0) { -- 青木峰郎