File Coverage

blib/lib/Devel/DumpTrace.pm
Criterion Covered Total %
statement 382 598 63.8
branch 132 256 51.5
condition 45 104 43.2
subroutine 63 77 81.8
pod 0 18 0.0
total 622 1053 59.0


line stmt bran cond sub pod time code
1             package Devel::DumpTrace;
2             ## no critic (NoStrict,StringyEval)
3              
4 16     16   74941 use 5.008000;
  16         132  
5 16     16   8310 use Hash::SafeKeys;
  16         15726  
  16         1254  
6 16     16   7106 use PadWalker;
  16         9246  
  16         787  
7 16     16   111 use Scalar::Util 1.14;
  16         500  
  16         1070  
8 16     16   7323 use Text::Shorten;
  16         38  
  16         826  
9 16     16   6900 use Devel::DumpTrace::CachedDisplayedArray;
  16         43  
  16         520  
10 16     16   6728 use Devel::DumpTrace::CachedDisplayedHash;
  16         42  
  16         486  
11 16     16   8969 use IO::Handle;
  16         100156  
  16         714  
12 16     16   11984 use File::Temp;
  16         256043  
  16         1159  
13 16     16   132 use Carp;
  16         28  
  16         808  
14 16     16   95 use Fcntl qw(:flock :seek);
  16         28  
  16         2204  
15 16     16   110 use strict;
  16         29  
  16         310  
16 16     16   99 use warnings;
  16         30  
  16         3035  
17              
18             our $VERSION = '0.29';
19              
20             my $Time_HiRes_avail;
21             my $color_avail;
22              
23             BEGIN {
24             # process environment before Devel::DumpTrace::Const is compiled
25 16 50   16   169 if (defined $ENV{DUMPTRACE}) {
26 0 0       0 my $kv_splitter = $ENV{DUMPTRACE}=~/;/ ? ';' : ',';
27 0         0 foreach my $kv (split $kv_splitter, $ENV{DUMPTRACE}) {
28 0         0 my ($k,$v) = split /=/, $kv, 2;
29 0         0 $ENV{"DUMPTRACE_$k"} = $v;
30             }
31             }
32              
33 16   50 16   1274 $Time_HiRes_avail = eval 'use Time::HiRes qw(time);1' || 0;
  16         9054  
  16         22319  
  16         71  
34 16   50 16   965 $color_avail = eval
  16         10374  
  16         134868  
  16         962  
35             'use Term::ANSIColor;$Term::ANSIColor::VERSION>=3.00' || 0;
36              
37             # idea from Devel::GlobalDestruction 0.13
38             # replace $_GLOBAL_DESTRUCTION used in earlier versions
39 16 50       87 if (defined ${^GLOBAL_PHASE}) {
40 16 0   0   1250 eval 'sub __inGD(){${^GLOBAL_PHASE}eq q{DESTRUCT}&&__END()};1';
  0         0  
41             } else {
42 0         0 require B;
43 0         0 eval 'sub __inGD(){${B::main_cv()}==0&&__END();};1';
44             }
45             }
46 16     16   7030 use Devel::DumpTrace::Const;
  16         43  
  16         16660  
47              
48             our $ARRAY_ELEM_SEPARATOR = ',';
49             our $HASH_ENTRY_SEPARATOR = ';';
50             our $HASH_PAIR_SEPARATOR = '=>';
51             our $XEVAL_SEPARATOR = ':';
52             our $SEPARATOR = "-------------------------------------------\n";
53              
54             my $pid = $$;
55             our $DUMPTRACE_FH;
56             our $DUMPTRACE_COLOR;
57             our $SMART_ABBREV = 1;
58             our $DB_ARGS_DEPTH = 3;
59             our %EXCLUDE_PKG = ();
60             our %INCLUDE_PKG = ('main' => 1);
61             our @EXCLUDE_PATTERN = ('^Devel::DumpTrace', '^Text::Shorten');
62             our @INCLUDE_PATTERN = ();
63             our (%DEFERRED, $PAD_MY, $PAD_OUR, $TRACE);
64             our $_THREADS = 0;
65             our $_INIT = 0;
66              
67             my (@matches, %sources);
68             my @_INC = @lib::ORIG_INC ? @lib::ORIG_INC : @INC;
69              
70             # these variables are always qualified into the 'main' package,
71             # regardless of the current package
72             my %ALWAYS_MAIN = (ENV => 1, INC => 1, ARGV => 1, ARGVOUT => 1,
73             SIG => 1, STDIN => 1, STDOUT => 1, STDERR => 1,);
74              
75             # used by _qquote below
76             my %esc = ("\a" => '\a', "\b" => '\b', "\t" => '\t', "\n" => '\n',
77             "\f" => '\f', "\r" => '\r', "\e" => '\e',);
78              
79             # use PPI by default, if available
80             $Devel::DumpTrace::NO_PPI
81             || $ENV{DUMPTRACE_NOPPI}
82 14     14   10130 || eval 'use Devel::DumpTrace::PPI;1';
  0         0  
  0         0  
83              
84             {
85             *Devel::Trace::TRACE = \$TRACE;
86             tie $TRACE, 'Devel::DumpTrace::VerboseLevel';
87             if (defined $ENV{DUMPTRACE_LEVEL}) {
88             $TRACE = $ENV{DUMPTRACE_LEVEL};
89             } else {
90             $TRACE = 'default';
91             }
92              
93             *DB::DB = \&DB__DB unless defined &DB::DB;
94              
95             if (defined $ENV{DUMPTRACE_FH}) {
96             if (uc $ENV{DUMPTRACE_FH} eq 'STDOUT') {
97             $DUMPTRACE_FH = *STDOUT;
98             } elsif (uc $ENV{DUMPTRACE_FH} eq 'TTY') {
99             my $tty = $^O eq 'MSWin32' ? 'CON' : '/dev/tty';
100             unless (open $DUMPTRACE_FH, '>>', $tty) {
101             warn "Failed to open tty as requsted by ",
102             "DUMPTRACE_FH=$ENV{DUMPTRACE_FH}. Failover to STDERR\n";
103             $DUMPTRACE_FH = *STDERR;
104             }
105             } else {
106             ## no critic (BriefOpen)
107             unless (open $DUMPTRACE_FH, '>', $ENV{DUMPTRACE_FH}) {
108             die "Can't use $ENV{DUMPTRACE_FH} as trace output file: $!\n",
109             "Devel::DumpTrace module is quitting.\n";
110             }
111             }
112             } else {
113             $DUMPTRACE_FH = *STDERR;
114             }
115             $DUMPTRACE_FH->autoflush(1);
116             $DUMPTRACE_COLOR = $ENV{DUMPTRACE_COLOR} || '';
117             if ($DUMPTRACE_COLOR) {
118             if ($color_avail) {
119             if ($DUMPTRACE_COLOR =~ /^\d+$/) {
120             my $bg = $DUMPTRACE_COLOR >> 4;
121             my $fg = $DUMPTRACE_COLOR & 7;
122             my $bold = ($DUMPTRACE_COLOR & 8) != 0;
123             my @c = ("black","red","green","yellow",
124             "blue","magenta","cyan","white");
125             $DUMPTRACE_COLOR = ($bold ? "bold " : "") . $c[$fg]
126             . ($bg ? " on_" . $c[$bg & 7] : "");
127             }
128             $DUMPTRACE_COLOR = Term::ANSIColor::color($DUMPTRACE_COLOR);
129             our $DUMPTRACE_RESET = Term::ANSIColor::color('reset');
130             } else {
131             carp "DUMPTRACE_COLOR spec ignored: ",
132             "Term::ANSIColor not available";
133             $DUMPTRACE_COLOR = '';
134             }
135             } else {
136             $DUMPTRACE_COLOR = "";
137             }
138             $SMART_ABBREV = 0 if $ENV{DUMPTRACE_DUMB_ABBREV};
139             }
140              
141             sub import {
142 32     32   207 my ($class, @args) = @_;
143              
144 32         94 push @EXCLUDE_PATTERN, map '^' . substr($_,1) . '$', grep { /^-/ } @args;
  11         43  
145 32         59 push @INCLUDE_PATTERN, map '^' . substr($_,1) . '$', grep { /^\+/ }@args;
  11         30  
146             # these packages will be included/excluded at CHECK time, after
147             # all packages have been loaded
148              
149             push @EXCLUDE_PATTERN,
150 32   50     199 map { '^' . $_ . '$' } split /,/, $ENV{DUMPTRACE_EXCLPKG} || '';
  0         0  
151             push @INCLUDE_PATTERN,
152 32   50     157 map { '^' . $_ . '$' } split /,/, $ENV{DUMPTRACE_INCLPKG} || '';
  0         0  
153              
154 32         61 @args = grep { /^[^+-]/ } @args;
  11         60  
155 32 100       82 if (grep { $_ eq ':test' } @args) {
  11         41  
156              
157             # :test
158             # import some low level routines to the calling
159             # namespace for testing.
160              
161 11         23 @args = grep { $_ ne ':test' } @args;
  11         28  
162 16     16   146 no strict 'refs';
  16         32  
  16         6704  
163 11         30 my $p = caller;
164 11         28 foreach my $name (qw(save_pads evaluate_and_display_line dump_scalar
165             hash_repr array_repr handle_deferred_output
166             evaluate save_previous_regex_matches)) {
167 88         180 *{$p . '::' . $name} = *$name;
  88         351  
168             }
169 11         24 *{$p . '::substitute'} = *perform_variable_substitutions;
  11         42  
170 11         26 *{$p . '::xsubstitute'} = *perform_extended_variable_substitutions;
  11         43  
171             }
172 32 50       119 if (@args > 0) {
173 0         0 $TRACE = join ',', @args;
174             }
175 32         1789 return;
176             }
177              
178             sub DB__DB {
179 0 0   0 0 0 return if __inGD();
180 0 0       0 return unless $Devel::DumpTrace::TRACE;
181              
182 0         0 my ($p, $f, $l) = caller();
183 0         0 my (undef, undef, undef, $sub) = caller(1);
184 0   0     0 $sub ||= '__top__';
185 0         0 $sub =~ s/::$/::__top__/;
186              
187 0 0       0 if ($DB::single < 2) {
188 0 0       0 return if _exclude_pkg($f,$p,$l);
189 0 0       0 return if _display_style() == DISPLAY_NONE;
190             }
191              
192 0         0 handle_deferred_output($sub, $f);
193 0         0 my $code = get_source($f,$l);
194              
195 0         0 save_pads(1);
196 0         0 save_previous_regex_matches();
197 0         0 evaluate_and_display_line($code, $p, $f, $l, $sub);
198 0         0 return;
199             }
200              
201             sub get_source {
202 0     0 0 0 my ($file, $line) = @_;
203 16     16   126 no strict 'refs';
  16         46  
  16         11155  
204              
205 0 0       0 if (!defined $sources{$file}) {
206             # die "source not available for $file ...\n";
207 0         0 my $source_key = "::_<" . $file;
208 0         0 eval {
209 0         0 $sources{$file} = [ @{$source_key} ]
  0         0  
210             };
211 0 0       0 if ($@) {
212             # this happens when we are poking around the symbol table?
213             # are we corrupting the source file data somehow?
214              
215 0         0 $sources{$file} = [
216             ("SOURCE NOT AVAILABLE FOR file $file: $@") x 999
217             ];
218 0 0       0 if (open my $grrrrr, '<', $file) {
219 0         0 $sources{$file} = [ "", <$grrrrr> ];
220 0         0 warn "Source for \"$file\" not loaded ",
221             "automatically at debugger level ...\n";
222 0         0 close $grrrrr;
223             }
224             }
225             }
226 0         0 return $sources{$file}->[$line];
227             }
228              
229             sub _exclude_pkg {
230 0     0   0 my($file,$pkg,$line) = @_;
231              
232 0 0 0     0 return 0 if $INCLUDE_PKG{$pkg} || $INCLUDE_PKG{$file};
233 0         0 foreach (@INCLUDE_PATTERN) {
234 0 0       0 if ($pkg =~ $_) {
235 0         0 $INCLUDE_PKG{$pkg} = 1;
236 0         0 return 0;
237             }
238             }
239              
240 0 0 0     0 return 1 if $EXCLUDE_PKG{$pkg} || $EXCLUDE_PKG{$file};
241 0         0 foreach (@EXCLUDE_PATTERN) {
242 0 0       0 if ($pkg =~ $_) {
243 0 0       0 return $EXCLUDE_PKG{$pkg}=1 if $pkg =~ $_;
244             }
245             }
246 0 0       0 return 0 if _package_style() > DISPLAY_NONE;
247              
248             # exclude files from @_INC when _package_style() is 0
249 0         0 foreach my $inc (@_INC) {
250 0 0 0     0 if (index($inc,"/") >= 0 && index($file,$inc) == 0) {
251 0         0 return $EXCLUDE_PKG{$file} = $EXCLUDE_PKG{$pkg} = 1;
252             }
253             }
254 0         0 $INCLUDE_PKG{$pkg} = 1;
255              
256 0         0 return 0;
257             }
258              
259             # map $TRACE variable to a display style
260             sub _display_style_old {
261 16 100   16   177 return DISPLAY_TERSE if $TRACE eq 'default'; # 5.8.8 bug?
262 12         90 return (DISPLAY_TERSE,
263             DISPLAY_TERSE,
264             DISPLAY_TERSE,
265             DISPLAY_TERSE,
266             DISPLAY_GABBY,
267             DISPLAY_GABBY,
268             DISPLAY_GABBY,
269             DISPLAY_GABBY,
270             DISPLAY_GABBY,
271             DISPLAY_GABBY)[$TRACE % 10];
272             }
273             sub _display_style_new {
274 0     0   0 return (DISPLAY_TERSE,
275             DISPLAY_TERSE,
276             DISPLAY_TERSE,
277             DISPLAY_TERSE,
278             DISPLAY_TERSE,
279             DISPLAY_GABBY,
280             DISPLAY_GABBY,
281             DISPLAY_GABBY,
282             DISPLAY_GABBY,
283             DISPLAY_GABBY)[$TRACE % 10];
284             }
285              
286             # map $TRACE variable to an abbreviation style
287             sub _abbrev_style_old {
288 1368     1368   2885 return (ABBREV_SMART,
289             ABBREV_SMART,
290             ABBREV_MILD_SM,
291             ABBREV_NONE,
292             ABBREV_MILD_SM,
293             ABBREV_NONE,
294             ABBREV_NONE,
295             ABBREV_NONE,
296             ABBREV_NONE,
297             ABBREV_NONE,)[$TRACE % 10]
298             }
299             sub _abbrev_style_new {
300 0     0   0 return (ABBREV_SMART,
301             ABBREV_SMART,
302             ABBREV_STRONG,
303             ABBREV_MILD_SM,
304             ABBREV_MILD,
305             ABBREV_NONE,
306             ABBREV_SMART,
307             ABBREV_STRONG,
308             ABBREV_MILD_SM,
309             ABBREV_NONE,)[$TRACE % 10]
310             }
311              
312             BEGIN {
313 16     16   104 *_display_style = *_display_style_old;
314 16         27836 *_abbrev_style = *_abbrev_style_old;
315             }
316              
317             sub _package_style {
318 0     0   0 return $TRACE >= 100;
319             }
320              
321             sub save_pads {
322 11   50 11 0 2686 my $n = shift || 0;
323 11         35 my $target_depth = current_depth() - $n - 1;
324              
325 11 50       44 if ($target_depth < 0) {
326 0         0 Carp::cluck "save_pads: request for negative frame ",
327             current_depth(), " $target_depth $n at ";
328 0         0 return;
329             }
330 11 50       35 if ($n < 0) {
331 0         0 Carp::cluck "save_pads: request for shallow frame ",
332             current_depth(), " $target_depth $n at ";
333 0         0 return;
334             }
335              
336             eval {
337 11         183 $PAD_MY = PadWalker::peek_my($n + 1);
338 11         104 $PAD_OUR = PadWalker::peek_our($n + 1);
339 11         45 1;
340 11 50       22 } or do {
341 0         0 Carp::confess("$@ from PadWalker: \$n=$n is too large.\n",
342             "Target depth was $target_depth\n");
343             };
344              
345             # add extra data to the pads so that they can be refreshed
346             # at an arbitrary point in the future
347 11         27 $PAD_MY->{__DEPTH__} = $PAD_OUR->{__DEPTH__} = current_depth() - $n - 1;
348              
349 11         29 return;
350             }
351              
352             sub current_depth {
353 22     22 0 37 my $n = 0;
354 22         100 $n++ while caller($n);
355 22         89 return $n-1;
356             }
357              
358             sub refresh_pads {
359 0 0   0 0 0 return if __inGD();
360 0         0 my $current = current_depth();
361 0         0 my $target = $PAD_MY->{__DEPTH__};
362 0 0       0 if ($current >= $target) {
363 0         0 save_pads($current - $target);
364             }
365             # $current < $target
366 0         0 return;
367             }
368              
369             our $last_dumptrace = '';
370             my @dt_prefix = (" ", ### not used
371             "> ", ### not used
372             ">> ", # to display current file/line/sub
373             ">>> ", # raw statement
374             ">>>> ", # with var substitution, before execution
375             ">>>>> ", # with var substitution after execution
376             " \t ", ### not used
377             "> \t ", ### not used
378             ">> \t ", ### not used
379             ">>> \t ", # raw statetment
380             ">>>> \t ", # with var substitution, before execution
381             ">>>>>\t ", # with var substitution after execution
382             "");
383              
384             sub dumptrace {
385 0     0 0 0 my ($n, $tab, @output) = @_;
386 0         0 my $dt = join ('', @output);
387 0         0 my $out = $dt_prefix[$n+6*!!$tab] . $dt;
388 0 0 0     0 if ($last_dumptrace && $dt eq $last_dumptrace) {
389             # duplicate
390 0         0 return;
391             }
392              
393 0         0 $last_dumptrace = $dt;
394 0 0       0 if ($DUMPTRACE_COLOR) {
395 0         0 our $DUMPTRACE_RESET;
396 0         0 $out = join $/, map( $DUMPTRACE_COLOR . $_ . $DUMPTRACE_RESET,
397             split($/,$out)), "";
398             }
399 0 0       0 our $LOCKOBJ && lock(my $lock = \$LOCKOBJ);
400 0         0 print {$DUMPTRACE_FH} $out;
  0         0  
401             }
402              
403             sub evaluate_and_display_line {
404 0     0 0 0 my ($code, $p, $f, $l, $sub) = @_;
405 0         0 my $style = _display_style();
406              
407 0 0       0 if ($style > DISPLAY_TERSE) {
408 0         0 _separate();
409 0         0 dumptrace(2,0, current_position_string($f,$l,$sub), "\n");
410 0         0 dumptrace(3,1,$code);
411             }
412              
413             # look for assignment operator.
414 0   0     0 $DEFERRED{"$sub : $f"} ||= [];
415 0 0 0     0 if ($code =~ m{[-+*/&|^.%]?=[^=>]}
416             || $code =~ m{[\b*&|/<>]{2}=\b} ) {
417              
418 0         0 my ($expr1, $op, $expr2) = ($`, $&, $'); # ');
419              
420 0 0       0 if ($style < DISPLAY_GABBY) {
421 0         0 $expr2 = perform_extended_variable_substitutions($op . $expr2, $p);
422             } else {
423 0         0 $expr2 = perform_variable_substitutions($op . $expr2, $p);
424             }
425              
426 0         0 push @{$DEFERRED{"$sub : $f"}},
  0         0  
427             { PACKAGE => $p,
428             MY_PAD => $PAD_MY,
429             OUR_PAD => $PAD_OUR,
430             SUB => $sub,
431             FILE => $f,
432             LINE => $l,
433             DISPLAY_FILE_AND_LINE => $style <= DISPLAY_TERSE,
434             EXPRESSION => [ $expr1, $expr2 ]
435             };
436              
437 0 0       0 if ("$expr1$expr2" ne $code) {
438 0 0       0 if ($style >= DISPLAY_GABBY) {
439 0         0 dumptrace(4,1,$expr1,$expr2);
440             }
441             }
442 0         0 return;
443             } else {
444 0         0 push @{$DEFERRED{"$sub : $f"}}, undef;
  0         0  
445             }
446              
447 0         0 my $xcode;
448              
449             # if this is a simple lexical declaration and NOT an assignment,
450             # then don't perform variable substitution:
451             # my $k;
452             # my ($a,$b,@c);
453             # our $xyz;
454              
455 0 0 0     0 if ($code =~ /^ \s* (my|our) \s*
      0        
456             [\$@%*\(] /x # lexical declaration
457              
458             && $code =~ / (?
459             \s* (\# .* )? $/x # single statement, single line
460              
461             && $code !~ /=/) { # NOT an assignment
462              
463 0         0 $xcode = $code;
464              
465             } else {
466              
467 0         0 $xcode = perform_variable_substitutions($code, $p);
468              
469             }
470              
471 0 0       0 if ($style >= DISPLAY_GABBY) {
    0          
472 0 0       0 if ($xcode ne $code) {
473 0         0 dumptrace(4,1,$xcode);
474             }
475             } elsif ($style == DISPLAY_TERSE) {
476 0         0 dumptrace(4,0, current_position_string($f,$l,$sub),
477             "\t $xcode");
478             }
479 0         0 return;
480             }
481              
482             sub _separate {
483 0     0   0 our $SEPARATOR_USED;
484 0 0       0 $SEPARATOR_USED++ && dumptrace(-1, 0, $SEPARATOR);
485 0         0 return;
486             }
487              
488             # a guard against deep recursion in dump_scalar subroutine
489             my %_dump_scalar_seen = ();
490              
491             sub _reset_dump {
492 193     193   328 %_dump_scalar_seen = ();
493             }
494              
495             sub dump_scalar {
496 1228     1228 0 3354 my $scalar = $_[0];
497             # was my $scalar = shift and was my ($scalar) = @_;
498             # but they caused "Modification of a read-only value attempted"
499             # error with Perl 5.8.8
500              
501 1228 100       4110 return 'undef' if !defined $scalar;
502 1159 100       1984 if (ref $scalar) {
503 42 100       143 if ($_dump_scalar_seen{$scalar}) {
504 1         6 return "... $scalar (prev. referenced)";
505             }
506 41         115 $_dump_scalar_seen{$scalar}++;
507 41         65 my $z;
508 41 100       189 if (Scalar::Util::reftype($scalar) eq 'ARRAY') {
    100          
    50          
509 22         61 $z = '[' . array_repr($scalar) . ']';
510             } elsif (Scalar::Util::reftype($scalar) eq 'HASH') {
511 11         29 $z = '{' . hash_repr($scalar) . '}';
512             } elsif (Scalar::Util::reftype($scalar) eq 'GLOB') {
513 0         0 $z = $scalar;
514             } else {
515 8         19 $z = "$scalar";
516             }
517 41         116 delete $_dump_scalar_seen{$scalar};
518 41         215 return $z;
519             }
520 1117 100       2586 if (Scalar::Util::looks_like_number($scalar)) {
521 464         1035 $scalar =~ s/^\s+//;
522 464         777 $scalar =~ s/\s+$//;
523 464         727 return _abbreviate_scalar($scalar);
524             }
525 653 100       1397 if (ref \$scalar eq 'GLOB') {
526 4         20 return $scalar;
527             }
528 649         1084 my $qq = _qquote($scalar);
529 649 100       1258 if ($qq ne $scalar) {
530 1         4 return _abbreviate_scalar(qq("$qq"));
531             }
532 648         1516 return _abbreviate_scalar(qq('$scalar'));
533             }
534              
535             sub _abbreviate_scalar {
536 1113     1113   1947 my ($value) = @_;
537 1113 50       1622 if (_abbrev_style() >= ABBREV_NONE) {
538 1113         3891 return $value;
539             }
540 0 0       0 if (_abbrev_style() > ABBREV_STRONG) {
541             # mild abbreviation: no token longer than 80 chars
542 0         0 return Text::Shorten::shorten_scalar($value, 80);
543             } else {
544             # strong abbreviation: no token longer than 20 chars
545 0         0 return Text::Shorten::shorten_scalar($value, 20);
546             }
547             }
548              
549             # shamelessly lifted from Data::Dumper::qquote
550             #
551             # converts a string of arbitrary characters to an ASCII string that
552             # produces the original string under double quote interpolation
553             sub _qquote {
554 649     649   1191 local($_) = shift;
555 649         1164 s/([\\\"\@\$])/\\$1/g;
556 16     16   10745 my $bytes; { use bytes; $bytes = length }
  16         247  
  16         182  
  649         825  
  649         867  
  649         894  
557 649 50       1228 ($bytes > length) && s/([^\x00-\x7f])/'\x{'.sprintf("%x",ord($1)).'}'/ge;
  0         0  
558 649 100       1867 /[^ !"\#\$%&'()*+,\-.\/0-9:;<=>?\@A-Z[\\\]^_`a-z{|}~]/ || return $_;
559              
560 1   50     7 my $high = shift || '';
561 1         9 s/([\a\b\t\n\f\r\e])/$esc{$1}/g;
562              
563 1         3 if (ord('^')==94) {
564             # no need for 3 digits in escape for these
565 1         3 s/([\0-\037])(?!\d)/'\\'.sprintf('%o',ord($1))/eg;
  0         0  
566 1         3 s/([\0-\037\177])/'\\'.sprintf('%03o',ord($1))/eg;
  0         0  
567             # all but last branch below not supported --BEHAVIOR SUBJECT TO CHANGE--
568 1 50       6 if ($high eq 'iso8859') {
    50          
    50          
569 0         0 s/([\200-\240])/'\\'.sprintf('%o',ord($1))/eg;
  0         0  
570             } elsif ($high eq 'utf8') {
571             # use utf8;
572             # $str =~ s/([^\040-\176])/sprintf "\\x{%04x}", ord($1)/ge;
573             } elsif ($high eq '8bit') {
574             # leave it as it is
575             } else {
576 1         3 s/([\200-\377])/'\\'.sprintf('%03o',ord($1))/eg;
  0         0  
577 1         2 s/([^\040-\176])/sprintf "\\x{%04x}", ord($1)/ge;
  0         0  
578             }
579             } else { # ebcdic
580             s{([^ !"\#\$%&'()*+,\-.\/0-9:;<=>?\@A-Z[\\\]^_`a-z{|}~])(?!\d)}
581             {my $v = ord($1); '\\'.sprintf(($v <= 037 ? '%o' : '%03o'), $v)}eg;
582             s{([^ !"\#\$%&'()*+,\-.\/0-9:;<=>?\@A-Z[\\\]^_`a-z{|}~])}
583 1         4 {'\\'.sprintf('%03o',ord($1))}eg;
584             }
585             return $_;
586             }
587 82     82 0 968  
588             sub hash_repr {
589 82 100       234 my ($hashref, @keys) = @_;
590 81 50       170  
591 81 100 66     476 return '' if !defined $hashref;
592             @keys = () unless $SMART_ABBREV;
593 81 0       263 my $ref = ref $hashref && ref $hashref ne 'HASH'
    50          
594             ? ref($hashref) . ': ' : '';
595 81         247 my $maxlen = _abbrev_style() < ABBREV_NONE
596             ? _abbrev_style() > ABBREV_STRONG ? 79 : 19 : -1;
597 81         124 my $cache_key = join ':',
598             $maxlen, $HASH_ENTRY_SEPARATOR, $HASH_PAIR_SEPARATOR;
599             my $hash;
600              
601             # When the hash table gets large, tie it to
602             # Devel::DumpTrace::CachedDisplayedHash and
603             # see if we can avoid some expensive calls
604 81 50 50     401 # to Text::Shorten::shorten_hash .
605              
606 0         0 if ((Scalar::Util::reftype($hashref)||'') ne 'HASH') {
607             # this can happen with globs, e.g., $$glob->{attribute} = value;
608             return "$hashref";
609 81 50 33     437 }
    50 66        
      66        
      33        
610              
611             if (@keys == 0 &&
612 0         0 Devel::DumpTrace::CachedDisplayedHash->is($hashref)) {
  0         0  
613 0 0       0  
614             my $result = (tied %{$hashref})->get_cache($cache_key);
615 0         0 if (defined $result) {
  0         0  
  0         0  
  0         0  
616             return $ref . join $HASH_ENTRY_SEPARATOR,
617 0         0 map { join $HASH_PAIR_SEPARATOR, @{$_} } _condsort(@{$result});
  0         0  
618 81         402 }
619             $hash = (tied %{$hashref})->{PHASH};
620             } elsif (!tied(%{$hashref})
621             && @keys == 0
622             && !__hashref_is_symbol_table($hashref)
623              
624             # use safekeys in case this DB hook is inside an `each` iterator
625 0         0 && 100 < scalar safekeys %$hashref) {
626 0         0  
  0         0  
627 0         0 my $cdh = tie %{$hashref}, 'Devel::DumpTrace::CachedDisplayedHash',
628             %{$hashref};
629             $hash = $cdh->{PHASH};
630 81         1206 } else {
631             # use Hash::SafeKeys so we don't reset an active `each` iterator
632 81         245 my $it = Hash::SafeKeys::save_iterator_state($hashref);
  430         1243  
633             $hash = { map {
634 81         334 dump_scalar($_) => dump_scalar($hashref->{$_})
635             } keys %$hashref };
636             Hash::SafeKeys::restore_iterator_state($hashref,$it);
637 81         149 }
638 81 50       144  
639 0         0 my @r;
640             if (_abbrev_style() < ABBREV_NONE) {
641 0         0 local $Text::Shortern::HASHREPR_SORTKEYS
642             = $Devel::DumpTrace::HASHREPR_SORT;
643             @r = Text::Shorten::shorten_hash(
644             $hash, $maxlen,
645             $HASH_ENTRY_SEPARATOR,
646             $HASH_PAIR_SEPARATOR, @keys );
647 81         249 } else {
648 81         249 # use Hash::Safekeys to not reset an active `each` iterator (RT#77673)
  430         866  
649 81         227 my $it = Hash::SafeKeys::save_iterator_state($hash);
650             @r = map { [ $_ => $hash->{$_} ] } _condsort(keys %$hash);
651             Hash::SafeKeys::restore_iterator_state($hash,$it);
652 81 50 33     360 }
653 0         0  
  0         0  
654             if (@keys == 0 && Devel::DumpTrace::CachedDisplayedHash->is($hashref)) {
655             (tied %{$hashref})->store_cache($cache_key, \@r);
656 81 50       204 }
657 0         0  
658 0         0 if (!defined $HASH_PAIR_SEPARATOR) {
659             Carp::cluck("setting \$HASH_PAIR_SEPARATOR definition ...");
660             $HASH_PAIR_SEPARATOR = " =======> ";
661             }
662 81         155  
663 430 50       563 return $ref . join ($HASH_ENTRY_SEPARATOR,
  860         2492  
  430         633  
664             map { join ($HASH_PAIR_SEPARATOR,
665             map{defined($_)?$_:'undef'}@{$_}) } @r );
666             }
667              
668 81 100   81   390 # sort an array iff $Devel::DumpTrace::HASHREPR_SORT is set.
669             sub _condsort {
670             $Devel::DumpTrace::HASHREPR_SORT ? sort @_ : @_;
671             }
672              
673             sub __hashref_is_symbol_table {
674             # if we pass a reference to a symbol table in repr_hash,
675             # we don't want to tie it to a D::DT::CachedDisplayedHash.
676             #
677             # Don't know if this is the best method or if it is
678 16     16   19652 # perfectly reliable, but it is getting there ...
  16         48  
  16         26355  
679 79     79   226  
680 79         260 use B;
681 79   33     743 my ($hashref) = @_;
682             my $sv = B::svref_2object($hashref);
683             return ref($sv) eq 'B::HV' && $sv->NAME;
684             }
685 94     94 0 1765  
686             sub array_repr {
687 94 100       208 my ($arrayref, @keys) = @_;
688 93 50       188  
689 93 100 66     422 return '' if !defined $arrayref;
690             @keys = () unless $SMART_ABBREV;
691 93 0       207 my $ref = ref $arrayref && ref $arrayref ne 'ARRAY'
    50          
692             ? ref($arrayref) . ': ' : '';
693 93         264 my $maxlen = _abbrev_style() < ABBREV_NONE
694 93         132 ? _abbrev_style() > ABBREV_STRONG ? 79 : 19 : -1;
695             my $cache_key = join ':', $maxlen, $ARRAY_ELEM_SEPARATOR;
696             my $array;
697              
698             # When the array gets large, tie it to
699             # Devel::DumpTrace::CachedDisplayedArray and
700             # see if we can avoid some expensive calls
701 93 50 33     455 # to Text::Shorten::shorten_array .
    50 33        
      33        
702              
703             if (@keys == 0
704 0         0 && Devel::DumpTrace::CachedDisplayedArray->is($arrayref)) {
  0         0  
705 0 0       0  
706 0         0 my $result = (tied @{$arrayref})->get_cache($cache_key);
707             if (defined $result) {
708 0         0 return $ref . join $ARRAY_ELEM_SEPARATOR, @$result;
  0         0  
709 93         316 }
  93         241  
710             $array = (tied @{$arrayref})->{PARRAY};
711 0         0 } elsif (@keys==0 && !tied(@{$arrayref}) && 100 < scalar @{$arrayref}) {
712 0         0 eval {
  0         0  
713 0         0 tie @{$arrayref}, 'Devel::DumpTrace::CachedDisplayedArray',
  0         0  
714 0 0       0 @{$arrayref};
715 0         0 $array = (tied @{$arrayref})->{PARRAY};
  0         0  
  0         0  
716             } or do {
717             $array = [ map { dump_scalar($_) } @{$arrayref} ];
718 93         136 };
  278         485  
  93         168  
719             } else {
720             $array = [ map { dump_scalar($_) } @{$arrayref} ];
721 93         205 }
722 93 50       201  
723 0         0 my @r;
724             if ($maxlen > 0) {
725             @r = Text::Shorten::shorten_array(
726 93         133 $array, $maxlen, $ARRAY_ELEM_SEPARATOR, @keys);
  93         241  
727             } else {
728 93 50 33     343 @r = @{$array};
729             }
730 0         0 if (@keys == 0
  0         0  
731             && Devel::DumpTrace::CachedDisplayedArray->is($arrayref)) {
732 93         727 (tied @{$arrayref})->store_cache($cache_key, \@r);
733             }
734             return $ref . join $ARRAY_ELEM_SEPARATOR, @r;
735             }
736 16     16 0 89  
737 0         0 sub handle_ALL_deferred_output {
738 0         0 foreach my $context (keys %DEFERRED) {
739             my ($sub, $file) = split / : /, $context, 2;
740 16 50       66 handle_deferred_output($sub, $file);
741 16         47 }
742             _separate() if _display_style() > DISPLAY_TERSE;
743             return;
744             }
745 0     0 0 0  
746 0         0 sub handle_deferred_output {
  0         0  
747 0         0 my ($sub, $file) = @_;
748             my $deferred = pop @{$DEFERRED{"$sub : $file"}};
749 0 0       0 delete $DEFERRED{"$sub : $file"};
750              
751 0         0 if (defined $deferred) {
  0         0  
752 0         0  
753 0         0 my ($expr1, $expr2) = @{$deferred->{EXPRESSION}};
754 0         0 my $deferred_pkg = $deferred->{PACKAGE};
755 0         0 $PAD_MY = $deferred->{MY_PAD};
756 0         0 $PAD_OUR = $deferred->{OUR_PAD};
757 0         0 refresh_pads();
758 0         0 $PAD_MY->{__STALE__} = $deferred->{MY_PAD};
759 0 0       0 $PAD_OUR->{__STALE__} = $deferred->{OUR_PAD};
760 0         0 my ($line);
761 0         0 if ($deferred->{DISPLAY_FILE_AND_LINE}) {
762             $file = $deferred->{FILE};
763 0         0 $line = $deferred->{LINE};
764 0 0       0 }
765             my $output = $expr2;
766 0         0 if (defined($line)) {
767             $output = current_position_string($file,$line,$deferred->{SUB})
768             . "\t" .
769             perform_extended_variable_substitutions($expr1, $deferred_pkg)
770 0         0 . $output;
771             } else {
772             $output = "\t "
773             . perform_variable_substitutions($expr1, $deferred_pkg)
774 0         0 . $output;
775             }
776 0         0 dumptrace(5,0,$output);
777             }
778             return;
779             }
780 107     107 0 30020  
781 107         839 sub perform_variable_substitutions {
782             my ($xcode, $pkg) = @_;
783             $xcode =~ s{ ([\$\@\%])\s* # sigil
784             ([\w:]+) # package (optional) and var name
785             (\s*->)? # optional dereference op
786 122   100     848 (\s*[\[\{])? # optional subscript
      100        
787             }{
788             evaluate($1,$2,$3||'',$4||'',$pkg)
789 107         380 }gex;
790              
791             return $xcode;
792             }
793              
794 0     0 0 0 my %output_count;
795 0         0 sub current_position_string {
796             my ($file, $line, $sub) = @_;
797             if (OUTPUT_COUNT) {
798             my $cnt = ++$output_count{$file}{$line};
799 0         0 $line .= "\[$cnt\]";
800             }
801             if (OUTPUT_TIME) {
802             if ($Time_HiRes_avail) {
803             $file = sprintf "%.3f:%s", Time::HiRes::time()-$^T, $file;
804             } else {
805             $file = sprintf "t=%d:%s", time-$^T, $file;
806 0         0 }
807 0   0     0 }
808             if (OUTPUT_SUB) {
809             $sub ||= '__top__';
810             # $file already probably contains package information.
811 0         0 # Keeping it in $sub is _usually_ redundant and makes the
812             # line too long.
813 0         0 $sub =~ s/.*:://;
814              
815             if (OUTPUT_PID) {
816             my $p = $$;
817             if ($_THREADS) {
818             $p .= eval { "-t" . threads->tid() }; warn $@ if $@;
819             }
820 0         0 return "$p:$file:$line:[$sub]:";
821             } else {
822             return "$file:$line:[$sub]:";
823             }
824             } elsif (OUTPUT_PID) {
825             my $p = $$;
826             if ($_THREADS) {
827             $p .= eval { "-t" . threads->tid() }; warn $@ if $@;
828             }
829             return "$p:$file:$line:";
830             } else {
831             return "$file:$line:";
832             }
833             }
834 59     59 0 20412  
835 59         493 sub perform_extended_variable_substitutions {
836             my ($xcode, $pkg) = @_;
837             $xcode =~ s{ ([\$\@\%])\s* # sigil
838             ([\w:]*\w)(?!:) # var name, may incl. pkg, ends in alphanum
839 70   100     573 (\s*->)? # optional dereference op
      100        
840             (\s*[\[\{])? # optional subscript
841             }{ $1 . $2 . $XEVAL_SEPARATOR
842 59         200 . evaluate($1,$2,$3||'',$4||'',$pkg)
843             }gex;
844             return $xcode;
845             }
846 8     8 0 12  
847 8         15 sub get_DB_args {
848 8         18 my $depth = 1 + shift;
849 8 50       16 my @z;
850             for (my $i=$depth; $i<=$depth; $i++) {
851 8         59 if ($i>=0) {
852 8 50       30 package DB;
853             my @y = caller($depth);
854             return if @y==0;
855             }
856              
857             # best efforts here. Sometimes this assignment gives a
858 8     1   587 # "Bizarre copy of ARRAY in aassign" error message
  1     1   6  
  1     1   12  
  1     1   56  
  1     1   7  
  1     1   4  
  1     1   30  
  1     1   8  
  1         8  
  1         42  
  1         7  
  1         2  
  1         30  
  1         7  
  1         2  
  1         31  
  1         6  
  1         2  
  1         38  
  1         6  
  1         2  
  1         37  
  1         16  
  1         3  
  1         27  
859             # (when $depth is too deep and @DB::args is not defined?).
860 8         37 eval 'no warnings q/internal/; @z = @DB::args';
861             }
862             return @z;
863             }
864              
865 193     193 0 1092 # McCabe score: 49
866 193         318 sub evaluate {
867 193         508 my ($sigil, $varname, $deref_op, $index_op, $pkg, @keys) = @_;
868             my $v;
869 16     16   138 _reset_dump();
  16         42  
  16         9819  
870              
871 193   100     665 no strict 'refs';
872 193   100     543  
873 193         374 $deref_op ||= '';
874             $index_op ||= '';
875 193 100 100     879 $index_op =~ s/^\s+//;
876 10         21  
877             if ($ALWAYS_MAIN{$varname} || $varname =~ /^\d+$/) {
878 193         432 $pkg = 'main';
879 193 100 100     710 }
880 15         36 $pkg .= '::';
881             if ($varname =~ /::/ || $pkg eq '::') {
882             $pkg = '';
883 193 100       390 }
884 42         92  
885 42         184 if ($deref_op) {
886             my $sigvar = "\$$varname";
887 42 100       180 (my $pkgvar = $sigvar) =~ s/\$/\$$pkg/;
    100          
    50          
    50          
888 14         32  
889             if (defined $PAD_MY->{$sigvar}) {
890 14         33 $v = $PAD_MY->{$sigvar};
891             } elsif (defined $PAD_OUR->{$sigvar}) {
892 0         0 $v = $PAD_OUR->{$sigvar};
893             } elsif (defined $PAD_MY->{__STALE__}{$sigvar}) {
894 0         0 $v = $PAD_MY->{__STALE__}{$sigvar};
895             } elsif (defined $PAD_OUR->{__STALE__}{$sigvar}) {
896 14         873 $v = $PAD_OUR->{__STALE__}{$sigvar};
897             } else {
898 42 100       139 $v = eval "\\$pkgvar";
899 12         18 }
  12         33  
900             if ($index_op eq '[') {
901 30 100       72 return '[' . array_repr(${$v}, @keys) . ']->[';
902 12         18 }
  12         43  
903             if ($index_op eq '{') {
904             return '{' . hash_repr(${$v}, @keys) . '}->{';
905 18         24 }
  18         66  
906 18 50 33     92  
    100          
    100          
907 0         0 my $reftype = Scalar::Util::reftype(${$v});
908             if (!defined($reftype) || $reftype eq '') {
909 6         10 return '(' . dump_scalar($v) . ')->';
  6         14  
910             } elsif ($reftype eq 'HASH') {
911 6         10 return '{' . hash_repr(${$v}, @keys) . '}->';
  6         14  
912             } elsif ($reftype eq 'ARRAY') {
913 6         17 return '[' . array_repr(${$v}, @keys) . ']->';
914             } else {
915             return '(' . dump_scalar($v) . ')->';
916             }
917 151 100       304 }
918 25         56  
919 25         144 if ($index_op eq '{') {
920 25 100       94 my $sigvar = "\%$varname";
    100          
921 7         13 (my $pkgvar = $sigvar) =~ s/\%/\%$pkg/;
922             if (defined($PAD_MY->{$sigvar})) {
923 7         15 $v = $PAD_MY->{$sigvar};
924             } elsif (defined($PAD_OUR->{$sigvar})) {
925 11         619 $v = $PAD_OUR->{$sigvar};
926             } else {
927 25         89 $v = eval "\\$pkgvar";
928             }
929 126 100       266 return '(' . hash_repr($v, @keys) . '){';
930 21         46 }
931 21         96 if ($sigil eq '@') {
932             my $sigvar = "\@$varname";
933 21 100       96 (my $pkgvar = $sigvar) =~ s/\@/\@$pkg/;
    100          
    100          
934              
935             if ($varname eq '_') {
936             # calling caller (1) with arg, (2) in list context,
937 2         4 # (3) from DB package will populate @DB::args, which is
938 16     16   132 # what we really want.
  16         49  
  16         13272  
939 2         17 my $depth = $DB_ARGS_DEPTH;
940 0         0 no warnings 'uninitialized';
941             while ((caller $depth)[CALLER_SUB] =~ /^\(eval/) {
942 2         8 $depth++;
943             }
944 8         27 $v = [ get_DB_args($depth) ];
945             } elsif (defined($PAD_MY->{$sigvar})) {
946 4         10 $v = $PAD_MY->{$sigvar};
947             } elsif (defined($PAD_OUR->{$sigvar})) {
948 7         17 $v = $PAD_OUR->{$sigvar};
949 7         468 } else {
950             eval {
951 7 50       45 $v = eval "\\" . $pkgvar;
952 0         0 };
  0         0  
953             if (!defined $v) {
954 0         0 print {$DUMPTRACE_FH} "Devel::DumpTrace: ",
955             "Couldn't find $sigvar/$pkgvar in any appropriate scope.\n";
956             $v = [];
957 21 100       53 }
958 8         53 }
959             if ($index_op eq '[') {
960 13         36 return '(' . array_repr($v, @keys) . ')[';
961             }
962 105 100       262 return '(' . array_repr($v, @keys) . ')';
963 19         53 }
964 19         112 if ($sigil eq '%') {
965 19 100       81 my $sigvar = "\%$varname";
    100          
966 5         60 (my $pkgvar = $sigvar) =~ s/\%/\%$pkg/;
967             if (defined($PAD_MY->{$sigvar})) {
968 5         12 $v = $PAD_MY->{$sigvar};
969             } elsif (defined($PAD_OUR->{$sigvar})) {
970 9         638 $v = $PAD_OUR->{$sigvar};
971             } else {
972 19         82 $v = eval "\\$pkgvar";
973             }
974 86 50       195 return '(' . hash_repr($v) . ')';
975 86 100       230 }
    100          
976 23         48 if ($sigil eq '$') {
977 23         107 if ($index_op eq '[') {
978 23 100       94 my $sigvar = "\@$varname";
    100          
    100          
979 6         8 (my $pkgvar = $sigvar) =~ s/\@/\@$pkg/;
980 6         12 if ($varname eq '_') {
981             my $depth = $DB_ARGS_DEPTH;
982 6         115 $v = [ get_DB_args($depth) ];
983             } elsif (defined($PAD_MY->{$sigvar})) {
984 4         10 $v = $PAD_MY->{$sigvar};
985             } elsif (defined($PAD_OUR->{$sigvar})) {
986 7         16 $v = $PAD_OUR->{$sigvar};
  7         380  
987 7 50       41 } else {
988 0         0 eval { $v = eval "\\$pkgvar" };
  0         0  
989             if (!defined $v) {
990             print {$DUMPTRACE_FH} "Devel::DumpTrace: ",
991 0         0 "Couldn't find $sigvar/$pkgvar ",
992             "in any appropriate scope.\n";
993             $v = [];
994 23         66 }
995             }
996             return '(' . array_repr($v, @keys) . ')[';
997             } elsif ($varname =~ /^\d+$/) {
998 7         13 # special regex match var $1,$2,...
999 7         13 # they were loaded into @matches in save_previous_regex_matches()
1000             $v = $matches[$varname];
1001             return dump_scalar($v);
1002 56         109 } else {
1003 56 100       120  
1004 2         3 my $sigvar = "\$$varname";
1005             if ($varname eq '_') {
1006 56         269 $pkg = 'main::';
1007             }
1008 56 100       194 (my $pkgvar = $sigvar) =~ s/\$/\$$pkg/;
    100          
1009 24         34  
  24         52  
1010             if (defined($PAD_MY->{$sigvar})) {
1011 12         36 $v = ${$PAD_MY->{$sigvar}};
  12         29  
1012             } elsif (defined($PAD_OUR->{$sigvar})) {
1013 20         1172 $v = ${$PAD_OUR->{$sigvar}};
1014             } else {
1015 56         172 $v = eval "$pkgvar";
1016             }
1017             return dump_scalar($v);
1018             }
1019 0         0 }
1020              
1021             Carp::confess 'No interpolation done for input: ',
1022             "
1023             "index:$index_op ; pkg:$pkg>\n"
1024             }
1025              
1026             sub save_previous_regex_matches {
1027 2 50   2 0 1222  
1028 2         13  
1029             if ($] > 5.025006) {
1030 16     16   142 @matches = ($0,@{^CAPTURE});
  16         32  
  16         1675  
1031 0         0 } else {
  0         0  
  0         0  
1032             no strict 'refs';
1033             @matches = ($0, map { ${$_} } 1..$#+);
1034 2         5 }
1035              
1036             return;
1037             }
1038              
1039             # RT#76864
1040             {
1041             # Devel::DumpTrace is typically loaded before any other module
1042             # (from the -d:DumpTrace switch). Running this thread-specific
1043 16     16   203 # code in a CHECK block gives the traced program a chance to
  16         33  
  16         2128  
1044             # load threads later.
1045 15 50   15   989536 no warnings 'void';
1046 0         0 CHECK {
1047 0         0 if ($INC{'threads.pm'}) {
1048 0         0 $_THREADS = 1;
1049 0         0 require threads::shared;
1050             our $LOCKOBJ = 1; # to synchronize access to output stream
1051             threads::shared::share(\$LOCKOBJ);
1052             }
1053             };
1054             }
1055 16     16   167  
  16         42  
  16         7292  
1056 16     0   139 sub __END {
        16      
1057 16         88 no warnings 'redefine';
1058 16         86 *DB::DB = sub { };
1059 16 50 33     179 *__inGD = sub () { 1 };
1060 16         91 untie $TRACE;
1061             handle_ALL_deferred_output() unless $_THREADS && threads->tid();
1062             1;
1063 16     16   15345 }
1064              
1065             END { &__END; }
1066              
1067              
1068             ##################################################################
1069             # Devel::DumpTrace::VerboseLevel: tie class for $Devel::DumpTrace::TRACE.
1070             #
1071             # This class allows us to say, for example,
1072             #
1073             # $TRACE = 'verbose'
1074             #
1075             # and have the keyword 'verbose' translated into the value "5".
1076             #
1077 16     16   53  
1078 16         33 sub Devel::DumpTrace::VerboseLevel::TIESCALAR {
1079 16         68 my ($pkg) = @_;
1080             my $scalar;
1081             return bless \$scalar, $pkg;
1082             }
1083 1388     1388   2054  
1084 1388         1811 sub Devel::DumpTrace::VerboseLevel::FETCH {
  1388         4422  
1085             my $self = shift;
1086             return ${$self};
1087             }
1088 36     36   4454  
1089             sub Devel::DumpTrace::VerboseLevel::STORE {
1090             my ($self, $value) = @_;
1091 36 50       117  
1092             #Carp::cluck $self,"->STORE($value) called !\n";
1093 36         55 return if !defined $value;
  36         196  
1094 36         130  
1095 36         128 my $old = ${$self};
1096 36         92 my ($style, $package) = split /,/, $value;
1097 16     16   142 $style =~ s/^\s+//;
  16         32  
  16         5422  
1098             $style =~ s/\s+$//;
1099 36   66     293 no warnings 'uninitialized';
1100 36 50       228 $style = {verbose=>5, normal=>3, default=>3,
1101 0         0 quiet=>1, on=>3, off=>'00'}->{lc $style} || $style;
1102 0         0 if ($style !~ /^\d+$/) {
1103             carp "Unrecognized debugging level $style\n";
1104 36         66 $style = 3;
  36         68  
1105 36 100       91 }
1106 2         6 ${$self} = $style;
1107 2         5 if (defined $package) {
1108 2 50       8 $package =~ s/^\s+//;
1109 2         3 $package =~ s/\s+$//;
  2         5  
1110             if ($package) {
1111             ${$self} += 100;
1112 36         98 }
1113             }
1114             return $old;
1115       16     }
1116              
1117             sub Devel::DumpTrace::VerboseLevel::UNTIE { }
1118              
1119             1;
1120              
1121             __END__