summaryrefslogtreecommitdiff
path: root/io.c
diff options
context:
space:
mode:
authornaruse <naruse@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2012-02-10 18:39:05 +0000
committernaruse <naruse@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2012-02-10 18:39:05 +0000
commita208a7507244c3819beff06ddf422066437ed5b5 (patch)
tree7007ac87dab416d2687a7b27422e91884c74e434 /io.c
parent877469197274d5ee7559e154cfac21dbdcec3854 (diff)
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] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/branches/ruby_1_9_3@34546 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'io.c')
-rw-r--r--io.c96
1 files changed, 77 insertions, 19 deletions
diff --git a/io.c b/io.c
index aa72d06a41..cbe2bff2c4 100644
--- a/io.c
+++ b/io.c
@@ -219,6 +219,10 @@ rb_update_max_fd(int fd)
# 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,22 +262,65 @@ rb_update_max_fd(int fd)
* 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 */
@@ -290,8 +337,6 @@ rb_update_max_fd(int fd)
#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 @@ rb_io_check_closed(rb_io_t *fptr)
}
}
-static int io_fflush(rb_io_t *);
VALUE
rb_io_get_io(VALUE io)
@@ -987,6 +1031,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)));
@@ -2301,6 +2348,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);
@@ -2321,7 +2371,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);