<?xml version="1.0" encoding="windows-1252"?>
<node id="710640" title="How to grab Parse::RecDescent error output in a variable?" created="2008-09-11 11:26:17" updated="2008-09-11 07:26:17">
<type id="115">
perlquestion</type>
<author id="399589">
w-ber</author>
<data>
<field name="doctext">
&lt;p&gt;
Dear monks,
&lt;/p&gt;

&lt;p&gt;
I would like to capture the error output of [cpan://Parse::RecDescent] to a variable instead of printing it to &lt;code&gt;STDERR&lt;/code&gt;. There does not seem to be any way of doing this easily; there is no documentation for it, and viewing the source code reveals that
&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;the module dups &lt;code&gt;STDERR&lt;/code&gt; into its own filehandle called &lt;code&gt;ERROR&lt;/code&gt;, and&lt;/li&gt;
&lt;li&gt;the module defines a format called &lt;code&gt;ERROR&lt;/code&gt; for printing to the filehandle.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;
Since the &lt;code&gt;ERROR&lt;/code&gt; filehandle is defined at module &lt;code&gt;use&lt;/code&gt; time, it is necessary to do &lt;code&gt;STDERR&lt;/code&gt; munging in a &lt;code&gt;BEGIN&lt;/code&gt; block, thusly:
&lt;/p&gt;

&lt;code&gt;
my $ParseError;

BEGIN {
    open(my $olderr, '&gt;&amp;', STDERR) or die "Cannot dup STDERR: $!";
    close STDERR;
    open(STDERR, '&gt;', \$ParseError) or die "Cannot open in-memory file: $!";
    select STDERR; $| = 1;

    # Cannot use, since that messes up execution order for some reason (since use 
    # implies a BEGIN block itself?).
    require Parse::RecDescent;

    close STDERR;
    open(STDERR, '&gt;&amp;', $olderr) or die "Cannot restore STDERR: $!";
}

# Then later:

my $p = Parse::RecDescent-&gt;new($grammar) or die "Invalid grammar";
my $output = $p-&gt;startrule($str) or die $ParseError;
&lt;/code&gt;

&lt;p&gt;
However, fine as it is though hairy, this will not produce any content in &lt;code&gt;$ParseError&lt;/code&gt;, which will stay undefined. If I replace the &lt;code&gt;STDERR&lt;/code&gt; re-open with an opening of a file, say
&lt;/p&gt;

&lt;code&gt;
    open(STDERR, '&gt;', '/tmp/error') or die $!;
&lt;/code&gt;

&lt;p&gt;
I do get the error strings in &lt;code&gt;/tmp/error&lt;/code&gt;!
&lt;/p&gt;

&lt;p&gt;
Is the cause of the problem the use of &lt;code&gt;format&lt;/code&gt; in &lt;code&gt;Parse::RecDescent&lt;/code&gt;, or some other subtle things I'm missing? An issue with buffering? Or is the approach fundamentally flawed? I guess I could open an anonymous temporary file somehow, redirect &lt;code&gt;STDERR&lt;/code&gt; to that, then read in the contents of the file, but surely there is a better way. (This is on Perl 5.8.8 on Linux, x86_64, if that's relevant.)
&lt;/p&gt;

&lt;div class="pmsig"&gt;
&lt;div class="pmsig-399589"&gt;
&lt;p&gt;
-- &lt;br&gt;
print "Just Another [href://http://prometheus.frii.com/~gnat/yapc/2000-stages/slide25.html|Perl Adept]\n";
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;</field>
</data>
</node>
