summaryrefslogtreecommitdiff
path: root/io.c
diff options
context:
space:
mode:
authorusa <usa@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2011-12-14 10:38:12 +0000
committerusa <usa@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2011-12-14 10:38:12 +0000
commit0c6103cf50fd3d7c43ff264c9cc9d62c1f723067 (patch)
treeed198b94b0166fd7a7d30b745ba5446307d2e94c /io.c
parent4474c83a9d2baca7c263009e722c02d105ae9336 (diff)
* 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
Diffstat (limited to 'io.c')
-rw-r--r--io.c86
1 files changed, 69 insertions, 17 deletions
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);