ruby-changes:8467
From: usa <ko1@a...>
Date: Tue, 28 Oct 2008 21:18:13 +0900 (JST)
Subject: [ruby-changes:8467] Ruby:r19999 (ruby_1_9_1): merge from trunk (r19984, r19985, r19991-r19998)
usa 2008-10-28 21:17:54 +0900 (Tue, 28 Oct 2008) New Revision: 19999 http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=19999 Log: merge from trunk (r19984, r19985, r19991-r19998) * io.c (extract_binmode): new function to extract binmode/textmode options from hash. * io.c (rb_io_extract_modeenc): use above function. * io.c (rb_io_s_pipe): recognize binmode/textmode options. * io.c (make_readconv): now can specify the size of cbuf. * io.c (read_all, appendline, io_getc, rb_io_ungetc): follow above change. * win32/win32.c (rb_w32_pipe_exec): internal fds should be always binmode. * test/ruby/test_file.rb (test_each_char_extended_file, test_getbyte_extended_file): add tests. * test/ruby/test_file.rb (test_*_extended_file): test in default/text/ binary mode. * test/ruby/test_file.rb (test_para_gets_extended_file): output file should be binmode. * test/ruby/test_io.rb (test_copy_stream, test_copy_stream_socket): skip some tests if there isn't IO#nonblock=. * test/ruby/test_io.rb (test_close_on_exec): skip if there isn't IO#close_on_exec=. * test/ruby/test_io.rb (test_bytes, test_readbyte): depend on binmode. * test/ruby/test_io.rb (test_sysopen): should specify the mode of IO::for_fd if F_GETFL is not available. * test/ruby/test_io_m17n.rb (test_getc_invalid3): should set binmode if enc is not compatible with ASCII. * test/ruby/test_require.rb (test_require_too_long_filename): too long commandline may be rejected by OS. Modified files: branches/ruby_1_9_1/ChangeLog branches/ruby_1_9_1/io.c branches/ruby_1_9_1/test/ruby/test_file.rb branches/ruby_1_9_1/test/ruby/test_io.rb branches/ruby_1_9_1/test/ruby/test_io_m17n.rb branches/ruby_1_9_1/test/ruby/test_require.rb branches/ruby_1_9_1/win32/win32.c Index: ruby_1_9_1/ChangeLog =================================================================== --- ruby_1_9_1/ChangeLog (revision 19998) +++ ruby_1_9_1/ChangeLog (revision 19999) @@ -1,3 +1,20 @@ +Tue Oct 28 21:11:58 2008 NAKAMURA Usaku <usa@r...> + + * io.c (extract_binmode): new function to extract binmode/textmode + options from hash. + + * io.c (rb_io_extract_modeenc): use above function. + + * io.c (rb_io_s_pipe): recognize binmode/textmode options. + + * io.c (make_readconv): now can specify the size of cbuf. + + * io.c (read_all, appendline, io_getc, rb_io_ungetc): follow above + change. + + * win32/win32.c (rb_w32_pipe_exec): internal fds should be always + binmode. + Tue Oct 28 17:22:35 2008 Yuki Sonoda (Yugui) <yugui@y...> * tool/make-snapshot.rb: merged back from trunk. Index: ruby_1_9_1/io.c =================================================================== --- ruby_1_9_1/io.c (revision 19998) +++ ruby_1_9_1/io.c (revision 19999) @@ -1430,7 +1430,7 @@ } static void -make_readconv(rb_io_t *fptr) +make_readconv(rb_io_t *fptr, int size) { if (!fptr->readconv) { int ecflags; @@ -1452,7 +1452,7 @@ rb_exc_raise(rb_econv_open_exc(sname, dname, ecflags)); fptr->cbuf_off = 0; fptr->cbuf_len = 0; - fptr->cbuf_capa = 1024; + fptr->cbuf_capa = size < 1024 ? 1024 : size; fptr->cbuf = ALLOC_N(char, fptr->cbuf_capa); } } @@ -1558,7 +1558,7 @@ if (NEED_READCONV(fptr)) { if (NIL_P(str)) str = rb_str_new(NULL, 0); else rb_str_set_len(str, 0); - make_readconv(fptr); + make_readconv(fptr, 0); while (1) { if (fptr->cbuf_len) { io_shift_cbuf(fptr, fptr->cbuf_len, &str); @@ -1940,7 +1940,7 @@ long limit = *lp; if (NEED_READCONV(fptr)) { - make_readconv(fptr); + make_readconv(fptr, 0); while (1) { const char *p, *e; int searchlen; @@ -2473,7 +2473,7 @@ if (NEED_READCONV(fptr)) { VALUE str = Qnil; - make_readconv(fptr); + make_readconv(fptr, 0); while (1) { if (fptr->cbuf_len) { @@ -2825,8 +2825,8 @@ SafeStringValue(c); } if (NEED_READCONV(fptr)) { - make_readconv(fptr); len = RSTRING_LEN(c); + make_readconv(fptr, len); if (fptr->cbuf_capa - fptr->cbuf_len < len) rb_raise(rb_eIOError, "ungetc failed"); if (fptr->cbuf_off < len) { @@ -3923,6 +3923,23 @@ } static void +extract_binmode(VALUE opthash, int *fmode) +{ + if (!NIL_P(opthash)) { + VALUE v; + v = rb_hash_aref(opthash, sym_textmode); + if (!NIL_P(v) && RTEST(v)) + *fmode |= FMODE_TEXTMODE; + v = rb_hash_aref(opthash, sym_binmode); + if (!NIL_P(v) && RTEST(v)) + *fmode |= FMODE_BINMODE; + + if ((*fmode & FMODE_BINMODE) && (*fmode & FMODE_TEXTMODE)) + rb_raise(rb_eArgError, "both textmode and binmode specified"); + } +} + +static void rb_io_extract_modeenc(VALUE *vmode_p, VALUE *vperm_p, VALUE opthash, int *oflags_p, int *fmode_p, convconfig_t *convconfig_p) { @@ -3975,16 +3992,11 @@ } else { VALUE v; - v = rb_hash_aref(opthash, sym_textmode); - if (!NIL_P(v) && RTEST(v)) - fmode |= FMODE_TEXTMODE; - v = rb_hash_aref(opthash, sym_binmode); - if (!NIL_P(v) && RTEST(v)) { - fmode |= FMODE_BINMODE; + extract_binmode(opthash, &fmode); #ifdef O_BINARY + if (fmode & FMODE_BINMODE) oflags |= O_BINARY; #endif - } if (!has_vmode) { v = rb_hash_aref(opthash, sym_mode); if (!NIL_P(v)) { @@ -4017,9 +4029,6 @@ } } - if ((fmode & FMODE_BINMODE) && (fmode & FMODE_TEXTMODE)) - rb_raise(rb_eArgError, "both textmode and binmode specified"); - validate_enc_binmode(fmode, enc, enc2); *vmode_p = vmode; @@ -6825,7 +6834,8 @@ int pipes[2], state; VALUE r, w, args[3], v1, v2; VALUE opt; - rb_io_t *fptr; + rb_io_t *fptr, *fptr2; + int fmode = 0; opt = pop_last_hash(&argc, argv); rb_scan_args(argc, argv, "02", &v1, &v2); @@ -6851,8 +6861,13 @@ if (!NIL_P(r)) rb_io_close(r); rb_jump_tag(state); } - rb_io_synchronized(RFILE(w)->fptr); + GetOpenFile(w, fptr2); + rb_io_synchronized(fptr2); + extract_binmode(opt, &fmode); + fptr->mode |= fmode; + fptr2->mode |= fmode; + return rb_assoc_new(r, w); } Index: ruby_1_9_1/win32/win32.c =================================================================== --- ruby_1_9_1/win32/win32.c (revision 19998) +++ ruby_1_9_1/win32/win32.c (revision 19999) @@ -764,9 +764,8 @@ reading = TRUE; writing = FALSE; } - mode &= ~(O_RDWR|O_RDONLY|O_WRONLY); - if (!(mode & O_BINARY)) - mode |= O_TEXT; + mode &= ~(O_RDWR|O_RDONLY|O_WRONLY|O_TEXT); + mode |= O_BINARY; sa.nLength = sizeof (SECURITY_ATTRIBUTES); sa.lpSecurityDescriptor = NULL; Index: ruby_1_9_1/test/ruby/test_io_m17n.rb =================================================================== --- ruby_1_9_1/test/ruby/test_io_m17n.rb (revision 19998) +++ ruby_1_9_1/test/ruby/test_io_m17n.rb (revision 19999) @@ -677,7 +677,7 @@ end def test_getc_invalid3 - with_pipe("utf-16le:euc-jp") {|r, w| + with_pipe("utf-16le:euc-jp", binmode: true) {|r, w| before1 = "\x42\x30".force_encoding("utf-16le") before2 = "\x44\x30".force_encoding("utf-16le") invalid = "\x00\xd8".force_encoding("utf-16le") Index: ruby_1_9_1/test/ruby/test_require.rb =================================================================== --- ruby_1_9_1/test/ruby/test_require.rb (revision 19998) +++ ruby_1_9_1/test/ruby/test_require.rb (revision 19999) @@ -27,11 +27,15 @@ end INPUT - assert_in_out_err(["-S", "foo/" * 10000 + "foo"], "") do |r, e| - assert_equal([], r) - assert_operator(2, :<=, e.size) - assert_equal("openpath: pathname too long (ignored)", e.first) - assert_match(/\(LoadError\)/, e.last) + begin + assert_in_out_err(["-S", "foo/" * 10000 + "foo"], "") do |r, e| + assert_equal([], r) + assert_operator(2, :<=, e.size) + assert_equal("openpath: pathname too long (ignored)", e.first) + assert_match(/\(LoadError\)/, e.last) + end + rescue Errno::EINVAL + # too long commandline may be blocked by OS. end end Index: ruby_1_9_1/test/ruby/test_file.rb =================================================================== --- ruby_1_9_1/test/ruby/test_file.rb (revision 19998) +++ ruby_1_9_1/test/ruby/test_file.rb (revision 19999) @@ -65,42 +65,72 @@ end def test_read_all_extended_file - f = Tempfile.new("test-extended-file") - assert_nil(f.getc) - open(f.path, "w") {|g| g.print "a" } - assert_equal("a", f.read) + [nil, {:textmode=>true}, {:binmode=>true}].each do |mode| + f = Tempfile.new("test-extended-file", mode) + assert_nil(f.getc) + open(f.path, "w") {|g| g.print "a" } + assert_equal("a", f.read, "mode = <#{mode}>") + end end def test_gets_extended_file - f = Tempfile.new("test-extended-file") - assert_nil(f.getc) - open(f.path, "w") {|g| g.print "a" } - assert_equal("a", f.gets("a")) + [nil, {:textmode=>true}, {:binmode=>true}].each do |mode| + f = Tempfile.new("test-extended-file", mode) + assert_nil(f.getc) + open(f.path, "w") {|g| g.print "a" } + assert_equal("a", f.gets("a"), "mode = <#{mode}>") + end end def test_gets_para_extended_file - f = Tempfile.new("test-extended-file") - assert_nil(f.getc) - open(f.path, "w") {|g| g.print "\na" } - assert_equal("a", f.gets("")) + [nil, {:textmode=>true}, {:binmode=>true}].each do |mode| + f = Tempfile.new("test-extended-file", mode) + assert_nil(f.getc) + open(f.path, "wb") {|g| g.print "\na" } + assert_equal("a", f.gets(""), "mode = <#{mode}>") + end end + def test_each_char_extended_file + [nil, {:textmode=>true}, {:binmode=>true}].each do |mode| + f = Tempfile.new("test-extended-file", mode) + assert_nil(f.getc) + open(f.path, "w") {|g| g.print "a" } + result = [] + f.each_char {|b| result << b } + assert_equal([?a], result, "mode = <#{mode}>") + end + end + def test_each_byte_extended_file - f = Tempfile.new("test-extended-file") - assert_nil(f.getc) - open(f.path, "w") {|g| g.print "a" } - result = [] - f.each_byte {|b| result << b.chr } - assert_equal([?a], result) + [nil, {:textmode=>true}, {:binmode=>true}].each do |mode| + f = Tempfile.new("test-extended-file", mode) + assert_nil(f.getc) + open(f.path, "w") {|g| g.print "a" } + result = [] + f.each_byte {|b| result << b.chr } + assert_equal([?a], result, "mode = <#{mode}>") + end end def test_getc_extended_file - f = Tempfile.new("test-extended-file") - assert_nil(f.getc) - open(f.path, "w") {|g| g.print "a" } - assert_equal(?a, f.getc) + [nil, {:textmode=>true}, {:binmode=>true}].each do |mode| + f = Tempfile.new("test-extended-file", mode) + assert_nil(f.getc) + open(f.path, "w") {|g| g.print "a" } + assert_equal(?a, f.getc, "mode = <#{mode}>") + end end + def test_getbyte_extended_file + [nil, {:textmode=>true}, {:binmode=>true}].each do |mode| + f = Tempfile.new("test-extended-file", mode) + assert_nil(f.getc) + open(f.path, "w") {|g| g.print "a" } + assert_equal(?a, f.getbyte.chr, "mode = <#{mode}>") + end + end + def test_s_chown assert_nothing_raised { File.chown -1, -1 } assert_nothing_raised { File.chown nil, nil } Index: ruby_1_9_1/test/ruby/test_io.rb =================================================================== --- ruby_1_9_1/test/ruby/test_io.rb (revision 19998) +++ ruby_1_9_1/test/ruby/test_io.rb (revision 19999) @@ -1,5 +1,6 @@ require 'test/unit' require 'tmpdir' +require "fcntl" require 'io/nonblock' require 'socket' require 'stringio' @@ -8,6 +9,19 @@ require_relative 'envutil' class TestIO < Test::Unit::TestCase + def have_close_on_exec? + begin + $stdin.close_on_exec? + true + rescue NotImplementedError + false + end + end + + def have_nonblock? + IO.instance_methods.index(:"nonblock=") + end + def test_gets_rs # default_rs r, w = IO.pipe @@ -236,18 +250,20 @@ assert_equal(content[1,1], r.read) } - with_read_pipe("abc") {|r1| - assert_equal("a", r1.getc) - with_pipe {|r2, w2| - w2.nonblock = true - s = w2.syswrite("a" * 100000) - t = Thread.new { sleep 0.1; r2.read } - ret = IO.copy_stream(r1, w2) - w2.close - assert_equal(2, ret) - assert_equal("a" * s + "bc", t.value) + if have_nonblock? + with_read_pipe("abc") {|r1| + assert_equal("a", r1.getc) + with_pipe {|r2, w2| + w2.nonblock = true + s = w2.syswrite("a" * 100000) + t = Thread.new { sleep 0.1; r2.read } + ret = IO.copy_stream(r1, w2) + w2.close + assert_equal(2, ret) + assert_equal("a" * s + "bc", t.value) + } } - } + end bigcontent = "abc" * 123456 File.open("bigsrc", "w") {|f| f << bigcontent } @@ -266,15 +282,19 @@ assert_equal(bigcontent[100, 30000], File.read("bigdst")) File.open("bigsrc") {|f| - assert_equal(0, f.pos) - ret = IO.copy_stream(f, "bigdst", nil, 10) - assert_equal(bigcontent.bytesize-10, ret) - assert_equal(bigcontent[10..-1], File.read("bigdst")) - assert_equal(0, f.pos) - ret = IO.copy_stream(f, "bigdst", 40, 30) - assert_equal(40, ret) - assert_equal(bigcontent[30, 40], File.read("bigdst")) - assert_equal(0, f.pos) + begin + assert_equal(0, f.pos) + ret = IO.copy_stream(f, "bigdst", nil, 10) + assert_equal(bigcontent.bytesize-10, ret) + assert_equal(bigcontent[10..-1], File.read("bigdst")) + assert_equal(0, f.pos) + ret = IO.copy_stream(f, "bigdst", 40, 30) + assert_equal(40, ret) + assert_equal(bigcontent[30, 40], File.read("bigdst")) + assert_equal(0, f.pos) + rescue NotImplementedError + #skip "pread(2) is not implemtented." + end } with_pipe {|r, w| @@ -285,19 +305,21 @@ megacontent = "abc" * 1234567 File.open("megasrc", "w") {|f| f << megacontent } - with_pipe {|r1, w1| - with_pipe {|r2, w2| - t1 = Thread.new { w1 << megacontent; w1.close } - t2 = Thread.new { r2.read } - r1.nonblock = true - w2.nonblock = true - ret = IO.copy_stream(r1, w2) - assert_equal(megacontent.bytesize, ret) - w2.close - t1.join - assert_equal(megacontent, t2.value) + if have_nonblock? + with_pipe {|r1, w1| + with_pipe {|r2, w2| + t1 = Thread.new { w1 << megacontent; w1.close } + t2 = Thread.new { r2.read } + r1.nonblock = true + w2.nonblock = true + ret = IO.copy_stream(r1, w2) + assert_equal(megacontent.bytesize, ret) + w2.close + t1.join + assert_equal(megacontent, t2.value) + } } - } + end with_pipe {|r1, w1| with_pipe {|r2, w2| @@ -323,15 +345,19 @@ def test_copy_stream_rbuf mkcdtmpdir { - with_pipe {|r, w| - File.open("foo", "w") {|f| f << "abcd" } - File.open("foo") {|f| - f.read(1) - assert_equal(3, IO.copy_stream(f, w, 10, 1)) + begin + with_pipe {|r, w| + File.open("foo", "w") {|f| f << "abcd" } + File.open("foo") {|f| + f.read(1) + assert_equal(3, IO.copy_stream(f, w, 10, 1)) + } + w.close + assert_equal("bcd", r.read) } - w.close - assert_equal("bcd", r.read) - } + rescue NotImplementedError + skip "pread(2) is not implemtented." + end } end @@ -410,15 +436,17 @@ megacontent = "abc" * 1234567 File.open("megasrc", "w") {|f| f << megacontent } - with_socketpair {|s1, s2| - t = Thread.new { s2.read } - s1.nonblock = true - ret = IO.copy_stream("megasrc", s1) - assert_equal(megacontent.bytesize, ret) - s1.close - result = t.value - assert_equal(megacontent, result) - } + if have_nonblock? + with_socketpair {|s1, s2| + t = Thread.new { s2.read } + s1.nonblock = true + ret = IO.copy_stream("megasrc", s1) + assert_equal(megacontent.bytesize, ret) + s1.close + result = t.value + assert_equal(megacontent, result) + } + end } end @@ -695,6 +723,7 @@ end def test_write_nonblock + skip "IO#write_nonblock is not supported on file/pipe." if /mswin|bccwin|mingw/ =~ RUBY_PLATFORM pipe(proc do |w| w.write_nonblock(1) w.close @@ -874,6 +903,7 @@ def test_bytes pipe(proc do |w| + w.binmode w.puts "foo" w.puts "bar" w.puts "baz" @@ -904,11 +934,13 @@ def test_readbyte pipe(proc do |w| + w.binmode w.puts "foo" w.puts "bar" w.puts "baz" w.close end, proc do |r| + r.binmode (%w(f o o) + ["\n"] + %w(b a r) + ["\n"] + %w(b a z) + ["\n"]).each do |c| assert_equal(c.ord, r.readbyte) end @@ -931,7 +963,7 @@ end def test_close_on_exec - # xxx + skip "IO\#close_on_exec is not implemented." unless have_close_on_exec? ruby do |f| assert_equal(false, f.close_on_exec?) f.close_on_exec = true @@ -1022,7 +1054,11 @@ fd = IO.sysopen(t.path, "w", 0666) assert_kind_of(Integer, fd) - f = IO.for_fd(fd) + if defined?(Fcntl::F_GETFL) + f = IO.for_fd(fd) + else + f = IO.for_fd(fd, 0666) + end f.write("FOO\n") f.close -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/