From 0c6103cf50fd3d7c43ff264c9cc9d62c1f723067 Mon Sep 17 00:00:00 2001 From: usa Date: Wed, 14 Dec 2011 10:38:12 +0000 Subject: * 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 --- io.c | 86 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 69 insertions(+), 17 deletions(-) (limited to 'io.c') diff --git a/io.c b/io.c index 0713f35fcb..3e184f2995 100644 --- a/io.c +++ b/io.c @@ -374,6 +374,8 @@ rb_cloexec_fcntl_dupfd(int fd, int minfd) # 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,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 * 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 */ @@ -494,7 +533,6 @@ rb_io_check_closed(rb_io_t *fptr) } } -static int io_fflush(rb_io_t *); VALUE 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)) { 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 @@ 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); @@ -2482,7 +2526,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); -- cgit v1.2.3