ruby-changes:15564
From: akr <ko1@a...>
Date: Sat, 24 Apr 2010 14:43:09 +0900 (JST)
Subject: [ruby-changes:15564] Ruby:r27470 (trunk): * io.c: raise IOError when byte oriented operations occur with
akr 2010-04-24 14:42:50 +0900 (Sat, 24 Apr 2010) New Revision: 27470 http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=27470 Log: * io.c: raise IOError when byte oriented operations occur with non-empty character buffer. [ruby-dev:40493] [ruby-dev:40506] Modified files: trunk/ChangeLog trunk/io.c trunk/test/ruby/test_io_m17n.rb Index: ChangeLog =================================================================== --- ChangeLog (revision 27469) +++ ChangeLog (revision 27470) @@ -1,3 +1,9 @@ +Sat Apr 24 14:40:20 2010 Tanaka Akira <akr@f...> + + * io.c: raise IOError when byte oriented operations occur with + non-empty character buffer. + [ruby-dev:40493] [ruby-dev:40506] + Sat Apr 24 13:06:57 2010 Nobuyoshi Nakada <nobu@r...> * ruby.c (get_arglen): skip the last terminator of argv before Index: io.c =================================================================== --- io.c (revision 27469) +++ io.c (revision 27470) @@ -180,6 +180,8 @@ #define READ_DATA_PENDING_PTR(fptr) ((fptr)->rbuf+(fptr)->rbuf_off) #define READ_DATA_BUFFERED(fptr) READ_DATA_PENDING(fptr) +#define READ_CHAR_PENDING(fptr) ((fptr)->cbuf_len) + #if defined(_WIN32) #define WAIT_FD_IN_WIN32(fptr) rb_thread_wait_fd((fptr)->fd); #else @@ -401,7 +403,7 @@ #define FMODE_SYNCWRITE (FMODE_SYNC|FMODE_WRITABLE) void -rb_io_check_readable(rb_io_t *fptr) +rb_io_check_char_readable(rb_io_t *fptr) { rb_io_check_closed(fptr); if (!(fptr->mode & FMODE_READABLE)) { @@ -419,6 +421,21 @@ } } +void +rb_io_check_byte_readable(rb_io_t *fptr) +{ + rb_io_check_char_readable(fptr); + if (READ_CHAR_PENDING(fptr)) { + rb_raise(rb_eIOError, "byte oriented read for character buffered IO"); + } +} + +void +rb_io_check_readable(rb_io_t *fptr) +{ + rb_io_check_byte_readable(fptr); +} + static rb_encoding* io_read_encoding(rb_io_t *fptr) { @@ -452,6 +469,9 @@ int rb_io_read_pending(rb_io_t *fptr) { + /* This function is used for bytes and chars. Confusing. */ + if (READ_CHAR_PENDING(fptr)) + return 1; /* should raise? */ return READ_DATA_PENDING(fptr); } @@ -1242,8 +1262,9 @@ rb_io_t *fptr; GetOpenFile(io, fptr); - rb_io_check_readable(fptr); + rb_io_check_char_readable(fptr); + if (READ_CHAR_PENDING(fptr)) return Qfalse; if (READ_DATA_PENDING(fptr)) return Qfalse; READ_CHECK(fptr); if (io_fillbuf(fptr) < 0) { @@ -1814,7 +1835,7 @@ OBJ_TAINT(str); GetOpenFile(io, fptr); - rb_io_check_readable(fptr); + rb_io_check_byte_readable(fptr); if (len == 0) return str; @@ -2133,7 +2154,7 @@ if (NIL_P(length)) { if (!NIL_P(str)) StringValue(str); GetOpenFile(io, fptr); - rb_io_check_readable(fptr); + rb_io_check_char_readable(fptr); return read_all(fptr, remain_size(fptr), str); } len = NUM2LONG(length); @@ -2151,7 +2172,7 @@ } GetOpenFile(io, fptr); - rb_io_check_readable(fptr); + rb_io_check_byte_readable(fptr); if (len == 0) return str; READ_CHECK(fptr); @@ -2385,7 +2406,7 @@ rb_encoding *enc; GetOpenFile(io, fptr); - rb_io_check_readable(fptr); + rb_io_check_char_readable(fptr); if (NIL_P(rs) && limit < 0) { str = read_all(fptr, 0, Qnil); if (RSTRING_LEN(str) == 0) return Qnil; @@ -2550,7 +2571,7 @@ rb_io_t *fptr; GetOpenFile(io, fptr); - rb_io_check_readable(fptr); + rb_io_check_char_readable(fptr); return INT2NUM(fptr->lineno); } @@ -2577,7 +2598,7 @@ rb_io_t *fptr; GetOpenFile(io, fptr); - rb_io_check_readable(fptr); + rb_io_check_char_readable(fptr); fptr->lineno = NUM2INT(lineno); return lineno; } @@ -2722,7 +2743,7 @@ p++; errno = 0; } - rb_io_check_readable(fptr); + rb_io_check_byte_readable(fptr); READ_CHECK(fptr); if (io_fillbuf(fptr) < 0) { break; @@ -2859,7 +2880,7 @@ RETURN_ENUMERATOR(io, 0, 0); GetOpenFile(io, fptr); - rb_io_check_readable(fptr); + rb_io_check_char_readable(fptr); enc = io_input_encoding(fptr); READ_CHECK(fptr); @@ -2899,7 +2920,7 @@ RETURN_ENUMERATOR(io, 0, 0); GetOpenFile(io, fptr); - rb_io_check_readable(fptr); + rb_io_check_char_readable(fptr); READ_CHECK(fptr); if (NEED_READCONV(fptr)) { @@ -2989,7 +3010,7 @@ rb_encoding *enc; GetOpenFile(io, fptr); - rb_io_check_readable(fptr); + rb_io_check_char_readable(fptr); enc = io_input_encoding(fptr); READ_CHECK(fptr); @@ -3038,7 +3059,7 @@ int c; GetOpenFile(io, fptr); - rb_io_check_readable(fptr); + rb_io_check_byte_readable(fptr); READ_CHECK(fptr); if (fptr->fd == 0 && (fptr->mode & FMODE_TTY) && TYPE(rb_stdout) == T_FILE) { rb_io_t *ofp; @@ -3098,7 +3119,7 @@ rb_io_t *fptr; GetOpenFile(io, fptr); - rb_io_check_readable(fptr); + rb_io_check_byte_readable(fptr); io_unset_eof(fptr); if (NIL_P(b)) return Qnil; if (FIXNUM_P(b)) { @@ -3135,7 +3156,7 @@ long len; GetOpenFile(io, fptr); - rb_io_check_readable(fptr); + rb_io_check_char_readable(fptr); io_unset_eof(fptr); if (NIL_P(c)) return Qnil; if (FIXNUM_P(c)) { @@ -3739,7 +3760,8 @@ } pos = NUM2OFFT(offset); GetOpenFile(io, fptr); - if ((fptr->mode & FMODE_READABLE) && READ_DATA_BUFFERED(fptr)) { + if ((fptr->mode & FMODE_READABLE) && + (READ_DATA_BUFFERED(fptr) || READ_CHAR_PENDING(fptr))) { rb_raise(rb_eIOError, "sysseek for buffered IO"); } if ((fptr->mode & FMODE_WRITABLE) && fptr->wbuf_len) { @@ -3830,7 +3852,7 @@ if (ilen == 0) return str; GetOpenFile(io, fptr); - rb_io_check_readable(fptr); + rb_io_check_byte_readable(fptr); if (READ_DATA_BUFFERED(fptr)) { rb_raise(rb_eIOError, "sysread for buffered IO"); @@ -8387,7 +8409,7 @@ stp->close_src = 1; } GetOpenFile(src_io, src_fptr); - rb_io_check_readable(src_fptr); + rb_io_check_byte_readable(src_fptr); src_fd = src_fptr->fd; } stp->src_fd = src_fd; Index: test/ruby/test_io_m17n.rb =================================================================== --- test/ruby/test_io_m17n.rb (revision 27469) +++ test/ruby/test_io_m17n.rb (revision 27470) @@ -1741,5 +1741,38 @@ end } end + + def test_cbuf + with_tmpdir { + fn = "tst" + open(fn, "w") {|f| f.print "foo" } + open(fn, "r+t") {|f| + f.ungetc(f.getc) + assert_raise(IOError, "[ruby-dev:40493]") { f.readpartial(2) } + assert_raise(IOError) { f.read(2) } + assert_raise(IOError) { f.each_byte {|c| } } + assert_raise(IOError) { f.getbyte } + assert_raise(IOError) { f.ungetbyte(0) } + assert_raise(IOError) { f.sysread(2) } + assert_raise(IOError) { IO.copy_stream(f, "tmpout") } + assert_raise(IOError) { f.sysseek(2) } + } + open(fn, "r+t") {|f| + f.ungetc(f.getc) + assert_equal("foo", f.read) + } + } + end + + def test_text_mode_ungetc_eof + with_tmpdir { + open("ff", "w") {|f| } + open("ff", "rt") {|f| + f.ungetc "a" + assert(!f.eof?, "[ruby-dev:40506] (3)") + } + } + end + end -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/