Project

General

Profile

Bug #5714 » read_binmode_fix_r34024.patch

h.shirosaki (Hiroshi Shirosaki), 12/13/2011 04:44 PM

View differences:

include/ruby/win32.h
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 *);
io.c
# 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)
......
* 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)
inline static void 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;
if ((fptr)->rbuf.len == 0 || (fptr)->mode & FMODE_DUPLEX) {
setmode((fptr)->fd, O_BINARY);
return;
}
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;
}
/* 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);
}
#define SET_BINARY_MODE_WITH_SEEK_CUR(fptr) set_binary_mode_with_seek_cur(fptr)
#else
/* Unix */
......
}
}
static int io_fflush(rb_io_t *);
VALUE
rb_io_get_io(VALUE io)
......
!(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)));
......
if (len == 0) return str;
READ_CHECK(fptr);
SET_BINARY_MODE_WITH_SEEK_CUR(fptr);
n = io_fread(str, 0, fptr);
if (n == 0) {
if (fptr->fd < 0) return Qnil;
test/ruby/test_io_m17n.rb
end
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\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\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_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
win32/win32.c
if (fileno(stdin) < 0) {
stdin->_file = open_null(0);
}
else {
setmode(fileno(stdin), O_BINARY);
}
if (fileno(stdout) < 0) {
stdout->_file = open_null(1);
}
......
}
return numaddr;
}
char
rb_w32_fd_is_text(int fd) {
return _osfile(fd) & FTEXT;
}
(3-3/6)