redirecting stdout in an extension

M

Mark Probert

Hi ..

Any ideas on how to redirect stdout in an extension and then revert it
back to its default behaviour? freopen() redirects, though I am not
sure of returning to normal programming.

So,

VALUE rb_dump(VALUE self, VALUE o_name)
{
VALUE rval; /* our result */
VALUE fname; /* holds the filename */

fname = StringValue(o_name);

/* redirect stdout */
freopen("a.xml", "w+", stdout);
if (foo_dump(STR2CSTR(fname)) == -1) {
rval = Qnil;
} else {
rval = Qtrue;
}
fclose(stdout); /* bad!!! want to go back to fd 1 */
return rval;
}

BTW, I have no way of modifying the call to foo_dump() to take a file
handle. It just splurts out to stdout.

Many thanks,
 
M

Mark Probert

Hi ..

Just a guess. I don't know how well it will play with the Ruby
interpreter.
Not so well, unfortunately:

$ ruby foo.rb
test.rb:29:in `write': Bad file descriptor (Errno::EBADF)
from test.rb:29:in `puts'
from test.rb:29

Thanks for the suggestion. I would think that there might be some
facility hidden with the API that might allow this redirection to
happen, but I have no idea of what it might be ..

Regards,
 
D

daz

Mark said:
Hi ..


Not so well, unfortunately:

$ ruby foo.rb
test.rb:29:in `write': Bad file descriptor (Errno::EBADF)
from test.rb:29:in `puts'
from test.rb:29

Thanks for the suggestion. I would think that there might be some
facility hidden with the API that might allow this redirection to
happen, but I have no idea of what it might be ..

Hi Mark,

I was thinking that a reply would pop up suggesting rb_io_reopen()
but just discovered what you already know ... it's not exposed :(

Here's my adaptation of a fairly well established method
blagged (including most comments) from the ether.

In short, the chant goes:
open, dup, dup2, close <"redirecting"> dup2, close

Will it work in a Ruby ext ?

#-------------------
require 'redir1'

puts Time.now
Time.redir1('foo/blah.txt')
puts File.read('dummy.tmp')
#-------------------
#-> Fri Jul 29 04:14:10 2005
#-> Fri Jul 29 04:14:10 2005 - foo/blah.txt

Result as expected. (C below)

daz


<redir1.c> (almost useless extension)
///////////////////////////////////////////////////////////////////////
#include "ruby.h"
#include <fcntl.h>

int foo_dump(char *fname)
{
VALUE t = rb_class_new_instance(0, NULL, rb_cTime);

// time and filename to STDOUT (possibly redirected)
printf("%s - %s\n", RSTRING(rb_inspect(t))->ptr, fname);

return 0;
}

VALUE redir1(VALUE self, VALUE o_name)
{
VALUE rval; /* our result */
char *fname; /* holds the filename */
int new_fh, sv_so, so_fh = _fileno(stdout);
/* OR so_fh = STDOUT_FILENO */

fname = StringValuePtr(o_name);

new_fh = open("dummy.tmp", O_CREAT | O_WRONLY, S_IREAD | S_IWRITE);
if (new_fh < 0)
rb_sys_fail("can't open file for STDOUT redirection");

/* create a duplicate handle for standard output */
sv_so = dup(so_fh);
/*
redirect standard output to output file
by duplicating the file handle onto
the file handle for standard output.
*/
dup2(new_fh, so_fh);
/* close the handle for output file */
close(new_fh);

/* will be redirected into output file */
rval = (foo_dump(fname) == -1) ? Qnil : Qtrue;

/* restore original standard output handle */
dup2(sv_so, so_fh);
/* close duplicate handle for STDOUT */
close(sv_so);

return rval;
}

void Init_redir1() {

rb_define_singleton_method(rb_cTime, "redir1", redir1, 1);
}
///////////////////////////////////////////////////////////////////////
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,059
Latest member
cryptoseoagencies

Latest Threads

Top