Bug #5714 ยป read_binmode_fix_r34035.patch
include/ruby/win32.h | ||
---|---|---|
304 | 304 |
extern int rb_w32_ustati64(const char *, struct stati64 *); |
305 | 305 |
extern int rb_w32_access(const char *, int); |
306 | 306 |
extern int rb_w32_uaccess(const char *, int); |
307 |
extern char rb_w32_fd_is_text(int); |
|
307 | 308 | |
308 | 309 |
#ifdef __BORLANDC__ |
309 | 310 |
extern int rb_w32_fstati64(int, struct stati64 *); |
io.c | ||
---|---|---|
374 | 374 |
# endif |
375 | 375 |
#endif |
376 | 376 | |
377 |
static int io_fflush(rb_io_t *); |
|
378 | ||
377 | 379 |
#define NEED_NEWLINE_DECORATOR_ON_READ(fptr) ((fptr)->mode & FMODE_TEXTMODE) |
378 | 380 |
#define NEED_NEWLINE_DECORATOR_ON_WRITE(fptr) ((fptr)->mode & FMODE_TEXTMODE) |
379 | 381 |
#if defined(RUBY_TEST_CRLF_ENVIRONMENT) || defined(_WIN32) |
... | ... | |
413 | 415 |
* but stdin and pipe cannot seek back. Stdin and pipe read should use encoding |
414 | 416 |
* conversion for working properly with mode change. |
415 | 417 |
*/ |
416 |
#define SET_BINARY_MODE_WITH_SEEK_CUR(fptr) do {\ |
|
417 |
if ((fptr)->rbuf.len > 0 && !((fptr)->mode & FMODE_DUPLEX)) {\ |
|
418 |
off_t r;\ |
|
419 |
errno = 0;\ |
|
420 |
r = io_seek((fptr), -(fptr)->rbuf.len, SEEK_CUR);\ |
|
421 |
if (r < 0 && errno) {\ |
|
422 |
if (errno == ESPIPE)\ |
|
423 |
(fptr)->mode |= FMODE_DUPLEX;\ |
|
424 |
}\ |
|
425 |
else {\ |
|
426 |
(fptr)->rbuf.off = 0;\ |
|
427 |
(fptr)->rbuf.len = 0;\ |
|
428 |
}\ |
|
429 |
}\ |
|
430 |
setmode((fptr)->fd, O_BINARY);\ |
|
431 |
} while(0) |
|
418 |
/* |
|
419 |
* Return previous translation mode. |
|
420 |
*/ |
|
421 |
inline static int set_binary_mode_with_seek_cur(rb_io_t *fptr) { |
|
422 |
off_t r, pos; |
|
423 |
ssize_t read_size; |
|
424 |
long i; |
|
425 |
long newlines = 0; |
|
426 |
char *p; |
|
427 | ||
428 |
if (!rb_w32_fd_is_text((fptr)->fd)) return O_BINARY; |
|
429 | ||
430 |
if ((fptr)->rbuf.len == 0 || (fptr)->mode & FMODE_DUPLEX) { |
|
431 |
setmode((fptr)->fd, O_BINARY); |
|
432 |
return O_TEXT; |
|
433 |
} |
|
434 | ||
435 |
if (io_fflush(fptr) < 0) { |
|
436 |
rb_sys_fail(0); |
|
437 |
} |
|
438 |
errno = 0; |
|
439 |
pos = lseek((fptr)->fd, 0, SEEK_CUR); |
|
440 |
if (pos < 0 && errno) { |
|
441 |
if (errno == ESPIPE) |
|
442 |
(fptr)->mode |= FMODE_DUPLEX; |
|
443 |
setmode((fptr)->fd, O_BINARY); |
|
444 |
return O_TEXT; |
|
445 |
} |
|
446 |
/* add extra offset for '\r' */ |
|
447 |
p = (fptr)->rbuf.ptr+(fptr)->rbuf.off; |
|
448 |
for (i = 0; i < (fptr)->rbuf.len; i++) { |
|
449 |
if (*p == '\n') newlines++; |
|
450 |
p++; |
|
451 |
} |
|
452 |
while (newlines >= 0) { |
|
453 |
r = lseek((fptr)->fd, pos - (fptr)->rbuf.len - newlines, SEEK_SET); |
|
454 |
if (newlines == 0) break; |
|
455 |
if (read_size = _read((fptr)->fd, (fptr)->rbuf.ptr, (fptr)->rbuf.len + newlines)) { |
|
456 |
if (read_size == (fptr)->rbuf.len) { |
|
457 |
lseek((fptr)->fd, r, SEEK_SET); |
|
458 |
break; |
|
459 |
} |
|
460 |
else { |
|
461 |
newlines--; |
|
462 |
} |
|
463 |
} |
|
464 |
} |
|
465 |
(fptr)->rbuf.off = 0; |
|
466 |
(fptr)->rbuf.len = 0; |
|
467 |
setmode((fptr)->fd, O_BINARY); |
|
468 |
return O_TEXT; |
|
469 |
} |
|
470 |
#define SET_BINARY_MODE_WITH_SEEK_CUR(fptr) set_binary_mode_with_seek_cur(fptr) |
|
432 | 471 | |
433 | 472 |
#else |
434 | 473 |
/* Unix */ |
... | ... | |
494 | 533 |
} |
495 | 534 |
} |
496 | 535 | |
497 |
static int io_fflush(rb_io_t *); |
|
498 | 536 | |
499 | 537 |
VALUE |
500 | 538 |
rb_io_get_io(VALUE io) |
... | ... | |
1142 | 1180 |
!(fptr->encs.ecflags & ECONV_NEWLINE_DECORATOR_MASK)) { |
1143 | 1181 |
setmode(fptr->fd, O_BINARY); |
1144 | 1182 |
} |
1183 |
else { |
|
1184 |
setmode(fptr->fd, O_TEXT); |
|
1185 |
} |
|
1145 | 1186 |
if (!rb_enc_asciicompat(rb_enc_get(str))) { |
1146 | 1187 |
rb_raise(rb_eArgError, "ASCII incompatible string written for text mode IO without encoding conversion: %s", |
1147 | 1188 |
rb_enc_name(rb_enc_get(str))); |
... | ... | |
2462 | 2503 |
rb_io_t *fptr; |
2463 | 2504 |
long n, len; |
2464 | 2505 |
VALUE length, str; |
2506 |
#if defined(RUBY_TEST_CRLF_ENVIRONMENT) || defined(_WIN32) |
|
2507 |
int previous_mode; |
|
2508 |
#endif |
|
2465 | 2509 | |
2466 | 2510 |
rb_scan_args(argc, argv, "02", &length, &str); |
2467 | 2511 | |
... | ... | |
2482 | 2526 |
if (len == 0) return str; |
2483 | 2527 | |
2484 | 2528 |
READ_CHECK(fptr); |
2529 |
#if defined(RUBY_TEST_CRLF_ENVIRONMENT) || defined(_WIN32) |
|
2530 |
previous_mode = set_binary_mode_with_seek_cur(fptr); |
|
2531 |
#endif |
|
2485 | 2532 |
n = io_fread(str, 0, fptr); |
2533 |
#if defined(RUBY_TEST_CRLF_ENVIRONMENT) || defined(_WIN32) |
|
2534 |
if (previous_mode == O_TEXT) { |
|
2535 |
setmode(fptr->fd, O_TEXT); |
|
2536 |
} |
|
2537 |
#endif |
|
2486 | 2538 |
if (n == 0) { |
2487 | 2539 |
if (fptr->fd < 0) return Qnil; |
2488 | 2540 |
rb_str_resize(str, 0); |
test/ruby/test_io_m17n.rb | ||
---|---|---|
2222 | 2222 |
end |
2223 | 2223 |
end |
2224 | 2224 |
end if /mswin|mingw/ =~ RUBY_PLATFORM |
2225 | ||
2226 |
def test_read_with_length |
|
2227 |
with_tmpdir { |
|
2228 |
str = "a\nb" |
|
2229 |
generate_file("tmp", str) |
|
2230 |
open("tmp", "r") do |f| |
|
2231 |
assert_equal(str, f.read(3)) |
|
2232 |
end |
|
2233 |
} |
|
2234 |
end if /mswin|mingw/ =~ RUBY_PLATFORM |
|
2235 | ||
2236 |
def test_read_with_length_binmode |
|
2237 |
with_tmpdir { |
|
2238 |
str = "a\r\nb\r\nc\r\n\r\n" |
|
2239 |
generate_file("tmp", str) |
|
2240 |
open("tmp", "r") do |f| |
|
2241 |
# read with length should be binary mode |
|
2242 |
assert_equal("a\r\n", f.read(3)) # binary |
|
2243 |
assert_equal("b\nc\n\n", f.read) # text |
|
2244 |
end |
|
2245 |
} |
|
2246 |
end if /mswin|mingw/ =~ RUBY_PLATFORM |
|
2247 | ||
2248 |
def test_gets_and_read_with_binmode |
|
2249 |
with_tmpdir { |
|
2250 |
str = "a\r\nb\r\nc\r\n\n\r\n" |
|
2251 |
generate_file("tmp", str) |
|
2252 |
open("tmp", "r") do |f| |
|
2253 |
assert_equal("a\n", f.gets) # text |
|
2254 |
assert_equal("b\r\n", f.read(3)) # binary |
|
2255 |
assert_equal("c\r\n", f.read(3)) # binary |
|
2256 |
assert_equal("\n\n", f.read) # text |
|
2257 |
end |
|
2258 |
} |
|
2259 |
end if /mswin|mingw/ =~ RUBY_PLATFORM |
|
2260 | ||
2261 |
def test_getc_and_read_with_binmode |
|
2262 |
with_tmpdir { |
|
2263 |
str = "a\r\nb\r\nc\n\n\r\n\r\n" |
|
2264 |
generate_file("tmp", str) |
|
2265 |
open("tmp", "r") do |f| |
|
2266 |
assert_equal("a", f.getc) # text |
|
2267 |
assert_equal("\n", f.getc) # text |
|
2268 |
assert_equal("b\r\n", f.read(3)) # binary |
|
2269 |
assert_equal("c\n\n\n\n", f.read) # text |
|
2270 |
end |
|
2271 |
} |
|
2272 |
end if /mswin|mingw/ =~ RUBY_PLATFORM |
|
2273 | ||
2274 |
def test_read_with_binmode_and_gets |
|
2275 |
with_tmpdir { |
|
2276 |
str = "a\r\nb\r\nc\r\n\r\n" |
|
2277 |
open("tmp", "wb") { |f| f.write str } |
|
2278 |
open("tmp", "r") do |f| |
|
2279 |
assert_equal("a", f.getc) # text |
|
2280 |
assert_equal("\n", f.getc) # text |
|
2281 |
assert_equal("b\r\n", f.read(3)) # binary |
|
2282 |
assert_equal("c\n", f.gets) # text |
|
2283 |
assert_equal("\n", f.gets) # text |
|
2284 |
end |
|
2285 |
} |
|
2286 |
end |
|
2287 | ||
2288 |
def test_read_with_binmode_and_getc |
|
2289 |
with_tmpdir { |
|
2290 |
str = "a\r\nb\r\nc\r\n\r\n" |
|
2291 |
open("tmp", "wb") { |f| f.write str } |
|
2292 |
open("tmp", "r") do |f| |
|
2293 |
assert_equal("a", f.getc) # text |
|
2294 |
assert_equal("\n", f.getc) # text |
|
2295 |
assert_equal("b\r\n", f.read(3)) # binary |
|
2296 |
assert_equal("c", f.getc) # text |
|
2297 |
assert_equal("\n", f.getc) # text |
|
2298 |
assert_equal("\n", f.getc) # text |
|
2299 |
end |
|
2300 |
} |
|
2301 |
end |
|
2302 | ||
2303 |
def test_read_write_with_binmode |
|
2304 |
with_tmpdir { |
|
2305 |
str = "a\r\n" |
|
2306 |
generate_file("tmp", str) |
|
2307 |
open("tmp", "r+") do |f| |
|
2308 |
assert_equal("a\r\n", f.read(3)) # binary |
|
2309 |
f.write("b\n\n"); # text |
|
2310 |
f.rewind |
|
2311 |
assert_equal("a\nb\n\n", f.read) # text |
|
2312 |
f.rewind |
|
2313 |
assert_equal("a\r\nb\r\n\r\n", f.binmode.read) # binary |
|
2314 |
end |
|
2315 |
} |
|
2316 |
end if /mswin|mingw/ =~ RUBY_PLATFORM |
|
2225 | 2317 |
end |
win32/win32.c | ||
---|---|---|
2259 | 2259 |
if (fileno(stdin) < 0) { |
2260 | 2260 |
stdin->_file = open_null(0); |
2261 | 2261 |
} |
2262 |
else { |
|
2263 |
setmode(fileno(stdin), O_BINARY); |
|
2264 |
} |
|
2262 | 2265 |
if (fileno(stdout) < 0) { |
2263 | 2266 |
stdout->_file = open_null(1); |
2264 | 2267 |
} |
... | ... | |
6137 | 6140 |
} |
6138 | 6141 |
return numaddr; |
6139 | 6142 |
} |
6143 | ||
6144 |
char |
|
6145 |
rb_w32_fd_is_text(int fd) { |
|
6146 |
return _osfile(fd) & FTEXT; |
|
6147 |
} |