diff options
author | naruse <naruse@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2012-02-10 18:39:05 +0000 |
---|---|---|
committer | naruse <naruse@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2012-02-10 18:39:05 +0000 |
commit | a208a7507244c3819beff06ddf422066437ed5b5 (patch) | |
tree | 7007ac87dab416d2687a7b27422e91884c74e434 | |
parent | 877469197274d5ee7559e154cfac21dbdcec3854 (diff) |
merge revision(s) 34043,34045,34132: [Backport #5791]
* win32/win32.c, include/ruby/win32.h (rb_w32_fd_is_text): new function.
* win32/win32.c (init_stdhandle): set default mode of stdin as binmode.
* io.c (set_binary_mode_with_seek_cur): new function to replace
SET_BINARY_MODE_WITH_SEEK_CUR macro. now returns previous mode of the
fd and take care of LF in rbuf.
* io.c (do_writeconv): set text mode when needed.
* io.c (io_read): need to change the mode of the IO to binmode
temporally when the length for IO#read, because IO#read with length
must behave so.
* test/ruby/test_io_m17n.rb (TestIO_M17N#est_{read_with_length,
read_with_length_binmode,get[cs]_and_read_with_binmode,
read_with_binmode_and_get[cs],read_write_with_binmode}): tests for
above changes.
all patches are written by Hiroshi Shirosaki. [ruby-core:41496]
[Feature #5714]
* test/ruby/test_io_m17n.rb
(TestIO_M17N#test_{read_with_binmode_and_get[cs]}): only for Windows.
* test/ruby/test_io_m17n.rb (TestIO_M17N#test_{read_with_length,
* io.c (rb_sys_fail_path): move the definition.
Move above for using it in set_binary_mode_with_seek_cur().
* io.c (set_binary_mode_with_seek_cur): fix improper seek cursor.
Seeking file cursor with setting binary mode has possibility to
cause infinite loop. Fixed the bug and refined error handling.
Introduced at r34043.
And cleanups as below.
Remove unnecessary parentheses of `fptr`.
Use return value of setmode().
* test/ruby/test_io_m17n.rb
(TestIO_M17N#test_seek_with_setting_binmode): add a test for abobe.
[ruby-core:41671] [Bug #5714]
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/branches/ruby_1_9_3@34546 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
-rw-r--r-- | ChangeLog | 47 | ||||
-rw-r--r-- | include/ruby/win32.h | 1 | ||||
-rw-r--r-- | io.c | 96 | ||||
-rw-r--r-- | test/ruby/test_io_m17n.rb | 103 | ||||
-rw-r--r-- | version.h | 2 | ||||
-rw-r--r-- | win32/win32.c | 8 |
6 files changed, 237 insertions, 20 deletions
@@ -1,3 +1,50 @@ +Sat Feb 11 03:38:48 2012 Hiroshi Shirosaki <h.shirosaki@gmail.com> + + * io.c (rb_sys_fail_path): move the definition. + Move above for using it in set_binary_mode_with_seek_cur(). + + * io.c (set_binary_mode_with_seek_cur): fix improper seek cursor. + Seeking file cursor with setting binary mode has possibility to + cause infinite loop. Fixed the bug and refined error handling. + Introduced at r34043. + + And cleanups as below. + Remove unnecessary parentheses of `fptr`. + Use return value of setmode(). + + * test/ruby/test_io_m17n.rb + (TestIO_M17N#test_seek_with_setting_binmode): add a test for abobe. + [ruby-core:41671] [Bug #5714] + +Sat Feb 11 03:38:48 2012 NAKAMURA Usaku <usa@ruby-lang.org> + + * test/ruby/test_io_m17n.rb + (TestIO_M17N#test_{read_with_binmode_and_get[cs]}): only for Windows. + +Sat Feb 11 03:38:48 2012 NAKAMURA Usaku <usa@ruby-lang.org> + + * win32/win32.c, include/ruby/win32.h (rb_w32_fd_is_text): new function. + + * win32/win32.c (init_stdhandle): set default mode of stdin as binmode. + + * io.c (set_binary_mode_with_seek_cur): new function to replace + SET_BINARY_MODE_WITH_SEEK_CUR macro. now returns previous mode of the + fd and take care of LF in rbuf. + + * io.c (do_writeconv): set text mode when needed. + + * io.c (io_read): need to change the mode of the IO to binmode + temporally when the length for IO#read, because IO#read with length + must behave so. + + * test/ruby/test_io_m17n.rb (TestIO_M17N#test_{read_with_length, + read_with_length_binmode,get[cs]_and_read_with_binmode, + read_with_binmode_and_get[cs],read_write_with_binmode}): tests for + above changes. + + all patches are written by Hiroshi Shirosaki. [ruby-core:41496] + [Feature #5714] + Sat Feb 11 03:37:56 2012 NAKAMURA Usaku <usa@ruby-lang.org> * test/rexml/test_order.rb (OrderTester#test_more_ordering): use diff --git a/include/ruby/win32.h b/include/ruby/win32.h index 4d8a66742f..7d3c1d0cef 100644 --- a/include/ruby/win32.h +++ b/include/ruby/win32.h @@ -303,6 +303,7 @@ extern int rb_w32_stati64(const char *, struct stati64 *); extern int rb_w32_ustati64(const char *, struct stati64 *); extern int rb_w32_access(const char *, int); extern int rb_w32_uaccess(const char *, int); +extern char rb_w32_fd_is_text(int); #ifdef __BORLANDC__ extern int rb_w32_fstati64(int, struct stati64 *); @@ -219,6 +219,10 @@ rb_update_max_fd(int fd) # endif #endif +#define rb_sys_fail_path(path) rb_sys_fail(NIL_P(path) ? 0 : RSTRING_PTR(path)) + +static int io_fflush(rb_io_t *); + #define NEED_NEWLINE_DECORATOR_ON_READ(fptr) ((fptr)->mode & FMODE_TEXTMODE) #define NEED_NEWLINE_DECORATOR_ON_WRITE(fptr) ((fptr)->mode & FMODE_TEXTMODE) #if defined(RUBY_TEST_CRLF_ENVIRONMENT) || defined(_WIN32) @@ -258,22 +262,65 @@ rb_update_max_fd(int fd) * but stdin and pipe cannot seek back. Stdin and pipe read should use encoding * conversion for working properly with mode change. */ -#define SET_BINARY_MODE_WITH_SEEK_CUR(fptr) do {\ - if ((fptr)->rbuf.len > 0 && !((fptr)->mode & FMODE_DUPLEX)) {\ - off_t r;\ - errno = 0;\ - r = io_seek((fptr), -(fptr)->rbuf.len, SEEK_CUR);\ - if (r < 0 && errno) {\ - if (errno == ESPIPE)\ - (fptr)->mode |= FMODE_DUPLEX;\ - }\ - else {\ - (fptr)->rbuf.off = 0;\ - (fptr)->rbuf.len = 0;\ - }\ - }\ - setmode((fptr)->fd, O_BINARY);\ -} while(0) +/* + * Return previous translation mode. + */ +inline static int set_binary_mode_with_seek_cur(rb_io_t *fptr) { + off_t r, pos; + ssize_t read_size; + long i; + long newlines = 0; + long extra_max; + char *p; + + if (!rb_w32_fd_is_text(fptr->fd)) return O_BINARY; + + if (fptr->rbuf.len == 0 || fptr->mode & FMODE_DUPLEX) { + return setmode(fptr->fd, O_BINARY); + } + + if (io_fflush(fptr) < 0) { + rb_sys_fail(0); + } + errno = 0; + pos = lseek(fptr->fd, 0, SEEK_CUR); + if (pos < 0 && errno) { + if (errno == ESPIPE) + fptr->mode |= FMODE_DUPLEX; + return setmode(fptr->fd, O_BINARY); + } + /* add extra offset for removed '\r' in rbuf */ + extra_max = pos - fptr->rbuf.len; + p = fptr->rbuf.ptr + fptr->rbuf.off; + for (i = 0; i < fptr->rbuf.len; i++) { + if (*p == '\n') newlines++; + if (extra_max == newlines) break; + p++; + } + while (newlines >= 0) { + r = lseek(fptr->fd, pos - fptr->rbuf.len - newlines, SEEK_SET); + if (newlines == 0) break; + if (r < 0) { + newlines--; + continue; + } + read_size = _read(fptr->fd, fptr->rbuf.ptr, fptr->rbuf.len + newlines); + if (read_size < 0) { + rb_sys_fail_path(fptr->pathv); + } + if (read_size == fptr->rbuf.len) { + lseek(fptr->fd, r, SEEK_SET); + break; + } + else { + newlines--; + } + } + fptr->rbuf.off = 0; + fptr->rbuf.len = 0; + return setmode(fptr->fd, O_BINARY); +} +#define SET_BINARY_MODE_WITH_SEEK_CUR(fptr) set_binary_mode_with_seek_cur(fptr) #else /* Unix */ @@ -290,8 +337,6 @@ rb_update_max_fd(int fd) #define shutdown(a,b) 0 #endif -#define rb_sys_fail_path(path) rb_sys_fail(NIL_P(path) ? 0 : RSTRING_PTR(path)) - #if defined(_WIN32) #define is_socket(fd, path) rb_w32_is_socket(fd) #elif !defined(S_ISSOCK) @@ -339,7 +384,6 @@ rb_io_check_closed(rb_io_t *fptr) } } -static int io_fflush(rb_io_t *); VALUE rb_io_get_io(VALUE io) @@ -987,6 +1031,9 @@ do_writeconv(VALUE str, rb_io_t *fptr) !(fptr->encs.ecflags & ECONV_NEWLINE_DECORATOR_MASK)) { setmode(fptr->fd, O_BINARY); } + else { + setmode(fptr->fd, O_TEXT); + } if (!rb_enc_asciicompat(rb_enc_get(str))) { rb_raise(rb_eArgError, "ASCII incompatible string written for text mode IO without encoding conversion: %s", rb_enc_name(rb_enc_get(str))); @@ -2301,6 +2348,9 @@ io_read(int argc, VALUE *argv, VALUE io) rb_io_t *fptr; long n, len; VALUE length, str; +#if defined(RUBY_TEST_CRLF_ENVIRONMENT) || defined(_WIN32) + int previous_mode; +#endif rb_scan_args(argc, argv, "02", &length, &str); @@ -2321,7 +2371,15 @@ io_read(int argc, VALUE *argv, VALUE io) if (len == 0) return str; READ_CHECK(fptr); +#if defined(RUBY_TEST_CRLF_ENVIRONMENT) || defined(_WIN32) + previous_mode = set_binary_mode_with_seek_cur(fptr); +#endif n = io_fread(str, 0, fptr); +#if defined(RUBY_TEST_CRLF_ENVIRONMENT) || defined(_WIN32) + if (previous_mode == O_TEXT) { + setmode(fptr->fd, O_TEXT); + } +#endif if (n == 0) { if (fptr->fd < 0) return Qnil; rb_str_resize(str, 0); diff --git a/test/ruby/test_io_m17n.rb b/test/ruby/test_io_m17n.rb index 6f823c85a3..b7460bf63e 100644 --- a/test/ruby/test_io_m17n.rb +++ b/test/ruby/test_io_m17n.rb @@ -2222,4 +2222,107 @@ EOT end end end if /mswin|mingw/ =~ RUBY_PLATFORM + + def test_read_with_length + with_tmpdir { + str = "a\nb" + generate_file("tmp", str) + open("tmp", "r") do |f| + assert_equal(str, f.read(3)) + end + } + end if /mswin|mingw/ =~ RUBY_PLATFORM + + def test_read_with_length_binmode + with_tmpdir { + str = "a\r\nb\r\nc\r\n\r\n" + generate_file("tmp", str) + open("tmp", "r") do |f| + # read with length should be binary mode + assert_equal("a\r\n", f.read(3)) # binary + assert_equal("b\nc\n\n", f.read) # text + end + } + end if /mswin|mingw/ =~ RUBY_PLATFORM + + def test_gets_and_read_with_binmode + with_tmpdir { + str = "a\r\nb\r\nc\r\n\n\r\n" + generate_file("tmp", str) + open("tmp", "r") do |f| + assert_equal("a\n", f.gets) # text + assert_equal("b\r\n", f.read(3)) # binary + assert_equal("c\r\n", f.read(3)) # binary + assert_equal("\n\n", f.read) # text + end + } + end if /mswin|mingw/ =~ RUBY_PLATFORM + + def test_getc_and_read_with_binmode + with_tmpdir { + str = "a\r\nb\r\nc\n\n\r\n\r\n" + generate_file("tmp", str) + open("tmp", "r") do |f| + assert_equal("a", f.getc) # text + assert_equal("\n", f.getc) # text + assert_equal("b\r\n", f.read(3)) # binary + assert_equal("c\n\n\n\n", f.read) # text + end + } + end if /mswin|mingw/ =~ RUBY_PLATFORM + + def test_read_with_binmode_and_gets + with_tmpdir { + str = "a\r\nb\r\nc\r\n\r\n" + open("tmp", "wb") { |f| f.write str } + open("tmp", "r") do |f| + assert_equal("a", f.getc) # text + assert_equal("\n", f.getc) # text + assert_equal("b\r\n", f.read(3)) # binary + assert_equal("c\n", f.gets) # text + assert_equal("\n", f.gets) # text + end + } + end if /mswin|mingw/ =~ RUBY_PLATFORM + + def test_read_with_binmode_and_getc + with_tmpdir { + str = "a\r\nb\r\nc\r\n\r\n" + open("tmp", "wb") { |f| f.write str } + open("tmp", "r") do |f| + assert_equal("a", f.getc) # text + assert_equal("\n", f.getc) # text + assert_equal("b\r\n", f.read(3)) # binary + assert_equal("c", f.getc) # text + assert_equal("\n", f.getc) # text + assert_equal("\n", f.getc) # text + end + } + end if /mswin|mingw/ =~ RUBY_PLATFORM + + def test_read_write_with_binmode + with_tmpdir { + str = "a\r\n" + generate_file("tmp", str) + open("tmp", "r+") do |f| + assert_equal("a\r\n", f.read(3)) # binary + f.write("b\n\n"); # text + f.rewind + assert_equal("a\nb\n\n", f.read) # text + f.rewind + assert_equal("a\r\nb\r\n\r\n", f.binmode.read) # binary + end + } + end if /mswin|mingw/ =~ RUBY_PLATFORM + + def test_seek_with_setting_binmode + with_tmpdir { + str = "a\r\nb\r\nc\r\n\r\n\n\n\n\n\n\n\n" + generate_file("tmp", str) + open("tmp", "r") do |f| + assert_equal("a\n", f.gets) # text + assert_equal("b\r\n", f.read(3)) # binary + end + } + end if /mswin|mingw/ =~ RUBY_PLATFORM end @@ -1,5 +1,5 @@ #define RUBY_VERSION "1.9.3" -#define RUBY_PATCHLEVEL 91 +#define RUBY_PATCHLEVEL 92 #define RUBY_RELEASE_DATE "2012-02-11" #define RUBY_RELEASE_YEAR 2012 diff --git a/win32/win32.c b/win32/win32.c index 8b7283ba6a..15832a8c0a 100644 --- a/win32/win32.c +++ b/win32/win32.c @@ -2135,6 +2135,9 @@ init_stdhandle(void) if (fileno(stdin) < 0) { stdin->_file = open_null(0); } + else { + setmode(fileno(stdin), O_BINARY); + } if (fileno(stdout) < 0) { stdout->_file = open_null(1); } @@ -5817,3 +5820,8 @@ rb_w32_inet_ntop(int af, void *addr, char *numaddr, size_t numaddr_len) } return numaddr; } + +char +rb_w32_fd_is_text(int fd) { + return _osfile(fd) & FTEXT; +} |