Backport #6179 » pos_backport.patch
branches/ruby_1_9_3/io.c (revision 35220) → branches/ruby_1_9_3/io.c (working copy) | ||
---|---|---|
#define rb_sys_fail_path(path) rb_sys_fail_str(path)
|
||
static int io_fflush(rb_io_t *);
|
||
static rb_io_t *flush_before_seek(rb_io_t *fptr);
|
||
#define NEED_NEWLINE_DECORATOR_ON_READ(fptr) ((fptr)->mode & FMODE_TEXTMODE)
|
||
#define NEED_NEWLINE_DECORATOR_ON_WRITE(fptr) ((fptr)->mode & FMODE_TEXTMODE)
|
||
... | ... | |
(ecflags) |= ECONV_UNIVERSAL_NEWLINE_DECORATOR;\
|
||
}\
|
||
} while(0)
|
||
/*
|
||
* We use io_seek to back cursor position when changing mode from text to binary,
|
||
* but stdin and pipe cannot seek back. Stdin and pipe read should use encoding
|
||
* conversion for working properly with mode change.
|
||
* IO unread with taking care of removed '\r' in text mode.
|
||
*/
|
||
/*
|
||
* Return previous translation mode.
|
||
*/
|
||
inline static int set_binary_mode_with_seek_cur(rb_io_t *fptr) {
|
||
static void
|
||
io_unread(rb_io_t *fptr)
|
||
{
|
||
off_t r, pos;
|
||
ssize_t read_size;
|
||
long i;
|
||
long newlines = 0;
|
||
long extra_max;
|
||
char *p;
|
||
char *buf;
|
||
if (!rb_w32_fd_is_text(fptr->fd)) return O_BINARY;
|
||
rb_io_check_closed(fptr);
|
||
if (fptr->rbuf.len == 0 || fptr->mode & FMODE_DUPLEX) {
|
||
return setmode(fptr->fd, O_BINARY);
|
||
return;
|
||
}
|
||
if (io_fflush(fptr) < 0) {
|
||
rb_sys_fail(0);
|
||
errno = 0;
|
||
if (!rb_w32_fd_is_text(fptr->fd)) {
|
||
r = lseek(fptr->fd, -fptr->rbuf.len, SEEK_CUR);
|
||
if (r < 0 && errno) {
|
||
if (errno == ESPIPE)
|
||
fptr->mode |= FMODE_DUPLEX;
|
||
return;
|
||
}
|
||
fptr->rbuf.off = 0;
|
||
fptr->rbuf.len = 0;
|
||
return;
|
||
}
|
||
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);
|
||
return;
|
||
}
|
||
/* add extra offset for removed '\r' in rbuf */
|
||
extra_max = pos - fptr->rbuf.len;
|
||
p = fptr->rbuf.ptr + fptr->rbuf.off;
|
||
... | ... | |
if (extra_max == newlines) break;
|
||
p++;
|
||
}
|
||
buf = ALLOC_N(char, fptr->rbuf.len + newlines);
|
||
while (newlines >= 0) {
|
||
r = lseek(fptr->fd, pos - fptr->rbuf.len - newlines, SEEK_SET);
|
||
if (newlines == 0) break;
|
||
... | ... | |
newlines--;
|
||
continue;
|
||
}
|
||
read_size = _read(fptr->fd, fptr->rbuf.ptr, fptr->rbuf.len + newlines);
|
||
read_size = _read(fptr->fd, buf, fptr->rbuf.len + newlines);
|
||
if (read_size < 0) {
|
||
free(buf);
|
||
rb_sys_fail_path(fptr->pathv);
|
||
}
|
||
if (read_size == fptr->rbuf.len) {
|
||
... | ... | |
newlines--;
|
||
}
|
||
}
|
||
free(buf);
|
||
fptr->rbuf.off = 0;
|
||
fptr->rbuf.len = 0;
|
||
return;
|
||
}
|
||
/*
|
||
* We use io_seek to back cursor position when changing mode from text to binary,
|
||
* but stdin and pipe cannot seek back. Stdin and pipe read should use encoding
|
||
* conversion for working properly with mode change.
|
||
*
|
||
* Return previous translation mode.
|
||
*/
|
||
static inline int
|
||
set_binary_mode_with_seek_cur(rb_io_t *fptr)
|
||
{
|
||
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);
|
||
}
|
||
flush_before_seek(fptr);
|
||
return setmode(fptr->fd, O_BINARY);
|
||
}
|
||
#define SET_BINARY_MODE_WITH_SEEK_CUR(fptr) set_binary_mode_with_seek_cur(fptr)
|
||
... | ... | |
return rb_io_check_io(io);
|
||
}
|
||
#if !(defined(RUBY_TEST_CRLF_ENVIRONMENT) || defined(_WIN32))
|
||
static void
|
||
io_unread(rb_io_t *fptr)
|
||
{
|
||
... | ... | |
fptr->rbuf.len = 0;
|
||
return;
|
||
}
|
||
#endif
|
||
static rb_encoding *io_input_encoding(rb_io_t *fptr);
|
||
branches/ruby_1_9_3/test/ruby/test_io.rb (revision 35220) → branches/ruby_1_9_3/test/ruby/test_io.rb (working copy) | ||
---|---|---|
end
|
||
end
|
||
def test_pos_with_getc
|
||
bug6179 = '[ruby-core:43497]'
|
||
t = make_tempfile
|
||
["", "t", "b"].each do |mode|
|
||
open(t.path, "w#{mode}") do |f|
|
||
f.write "0123456789\n"
|
||
end
|
||
open(t.path, "r#{mode}") do |f|
|
||
assert_equal 0, f.pos, "mode=r#{mode}"
|
||
assert_equal '0', f.getc, "mode=r#{mode}"
|
||
assert_equal 1, f.pos, "mode=r#{mode}"
|
||
assert_equal '1', f.getc, "mode=r#{mode}"
|
||
assert_equal 2, f.pos, "mode=r#{mode}"
|
||
assert_equal '2', f.getc, "mode=r#{mode}"
|
||
assert_equal 3, f.pos, "mode=r#{mode}"
|
||
assert_equal '3', f.getc, "mode=r#{mode}"
|
||
assert_equal 4, f.pos, "mode=r#{mode}"
|
||
assert_equal '4', f.getc, "mode=r#{mode}"
|
||
end
|
||
end
|
||
end
|
||
def test_sysseek
|
||
t = make_tempfile
|
||
branches/ruby_1_9_3/test/ruby/test_io_m17n.rb (revision 35220) → branches/ruby_1_9_3/test/ruby/test_io_m17n.rb (working copy) | ||
---|---|---|
}
|
||
assert_equal(paths.map(&:encoding), encs, bug6072)
|
||
end
|
||
def test_pos_dont_move_cursor_position
|
||
bug6179 = '[ruby-core:43497]'
|
||
with_tmpdir {
|
||
str = "line one\r\nline two\r\nline three\r\n"
|
||
generate_file("tmp", str)
|
||
open("tmp", "r") do |f|
|
||
assert_equal("line one\n", f.readline)
|
||
assert_equal(10, f.pos, bug6179)
|
||
assert_equal("line two\n", f.readline, bug6179)
|
||
assert_equal(20, f.pos, bug6179)
|
||
assert_equal("line three\n", f.readline, bug6179)
|
||
end
|
||
}
|
||
end if /mswin|mingw/ =~ RUBY_PLATFORM
|
||
end
|
- « Previous
- 1
- 2
- Next »