So I've been toying around with wrapping some C functions that simply take arguments and print via stdout. The input was fairly straightforward. Capturing the output however, has been difficult to say the least.

Regardless of the PerlIO layer, I can't seem to capture data written to FILE streams from XS.

#!/usr/bin/perl use strict; use warnings; use Inline C => <<'C_HUNK'; void c_output() { fprintf(stdout, "###c_output"); } void c_output_newline() { fprintf(stdout, "###c_output_newline\n"); } C_HUNK sub test_global { my $out_var = ''; my $prev_select = select; open my $prev_stdout, '>&', \*STDOUT or die "Error: $!"; close STDOUT; open STDOUT, '>', \$out_var or die "Error: $!"; select $out_var; $|=1; select $prev_select; outp_test(); open STDOUT, '>&', \$prev_stdout or die "Error: $!"; return $out_var; } sub outp_test { # Test with newline (autoflush) warn "\tprinting [perl_output_newline]\n"; print STDOUT "***perl_output_newline\n"; warn "\tcalling [c_output_newline]\n"; c_output_newline(); # Test without newline warn "\tprinting [perl_output]\n"; print STDOUT "***perl_output"; warn "\tcalling [c_output]\n"; c_output(); } warn "===============dry run============\n"; outp_test(); print "\n"; warn "=============test_global==========\n"; my $buffer = test_global(); $buffer =~ s/\n/\\n/g; warn "test_global buffer:\n($buffer)\n"; print "\n";

When I set PERLIO to perlio (ala default), I get the following output:

===============dry run============ printing [perl_output_newline] ***perl_output_newline calling [c_output_newline] ###c_output_newline printing [perl_output] calling [c_output] ***perl_output###c_output =============test_global========== printing [perl_output_newline] calling [c_output_newline] printing [perl_output] calling [c_output] test_global buffer: (***perl_output_newline\n***perl_output)

The dry run is logically outputting the non-flushed Perl and C output as soon as there is a flush. The redirection however, never returns any of the C output.

Setting PERLIO to stdio gives the following:

===============dry run============ printing [perl_output_newline] ***perl_output_newline calling [c_output_newline] ###c_output_newline printing [perl_output] calling [c_output] ***perl_output =============test_global========== printing [perl_output_newline] calling [c_output_newline] printing [perl_output] calling [c_output] test_global buffer: (***perl_output_newline\n***perl_output) ###c_output

The dry run only outputs the flushed C output, and not the non-flushed. The redirection seems to be caching the non-flushed C output, and releasing it only after everything else is done.

So... I'm hoping to avoid forking, but I'm thinking I might not have any other option. Oh, tested this on 5.10.1 and 5.8.8 with the same behavior.

Any ideas?


In reply to Redirecting XS stdout by innominate

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.