Here's one possible solution. Does anyone know how to get rid of this
ugly eval hack?
Paul
---
setvbuf.c:
#include <ruby.h>
#include <rubyio.h>
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