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');
500 A new dumper is created by a call
502 $d = new Dumpvalue(option1 => value1, option2 => value2)
508 =item C<arrayDepth>, C<hashDepth>
510 Print only first N elements of arrays and hashes. If false, prints all the
513 =item C<compactDump>, C<veryCompact>
515 Change style of array and hash dump. If true, short array
516 may be printed on one line.
520 Whether to print contents of globs.
524 Dump arrays holding contents of debugged files.
526 =item C<dumpPackages>
528 Dump symbol tables of packages.
532 Dump contents of "reused" addresses.
534 =item C<tick>, C<quoteHighBit>, C<printUndef>
536 Change style of string dump. Default value of C<tick> is C<auto>, one
537 can enable either double-quotish dump, or single-quotish by setting it
538 to C<"> or C<'>. By default, characters with high bit set are printed
539 I<as is>. If C<quoteHighBit> is set, they will be quoted.
543 rudimentally per-package memory usage dump. If set,
544 C<dumpvars> calculates total size of strings in variables in the package.
548 Changes the style of printout of strings. Possible values are
549 C<unctrl> and C<quote>.
553 Whether to try to find the subroutine name given the reference.
557 Whether to write the non-overloaded form of the stringify-overloaded objects.
561 Whether to print chars with high bit set in binary or "as is".
565 Whether to abort printing if debugger signal flag is raised.
569 Later in the life of the object the methods may be queries with get()
570 method and set() method (which accept multiple arguments).
578 $dumper->dumpValue($value);
579 $dumper->dumpValue([$value1, $value2]);
583 $dumper->dumpValues($value1, $value2);
587 $dumper->dumpvars('my_package');
588 $dumper->dumpvars('my_package', 'foo', '~bar$', '!......');
590 The optional arguments are considered as literal strings unless they
591 start with C<~> or C<!>, in which case they are interpreted as regular
592 expressions (possibly negated).
594 The second example prints entries with names C<foo>, and also entries
595 with names which ends on C<bar>, or are shorter than 5 chars.
601 Sets C<tick> and C<unctrl> options to suitable values for printout with the
602 given quote char. Possible values are C<auto>, C<'> and C<">.
608 Sets C<unctrl> option with checking for an invalid argument.
609 Possible values are C<unctrl> and C<quote>.
615 Sets C<compactDump> option. If the value is 1, sets to a reasonable
622 Sets C<compactDump> and C<veryCompact> options simultaneously.
626 $d->set(option1 => value1, option2 => value2);
630 @values = $d->get('option1', 'option2');