blazar has asked for the wisdom of the Perl Monks concerning the following question:
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.
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
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.
|
|---|
| Replies are listed 'Best First'. | |
|---|---|
|
Re: croak/confess from within File::Find
by shmem (Chancellor) on Sep 12, 2007 at 12:46 UTC | |
|
Re: croak/confess from within File::Find
by blazar (Canon) on Sep 13, 2007 at 08:32 UTC |