Fix a manual edit typo from #7993, fix the message formatting
[p5sagit/p5-mst-13.2.git] / lib / Carp / Heavy.pm
1 package Carp;
2
3 our $MaxEvalLen;
4 our $MaxLenArg;
5 our $Verbose;
6
7 sub caller_info {
8   my $i = shift(@_) + 1;
9   package DB;
10   my %call_info;
11   @call_info{
12     qw(pack file line sub has_args wantarray evaltext is_require)
13   } = caller($i);
14   
15   unless (defined $call_info{pack}) {
16     return ();
17   }
18
19   my $sub_name = Carp::get_subname(\%call_info);
20   if ($call_info{has_args}) {
21     # Reuse the @args array to avoid warnings. :-)
22     local @args = map {Carp::format_arg($_)} @args;
23     if ($MaxArgNums and @args > $MaxArgNums) { # More than we want to show?
24       $#args = $MaxArgNums;
25       push @args, '...';
26     }
27     # Push the args onto the subroutine
28     $sub_name .= '(' . join (',', @args) . ')';
29   }
30   $call_info{sub_name} = $sub_name;
31   return wantarray() ? %call_info : \%call_info;
32 }
33
34 # Transform an argument to a function into a string.
35 sub format_arg {
36   my $arg = shift;
37   if (not defined($arg)) {
38     $arg = 'undef';
39   }
40   elsif (ref($arg)) {
41     $arg .= ''; # Make it a string;
42   }
43   $arg =~ s/'/\\'/g;
44   $arg = str_len_trim($arg, $MaxLenArg);
45   
46   # Quote it?
47   $arg = "'$arg'" unless $arg =~ /^-?[\d.]+\z/;
48
49   # The following handling of "control chars" is direct from
50   # the original code - I think it is broken on Unicode though.
51   # Suggestions?
52   $arg =~ s/([[:cntrl:]]|[[^:ascii:]])/sprintf("\\x{%x}",ord($1))/eg;
53   return $arg;
54 }
55
56 # Takes an inheritance cache and a package and returns
57 # an anon hash of known inheritances and anon array of
58 # inheritances which consequences have not been figured
59 # for.
60 sub get_status {
61     my $cache = shift;
62     my $pkg = shift;
63     $cache->{$pkg} ||= [{$pkg => $pkg}, [trusts_directly($pkg)]];
64     return @{$cache->{$pkg}};
65 }
66
67 # Takes the info from caller() and figures out the name of
68 # the sub/require/eval
69 sub get_subname {
70   my $info = shift;
71   if (defined($info->{eval})) {
72     my $eval = $info->{eval};
73     if ($info->{is_require}) {
74       return "require $eval";
75     }
76     else {
77       $eval =~ s/([\\\'])/\\$1/g;
78       return str_len_trim($eval, $MaxEvalLen);
79     }
80   }
81
82   return ($info->{sub} eq '(eval)') ? 'eval {...}' : $info->{sub};
83 }
84
85 # Figures out what call (from the point of view of the caller)
86 # the long error backtrace should start at.
87 sub long_error_loc {
88   my $i;
89   my $lvl = $CarpLevel;
90   {
91     my $pkg = caller(++$i);
92     unless(defined($pkg)) {
93       # This *shouldn't* happen.
94       if (%Internal) {
95         local %Internal;
96         $i = long_error_loc();
97         last;
98       }
99       else {
100         # OK, now I am irritated.
101         return 2;
102       }
103     }
104     redo if $CarpInternal{$pkg};
105     redo unless 0 > --$lvl;
106     redo if $Internal{$pkg};
107   }
108   return $i - 1;
109 }
110
111
112 sub longmess_heavy {
113   return @_ if ref($_[0]); # WHAT IS THIS FOR???
114   my $i = long_error_loc();
115   return ret_backtrace($i, @_);
116 }
117
118 # Returns a full stack backtrace starting from where it is
119 # told.
120 sub ret_backtrace {
121   my ($i, @error) = @_;
122   my $mess;
123   my $err = join '', @error;
124   $i++;
125
126   my $tid_msg = '';
127   if (defined &Thread::tid) {
128     my $tid = Thread->self->tid;
129     $tid_msg = " thread $tid" if $tid;
130   }
131
132   if ($err =~ /\n$/) {
133     $mess = $err;
134   }
135   else {
136     my %i = caller_info($i);
137     $mess = "$err at $i{file} line $i{line}$tid_msg\n";
138   }
139
140   while (my %i = caller_info(++$i)) {
141       $mess .= "\t$i{sub_name} called at $i{file} line $i{line}$tid_msg\n";
142   }
143   
144   return $mess || $err;
145 }
146
147 sub ret_summary {
148   my ($i, @error) = @_;
149   my $mess;
150   my $err = join '', @error;
151   $i++;
152
153   my $tid_msg = '';
154   if (defined &Thread::tid) {
155     my $tid = Thread->self->tid;
156     $tid_msg = " thread $tid" if $tid;
157   }
158
159   my %i = caller_info($i);
160   return "$err at $i{file} line $i{line}$tid_msg\n";
161 }
162
163
164 sub short_error_loc {
165   my $cache;
166   my $i = 1;
167   my $lvl = $CarpLevel;
168   {
169     my $called = caller($i++);
170     my $caller = caller($i);
171     return 0 unless defined($caller); # What happened?
172     redo if $Internal{$caller};
173     redo if $CarpInternal{$called};
174     redo if trusts($called, $caller, $cache);
175     redo if trusts($caller, $called, $cache);
176     redo unless 0 > --$lvl;
177   }
178   return $i - 1;
179 }
180
181 sub shortmess_heavy {
182   return longmess_heavy(@_) if $Verbose;
183   return @_ if ref($_[0]); # WHAT IS THIS FOR???
184   my $i = short_error_loc();
185   if ($i) {
186     ret_summary($i, @_);
187   }
188   else {
189     longmess_heavy(@_);
190   }
191 }
192
193 # If a string is too long, trims it with ...
194 sub str_len_trim {
195   my $str = shift;
196   my $max = shift || 0;
197   if (2 < $max and $max < length($str)) {
198     substr($str, $max - 3) = '...';
199   }
200   return $str;
201 }
202
203 # Takes two packages and an optional cache.  Says whether the
204 # first inherits from the second.
205 #
206 # Recursive versions of this have to work to avoid certain
207 # possible endless loops, and when following long chains of
208 # inheritance are less efficient.
209 sub trusts {
210     my $child = shift;
211     my $parent = shift;
212     my $cache = shift || {};
213     my ($known, $partial) = get_status($cache, $child);
214     # Figure out consequences until we have an answer
215     while (@$partial and not exists $known->{$parent}) {
216         my $anc = shift @$partial;
217         next if exists $known->{$anc};
218         $known->{$anc}++;
219         my ($anc_knows, $anc_partial) = get_status($cache, $anc);
220         my @found = keys %$anc_knows;
221         @$known{@found} = ();
222         push @$partial, @$anc_partial;
223     }
224     return exists $known->{$parent};
225 }
226
227 # Takes a package and gives a list of those trusted directly
228 sub trusts_directly {
229     my $class = shift;
230     return @{"$class\::ISA"};
231 }
232
233 1;
234