1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00

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


git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@34043 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
usa 2011-12-14 10:38:12 +00:00
parent 4474c83a9d
commit 0c6103cf50
5 changed files with 194 additions and 17 deletions

View file

@ -1,3 +1,27 @@
Wed Dec 14 19:22:33 2011 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#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@ruby-lang.org> Wed Dec 14 15:28:31 2011 Nobuyoshi Nakada <nobu@ruby-lang.org>
* transcode.c (str_encode): about the extension of :fallback * transcode.c (str_encode): about the extension of :fallback

View file

@ -304,6 +304,7 @@ extern int rb_w32_stati64(const char *, struct stati64 *);
extern int rb_w32_ustati64(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_access(const char *, int);
extern int rb_w32_uaccess(const char *, int); extern int rb_w32_uaccess(const char *, int);
extern char rb_w32_fd_is_text(int);
#ifdef __BORLANDC__ #ifdef __BORLANDC__
extern int rb_w32_fstati64(int, struct stati64 *); extern int rb_w32_fstati64(int, struct stati64 *);

86
io.c
View file

@ -374,6 +374,8 @@ rb_cloexec_fcntl_dupfd(int fd, int minfd)
# endif # endif
#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_READ(fptr) ((fptr)->mode & FMODE_TEXTMODE)
#define NEED_NEWLINE_DECORATOR_ON_WRITE(fptr) ((fptr)->mode & FMODE_TEXTMODE) #define NEED_NEWLINE_DECORATOR_ON_WRITE(fptr) ((fptr)->mode & FMODE_TEXTMODE)
#if defined(RUBY_TEST_CRLF_ENVIRONMENT) || defined(_WIN32) #if defined(RUBY_TEST_CRLF_ENVIRONMENT) || defined(_WIN32)
@ -413,22 +415,59 @@ rb_cloexec_fcntl_dupfd(int fd, int minfd)
* but stdin and pipe cannot seek back. Stdin and pipe read should use encoding * but stdin and pipe cannot seek back. Stdin and pipe read should use encoding
* conversion for working properly with mode change. * 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)) {\ * Return previous translation mode.
off_t r;\ */
errno = 0;\ inline static int set_binary_mode_with_seek_cur(rb_io_t *fptr) {
r = io_seek((fptr), -(fptr)->rbuf.len, SEEK_CUR);\ off_t r, pos;
if (r < 0 && errno) {\ ssize_t read_size;
if (errno == ESPIPE)\ long i;
(fptr)->mode |= FMODE_DUPLEX;\ long newlines = 0;
}\ char *p;
else {\
(fptr)->rbuf.off = 0;\ if (!rb_w32_fd_is_text((fptr)->fd)) return O_BINARY;
(fptr)->rbuf.len = 0;\
}\ if ((fptr)->rbuf.len == 0 || (fptr)->mode & FMODE_DUPLEX) {
}\ setmode((fptr)->fd, O_BINARY);
setmode((fptr)->fd, O_BINARY);\ return O_TEXT;
} while(0) }
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 #else
/* Unix */ /* Unix */
@ -494,7 +533,6 @@ rb_io_check_closed(rb_io_t *fptr)
} }
} }
static int io_fflush(rb_io_t *);
VALUE VALUE
rb_io_get_io(VALUE io) rb_io_get_io(VALUE io)
@ -1142,6 +1180,9 @@ do_writeconv(VALUE str, rb_io_t *fptr)
!(fptr->encs.ecflags & ECONV_NEWLINE_DECORATOR_MASK)) { !(fptr->encs.ecflags & ECONV_NEWLINE_DECORATOR_MASK)) {
setmode(fptr->fd, O_BINARY); setmode(fptr->fd, O_BINARY);
} }
else {
setmode(fptr->fd, O_TEXT);
}
if (!rb_enc_asciicompat(rb_enc_get(str))) { 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_raise(rb_eArgError, "ASCII incompatible string written for text mode IO without encoding conversion: %s",
rb_enc_name(rb_enc_get(str))); rb_enc_name(rb_enc_get(str)));
@ -2462,6 +2503,9 @@ io_read(int argc, VALUE *argv, VALUE io)
rb_io_t *fptr; rb_io_t *fptr;
long n, len; long n, len;
VALUE length, str; VALUE length, str;
#if defined(RUBY_TEST_CRLF_ENVIRONMENT) || defined(_WIN32)
int previous_mode;
#endif
rb_scan_args(argc, argv, "02", &length, &str); rb_scan_args(argc, argv, "02", &length, &str);
@ -2482,7 +2526,15 @@ io_read(int argc, VALUE *argv, VALUE io)
if (len == 0) return str; if (len == 0) return str;
READ_CHECK(fptr); 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); 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 (n == 0) {
if (fptr->fd < 0) return Qnil; if (fptr->fd < 0) return Qnil;
rb_str_resize(str, 0); rb_str_resize(str, 0);

View file

@ -2222,4 +2222,96 @@ EOT
end end
end end
end if /mswin|mingw/ =~ RUBY_PLATFORM 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 end

View file

@ -2259,6 +2259,9 @@ init_stdhandle(void)
if (fileno(stdin) < 0) { if (fileno(stdin) < 0) {
stdin->_file = open_null(0); stdin->_file = open_null(0);
} }
else {
setmode(fileno(stdin), O_BINARY);
}
if (fileno(stdout) < 0) { if (fileno(stdout) < 0) {
stdout->_file = open_null(1); stdout->_file = open_null(1);
} }
@ -6137,3 +6140,8 @@ rb_w32_inet_ntop(int af, const void *addr, char *numaddr, size_t numaddr_len)
} }
return numaddr; return numaddr;
} }
char
rb_w32_fd_is_text(int fd) {
return _osfile(fd) & FTEXT;
}