From 1990d9fd70f206ae79d5e80bd0034fe8c0c44327 Mon Sep 17 00:00:00 2001 From: take-cheeze Date: Mon, 10 Aug 2020 13:50:47 +0900 Subject: [PATCH 1/3] Add partial ungetc support --- src/stringio.c | 21 +++++++++++++++++++++ test/stringio.rb | 9 +++++++++ 2 files changed, 30 insertions(+) diff --git a/src/stringio.c b/src/stringio.c index 5560e00..58a972d 100644 --- a/src/stringio.c +++ b/src/stringio.c @@ -468,6 +468,26 @@ stringio_getc(mrb_state *mrb, mrb_value self) return ret; } +static mrb_value +stringio_ungetc(mrb_state *mrb, mrb_value self) +{ + struct StringIO *ptr = StringIO(self); + mrb_value string = stringio_iv_get("@string"); + mrb_int in_len; + const char* in_data; + mrb_get_args(mrb, "s", &in_data, &in_len); + + if (in_len != 1) { + mrb_raisef(mrb, E_IOERROR, "ungetc is only support for single byte string. len: %S", mrb_fixnum_value(in_len)); + } + if (ptr->pos <= 0) { + mrb_raise(mrb, E_IOERROR, "ungetc not supported in beginning of stream"); + } + ptr->pos -= 1; + + return mrb_nil_value(); +} + static mrb_value stringio_gets(mrb_state *mrb, mrb_value self) { @@ -653,6 +673,7 @@ mrb_mruby_stringio_gem_init(mrb_state* mrb) mrb_define_alias(mrb, stringio, "syswrite", "write"); mrb_define_method(mrb, stringio, "getc", stringio_getc, MRB_ARGS_ANY()); mrb_define_method(mrb, stringio, "gets", stringio_gets, MRB_ARGS_ANY()); + mrb_define_method(mrb, stringio, "ungetc", stringio_ungetc, MRB_ARGS_REQ(1)); mrb_define_method(mrb, stringio, "seek", stringio_seek, MRB_ARGS_ANY()); mrb_define_method(mrb, stringio, "size", stringio_size, MRB_ARGS_NONE()); mrb_define_alias(mrb, stringio, "length", "size"); diff --git a/test/stringio.rb b/test/stringio.rb index 26c1497..3a5fdce 100644 --- a/test/stringio.rb +++ b/test/stringio.rb @@ -206,6 +206,15 @@ def o.to_s; "baz"; end assert_equal nil, strio.getc end +assert 'StringIO#ungetc' do + strio = StringIO.new("abc") + assert_raise(IOError) { strio.ungetc '' } + assert_raise(IOError) { strio.ungetc 'a' } + assert_equal 'a', strio.getc + assert_nil strio.ungetc 'a' + assert_equal 'a', strio.getc +end + assert 'StringIO#gets' do io = StringIO.new("this>is>an>example") assert_equal "this>", io.gets(">") From fe77d63202a0b465f7a734cbe1ab813ff68b245f Mon Sep 17 00:00:00 2001 From: take-cheeze Date: Wed, 12 Aug 2020 16:03:53 +0900 Subject: [PATCH 2/3] Make ungetc more compatible to CRuby --- src/stringio.c | 13 +++++++++++-- test/stringio.rb | 6 +++++- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/src/stringio.c b/src/stringio.c index 58a972d..dec1f02 100644 --- a/src/stringio.c +++ b/src/stringio.c @@ -477,11 +477,20 @@ stringio_ungetc(mrb_state *mrb, mrb_value self) const char* in_data; mrb_get_args(mrb, "s", &in_data, &in_len); + mrb_int flags = mrb_fixnum(stringio_iv_get("@flags")); + if ((flags & FMODE_READABLE) == 0) { + mrb_raise(mrb, E_IOERROR, "not opened for reading"); + } + + if (in_len == 0) { + return mrb_nil_value(); + } + if (in_len != 1) { - mrb_raisef(mrb, E_IOERROR, "ungetc is only support for single byte string. len: %S", mrb_fixnum_value(in_len)); + mrb_raisef(mrb, E_IOERROR, "mruby-ext: ungetc is only supported for single byte string. len: %S", mrb_fixnum_value(in_len)); } if (ptr->pos <= 0) { - mrb_raise(mrb, E_IOERROR, "ungetc not supported in beginning of stream"); + mrb_raise(mrb, E_IOERROR, "mruby-ext: ungetc not supported in beginning of stream"); } ptr->pos -= 1; diff --git a/test/stringio.rb b/test/stringio.rb index 3a5fdce..7227289 100644 --- a/test/stringio.rb +++ b/test/stringio.rb @@ -208,11 +208,15 @@ def o.to_s; "baz"; end assert 'StringIO#ungetc' do strio = StringIO.new("abc") - assert_raise(IOError) { strio.ungetc '' } + strio.ungetc '' + assert_equal 'abc', strio.string assert_raise(IOError) { strio.ungetc 'a' } assert_equal 'a', strio.getc assert_nil strio.ungetc 'a' assert_equal 'a', strio.getc + + strio = StringIO.new("abc", 'w') + assert_raise(IOError) { strio.ungetc 'a' } end assert 'StringIO#gets' do From 92c06329b833803ab3c3c2840981c60d90e4a9bf Mon Sep 17 00:00:00 2001 From: take-cheeze Date: Wed, 12 Aug 2020 16:43:19 +0900 Subject: [PATCH 3/3] Check ungetc data --- src/stringio.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/stringio.c b/src/stringio.c index dec1f02..353aacd 100644 --- a/src/stringio.c +++ b/src/stringio.c @@ -494,6 +494,7 @@ stringio_ungetc(mrb_state *mrb, mrb_value self) } ptr->pos -= 1; + mrb_assert(RSTRING_PTR(string)[ptr->pos] == *in_data); return mrb_nil_value(); }