ruby-changes:22497
From: naruse <ko1@a...>
Date: Sat, 11 Feb 2012 03:39:20 +0900 (JST)
Subject: [ruby-changes:22497] naruse:r34546 (ruby_1_9_3): merge revision(s) 34043,34045,34132: [Backport #5791]
naruse 2012-02-11 03:39:05 +0900 (Sat, 11 Feb 2012) New Revision: 34546 http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=34546 Log: 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] Modified files: branches/ruby_1_9_3/ChangeLog branches/ruby_1_9_3/include/ruby/win32.h branches/ruby_1_9_3/io.c branches/ruby_1_9_3/test/ruby/test_io_m17n.rb branches/ruby_1_9_3/version.h branches/ruby_1_9_3/win32/win32.c Index: ruby_1_9_3/include/ruby/win32.h =================================================================== --- ruby_1_9_3/include/ruby/win32.h (revision 34545) +++ ruby_1_9_3/include/ruby/win32.h (revision 34546) @@ -303,6 +303,7 @@ 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 *); Index: ruby_1_9_3/ChangeLog =================================================================== --- ruby_1_9_3/ChangeLog (revision 34545) +++ ruby_1_9_3/ChangeLog (revision 34546) @@ -1,3 +1,50 @@ +Sat Feb 11 03:38:48 2012 Hiroshi Shirosaki <h.shirosaki@g...> + + * 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@r...> + + * 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@r...> + + * 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@r...> * test/rexml/test_order.rb (OrderTester#test_more_ordering): use Index: ruby_1_9_3/io.c =================================================================== --- ruby_1_9_3/io.c (revision 34545) +++ ruby_1_9_3/io.c (revision 34546) @@ -219,6 +219,10 @@ # 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,23 +262,66 @@ * 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 */ # define DEFAULT_TEXTMODE 0 @@ -290,8 +337,6 @@ #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 @@ } } -static int io_fflush(rb_io_t *); VALUE rb_io_get_io(VALUE io) @@ -987,6 +1031,9 @@ !(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 @@ 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 @@ 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); Index: ruby_1_9_3/win32/win32.c =================================================================== --- ruby_1_9_3/win32/win32.c (revision 34545) +++ ruby_1_9_3/win32/win32.c (revision 34546) @@ -2135,6 +2135,9 @@ 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 @@ } return numaddr; } + +char +rb_w32_fd_is_text(int fd) { + return _osfile(fd) & FTEXT; +} Index: ruby_1_9_3/version.h =================================================================== --- ruby_1_9_3/version.h (revision 34545) +++ ruby_1_9_3/version.h (revision 34546) @@ -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 Index: ruby_1_9_3/test/ruby/test_io_m17n.rb =================================================================== --- ruby_1_9_3/test/ruby/test_io_m17n.rb (revision 34545) +++ ruby_1_9_3/test/ruby/test_io_m17n.rb (revision 34546) @@ -2222,4 +2222,107 @@ 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 -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/