[前][次][番号順一覧][スレッド一覧]

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/

[前][次][番号順一覧][スレッド一覧]