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   66179 use 5.008000;
  16         127  
5 16     16   7336 use Hash::SafeKeys;
  16         14343  
  16         1037  
6 16     16   6216 use PadWalker;
  16         8789  
  16         681  
7 16     16   96 use Scalar::Util 1.14;
  16         399  
  16         1009  
8 16     16   6548 use Text::Shorten;
  16         38  
  16         688  
9 16     16   6956 use Devel::DumpTrace::CachedDisplayedArray;
  16         40  
  16         488  
10 16     16   6155 use Devel::DumpTrace::CachedDisplayedHash;
  16         39  
  16         415  
11 16     16   8328 use IO::Handle;
  16         91562  
  16         892  
12 16     16   10943 use File::Temp;
  16         227293  
  16         1090  
13 16     16   117 use Carp;
  16         30  
  16         770  
14 16     16   78 use Fcntl qw(:flock :seek);
  16         31  
  16         2162  
15 16     16   113 use strict;
  16         32  
  16         289  
16 16     16   67 use warnings;
  16         29  
  16         2706  
17              
18             our $VERSION = '0.28';
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   101 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   1115 $Time_HiRes_avail = eval 'use Time::HiRes qw(time);1' || 0;
  16         7751  
  16         20847  
  16         63  
34 16   50 16   850 $color_avail = eval
  16         9173  
  16         117897  
  16         1099  
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       95 if (defined ${^GLOBAL_PHASE}) {
40 16 0   0   1162 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   7054 use Devel::DumpTrace::Const;
  16         36  
  16         14724  
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   8965 || 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   198 my ($class, @args) = @_;
143              
144 32         100 push @EXCLUDE_PATTERN, map '^' . substr($_,1) . '$', grep { /^-/ } @args;
  11         50  
145 32         75 push @INCLUDE_PATTERN, map '^' . substr($_,1) . '$', grep { /^\+/ }@args;
  11         33  
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     217 map { '^' . $_ . '$' } split /,/, $ENV{DUMPTRACE_EXCLPKG} || '';
  0         0  
151             push @INCLUDE_PATTERN,
152 32   50     171 map { '^' . $_ . '$' } split /,/, $ENV{DUMPTRACE_INCLPKG} || '';
  0         0  
153              
154 32         67 @args = grep { /^[^+-]/ } @args;
  11         60  
155 32 100       84 if (grep { $_ eq ':test' } @args) {
  11         44  
156              
157             # :test
158             # import some low level routines to the calling
159             # namespace for testing.
160              
161 11         25 @args = grep { $_ ne ':test' } @args;
  11         33  
162 16     16   115 no strict 'refs';
  16         75  
  16         5909  
163 11         30 my $p = caller;
164 11         33 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         179 *{$p . '::' . $name} = *$name;
  88         336  
168             }
169 11         31 *{$p . '::substitute'} = *perform_variable_substitutions;
  11         65  
170 11         28 *{$p . '::xsubstitute'} = *perform_extended_variable_substitutions;
  11         47  
171             }
172 32 50       116 if (@args > 0) {
173 0         0 $TRACE = join ',', @args;
174             }
175 32         1494 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   109 no strict 'refs';
  16         27  
  16         9255  
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   185 return DISPLAY_TERSE if $TRACE eq 'default'; # 5.8.8 bug?
262 12         81 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   2693 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   107 *_display_style = *_display_style_old;
314 16         23668 *_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 2336 my $n = shift || 0;
323 11         35 my $target_depth = current_depth() - $n - 1;
324              
325 11 50       35 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       33 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         181 $PAD_MY = PadWalker::peek_my($n + 1);
338 11         82 $PAD_OUR = PadWalker::peek_our($n + 1);
339 11         36 1;
340 11 50       19 } 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         26 $PAD_MY->{__DEPTH__} = $PAD_OUR->{__DEPTH__} = current_depth() - $n - 1;
348              
349 11         27 return;
350             }
351              
352             sub current_depth {
353 22     22 0 32 my $n = 0;
354 22         92 $n++ while caller($n);
355 22         65 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 $ZZZ;
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   321 %_dump_scalar_seen = ();
493             }
494              
495             sub dump_scalar {
496 1228     1228 0 2997 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       4074 return 'undef' if !defined $scalar;
502 1159 100       1904 if (ref $scalar) {
503 42 100       145 if ($_dump_scalar_seen{$scalar}) {
504 1         7 return "... $scalar (prev. referenced)";
505             }
506 41         93 $_dump_scalar_seen{$scalar}++;
507 41         61 my $z;
508 41 100       178 if (Scalar::Util::reftype($scalar) eq 'ARRAY') {
    100          
    50          
509 22         64 $z = '[' . array_repr($scalar) . ']';
510             } elsif (Scalar::Util::reftype($scalar) eq 'HASH') {
511 11         31 $z = '{' . hash_repr($scalar) . '}';
512             } elsif (Scalar::Util::reftype($scalar) eq 'GLOB') {
513 0         0 $z = $scalar;
514             } else {
515 8         16 $z = "$scalar";
516             }
517 41         113 delete $_dump_scalar_seen{$scalar};
518 41         190 return $z;
519             }
520 1117 100       2572 if (Scalar::Util::looks_like_number($scalar)) {
521 464         993 $scalar =~ s/^\s+//;
522 464         748 $scalar =~ s/\s+$//;
523 464         727 return _abbreviate_scalar($scalar);
524             }
525 653 100       1371 if (ref \$scalar eq 'GLOB') {
526 4         17 return $scalar;
527             }
528 649         1041 my $qq = _qquote($scalar);
529 649 100       1288 if ($qq ne $scalar) {
530 1         4 return _abbreviate_scalar(qq("$qq"));
531             }
532 648         1476 return _abbreviate_scalar(qq('$scalar'));
533             }
534              
535             sub _abbreviate_scalar {
536 1113     1113   1798 my ($value) = @_;
537 1113 50       1684 if (_abbrev_style() >= ABBREV_NONE) {
538 1113         3685 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   1206 local($_) = shift;
555 649         1161 s/([\\\"\@\$])/\\$1/g;
556 16     16   9638 my $bytes; { use bytes; $bytes = length }
  16         231  
  16         161  
  649         785  
  649         805  
  649         942  
557 649 50       1126 ($bytes > length) && s/([^\x00-\x7f])/'\x{'.sprintf("%x",ord($1)).'}'/ge;
  0         0  
558 649 100       2183 /[^ !"\#\$%&'()*+,\-.\/0-9:;<=>?\@A-Z[\\\]^_`a-z{|}~]/ || return $_;
559              
560 1   50     14 my $high = shift || '';
561 1         8 s/([\a\b\t\n\f\r\e])/$esc{$1}/g;
562              
563 1         2 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         2 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       7 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         2 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 942  
588             sub hash_repr {
589 82 100       176 my ($hashref, @keys) = @_;
590 81 50       154  
591 81 100 66     451 return '' if !defined $hashref;
592             @keys = () unless $SMART_ABBREV;
593 81 0       235 my $ref = ref $hashref && ref $hashref ne 'HASH'
    50          
594             ? ref($hashref) . ': ' : '';
595 81         239 my $maxlen = _abbrev_style() < ABBREV_NONE
596             ? _abbrev_style() > ABBREV_STRONG ? 79 : 19 : -1;
597 81         107 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     389 # 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     392 }
    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         366 }
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         1042 } else {
631             # use Hash::SafeKeys so we don't reset an active `each` iterator
632 81         213 my $it = Hash::SafeKeys::save_iterator_state($hashref);
  430         1210  
633             $hash = { map {
634 81         286 dump_scalar($_) => dump_scalar($hashref->{$_})
635             } keys %$hashref };
636             Hash::SafeKeys::restore_iterator_state($hashref,$it);
637 81         142 }
638 81 50       116  
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         234 } else {
648 81         237 # use Hash::Safekeys to not reset an active `each` iterator (RT#77673)
  430         874  
649 81         194 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     337 }
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       172 }
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         143  
663 430 50       575 return $ref . join ($HASH_ENTRY_SEPARATOR,
  860         2609  
  430         647  
664             map { join ($HASH_PAIR_SEPARATOR,
665             map{defined($_)?$_:'undef'}@{$_}) } @r );
666             }
667              
668 81 100   81   309 # 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   17042 # perfectly reliable, but it is getting there ...
  16         36  
  16         22740  
679 79     79   211  
680 79         256 use B;
681 79   33     729 my ($hashref) = @_;
682             my $sv = B::svref_2object($hashref);
683             return ref($sv) eq 'B::HV' && $sv->NAME;
684             }
685 94     94 0 1501  
686             sub array_repr {
687 94 100       191 my ($arrayref, @keys) = @_;
688 93 50       168  
689 93 100 66     378 return '' if !defined $arrayref;
690             @keys = () unless $SMART_ABBREV;
691 93 0       202 my $ref = ref $arrayref && ref $arrayref ne 'ARRAY'
    50          
692             ? ref($arrayref) . ': ' : '';
693 93         339 my $maxlen = _abbrev_style() < ABBREV_NONE
694 93         125 ? _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     417 # 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         258 }
  93         223  
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         121 };
  278         435  
  93         159  
719             } else {
720             $array = [ map { dump_scalar($_) } @{$arrayref} ];
721 93         187 }
722 93 50       176  
723 0         0 my @r;
724             if ($maxlen > 0) {
725             @r = Text::Shorten::shorten_array(
726 93         118 $array, $maxlen, $ARRAY_ELEM_SEPARATOR, @keys);
  93         214  
727             } else {
728 93 50 33     314 @r = @{$array};
729             }
730 0         0 if (@keys == 0
  0         0  
731             && Devel::DumpTrace::CachedDisplayedArray->is($arrayref)) {
732 93         627 (tied @{$arrayref})->store_cache($cache_key, \@r);
733             }
734             return $ref . join $ARRAY_ELEM_SEPARATOR, @r;
735             }
736 16     16 0 67  
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       67 handle_deferred_output($sub, $file);
741 16         35 }
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 28501  
781 107         765 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     747 (\s*[\[\{])? # optional subscript
      100        
787             }{
788             evaluate($1,$2,$3||'',$4||'',$pkg)
789 107         342 }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 22506  
835 59         490 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     523 (\s*->)? # optional dereference op
      100        
840             (\s*[\[\{])? # optional subscript
841             }{ $1 . $2 . $XEVAL_SEPARATOR
842 59         182 . evaluate($1,$2,$3||'',$4||'',$pkg)
843             }gex;
844             return $xcode;
845             }
846 8     8 0 10  
847 8         9 sub get_DB_args {
848 8         17 my $depth = 1 + shift;
849 8 50       14 my @z;
850             for (my $i=$depth; $i<=$depth; $i++) {
851 8         51 if ($i>=0) {
852 8 50       24 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   530 # "Bizarre copy of ARRAY in aassign" error message
  1     1   6  
  1     1   9  
  1     1   39  
  1     1   6  
  1     1   2  
  1     1   25  
  1     1   8  
  1         2  
  1         31  
  1         6  
  1         1  
  1         25  
  1         6  
  1         2  
  1         26  
  1         5  
  1         2  
  1         33  
  1         6  
  1         2  
  1         31  
  1         6  
  1         2  
  1         23  
859             # (when $depth is too deep and @DB::args is not defined?).
860 8         31 eval 'no warnings q/internal/; @z = @DB::args';
861             }
862             return @z;
863             }
864              
865 193     193 0 1013 # McCabe score: 49
866 193         296 sub evaluate {
867 193         404 my ($sigil, $varname, $deref_op, $index_op, $pkg, @keys) = @_;
868             my $v;
869 16     16   131 _reset_dump();
  16         33  
  16         8144  
870              
871 193   100     558 no strict 'refs';
872 193   100     459  
873 193         324 $deref_op ||= '';
874             $index_op ||= '';
875 193 100 100     799 $index_op =~ s/^\s+//;
876 10         16  
877             if ($ALWAYS_MAIN{$varname} || $varname =~ /^\d+$/) {
878 193         380 $pkg = 'main';
879 193 100 100     609 }
880 15         24 $pkg .= '::';
881             if ($varname =~ /::/ || $pkg eq '::') {
882             $pkg = '';
883 193 100       323 }
884 42         68  
885 42         160 if ($deref_op) {
886             my $sigvar = "\$$varname";
887 42 100       158 (my $pkgvar = $sigvar) =~ s/\$/\$$pkg/;
    100          
    50          
    50          
888 14         23  
889             if (defined $PAD_MY->{$sigvar}) {
890 14         24 $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         820 $v = $PAD_OUR->{__STALE__}{$sigvar};
897             } else {
898 42 100       108 $v = eval "\\$pkgvar";
899 12         17 }
  12         32  
900             if ($index_op eq '[') {
901 30 100       58 return '[' . array_repr(${$v}, @keys) . ']->[';
902 12         16 }
  12         40  
903             if ($index_op eq '{') {
904             return '{' . hash_repr(${$v}, @keys) . '}->{';
905 18         21 }
  18         54  
906 18 50 33     75  
    100          
    100          
907 0         0 my $reftype = Scalar::Util::reftype(${$v});
908             if (!defined($reftype) || $reftype eq '') {
909 6         9 return '(' . dump_scalar($v) . ')->';
  6         11  
910             } elsif ($reftype eq 'HASH') {
911 6         7 return '{' . hash_repr(${$v}, @keys) . '}->';
  6         9  
912             } elsif ($reftype eq 'ARRAY') {
913 6         14 return '[' . array_repr(${$v}, @keys) . ']->';
914             } else {
915             return '(' . dump_scalar($v) . ')->';
916             }
917 151 100       271 }
918 25         43  
919 25         98 if ($index_op eq '{') {
920 25 100       80 my $sigvar = "\%$varname";
    100          
921 7         14 (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         581 $v = $PAD_OUR->{$sigvar};
926             } else {
927 25         79 $v = eval "\\$pkgvar";
928             }
929 126 100       226 return '(' . hash_repr($v, @keys) . '){';
930 21         40 }
931 21         86 if ($sigil eq '@') {
932             my $sigvar = "\@$varname";
933 21 100       84 (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   112 # what we really want.
  16         42  
  16         11698  
939 2         16 my $depth = $DB_ARGS_DEPTH;
940 0         0 no warnings 'uninitialized';
941             while ((caller $depth)[CALLER_SUB] =~ /^\(eval/) {
942 2         7 $depth++;
943             }
944 8         25 $v = [ get_DB_args($depth) ];
945             } elsif (defined($PAD_MY->{$sigvar})) {
946 4         11 $v = $PAD_MY->{$sigvar};
947             } elsif (defined($PAD_OUR->{$sigvar})) {
948 7         13 $v = $PAD_OUR->{$sigvar};
949 7         420 } else {
950             eval {
951 7 50       36 $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       49 }
958 8         21 }
959             if ($index_op eq '[') {
960 13         31 return '(' . array_repr($v, @keys) . ')[';
961             }
962 105 100       189 return '(' . array_repr($v, @keys) . ')';
963 19         36 }
964 19         82 if ($sigil eq '%') {
965 19 100       75 my $sigvar = "\%$varname";
    100          
966 5         12 (my $pkgvar = $sigvar) =~ s/\%/\%$pkg/;
967             if (defined($PAD_MY->{$sigvar})) {
968 5         10 $v = $PAD_MY->{$sigvar};
969             } elsif (defined($PAD_OUR->{$sigvar})) {
970 9         506 $v = $PAD_OUR->{$sigvar};
971             } else {
972 19         63 $v = eval "\\$pkgvar";
973             }
974 86 50       162 return '(' . hash_repr($v) . ')';
975 86 100       240 }
    100          
976 23         41 if ($sigil eq '$') {
977 23         100 if ($index_op eq '[') {
978 23 100       82 my $sigvar = "\@$varname";
    100          
    100          
979 6         9 (my $pkgvar = $sigvar) =~ s/\@/\@$pkg/;
980 6         10 if ($varname eq '_') {
981             my $depth = $DB_ARGS_DEPTH;
982 6         81 $v = [ get_DB_args($depth) ];
983             } elsif (defined($PAD_MY->{$sigvar})) {
984 4         12 $v = $PAD_MY->{$sigvar};
985             } elsif (defined($PAD_OUR->{$sigvar})) {
986 7         16 $v = $PAD_OUR->{$sigvar};
  7         359  
987 7 50       35 } 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         95 }
995             }
996             return '(' . array_repr($v, @keys) . ')[';
997             } elsif ($varname =~ /^\d+$/) {
998 7         13 # special regex match var $1,$2,...
999 7         11 # they were loaded into @matches in save_previous_regex_matches()
1000             $v = $matches[$varname];
1001             return dump_scalar($v);
1002 56         99 } else {
1003 56 100       101  
1004 2         3 my $sigvar = "\$$varname";
1005             if ($varname eq '_') {
1006 56         213 $pkg = 'main::';
1007             }
1008 56 100       164 (my $pkgvar = $sigvar) =~ s/\$/\$$pkg/;
    100          
1009 24         29  
  24         46  
1010             if (defined($PAD_MY->{$sigvar})) {
1011 12         18 $v = ${$PAD_MY->{$sigvar}};
  12         23  
1012             } elsif (defined($PAD_OUR->{$sigvar})) {
1013 20         1146 $v = ${$PAD_OUR->{$sigvar}};
1014             } else {
1015 56         145 $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 1028  
1028 2         9  
1029             if ($] > 5.025006) {
1030 16     16   131 @matches = ($0,@{^CAPTURE});
  16         31  
  16         1420  
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   146 # code in a CHECK block gives the traced program a chance to
  16         34  
  16         1824  
1044             # load threads later.
1045 15 50   15   888038 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   99  
  16         29  
  16         4506  
1056 16     0   146 sub __END {
        16      
1057 16         84 no warnings 'redefine';
1058 16         88 *DB::DB = sub { };
1059 16 50 33     137 *__inGD = sub () { 1 };
1060 16         85 untie $TRACE;
1061             handle_ALL_deferred_output() unless $_THREADS && threads->tid();
1062             1;
1063 16     16   15406 }
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   55  
1078 16         35 sub Devel::DumpTrace::VerboseLevel::TIESCALAR {
1079 16         68 my ($pkg) = @_;
1080             my $scalar;
1081             return bless \$scalar, $pkg;
1082             }
1083 1388     1388   1979  
1084 1388         1791 sub Devel::DumpTrace::VerboseLevel::FETCH {
  1388         4143  
1085             my $self = shift;
1086             return ${$self};
1087             }
1088 36     36   3568  
1089             sub Devel::DumpTrace::VerboseLevel::STORE {
1090             my ($self, $value) = @_;
1091 36 50       105  
1092             #Carp::cluck $self,"->STORE($value) called !\n";
1093 36         46 return if !defined $value;
  36         173  
1094 36         123  
1095 36         128 my $old = ${$self};
1096 36         93 my ($style, $package) = split /,/, $value;
1097 16     16   109 $style =~ s/^\s+//;
  16         33  
  16         4885  
1098             $style =~ s/\s+$//;
1099 36   66     277 no warnings 'uninitialized';
1100 36 50       212 $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         61 $style = 3;
  36         60  
1105 36 100       88 }
1106 2         5 ${$self} = $style;
1107 2         3 if (defined $package) {
1108 2 50       8 $package =~ s/^\s+//;
1109 2         3 $package =~ s/\s+$//;
  2         3  
1110             if ($package) {
1111             ${$self} += 100;
1112 36         94 }
1113             }
1114             return $old;
1115       16     }
1116              
1117             sub Devel::DumpTrace::VerboseLevel::UNTIE { }
1118              
1119             1;
1120              
1121             __END__