diff options
-rw-r--r-- | ChangeLog | 5 | ||||
-rw-r--r-- | ext/stringio/stringio.c | 22 | ||||
-rw-r--r-- | test/stringio/test_stringio.rb | 30 |
3 files changed, 50 insertions, 7 deletions
@@ -1,3 +1,8 @@ +Fri Dec 18 12:09:21 2015 Nobuyoshi Nakada <nobu@ruby-lang.org> + + * ext/stringio/stringio.c (strio_ungetbyte): pad with \000 when + the current position is after the end. + Fri Dec 18 11:24:48 2015 Shugo Maeda <shugo@ruby-lang.org> * vm_method.c (rb_method_entry_make, check_override_opt_method): diff --git a/ext/stringio/stringio.c b/ext/stringio/stringio.c index 7c2c51dca8..23d7deba02 100644 --- a/ext/stringio/stringio.c +++ b/ext/stringio/stringio.c @@ -780,8 +780,9 @@ strio_ungetbyte(VALUE self, VALUE c) { struct StringIO *ptr = readable(self); char buf[1], *cp = buf; - long pos = ptr->pos, cl = 1; + long pos = ptr->pos, cl = 1, len, rest; VALUE str = ptr->string; + char *s; if (NIL_P(c)) return Qnil; if (FIXNUM_P(c)) { @@ -794,19 +795,26 @@ strio_ungetbyte(VALUE self, VALUE c) if (cl == 0) return Qnil; } check_modifiable(ptr); - rb_str_modify(str); + len = RSTRING_LEN(str); + rest = pos - len; if (cl > pos) { - char *s; - long rest = RSTRING_LEN(str) - pos; - rb_str_resize(str, rest + cl); + long ex = (rest < 0 ? cl-pos : cl+rest); + rb_str_modify_expand(str, ex); + rb_str_set_len(str, len + ex); s = RSTRING_PTR(str); - memmove(s + cl, s + pos, rest); + if (rest < 0) memmove(s + cl, s + pos, -rest); pos = 0; } else { + if (rest > 0) { + rb_str_modify_expand(str, rest); + rb_str_set_len(str, len + rest); + } + s = RSTRING_PTR(str); + if (rest > cl) memset(s + len, 0, rest - cl); pos -= cl; } - memcpy(RSTRING_PTR(str) + pos, cp, cl); + memcpy(s + pos, cp, cl); ptr->pos = pos; RB_GC_GUARD(c); return Qnil; diff --git a/test/stringio/test_stringio.rb b/test/stringio/test_stringio.rb index af6efc684e..7b99d62f51 100644 --- a/test/stringio/test_stringio.rb +++ b/test/stringio/test_stringio.rb @@ -362,6 +362,11 @@ class TestStringIO < Test::Unit::TestCase t.ungetbyte("\xe7") t.ungetbyte("\xe7\xb4\x85") assert_equal("\u7d05\u7389bar\n", t.gets) + assert_equal("q\u7d05\u7389bar\n", s) + t.pos = 1 + t.ungetbyte("\u{30eb 30d3 30fc}") + assert_equal(0, t.pos) + assert_equal("\u{30eb 30d3 30fc}\u7d05\u7389bar\n", s) end def test_ungetc @@ -582,6 +587,31 @@ class TestStringIO < Test::Unit::TestCase assert_equal("b""\0""a", s.string) end + def test_ungetbyte_pos + b = '\\b00010001 \\B00010001 \\b1 \\B1 \\b000100011' + s = StringIO.new( b ) + expected_pos = 0 + while n = s.getbyte + assert_equal( expected_pos + 1, s.pos ) + + s.ungetbyte( n ) + assert_equal( expected_pos, s.pos ) + assert_equal( n, s.getbyte ) + + expected_pos += 1 + end + end + + def test_ungetbyte_padding + s = StringIO.new() + s.pos = 2 + s.ungetbyte("a".ord) + assert_equal("\0""a", s.string) + s.pos = 0 + s.ungetbyte("b".ord) + assert_equal("b""\0""a", s.string) + end + def test_frozen s = StringIO.new s.freeze |