diff options
| author | Yukihiro "Matz" Matsumoto <[email protected]> | 2020-04-28 17:59:40 +0900 |
|---|---|---|
| committer | Hiroshi Mimaki <[email protected]> | 2020-05-07 09:32:46 +0900 |
| commit | 6b839b231971f058656521dc39bd4f27968230c6 (patch) | |
| tree | 3ea028c51527b22ec189dd2d9c0344b48b1735b3 | |
| parent | 45bd372755171cee72fd547f3295653918231f77 (diff) | |
| download | mruby-6b839b231971f058656521dc39bd4f27968230c6.tar.gz mruby-6b839b231971f058656521dc39bd4f27968230c6.zip | |
Fix `IO#readchar` to return broken UTF-8 rather than `EOF` error.
The behavior is different from CRuby, but we believe this is a right
behavior for mruby, which only supports either ASCII or UTF-8
exclusively; fix #4983, ref #4982
```
$ printf '\xe3\x81' | ruby -e 'p STDIN.readchar'
"\xE3\x81"
```
```
$ printf '\xe3\x81' | mruby -e 'p STDIN.readchar'
"\xE3"
```
| -rw-r--r-- | mrbgems/mruby-io/mrblib/io.rb | 5 | ||||
| -rw-r--r-- | mrbgems/mruby-io/src/io.c | 17 |
2 files changed, 16 insertions, 6 deletions
diff --git a/mrbgems/mruby-io/mrblib/io.rb b/mrbgems/mruby-io/mrblib/io.rb index e43b81004..e597db886 100644 --- a/mrbgems/mruby-io/mrblib/io.rb +++ b/mrbgems/mruby-io/mrblib/io.rb @@ -284,15 +284,14 @@ class IO def readchar _read_buf _readchar(@buf) -# c = @buf[0] -# @buf[0] = "" -# c end def getc begin readchar rescue EOFError + c = @buf[0] + @buf[0,1]="" if c nil end end diff --git a/mrbgems/mruby-io/src/io.c b/mrbgems/mruby-io/src/io.c index 332539ba5..b28223f36 100644 --- a/mrbgems/mruby-io/src/io.c +++ b/mrbgems/mruby-io/src/io.c @@ -1451,14 +1451,25 @@ mrb_io_readchar(mrb_state *mrb, mrb_value self) mrb_get_args(mrb, "S", &buf); mrb_assert(RSTRING_PTR(buf) > 0); + mrb_str_modify(mrb, RSTRING(buf)); #ifdef MRB_UTF8_STRING c = RSTRING_PTR(buf)[0]; if (c & 0x80) { len = mrb_utf8len(RSTRING_PTR(buf), RSTRING_END(buf)); - if (len == 1 && RSTRING_LEN(buf) < 5) { /* partial UTF-8 */ + if (len == 1 && RSTRING_LEN(buf) < 4) { /* partial UTF-8 */ + mrb_int blen = RSTRING_LEN(buf); + ssize_t n; + + struct mrb_io *fptr = (struct mrb_io*)io_get_open_fptr(mrb, self); + + if (!fptr->readable) { + mrb_raise(mrb, E_IO_ERROR, "not opened for reading"); + } /* refill the buffer */ - mrb_value b = mrb_io_sysread_common(mrb, mrb_sysread_dummy, self, mrb_nil_value(), 4096, 0); - mrb_str_concat(mrb, buf, b); + mrb_str_resize(mrb, buf, 4096); + n = read(fptr->fd, RSTRING_PTR(buf)+blen, 4096-blen); + if (n < 0) mrb_sys_fail(mrb, "sysread failed"); + mrb_str_resize(mrb, buf, blen+n); } len = mrb_utf8len(RSTRING_PTR(buf), RSTRING_END(buf)); } |
