遠藤です。 2010年1月31日19:21 Yusuke ENDOH <mame / tsg.ne.jp>: > stringio に関して、バッファ終端より先に pos を合わせた状態で > StringIO#ungetc を呼んだ時の挙動が 1.8 と 1.9 で違います。 > > > # 1.8 では間が \0 で埋められる > $ ruby18 -rstringio -e ' > io = StringIO.new("1234") > io.pos = 15 > io.ungetc(?A) > p io.string > ' > "1234\000\000\000\000\000\000\000\000\000\000A" > > > # 1.9 では例外になる > $ ./ruby -rstringio -e ' > io = StringIO.new("1234") > io.pos = 15 > io.ungetc(?A) > p io.string > ' > -e:4:in `ungetc': index 14 out of string (IndexError) > from -e:4:in `<main>' > > > r13261 が原因のようです。この挙動の変更を狙ったものではない > ような気がしますが、いかがでしょうか。 成瀬さんの監修のもと、パッチを書いてみました。 反対がなければコミットしてしまいます。 diff --git a/ext/stringio/stringio.c b/ext/stringio/stringio.c index f193c6e..faf974e 100644 --- a/ext/stringio/stringio.c +++ b/ext/stringio/stringio.c @@ -725,17 +725,26 @@ strio_ungetc(VALUE self, VALUE c) c = rb_str_conv_enc(c, enc2, enc); } } - /* get logical position */ - lpos = 0; p = RSTRING_PTR(ptr->string); pend = p + ptr->pos; - for (;;) { - clen = rb_enc_mbclen(p, pend, enc); - if (p+clen >= pend) break; - p += clen; - lpos++; + if (RSTRING_LEN(ptr->string) < ptr->pos) { + long len = RSTRING_LEN(ptr->string); + rb_str_resize(ptr->string, ptr->pos - 1); + memset(RSTRING_PTR(ptr->string) + len, 0, ptr->pos - len - 1); + rb_str_concat(ptr->string, c); + ptr->pos--; + } + else { + /* get logical position */ + lpos = 0; p = RSTRING_PTR(ptr->string); pend = p + ptr->pos; + for (;;) { + clen = rb_enc_mbclen(p, pend, enc); + if (p+clen >= pend) break; + p += clen; + lpos++; + } + clen = p - RSTRING_PTR(ptr->string); + rb_str_update(ptr->string, lpos, ptr->pos ? 1 : 0, c); + ptr->pos = clen; } - clen = p - RSTRING_PTR(ptr->string); - rb_str_update(ptr->string, lpos, ptr->pos ? 1 : 0, c); - ptr->pos = clen; return Qnil; } -- Yusuke ENDOH <mame / tsg.ne.jp>