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

ruby-changes:21994

From: usa <ko1@a...>
Date: Wed, 14 Dec 2011 19:38:25 +0900 (JST)
Subject: [ruby-changes:21994] usa:r34043 (trunk): * win32/win32.c, include/ruby/win32.h (rb_w32_fd_is_text): new function.

usa	2011-12-14 19:38:12 +0900 (Wed, 14 Dec 2011)

  New Revision: 34043

  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=34043

  Log:
    * 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]

  Modified files:
    trunk/ChangeLog
    trunk/include/ruby/win32.h
    trunk/io.c
    trunk/test/ruby/test_io_m17n.rb
    trunk/win32/win32.c

Index: include/ruby/win32.h
===================================================================
--- include/ruby/win32.h	(revision 34042)
+++ include/ruby/win32.h	(revision 34043)
@@ -304,6 +304,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: ChangeLog
===================================================================
--- ChangeLog	(revision 34042)
+++ ChangeLog	(revision 34043)
@@ -1,3 +1,27 @@
+Wed Dec 14 19:22:33 2011  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#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]
+
 Wed Dec 14 15:28:31 2011  Nobuyoshi Nakada  <nobu@r...>
 
 	* transcode.c (str_encode): about the extension of :fallback
Index: io.c
===================================================================
--- io.c	(revision 34042)
+++ io.c	(revision 34043)
@@ -374,6 +374,8 @@
 #  endif
 #endif
 
+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)
@@ -413,23 +415,60 @@
  * 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;
+    char *p;
 
+    if (!rb_w32_fd_is_text((fptr)->fd)) return O_BINARY;
+
+    if ((fptr)->rbuf.len == 0 || (fptr)->mode & FMODE_DUPLEX) {
+	setmode((fptr)->fd, O_BINARY);
+	return O_TEXT;
+    }
+
+    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;
+	setmode((fptr)->fd, O_BINARY);
+	return O_TEXT;
+    }
+    /* add extra offset for '\r' */
+    p = (fptr)->rbuf.ptr+(fptr)->rbuf.off;
+    for (i = 0; i < (fptr)->rbuf.len; i++) {
+	if (*p == '\n') newlines++;
+	p++;
+    }
+    while (newlines >= 0) {
+	r = lseek((fptr)->fd, pos - (fptr)->rbuf.len - newlines, SEEK_SET);
+	if (newlines == 0) break;
+	if (read_size = _read((fptr)->fd, (fptr)->rbuf.ptr, (fptr)->rbuf.len + newlines)) {
+	    if (read_size == (fptr)->rbuf.len) {
+		lseek((fptr)->fd, r, SEEK_SET);
+		break;
+	    }
+	    else {
+		newlines--;
+	    }
+	}
+    }
+    (fptr)->rbuf.off = 0;
+    (fptr)->rbuf.len = 0;
+    setmode((fptr)->fd, O_BINARY);
+    return O_TEXT;
+}
+#define SET_BINARY_MODE_WITH_SEEK_CUR(fptr) set_binary_mode_with_seek_cur(fptr)
+
 #else
 /* Unix */
 # define DEFAULT_TEXTMODE 0
@@ -494,7 +533,6 @@
     }
 }
 
-static int io_fflush(rb_io_t *);
 
 VALUE
 rb_io_get_io(VALUE io)
@@ -1142,6 +1180,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)));
@@ -2462,6 +2503,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);
 
@@ -2482,7 +2526,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: win32/win32.c
===================================================================
--- win32/win32.c	(revision 34042)
+++ win32/win32.c	(revision 34043)
@@ -2259,6 +2259,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);
     }
@@ -6137,3 +6140,8 @@
     }
     return numaddr;
 }
+
+char
+rb_w32_fd_is_text(int fd) {
+    return _osfile(fd) & FTEXT;
+}
Index: test/ruby/test_io_m17n.rb
===================================================================
--- test/ruby/test_io_m17n.rb	(revision 34042)
+++ test/ruby/test_io_m17n.rb	(revision 34043)
@@ -2222,4 +2222,96 @@
       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
+
+  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
+
+  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
 end

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

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