1 use 5.006_001; # for (defined ref) and $#$v and our
5 our(%address, $stab, @stab, %stab, %subs);
7 # documentation nits, handle complex data structures better by chromatic
8 # translate control chars to ^X - Randal Schwartz
9 # Modifications to print types by Peter Gordon v1.0
11 # Ilya Zakharevich -- patches after 5.001 (and some before ;-)
13 # Won't dump symbol tables and contents of debugged files by default
15 # (IZ) changes for objectification:
16 # c) quote() renamed to method set_quote();
17 # d) unctrlSet() renamed to method set_unctrl();
18 # f) Compiles with `use strict', but in two places no strict refs is needed:
19 # maybe more problems are waiting...
42 my %opt = (%defaults, @_);
49 @$self{keys %opt} = values %opt;
54 wantarray ? @$self{@_} : $$self{pop @_};
59 die "usage: \$dumper->dumpValue(value)" unless @_ == 1;
62 (print "undef\n"), return unless defined $_[0];
63 (print $self->stringify($_[0]), "\n"), return unless ref $_[0];
64 $self->unwrap($_[0],0);
71 (print "undef\n"), return unless defined $_[0];
75 # This one is good for variable names:
80 return \$_ if ref \$_ eq "GLOB";
81 s/([\001-\037\177])/'^'.pack('c',ord($1)^64)/eg;
89 my $tick = $self->{tick};
91 return 'undef' unless defined $_ or not $self->{printUndef};
92 return $_ . "" if ref \$_ eq 'GLOB';
94 $_ = &{'overload::StrVal'}($_)
95 if $self->{bareStringify} and ref $_
96 and %overload:: and defined &{'overload::StrVal'};
99 if ($tick eq 'auto') {
100 if (/[\000-\011\013-\037\177]/) {
108 } elsif ($self->{unctrl} eq 'unctrl') {
110 s/([\000-\037\177])/'^'.pack('c',ord($1)^64)/eg;
111 s/([\200-\377])/'\\0x'.sprintf('%2X',ord($1))/eg
112 if $self->{quoteHighBit};
113 } elsif ($self->{unctrl} eq 'quote') {
114 s/([\"\\\$\@])/\\$1/g if $tick eq '"';
116 s/([\000-\037\177])/'\\c'.chr(ord($1)^64)/eg;
118 s/([\200-\377])/'\\'.sprintf('%3o',ord($1))/eg if $self->{quoteHighBit};
119 ($noticks || /^\d+(\.\d*)?\Z/)
121 : $tick . $_ . $tick;
125 my ($self, $v) = (shift, shift);
126 my $short = $self->stringify($v, ref $v);
128 if ($self->{veryCompact} && ref $v
129 && (ref $v eq 'ARRAY' and !grep(ref $_, @$v) )) {
131 ($shortmore, $depth) = (' ...', $self->{arrayDepth} - 1)
132 if $self->{arrayDepth} and $depth >= $self->{arrayDepth};
133 my @a = map $self->stringify($_), @$v[0..$depth];
134 print "0..$#{$v} @a$shortmore\n";
135 } elsif ($self->{veryCompact} && ref $v
136 && (ref $v eq 'HASH') and !grep(ref $_, values %$v)) {
137 my @a = sort keys %$v;
139 ($shortmore, $depth) = (' ...', $self->{hashDepth} - 1)
140 if $self->{hashDepth} and $depth >= $self->{hashDepth};
141 my @b = map {$self->stringify($_) . " => " . $self->stringify($$v{$_})}
144 print "@b$shortmore\n";
147 $self->unwrap($v,shift);
153 return if $DB::signal and $self->{stopDbSignal};
155 my ($s) = shift ; # extra no of spaces
157 my (%v,@v,$address,$short,$fileno);
162 # Check for reused addresses
166 $val = &{'overload::StrVal'}($v)
167 if %overload:: and defined &{'overload::StrVal'};
169 ($address) = $val =~ /(0x[0-9a-f]+)\)$/ ;
170 if (!$self->{dumpReused} && defined $address) {
171 $address{$address}++ ;
172 if ( $address{$address} > 1 ) {
173 print "${sp}-> REUSED_ADDRESS\n" ;
177 } elsif (ref \$v eq 'GLOB') {
178 $address = "$v" . ""; # To avoid a bug with globs
179 $address{$address}++ ;
180 if ( $address{$address} > 1 ) {
181 print "${sp}*DUMPED_GLOB*\n" ;
186 if (ref $v eq 'Regexp') {
189 print "$sp-> qr/$re/\n";
193 if ( UNIVERSAL::isa($v, 'HASH') ) {
194 my @sortKeys = sort keys(%$v) ;
196 my $tHashDepth = $#sortKeys ;
197 $tHashDepth = $#sortKeys < $self->{hashDepth}-1 ? $#sortKeys : $self->{hashDepth}-1
198 unless $self->{hashDepth} eq '' ;
199 $more = "....\n" if $tHashDepth < $#sortKeys ;
201 $shortmore = ", ..." if $tHashDepth < $#sortKeys ;
202 $#sortKeys = $tHashDepth ;
203 if ($self->{compactDump} && !grep(ref $_, values %{$v})) {
207 push @keys, $self->stringify($_) . " => " . $self->stringify($v->{$_});
209 $short .= join ', ', @keys;
210 $short .= $shortmore;
211 (print "$short\n"), return if length $short <= $self->{compactDump};
213 for my $key (@sortKeys) {
214 return if $DB::signal and $self->{stopDbSignal};
215 my $value = $ {$v}{$key} ;
216 print $sp, $self->stringify($key), " => ";
217 $self->DumpElem($value, $s);
219 print "$sp empty hash\n" unless @sortKeys;
220 print "$sp$more" if defined $more ;
221 } elsif ( UNIVERSAL::isa($v, 'ARRAY') ) {
222 my $tArrayDepth = $#{$v} ;
224 $tArrayDepth = $#$v < $self->{arrayDepth}-1 ? $#$v : $self->{arrayDepth}-1
225 unless $self->{arrayDepth} eq '' ;
226 $more = "....\n" if $tArrayDepth < $#{$v} ;
228 $shortmore = " ..." if $tArrayDepth < $#{$v} ;
229 if ($self->{compactDump} && !grep(ref $_, @{$v})) {
231 $short = $sp . "0..$#{$v} " .
233 map {exists $v->[$_] ? $self->stringify($v->[$_]) : "empty"} ($[..$tArrayDepth)
236 $short = $sp . "empty array";
238 (print "$short\n"), return if length $short <= $self->{compactDump};
240 for my $num ($[ .. $tArrayDepth) {
241 return if $DB::signal and $self->{stopDbSignal};
243 if (exists $v->[$num]) {
244 $self->DumpElem($v->[$num], $s);
246 print "empty slot\n";
249 print "$sp empty array\n" unless @$v;
250 print "$sp$more" if defined $more ;
251 } elsif ( UNIVERSAL::isa($v, 'SCALAR') or ref $v eq 'REF' ) {
253 $self->DumpElem($$v, $s);
254 } elsif ( UNIVERSAL::isa($v, 'CODE') ) {
256 $self->dumpsub(0, $v);
257 } elsif ( UNIVERSAL::isa($v, 'GLOB') ) {
258 print "$sp-> ",$self->stringify($$v,1),"\n";
259 if ($self->{globPrint}) {
261 $self->dumpglob('', $s, "{$$v}", $$v, 1);
262 } elsif (defined ($fileno = fileno($v))) {
263 print( (' ' x ($s+3)) . "FileHandle({$$v}) => fileno($fileno)\n" );
265 } elsif (ref \$v eq 'GLOB') {
266 if ($self->{globPrint}) {
267 $self->dumpglob('', $s, "{$v}", $v, 1);
268 } elsif (defined ($fileno = fileno(\$v))) {
269 print( (' ' x $s) . "FileHandle({$v}) => fileno($fileno)\n" );
276 ($_[1] =~ /^([!~])(.)([\x00-\xff]*)/) and
277 ($1 eq '!') ^ (eval {($_[2] . "::" . $_[0]) =~ /$2$3/});
282 $self->{compactDump} = shift if @_;
283 $self->{compactDump} = 6*80-1
284 if $self->{compactDump} and $self->{compactDump} < 2;
285 $self->{compactDump};
290 $self->{veryCompact} = shift if @_;
291 $self->compactDump(1) if !$self->{compactDump} and $self->{veryCompact};
292 $self->{veryCompact};
299 if ($in eq 'unctrl' or $in eq 'quote') {
300 $self->{unctrl} = $in;
302 print "Unknown value for `unctrl'.\n";
310 if (@_ and $_[0] eq '"') {
312 $self->{unctrl} = 'quote';
313 } elsif (@_ and $_[0] eq 'auto') {
314 $self->{tick} = 'auto';
315 $self->{unctrl} = 'quote';
316 } elsif (@_) { # Need to set
318 $self->{unctrl} = 'unctrl';
325 return if $DB::signal and $self->{stopDbSignal};
326 my ($package, $off, $key, $val, $all) = @_;
329 if (($key !~ /^_</ or $self->{dumpDBFiles}) and defined $stab) {
330 print( (' ' x $off) . "\$", &unctrl($key), " = " );
331 $self->DumpElem($stab, 3+$off);
333 if (($key !~ /^_</ or $self->{dumpDBFiles}) and @stab) {
334 print( (' ' x $off) . "\@$key = (\n" );
335 $self->unwrap(\@stab,3+$off) ;
336 print( (' ' x $off) . ")\n" );
338 if ($key ne "main::" && $key ne "DB::" && %stab
339 && ($self->{dumpPackages} or $key !~ /::$/)
340 && ($key !~ /^_</ or $self->{dumpDBFiles})
341 && !($package eq "Dumpvalue" and $key eq "stab")) {
342 print( (' ' x $off) . "\%$key = (\n" );
343 $self->unwrap(\%stab,3+$off) ;
344 print( (' ' x $off) . ")\n" );
346 if (defined ($fileno = fileno(*stab))) {
347 print( (' ' x $off) . "FileHandle($key) => fileno($fileno)\n" );
351 $self->dumpsub($off, $key);
359 return if $self->{skipCvGV}; # Backdoor to avoid problems if XS broken...
360 $in = \&$in; # Hard reference...
361 eval {require Devel::Peek; 1} or return;
362 my $gv = Devel::Peek::CvGV($in) or return;
363 *$gv{PACKAGE} . '::' . *$gv{NAME};
371 $sub = $1 if $sub =~ /^\{\*(.*)\}$/;
372 my $subref = defined $1 ? \&$sub : \&$ini;
373 my $place = $DB::sub{$sub} || (($s = $subs{"$subref"}) && $DB::sub{$s})
374 || (($s = $self->CvGV_name($subref)) && $DB::sub{$s})
375 || ($self->{subdump} && ($s = $self->findsubs("$subref"))
377 $s = $sub unless defined $s;
378 $place = '???' unless defined $place;
379 print( (' ' x $off) . "&$s in $place\n" );
384 return undef unless %DB::sub;
385 my ($addr, $name, $loc);
386 while (($name, $loc) = each %DB::sub) {
388 $subs{"$addr"} = $name;
390 $self->{subdump} = 0;
396 my ($package,@vars) = @_;
399 $package .= "::" unless $package =~ /::$/;
402 while ($package =~ /(\w+?::)/g) {
403 *stab = $ {stab}{$1};
405 $self->{TotalStrings} = 0;
406 $self->{Strings} = 0;
407 $self->{CompleteTotal} = 0;
408 while (($key,$val) = each(%stab)) {
409 return if $DB::signal and $self->{stopDbSignal};
410 next if @vars && !grep( matchvar($key, $_), @vars );
411 if ($self->{usageOnly}) {
412 $self->globUsage(\$val, $key)
413 if ($package ne 'Dumpvalue' or $key ne 'stab')
414 and ref(\$val) eq 'GLOB';
416 $self->dumpglob($package, 0,$key, $val);
419 if ($self->{usageOnly}) {
421 String space: $self->{TotalStrings} bytes in $self->{Strings} strings.
423 $self->{CompleteTotal} += $self->{TotalStrings};
425 Grand total = $self->{CompleteTotal} bytes (1 level deep) + overhead.
433 if (UNIVERSAL::isa($_[0], 'ARRAY')) {
434 $size = $self->arrayUsage($_[0]);
435 } elsif (UNIVERSAL::isa($_[0], 'HASH')) {
436 $size = $self->hashUsage($_[0]);
437 } elsif (!ref($_[0])) {
438 $size = length($_[0]);
440 $self->{TotalStrings} += $size;
445 sub arrayUsage { # array ref, name
448 map {$size += $self->scalarUsage($_)} @{$_[0]};
450 print "\@$_[1] = $len item", ($len > 1 ? "s" : ""), " (data: $size bytes)\n"
452 $self->{CompleteTotal} += $size;
456 sub hashUsage { # hash ref, name
458 my @keys = keys %{$_[0]};
459 my @values = values %{$_[0]};
460 my $keys = $self->arrayUsage(\@keys);
461 my $values = $self->arrayUsage(\@values);
463 my $total = $keys + $values;
464 print "\%$_[1] = $len item", ($len > 1 ? "s" : ""),
465 " (keys: $keys; values: $values; total: $total bytes)\n"
470 sub globUsage { # glob ref, name
472 local *stab = *{$_[0]};
474 $total += $self->scalarUsage($stab) if defined $stab;
475 $total += $self->arrayUsage(\@stab, $_[1]) if @stab;
476 $total += $self->hashUsage(\%stab, $_[1])
477 if %stab and $_[1] ne "main::" and $_[1] ne "DB::";
478 #and !($package eq "Dumpvalue" and $key eq "stab"));
486 Dumpvalue - provides screen dump of Perl data.
491 my $dumper = new Dumpvalue;
492 $dumper->set(globPrint => 1);
493 $dumper->dumpValue(\*::);
494 $dumper->dumpvars('main');
495 my $dump = $dumper->stringify($some_value);
501 A new dumper is created by a call
503 $d = new Dumpvalue(option1 => value1, option2 => value2)
509 =item C<arrayDepth>, C<hashDepth>
511 Print only first N elements of arrays and hashes. If false, prints all the
514 =item C<compactDump>, C<veryCompact>
516 Change style of array and hash dump. If true, short array
517 may be printed on one line.
521 Whether to print contents of globs.
525 Dump arrays holding contents of debugged files.
527 =item C<dumpPackages>
529 Dump symbol tables of packages.
533 Dump contents of "reused" addresses.
535 =item C<tick>, C<quoteHighBit>, C<printUndef>
537 Change style of string dump. Default value of C<tick> is C<auto>, one
538 can enable either double-quotish dump, or single-quotish by setting it
539 to C<"> or C<'>. By default, characters with high bit set are printed
540 I<as is>. If C<quoteHighBit> is set, they will be quoted.
544 rudimentally per-package memory usage dump. If set,
545 C<dumpvars> calculates total size of strings in variables in the package.
549 Changes the style of printout of strings. Possible values are
550 C<unctrl> and C<quote>.
554 Whether to try to find the subroutine name given the reference.
558 Whether to write the non-overloaded form of the stringify-overloaded objects.
562 Whether to print chars with high bit set in binary or "as is".
566 Whether to abort printing if debugger signal flag is raised.
570 Later in the life of the object the methods may be queries with get()
571 method and set() method (which accept multiple arguments).
579 $dumper->dumpValue($value);
580 $dumper->dumpValue([$value1, $value2]);
582 Prints a dump to the currently selected filehandle.
586 $dumper->dumpValues($value1, $value2);
588 Same as C< $dumper->dumpValue([$value1, $value2]); >.
592 my $dump = $dumper->stringify($value [,$noticks] );
594 Returns the dump of a single scalar without printing. If the second
595 argument is true, the return value does not contain enclosing ticks.
596 Does not handle data structures.
600 $dumper->dumpvars('my_package');
601 $dumper->dumpvars('my_package', 'foo', '~bar$', '!......');
603 The optional arguments are considered as literal strings unless they
604 start with C<~> or C<!>, in which case they are interpreted as regular
605 expressions (possibly negated).
607 The second example prints entries with names C<foo>, and also entries
608 with names which ends on C<bar>, or are shorter than 5 chars.
614 Sets C<tick> and C<unctrl> options to suitable values for printout with the
615 given quote char. Possible values are C<auto>, C<'> and C<">.
621 Sets C<unctrl> option with checking for an invalid argument.
622 Possible values are C<unctrl> and C<quote>.
628 Sets C<compactDump> option. If the value is 1, sets to a reasonable
635 Sets C<compactDump> and C<veryCompact> options simultaneously.
639 $d->set(option1 => value1, option2 => value2);
643 @values = $d->get('option1', 'option2');