Not really a question, but not a meditation, either. Just reporting an interesting clpmisc thread (link @ GG). Someone may have to add something after all.

croak/confess from within File::Find (Paul Lalli)

I've been staring at this and playing with variations for over an hour now. Can someone help me out? My goal is to be able to use croak() from within a subroutine that is called by the &wanted subroutine which is passed to File::Find::find(). I want the error message printed as a result of this croak() to list the line number of the call to the final subroutine. Here is a short-but-complete script to demonstrate the problem I'm having:

#!/usr/bin/perl use strict; use warnings; use Carp; use File::Find; die "Usage: $0 [croak|confess] [level]\n" unless @ARGV == 2; my ($which, $carplevel) = @ARGV; sub err { $Carp::CarpLevel = $carplevel; if ($which eq 'croak') { croak "You did something bad!"; #line 12 } else { confess "You did something bad!"; #line 14 } } sub wanted { err(); #line 19 } find(\&wanted, '.'); #line 22 __END__

So, find() is calling wanted() which is calling err() which is calling croak(). What I want is an error message saying: "You did something bad! at ff_carp.pl line 19". However:

$ ./ff_carp.pl croak 0 You did something bad! at /opt2/Perl5_8_4/lib/perl5/5.8.4/File/Find.pm line 810

Calling croak with a CarpLevel of 0 shows me where in File::Find the wanted() subroutine is being called.

$ ./ff_carp.pl croak 1 You did something bad! at ./ff_carp.pl line 22

But if I call croak with a CarpLevel of 1, I instead get where in my main file find() is being called.

So instead I tried looking at the whole stack trace, to see what's going wrong. I tried calling confess with a CarpLevel of 0:

$ ./ff_carp.pl confess 0 You did something bad! at ./ff_carp.pl line 14 main::err() called at ./ff_carp.pl line 19 main::wanted() called at /opt2/Perl5_8_4/lib/perl5/5.8.4/File/ Find.pm line 810 File::Find::_find_dir('HASH(0x13e82c)', ., 2) called at /opt2/ Perl5_8_4/lib/perl5/5.8.4/File/Find.pm line 690 File::Find::_find_opt('HASH(0x13e82c)', .) called at /opt2/ Perl5_8_4/lib/perl5/5.8.4/File/Find.pm line 1193 File::Find::find('CODE(0x1b66d0)', .) called at ./ff_carp.pl line 22

Now this is exactly what I'd expect. It's telling me the actual confess was called on line 14, inside the err() function that was called on line 19, inside the wanted() function that was called within File::Find.pm. Exactly. And furthermore, if I skip a level by setting CarpLevel to 1:

$ ./ff_carp.pl confess 1 You did something bad! at ./ff_carp.pl line 19 main::wanted() called at /opt2/Perl5_8_4/lib/perl5/5.8.4/File/ Find.pm line 810 File::Find::_find_dir('HASH(0x13e82c)', ., 2) called at /opt2/ Perl5_8_4/lib/perl5/5.8.4/File/Find.pm line 690 File::Find::_find_opt('HASH(0x13e82c)', .) called at /opt2/ Perl5_8_4/lib/perl5/5.8.4/File/Find.pm line 1193 File::Find::find('CODE(0x1b66d0)', .) called at ./ff_carp.pl line 22

Again, Exactly what I expect. I skipped a level, so the first level being printed is the source of the err() call, line 19.

Now - how do I get croak() to behave the same way? I don't want to print the entire stack trace, I just want it to tell me that the subroutine was called from line 19, like confess() does when I skip a level.

Thank you for any insight you can provide,
Paul Lalli

Re: croak/confess from within File::Find (Anno)

I've been staring at this and playing with variations for over an hour now. Can someone help me out? My goal is to be able to use croak() from within a subroutine that is called by the &wanted subroutine which is passed to File::Find::find(). I want the error message printed as a result of this croak() to list the line number of the call to the final subroutine. Here is a short-but-complete script to demonstrate the problem I'm having:

#!/usr/bin/perl use strict; use warnings; use Carp; use File::Find; die "Usage: $0 [croak|confess] [level]\n" unless @ARGV == 2; my ($which, $carplevel) = @ARGV; sub err { $Carp::CarpLevel = $carplevel; if ($which eq 'croak') { croak "You did something bad!"; #line 12 } else { confess "You did something bad!"; #line 14 } } sub wanted { err(); #line 19 }

Add this:

push our @CARP_NOT, 'File::Find';
find(\&wanted, '.'); #line 22 __END__

Carp has a hard time assigning an error location in callback situations. It climbs the stack, essentially watching for a change in the calling package. When called from a callback it meets that change earlier than intended (from your main to File::Find). The variable @CARP_NOT is checked and a package change is ignored if one of the packages is on the other's @CARP_NOT.

Anno


In reply to croak/confess from within File::Find by blazar

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.