in reply to Overloading print()
Hi Rob,
from reading the rest of this thread, I figure your real problem is to capture the stdout of an XS routine.
The key thing to note here is that, within the C routine, stdout corresponds to fileno 1. So, in your Perl code, you'll need to arrange for things to read the output written to exactly that filehandle, e.g. by setting up a pipe to it.
This a bit more involved than you might think, but the following should do the trick (to keep the example concise, I'm using Inline here, but it should equally work with regular XS code):
#!/usr/bin/perl use Inline C => <<'EOC'; void foo() { printf("something being sent to stdout\n"); fflush(stdout); } EOC my $output; { # save original STDOUT open my $saved_stdout, ">&STDOUT"; # create a pipe, which we'll use to read from our own STDOUT local(*RH, *WH); pipe RH, WH; # connect the writing side of the pipe to STDOUT, with # STDOUT being (and remaining) fileno 1 (!) open STDOUT, ">&WH" or die "open: $!"; # debug: verify that fileno really is 1 printf STDERR "fileno(STDOUT): %d\n", fileno(STDOUT); # call the C/XS function whose stdout we want to capture foo(); # close WH to avoid buffering issues (pipes are buffered) close WH; # read output (one line) $output = <RH>; close RH; # restore original STDOUT open STDOUT, ">&", $saved_stdout or die "open: $!"; } print "output of foo(): $output";
prints:
fileno(STDOUT): 1 output of foo(): something being sent to stdout
The crucial thing is that STDOUT has to correspond to fileno 1, so localising STDOUT will not work here (local *STDOUT will result in a new fileno...). For the same reason, you can't use "open-to-a-string", because in that case the filehandle will be a Perl internal one (fileno -1), which the C side knows nothing about...
With the above code, the open STDOUT, ">&WH" is doing a dup2 system call (among other things), which (in this particular case) will first close STDOUT and then immediately reassign that same fileno, which is 1. BTW, this works only if you haven't messed with Perl's STDOUT before (by default, it is fileno 1).
To get a deeper understanding of the mechanics under the hood, you might want to play around with tracing system calls (i.e. strace and friends). HTH.
|
|---|
| Replies are listed 'Best First'. | |
|---|---|
|
Re^2: Overloading print() (full pipe)
by tye (Sage) on Sep 08, 2007 at 02:07 UTC | |
|
Re^2: Overloading print()
by syphilis (Archbishop) on Sep 06, 2007 at 04:59 UTC |