1 require 5.002; # For (defined ref)
4 # Needed for PrettyPrinter only:
6 # require 5.001; # Well, it coredumps anyway undef DB in 5.000 (not now)
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 $winsize = 80 unless defined $winsize;
21 $printUndef = 1 unless defined $printUndef;
22 $tick = "auto" unless defined $tick;
23 $unctrl = 'quote' unless defined $unctrl;
25 $dumpReused = 0 unless defined $dumpReused;
26 $bareStringify = 1 unless defined $bareStringify;
31 (print "undef\n"), return unless defined $_[0];
32 (print &stringify($_[0]), "\n"), return unless ref $_[0];
33 push @_, -1 if @_ == 1;
34 dumpvar::unwrap($_[0], 0, $_[1]);
37 # This one is good for variable names:
43 return \$_ if ref \$_ eq "GLOB";
44 s/([\001-\037\177])/'^'.pack('c',ord($1)^64)/eg;
50 map { $_ > 255 ? sprintf("\\x{%04X}", $_) : chr($_) }
55 local($_,$noticks) = @_;
59 return 'undef' unless defined $_ or not $printUndef;
60 return $_ . "" if ref \$_ eq 'GLOB';
61 $_ = &{'overload::StrVal'}($_)
62 if $bareStringify and ref $_
63 and %overload:: and defined &{'overload::StrVal'};
65 if ($tick eq 'auto') {
66 if (/[\000-\011\013-\037\177]/) {
74 } elsif ($unctrl eq 'unctrl') {
76 s/([\000-\037\177])/'^'.pack('c',ord($1)^64)/eg;
78 s/([\200-\377])/'\\0x'.sprintf('%2X',ord($1))/eg
80 } elsif ($unctrl eq 'quote') {
81 s/([\"\\\$\@])/\\$1/g if $tick eq '"';
83 s/([\000-\037\177])/'\\c'._escaped_ord($1)/eg;
86 s/([\200-\377])/'\\'.sprintf('%3o',ord($1))/eg if $quoteHighBit;
87 ($noticks || /^\d+(\.\d*)?\Z/)
92 # Ensure a resulting \ is escaped to be \\
95 $chr = chr(ord($chr)^64);
101 my $tArrayDepth = $#{$_[0]} ;
102 $tArrayDepth = $#{$_[0]} < $arrayDepth-1 ? $#{$_[0]} : $arrayDepth-1
103 unless $arrayDepth eq '' ;
105 $shortmore = " ..." if $tArrayDepth < $#{$_[0]} ;
106 if (!grep(ref $_, @{$_[0]})) {
107 $short = "0..$#{$_[0]} '" .
108 join("' '", @{$_[0]}[0..$tArrayDepth]) . "'$shortmore";
109 return $short if length $short <= $compactDump;
115 my $short = &stringify($_[0], ref $_[0]);
116 if ($veryCompact && ref $_[0]
117 && (ref $_[0] eq 'ARRAY' and !grep(ref $_, @{$_[0]}) )) {
118 my $end = "0..$#{$v} '" .
119 join("' '", @{$_[0]}[0..$tArrayDepth]) . "'$shortmore";
120 } elsif ($veryCompact && ref $_[0]
121 && (ref $_[0] eq 'HASH') and !grep(ref $_, values %{$_[0]})) {
123 $short = $sp . "0..$#{$v} '" .
124 join("' '", @{$v}[0..$tArrayDepth]) . "'$shortmore";
127 unwrap($_[0],$_[1],$_[2]) if ref $_[0];
132 return if $DB::signal;
134 local($s) = shift ; # extra no of spaces
135 local($m) = shift ; # maximum recursion depth
137 local(%v,@v,$sp,$value,$key,@sortKeys,$more,$shortmore,$short) ;
138 local($tHashDepth,$tArrayDepth) ;
143 # Check for reused addresses
146 $val = &{'overload::StrVal'}($v)
147 if %overload:: and defined &{'overload::StrVal'};
148 # Match type and address.
149 # Unblessed references will look like TYPE(0x...)
150 # Blessed references will look like Class=TYPE(0x...)
151 ($start_part, $val) = split /=/,$val;
152 $val = $start_part unless defined $val;
153 ($item_type, $address) =
154 $val =~ /([^\(]+) # Keep stuff that's
157 (0x[0-9a-f]+) # Save the address
158 \) # Skip close paren
159 $/x; # Should be at end now
161 if (!$dumpReused && defined $address) {
162 $address{$address}++ ;
163 if ( $address{$address} > 1 ) {
164 print "${sp}-> REUSED_ADDRESS\n" ;
168 } elsif (ref \$v eq 'GLOB') {
169 # This is a raw glob. Special handling for that.
170 $address = "$v" . ""; # To avoid a bug with globs
171 $address{$address}++ ;
172 if ( $address{$address} > 1 ) {
173 print "${sp}*DUMPED_GLOB*\n" ;
178 if (ref $v eq 'Regexp') {
179 # Reformat the regexp to look the standard way.
182 print "$sp-> qr/$re/\n";
186 if ( $item_type eq 'HASH' ) {
187 # Hash ref or hash-based object.
188 my @sortKeys = sort keys(%$v) ;
190 $tHashDepth = $#sortKeys ;
191 $tHashDepth = $#sortKeys < $hashDepth-1 ? $#sortKeys : $hashDepth-1
192 unless $hashDepth eq '' ;
193 $more = "....\n" if $tHashDepth < $#sortKeys ;
195 $shortmore = ", ..." if $tHashDepth < $#sortKeys ;
196 $#sortKeys = $tHashDepth ;
197 if ($compactDump && !grep(ref $_, values %{$v})) {
200 # Next row core dumps during require from DB on 5.000, even with map {"_"}
201 # map {&stringify($_) . " => " . &stringify($v->{$_})}
202 # @sortKeys) . "'$shortmore";
206 push @keys, &stringify($_) . " => " . &stringify($v->{$_});
208 $short .= join ', ', @keys;
209 $short .= $shortmore;
210 (print "$short\n"), return if length $short <= $compactDump;
212 for $key (@sortKeys) {
213 return if $DB::signal;
214 $value = $ {$v}{$key} ;
215 print "$sp", &stringify($key), " => ";
216 DumpElem $value, $s, $m-1;
218 print "$sp empty hash\n" unless @sortKeys;
219 print "$sp$more" if defined $more ;
220 } elsif ( $item_type eq 'ARRAY' ) {
221 # Array ref or array-based object. Also: undef.
222 # See how big the array is.
223 $tArrayDepth = $#{$v} ;
225 # Bigger than the max?
226 $tArrayDepth = $#{$v} < $arrayDepth-1 ? $#{$v} : $arrayDepth-1
227 if defined $arrayDepth && $arrayDepth ne '';
228 # Yep. Don't show it all.
229 $more = "....\n" if $tArrayDepth < $#{$v} ;
231 $shortmore = " ..." if $tArrayDepth < $#{$v} ;
233 if ($compactDump && !grep(ref $_, @{$v})) {
235 $short = $sp . "0..$#{$v} " .
237 map {exists $v->[$_] ? stringify $v->[$_] : "empty"} ($[..$tArrayDepth)
240 $short = $sp . "empty array";
242 (print "$short\n"), return if length $short <= $compactDump;
244 #if ($compactDump && $short = ShortArray($v)) {
248 for $num ($[ .. $tArrayDepth) {
249 return if $DB::signal;
251 if (exists $v->[$num]) {
252 if (defined $v->[$num]) {
253 DumpElem $v->[$num], $s, $m-1;
259 print "empty slot\n";
262 print "$sp empty array\n" unless @$v;
263 print "$sp$more" if defined $more ;
264 } elsif ( $item_type eq 'SCALAR' ) {
265 unless (defined $$v) {
266 print "$sp-> undef\n";
270 DumpElem $$v, $s, $m-1;
271 } elsif ( $item_type eq 'REF' ) {
273 return unless defined $$v;
274 unwrap($$v, $s+3, $m-1);
275 } elsif ( $item_type eq 'CODE' ) {
276 # Code object or reference.
279 } elsif ( $item_type eq 'GLOB' ) {
280 # Glob object or reference.
281 print "$sp-> ",&stringify($$v,1),"\n";
284 dumpglob($s, "{$$v}", $$v, 1, $m-1);
285 } elsif (defined ($fileno = fileno($v))) {
286 print( (' ' x ($s+3)) . "FileHandle({$$v}) => fileno($fileno)\n" );
288 } elsif (ref \$v eq 'GLOB') {
291 dumpglob($s, "{$v}", $v, 1, $m-1) if $globPrint;
292 } elsif (defined ($fileno = fileno(\$v))) {
293 print( (' ' x $s) . "FileHandle({$v}) => fileno($fileno)\n" );
299 (my $var = $_[0]) =~ s/.//;
301 ($_[1] =~ /^([!~])(.)([\x00-\xff]*)/) and
302 ($1 eq '!') ^ (eval { $var =~ /$2$3/ });
307 ($_[1] =~ /^([!~])(.)([\x00-\xff]*)/) and
308 ($1 eq '!') ^ (eval {($_[2] . "::" . $_[0]) =~ /$2$3/});
312 $compactDump = shift if @_;
313 $compactDump = 6*80-1 if $compactDump and $compactDump < 2;
318 $veryCompact = shift if @_;
319 compactDump(1) if !$compactDump and $veryCompact;
326 if ($in eq 'unctrl' or $in eq 'quote') {
329 print "Unknown value for `unctrl'.\n";
336 if (@_ and $_[0] eq '"') {
339 } elsif (@_ and $_[0] eq 'auto') {
342 } elsif (@_) { # Need to set
350 return if $DB::signal;
351 my ($off,$key, $val, $all, $m) = @_;
352 local(*entry) = $val;
354 if (($key !~ /^_</ or $dumpDBFiles) and defined $entry) {
355 print( (' ' x $off) . "\$", &unctrl($key), " = " );
356 DumpElem $entry, 3+$off, $m;
358 if (($key !~ /^_</ or $dumpDBFiles) and @entry) {
359 print( (' ' x $off) . "\@$key = (\n" );
360 unwrap(\@entry,3+$off,$m) ;
361 print( (' ' x $off) . ")\n" );
363 if ($key ne "main::" && $key ne "DB::" && %entry
364 && ($dumpPackages or $key !~ /::$/)
365 && ($key !~ /^_</ or $dumpDBFiles)
366 && !($package eq "dumpvar" and $key eq "stab")) {
367 print( (' ' x $off) . "\%$key = (\n" );
368 unwrap(\%entry,3+$off,$m) ;
369 print( (' ' x $off) . ")\n" );
371 if (defined ($fileno = fileno(*entry))) {
372 print( (' ' x $off) . "FileHandle($key) => fileno($fileno)\n" );
375 if (defined &entry) {
382 return if $DB::signal;
383 my ($key, $val, $m, @vars) = @_;
384 return if @vars && !grep( matchlex($key, $_), @vars );
386 my $off = 0; # It reads better this way
388 if (UNIVERSAL::isa($val,'ARRAY')) {
389 print( (' ' x $off) . "$key = (\n" );
390 unwrap($val,3+$off,$m) ;
391 print( (' ' x $off) . ")\n" );
393 elsif (UNIVERSAL::isa($val,'HASH')) {
394 print( (' ' x $off) . "$key = (\n" );
395 unwrap($val,3+$off,$m) ;
396 print( (' ' x $off) . ")\n" );
398 elsif (UNIVERSAL::isa($val,'IO')) {
399 print( (' ' x $off) . "FileHandle($key) => fileno($fileno)\n" );
401 # No lexical subroutines yet...
402 # elsif (UNIVERSAL::isa($val,'CODE')) {
403 # dumpsub($off, $$val);
406 print( (' ' x $off) . &unctrl($key), " = " );
407 DumpElem $$val, 3+$off, $m;
411 sub CvGV_name_or_bust {
413 return if $skipCvGV; # Backdoor to avoid problems if XS broken...
414 $in = \&$in; # Hard reference...
415 eval {require Devel::Peek; 1} or return;
416 my $gv = Devel::Peek::CvGV($in) or return;
417 *$gv{PACKAGE} . '::' . *$gv{NAME};
424 $sub = $1 if $sub =~ /^\{\*(.*)\}$/;
425 my $subref = defined $1 ? \&$sub : \&$ini;
426 my $place = $DB::sub{$sub} || (($s = $subs{"$subref"}) && $DB::sub{$s})
427 || (($s = CvGV_name_or_bust($subref)) && $DB::sub{$s})
428 || ($subdump && ($s = findsubs("$subref")) && $DB::sub{$s});
429 $place = '???' unless defined $place;
430 $s = $sub unless defined $s;
431 print( (' ' x $off) . "&$s in $place\n" );
435 return undef unless %DB::sub;
436 my ($addr, $name, $loc);
437 while (($name, $loc) = each %DB::sub) {
439 $subs{"$addr"} = $name;
446 my ($package,$m,@vars) = @_;
447 local(%address,$key,$val,$^W);
448 $package .= "::" unless $package =~ /::$/;
450 while ($package =~ /(\w+?::)/g){
451 *stab = $ {stab}{$1};
453 local $TotalStrings = 0;
455 local $CompleteTotal = 0;
456 while (($key,$val) = each(%stab)) {
457 return if $DB::signal;
458 next if @vars && !grep( matchvar($key, $_), @vars );
460 globUsage(\$val, $key)
461 if ($package ne 'dumpvar' or $key ne 'stab')
462 and ref(\$val) eq 'GLOB';
464 dumpglob(0,$key, $val, 0, $m);
468 print "String space: $TotalStrings bytes in $Strings strings.\n";
469 $CompleteTotal += $TotalStrings;
470 print "Grand total = $CompleteTotal bytes (1 level deep) + overhead.\n";
475 my $size = length($_[0]);
476 $TotalStrings += $size;
481 sub arrayUsage { # array ref, name
483 map {$size += scalarUsage($_)} @{$_[0]};
485 print "\@$_[1] = $len item", ($len > 1 ? "s" : ""),
486 " (data: $size bytes)\n"
488 $CompleteTotal += $size;
492 sub hashUsage { # hash ref, name
493 my @keys = keys %{$_[0]};
494 my @values = values %{$_[0]};
495 my $keys = arrayUsage \@keys;
496 my $values = arrayUsage \@values;
498 my $total = $keys + $values;
499 print "\%$_[1] = $len item", ($len > 1 ? "s" : ""),
500 " (keys: $keys; values: $values; total: $total bytes)\n"
505 sub globUsage { # glob ref, name
506 local *name = *{$_[0]};
508 $total += scalarUsage $name if defined $name;
509 $total += arrayUsage \@name, $_[1] if @name;
510 $total += hashUsage \%name, $_[1] if %name and $_[1] ne "main::"
511 and $_[1] ne "DB::"; #and !($package eq "dumpvar" and $key eq "stab"));
516 my ($package,@vars) = @_;
517 $package .= "::" unless $package =~ /::$/;
518 local *stab = *{"main::"};
519 while ($package =~ /(\w+?::)/g){
520 *stab = $ {stab}{$1};
522 local $TotalStrings = 0;
523 local $CompleteTotal = 0;
525 while (($key,$val) = each(%stab)) {
526 next if @vars && !grep($key eq $_,@vars);
527 globUsage \$val, $key unless $package eq 'dumpvar' and $key eq 'stab';
529 print "String space: $TotalStrings.\n";
530 $CompleteTotal += $TotalStrings;
531 print "\nGrand total = $CompleteTotal bytes\n";