From: Paul Brannan Date: 2002-01-30T02:36:54+09:00 Subject: Re: popen3 and buffering Here's one possible solution. Does anyone know how to get rid of this ugly eval hack? Paul --- setvbuf.c: #include #include static VALUE ruby_setvbuf(VALUE self, VALUE mode, VALUE buf) { char * c_buf = (buf == Qnil) ? NULL : STR2CSTR(buf); size_t size = (buf == Qnil) ? 0 : RSTRING(buf)->len; int c_mode = NUM2INT(mode); OpenFile * fptr; FILE * f1, * f2; GetOpenFile(self, fptr); f1 = GetReadFile(fptr); f2 = GetWriteFile(fptr); setvbuf(f1, c_buf, c_mode, size); if(f1 != f2) { setvbuf(f2, c_buf, c_mode, size); } return Qnil; } void Init_setvbuf() { rb_define_method(rb_cIO, "c_setvbuf", ruby_setvbuf, 2); rb_eval_string( "class IO\n" " PIPE_BUFFERS = Hash.new\n" " def self.pipe_buffer_finalizer(buf)\n" " PIPE_BUFFERS[buf] = true\n" " return proc { PIPE_BUFFERS.delete(buf) }\n" " end\n" " def setvbuf(mode, buf=nil)\n" " if buf then\n" " ObjectSpace.define_finalizer(self, IO.pipe_buffer_finalizer(buf))\n" " end\n" " c_setvbuf(mode, buf)\n" " end\n" "end\n"); rb_define_const(rb_cIO, "NBF", INT2NUM(_IONBF)); rb_define_const(rb_cIO, "LBF", INT2NUM(_IOLBF)); rb_define_const(rb_cIO, "FBF", INT2NUM(_IOFBF)); pipe.rb: require 'open3' Open3.popen3('ruby test.rb') do |pin, pout, perr| write_map = { pout => $stdout, perr => $stderr, $stdin => pin } loop do retval = select([pout, perr, $stdin], nil, [pin, $stdout, $stderr], nil) puts "select returned" for i in retval[0] str = i.read(512) write_map[i].write(str) end for i in retval[2] exit(1) end end end test.rb: require 'setvbuf' $stdout.setvbuf(IO::NBF) $stdout.sync = false loop do puts "This is a test." sleep 0.01 end