run4flat has asked for the wisdom of the Perl Monks concerning the following question:
Hello monks -
I am building a GUI REPL with Prima. One major part of this is to capture the output of print, printf, warn, etc. Not a trivial problem, but solvable. A simple solution is given on Stack Overflow and serves as the basis for my current work. Basically, you create a tied file handle and either select() it or assign STDOUT (and STDERR) to it. Simple. However, all is not well. I have a REPL, remember, and it's not hard to generate an Inline block that uses C's printf. Unfortunately, the output of this printf statement does not get captured!
I was recently directed to Capture::Tiny and thought, "This is exactly what I need!" Almost. For long running XS functions, I like to print output to the screen using something like
... printf("On step %d\n", i); ...
I would *really* like to have the output screen update with each round of that printout, but Capture::Tiny won't work with tied file handles. It unties them and directs the results to the tie only at the end of the "captured" code. No matter how I implement that, I won't get the output until after the XS function returns.
Not to be dismayed, I dug into Capture::Tiny to see if I could extract the goodies, and that is where I'm stuck. It looks like the way to override STDOUT, in both Perl and underlying XS functions, is to call
open *NEWHANDLE, ">&STDOUT",
but do you notice the catch? The open command creates the new file handle for me. But unless I'm mistaken, that's what the tie operation is supposed to do! They both want to create the new file handle for me, which means I either get the tying behavior or I get the full STDOUT overriding, but not both.
At this stage, I'm beginning to believe that the only real way to keep the REPL responsive and have it print every single output is to have it fork a separate Perl process (an eval daemon, so to speak) and capture the output of the process. This gets pretty crazy, though, because I'm actually targeting PDL, and I have a plotting library that I would like to have open new tabs when you create new plots. Neither PDL nor Prima are Perl threadsafe, so they'd have to be their own processes and I'd probably have to communicate over sockets. Since neither are threadsafe, I don't know how to share data between the two processes, which means that for good plotting, they would both need a copy of the data... You can see that this is turning the whole thing into a much larger project. It might not be a bad direction to eventually take, but it's not where I want to go at the moment.
If I can't universally capture XS output without creating an eval daemon, I have one last hope, which is to direct my users to use a special C function to print their output. I assumed that PerlIO_stdoutf would have been that function, but it turns out not to be the case. The only remaining idea I have is to suggest the creation of a C function that explicitly calls Perl's print by explicitly calling Perl code from within C.
But surely there's a better solution?
|
|---|
| Replies are listed 'Best First'. | |
|---|---|
|
Re: Capturing XS printf output with a tied filehandle (lots)
by tye (Sage) on Feb 17, 2012 at 03:48 UTC | |
by run4flat (Initiate) on Feb 17, 2012 at 15:02 UTC | |
by Anonymous Monk on Feb 18, 2012 at 00:26 UTC | |
by run4flat (Initiate) on Feb 18, 2012 at 03:47 UTC | |
by Anonymous Monk on Feb 18, 2012 at 08:00 UTC | |
|
Re: Capturing XS printf output with a tied filehandle
by Anonymous Monk on Feb 17, 2012 at 00:14 UTC | |
by Anonymous Monk on Feb 17, 2012 at 03:44 UTC | |
by Anonymous Monk on Feb 17, 2012 at 04:10 UTC |