1*0Sstevel@tonic-gaterequire 5.002; # For (defined ref) 2*0Sstevel@tonic-gatepackage dumpvar; 3*0Sstevel@tonic-gate 4*0Sstevel@tonic-gate# Needed for PrettyPrinter only: 5*0Sstevel@tonic-gate 6*0Sstevel@tonic-gate# require 5.001; # Well, it coredumps anyway undef DB in 5.000 (not now) 7*0Sstevel@tonic-gate 8*0Sstevel@tonic-gate# translate control chars to ^X - Randal Schwartz 9*0Sstevel@tonic-gate# Modifications to print types by Peter Gordon v1.0 10*0Sstevel@tonic-gate 11*0Sstevel@tonic-gate# Ilya Zakharevich -- patches after 5.001 (and some before ;-) 12*0Sstevel@tonic-gate 13*0Sstevel@tonic-gate# Won't dump symbol tables and contents of debugged files by default 14*0Sstevel@tonic-gate 15*0Sstevel@tonic-gate$winsize = 80 unless defined $winsize; 16*0Sstevel@tonic-gate 17*0Sstevel@tonic-gate 18*0Sstevel@tonic-gate# Defaults 19*0Sstevel@tonic-gate 20*0Sstevel@tonic-gate# $globPrint = 1; 21*0Sstevel@tonic-gate$printUndef = 1 unless defined $printUndef; 22*0Sstevel@tonic-gate$tick = "auto" unless defined $tick; 23*0Sstevel@tonic-gate$unctrl = 'quote' unless defined $unctrl; 24*0Sstevel@tonic-gate$subdump = 1; 25*0Sstevel@tonic-gate$dumpReused = 0 unless defined $dumpReused; 26*0Sstevel@tonic-gate$bareStringify = 1 unless defined $bareStringify; 27*0Sstevel@tonic-gate 28*0Sstevel@tonic-gatesub main::dumpValue { 29*0Sstevel@tonic-gate local %address; 30*0Sstevel@tonic-gate local $^W=0; 31*0Sstevel@tonic-gate (print "undef\n"), return unless defined $_[0]; 32*0Sstevel@tonic-gate (print &stringify($_[0]), "\n"), return unless ref $_[0]; 33*0Sstevel@tonic-gate push @_, -1 if @_ == 1; 34*0Sstevel@tonic-gate dumpvar::unwrap($_[0], 0, $_[1]); 35*0Sstevel@tonic-gate} 36*0Sstevel@tonic-gate 37*0Sstevel@tonic-gate# This one is good for variable names: 38*0Sstevel@tonic-gate 39*0Sstevel@tonic-gatesub unctrl { 40*0Sstevel@tonic-gate local($_) = @_; 41*0Sstevel@tonic-gate local($v) ; 42*0Sstevel@tonic-gate 43*0Sstevel@tonic-gate return \$_ if ref \$_ eq "GLOB"; 44*0Sstevel@tonic-gate s/([\001-\037\177])/'^'.pack('c',ord($1)^64)/eg; 45*0Sstevel@tonic-gate $_; 46*0Sstevel@tonic-gate} 47*0Sstevel@tonic-gate 48*0Sstevel@tonic-gatesub uniescape { 49*0Sstevel@tonic-gate join("", 50*0Sstevel@tonic-gate map { $_ > 255 ? sprintf("\\x{%04X}", $_) : chr($_) } 51*0Sstevel@tonic-gate unpack("U*", $_[0])); 52*0Sstevel@tonic-gate} 53*0Sstevel@tonic-gate 54*0Sstevel@tonic-gatesub stringify { 55*0Sstevel@tonic-gate local($_,$noticks) = @_; 56*0Sstevel@tonic-gate local($v) ; 57*0Sstevel@tonic-gate my $tick = $tick; 58*0Sstevel@tonic-gate 59*0Sstevel@tonic-gate return 'undef' unless defined $_ or not $printUndef; 60*0Sstevel@tonic-gate return $_ . "" if ref \$_ eq 'GLOB'; 61*0Sstevel@tonic-gate $_ = &{'overload::StrVal'}($_) 62*0Sstevel@tonic-gate if $bareStringify and ref $_ 63*0Sstevel@tonic-gate and %overload:: and defined &{'overload::StrVal'}; 64*0Sstevel@tonic-gate 65*0Sstevel@tonic-gate if ($tick eq 'auto') { 66*0Sstevel@tonic-gate if (/[\000-\011\013-\037\177]/) { 67*0Sstevel@tonic-gate $tick = '"'; 68*0Sstevel@tonic-gate }else { 69*0Sstevel@tonic-gate $tick = "'"; 70*0Sstevel@tonic-gate } 71*0Sstevel@tonic-gate } 72*0Sstevel@tonic-gate if ($tick eq "'") { 73*0Sstevel@tonic-gate s/([\'\\])/\\$1/g; 74*0Sstevel@tonic-gate } elsif ($unctrl eq 'unctrl') { 75*0Sstevel@tonic-gate s/([\"\\])/\\$1/g ; 76*0Sstevel@tonic-gate s/([\000-\037\177])/'^'.pack('c',ord($1)^64)/eg; 77*0Sstevel@tonic-gate # uniescape? 78*0Sstevel@tonic-gate s/([\200-\377])/'\\0x'.sprintf('%2X',ord($1))/eg 79*0Sstevel@tonic-gate if $quoteHighBit; 80*0Sstevel@tonic-gate } elsif ($unctrl eq 'quote') { 81*0Sstevel@tonic-gate s/([\"\\\$\@])/\\$1/g if $tick eq '"'; 82*0Sstevel@tonic-gate s/\033/\\e/g; 83*0Sstevel@tonic-gate s/([\000-\037\177])/'\\c'.chr(ord($1)^64)/eg; 84*0Sstevel@tonic-gate } 85*0Sstevel@tonic-gate $_ = uniescape($_); 86*0Sstevel@tonic-gate s/([\200-\377])/'\\'.sprintf('%3o',ord($1))/eg if $quoteHighBit; 87*0Sstevel@tonic-gate ($noticks || /^\d+(\.\d*)?\Z/) 88*0Sstevel@tonic-gate ? $_ 89*0Sstevel@tonic-gate : $tick . $_ . $tick; 90*0Sstevel@tonic-gate} 91*0Sstevel@tonic-gate 92*0Sstevel@tonic-gatesub ShortArray { 93*0Sstevel@tonic-gate my $tArrayDepth = $#{$_[0]} ; 94*0Sstevel@tonic-gate $tArrayDepth = $#{$_[0]} < $arrayDepth-1 ? $#{$_[0]} : $arrayDepth-1 95*0Sstevel@tonic-gate unless $arrayDepth eq '' ; 96*0Sstevel@tonic-gate my $shortmore = ""; 97*0Sstevel@tonic-gate $shortmore = " ..." if $tArrayDepth < $#{$_[0]} ; 98*0Sstevel@tonic-gate if (!grep(ref $_, @{$_[0]})) { 99*0Sstevel@tonic-gate $short = "0..$#{$_[0]} '" . 100*0Sstevel@tonic-gate join("' '", @{$_[0]}[0..$tArrayDepth]) . "'$shortmore"; 101*0Sstevel@tonic-gate return $short if length $short <= $compactDump; 102*0Sstevel@tonic-gate } 103*0Sstevel@tonic-gate undef; 104*0Sstevel@tonic-gate} 105*0Sstevel@tonic-gate 106*0Sstevel@tonic-gatesub DumpElem { 107*0Sstevel@tonic-gate my $short = &stringify($_[0], ref $_[0]); 108*0Sstevel@tonic-gate if ($veryCompact && ref $_[0] 109*0Sstevel@tonic-gate && (ref $_[0] eq 'ARRAY' and !grep(ref $_, @{$_[0]}) )) { 110*0Sstevel@tonic-gate my $end = "0..$#{$v} '" . 111*0Sstevel@tonic-gate join("' '", @{$_[0]}[0..$tArrayDepth]) . "'$shortmore"; 112*0Sstevel@tonic-gate } elsif ($veryCompact && ref $_[0] 113*0Sstevel@tonic-gate && (ref $_[0] eq 'HASH') and !grep(ref $_, values %{$_[0]})) { 114*0Sstevel@tonic-gate my $end = 1; 115*0Sstevel@tonic-gate $short = $sp . "0..$#{$v} '" . 116*0Sstevel@tonic-gate join("' '", @{$v}[0..$tArrayDepth]) . "'$shortmore"; 117*0Sstevel@tonic-gate } else { 118*0Sstevel@tonic-gate print "$short\n"; 119*0Sstevel@tonic-gate unwrap($_[0],$_[1],$_[2]) if ref $_[0]; 120*0Sstevel@tonic-gate } 121*0Sstevel@tonic-gate} 122*0Sstevel@tonic-gate 123*0Sstevel@tonic-gatesub unwrap { 124*0Sstevel@tonic-gate return if $DB::signal; 125*0Sstevel@tonic-gate local($v) = shift ; 126*0Sstevel@tonic-gate local($s) = shift ; # extra no of spaces 127*0Sstevel@tonic-gate local($m) = shift ; # maximum recursion depth 128*0Sstevel@tonic-gate return if $m == 0; 129*0Sstevel@tonic-gate local(%v,@v,$sp,$value,$key,@sortKeys,$more,$shortmore,$short) ; 130*0Sstevel@tonic-gate local($tHashDepth,$tArrayDepth) ; 131*0Sstevel@tonic-gate 132*0Sstevel@tonic-gate $sp = " " x $s ; 133*0Sstevel@tonic-gate $s += 3 ; 134*0Sstevel@tonic-gate 135*0Sstevel@tonic-gate # Check for reused addresses 136*0Sstevel@tonic-gate if (ref $v) { 137*0Sstevel@tonic-gate my $val = $v; 138*0Sstevel@tonic-gate $val = &{'overload::StrVal'}($v) 139*0Sstevel@tonic-gate if %overload:: and defined &{'overload::StrVal'}; 140*0Sstevel@tonic-gate # Match type and address. 141*0Sstevel@tonic-gate # Unblessed references will look like TYPE(0x...) 142*0Sstevel@tonic-gate # Blessed references will look like Class=TYPE(0x...) 143*0Sstevel@tonic-gate ($start_part, $val) = split /=/,$val; 144*0Sstevel@tonic-gate $val = $start_part unless defined $val; 145*0Sstevel@tonic-gate ($item_type, $address) = 146*0Sstevel@tonic-gate $val =~ /([^\(]+) # Keep stuff that's 147*0Sstevel@tonic-gate # not an open paren 148*0Sstevel@tonic-gate \( # Skip open paren 149*0Sstevel@tonic-gate (0x[0-9a-f]+) # Save the address 150*0Sstevel@tonic-gate \) # Skip close paren 151*0Sstevel@tonic-gate $/x; # Should be at end now 152*0Sstevel@tonic-gate 153*0Sstevel@tonic-gate if (!$dumpReused && defined $address) { 154*0Sstevel@tonic-gate $address{$address}++ ; 155*0Sstevel@tonic-gate if ( $address{$address} > 1 ) { 156*0Sstevel@tonic-gate print "${sp}-> REUSED_ADDRESS\n" ; 157*0Sstevel@tonic-gate return ; 158*0Sstevel@tonic-gate } 159*0Sstevel@tonic-gate } 160*0Sstevel@tonic-gate } elsif (ref \$v eq 'GLOB') { 161*0Sstevel@tonic-gate # This is a raw glob. Special handling for that. 162*0Sstevel@tonic-gate $address = "$v" . ""; # To avoid a bug with globs 163*0Sstevel@tonic-gate $address{$address}++ ; 164*0Sstevel@tonic-gate if ( $address{$address} > 1 ) { 165*0Sstevel@tonic-gate print "${sp}*DUMPED_GLOB*\n" ; 166*0Sstevel@tonic-gate return ; 167*0Sstevel@tonic-gate } 168*0Sstevel@tonic-gate } 169*0Sstevel@tonic-gate 170*0Sstevel@tonic-gate if (ref $v eq 'Regexp') { 171*0Sstevel@tonic-gate # Reformat the regexp to look the standard way. 172*0Sstevel@tonic-gate my $re = "$v"; 173*0Sstevel@tonic-gate $re =~ s,/,\\/,g; 174*0Sstevel@tonic-gate print "$sp-> qr/$re/\n"; 175*0Sstevel@tonic-gate return; 176*0Sstevel@tonic-gate } 177*0Sstevel@tonic-gate 178*0Sstevel@tonic-gate if ( $item_type eq 'HASH' ) { 179*0Sstevel@tonic-gate # Hash ref or hash-based object. 180*0Sstevel@tonic-gate my @sortKeys = sort keys(%$v) ; 181*0Sstevel@tonic-gate undef $more ; 182*0Sstevel@tonic-gate $tHashDepth = $#sortKeys ; 183*0Sstevel@tonic-gate $tHashDepth = $#sortKeys < $hashDepth-1 ? $#sortKeys : $hashDepth-1 184*0Sstevel@tonic-gate unless $hashDepth eq '' ; 185*0Sstevel@tonic-gate $more = "....\n" if $tHashDepth < $#sortKeys ; 186*0Sstevel@tonic-gate $shortmore = ""; 187*0Sstevel@tonic-gate $shortmore = ", ..." if $tHashDepth < $#sortKeys ; 188*0Sstevel@tonic-gate $#sortKeys = $tHashDepth ; 189*0Sstevel@tonic-gate if ($compactDump && !grep(ref $_, values %{$v})) { 190*0Sstevel@tonic-gate #$short = $sp . 191*0Sstevel@tonic-gate # (join ', ', 192*0Sstevel@tonic-gate# Next row core dumps during require from DB on 5.000, even with map {"_"} 193*0Sstevel@tonic-gate # map {&stringify($_) . " => " . &stringify($v->{$_})} 194*0Sstevel@tonic-gate # @sortKeys) . "'$shortmore"; 195*0Sstevel@tonic-gate $short = $sp; 196*0Sstevel@tonic-gate my @keys; 197*0Sstevel@tonic-gate for (@sortKeys) { 198*0Sstevel@tonic-gate push @keys, &stringify($_) . " => " . &stringify($v->{$_}); 199*0Sstevel@tonic-gate } 200*0Sstevel@tonic-gate $short .= join ', ', @keys; 201*0Sstevel@tonic-gate $short .= $shortmore; 202*0Sstevel@tonic-gate (print "$short\n"), return if length $short <= $compactDump; 203*0Sstevel@tonic-gate } 204*0Sstevel@tonic-gate for $key (@sortKeys) { 205*0Sstevel@tonic-gate return if $DB::signal; 206*0Sstevel@tonic-gate $value = $ {$v}{$key} ; 207*0Sstevel@tonic-gate print "$sp", &stringify($key), " => "; 208*0Sstevel@tonic-gate DumpElem $value, $s, $m-1; 209*0Sstevel@tonic-gate } 210*0Sstevel@tonic-gate print "$sp empty hash\n" unless @sortKeys; 211*0Sstevel@tonic-gate print "$sp$more" if defined $more ; 212*0Sstevel@tonic-gate } elsif ( $item_type eq 'ARRAY' ) { 213*0Sstevel@tonic-gate # Array ref or array-based object. Also: undef. 214*0Sstevel@tonic-gate # See how big the array is. 215*0Sstevel@tonic-gate $tArrayDepth = $#{$v} ; 216*0Sstevel@tonic-gate undef $more ; 217*0Sstevel@tonic-gate # Bigger than the max? 218*0Sstevel@tonic-gate $tArrayDepth = $#{$v} < $arrayDepth-1 ? $#{$v} : $arrayDepth-1 219*0Sstevel@tonic-gate if defined $arrayDepth && $arrayDepth ne ''; 220*0Sstevel@tonic-gate # Yep. Don't show it all. 221*0Sstevel@tonic-gate $more = "....\n" if $tArrayDepth < $#{$v} ; 222*0Sstevel@tonic-gate $shortmore = ""; 223*0Sstevel@tonic-gate $shortmore = " ..." if $tArrayDepth < $#{$v} ; 224*0Sstevel@tonic-gate 225*0Sstevel@tonic-gate if ($compactDump && !grep(ref $_, @{$v})) { 226*0Sstevel@tonic-gate if ($#$v >= 0) { 227*0Sstevel@tonic-gate $short = $sp . "0..$#{$v} " . 228*0Sstevel@tonic-gate join(" ", 229*0Sstevel@tonic-gate map {exists $v->[$_] ? stringify $v->[$_] : "empty"} ($[..$tArrayDepth) 230*0Sstevel@tonic-gate ) . "$shortmore"; 231*0Sstevel@tonic-gate } else { 232*0Sstevel@tonic-gate $short = $sp . "empty array"; 233*0Sstevel@tonic-gate } 234*0Sstevel@tonic-gate (print "$short\n"), return if length $short <= $compactDump; 235*0Sstevel@tonic-gate } 236*0Sstevel@tonic-gate #if ($compactDump && $short = ShortArray($v)) { 237*0Sstevel@tonic-gate # print "$short\n"; 238*0Sstevel@tonic-gate # return; 239*0Sstevel@tonic-gate #} 240*0Sstevel@tonic-gate for $num ($[ .. $tArrayDepth) { 241*0Sstevel@tonic-gate return if $DB::signal; 242*0Sstevel@tonic-gate print "$sp$num "; 243*0Sstevel@tonic-gate if (exists $v->[$num]) { 244*0Sstevel@tonic-gate if (defined $v->[$num]) { 245*0Sstevel@tonic-gate DumpElem $v->[$num], $s, $m-1; 246*0Sstevel@tonic-gate } 247*0Sstevel@tonic-gate else { 248*0Sstevel@tonic-gate print "undef\n"; 249*0Sstevel@tonic-gate } 250*0Sstevel@tonic-gate } else { 251*0Sstevel@tonic-gate print "empty slot\n"; 252*0Sstevel@tonic-gate } 253*0Sstevel@tonic-gate } 254*0Sstevel@tonic-gate print "$sp empty array\n" unless @$v; 255*0Sstevel@tonic-gate print "$sp$more" if defined $more ; 256*0Sstevel@tonic-gate } elsif ( $item_type eq 'SCALAR' ) { 257*0Sstevel@tonic-gate unless (defined $$v) { 258*0Sstevel@tonic-gate print "$sp-> undef\n"; 259*0Sstevel@tonic-gate return; 260*0Sstevel@tonic-gate } 261*0Sstevel@tonic-gate print "$sp-> "; 262*0Sstevel@tonic-gate DumpElem $$v, $s, $m-1; 263*0Sstevel@tonic-gate } elsif ( $item_type eq 'REF' ) { 264*0Sstevel@tonic-gate print "$sp-> $$v\n"; 265*0Sstevel@tonic-gate return unless defined $$v; 266*0Sstevel@tonic-gate unwrap($$v, $s+3, $m-1); 267*0Sstevel@tonic-gate } elsif ( $item_type eq 'CODE' ) { 268*0Sstevel@tonic-gate # Code object or reference. 269*0Sstevel@tonic-gate print "$sp-> "; 270*0Sstevel@tonic-gate dumpsub (0, $v); 271*0Sstevel@tonic-gate } elsif ( $item_type eq 'GLOB' ) { 272*0Sstevel@tonic-gate # Glob object or reference. 273*0Sstevel@tonic-gate print "$sp-> ",&stringify($$v,1),"\n"; 274*0Sstevel@tonic-gate if ($globPrint) { 275*0Sstevel@tonic-gate $s += 3; 276*0Sstevel@tonic-gate dumpglob($s, "{$$v}", $$v, 1, $m-1); 277*0Sstevel@tonic-gate } elsif (defined ($fileno = fileno($v))) { 278*0Sstevel@tonic-gate print( (' ' x ($s+3)) . "FileHandle({$$v}) => fileno($fileno)\n" ); 279*0Sstevel@tonic-gate } 280*0Sstevel@tonic-gate } elsif (ref \$v eq 'GLOB') { 281*0Sstevel@tonic-gate # Raw glob (again?) 282*0Sstevel@tonic-gate if ($globPrint) { 283*0Sstevel@tonic-gate dumpglob($s, "{$v}", $v, 1, $m-1) if $globPrint; 284*0Sstevel@tonic-gate } elsif (defined ($fileno = fileno(\$v))) { 285*0Sstevel@tonic-gate print( (' ' x $s) . "FileHandle({$v}) => fileno($fileno)\n" ); 286*0Sstevel@tonic-gate } 287*0Sstevel@tonic-gate } 288*0Sstevel@tonic-gate} 289*0Sstevel@tonic-gate 290*0Sstevel@tonic-gatesub matchlex { 291*0Sstevel@tonic-gate (my $var = $_[0]) =~ s/.//; 292*0Sstevel@tonic-gate $var eq $_[1] or 293*0Sstevel@tonic-gate ($_[1] =~ /^([!~])(.)([\x00-\xff]*)/) and 294*0Sstevel@tonic-gate ($1 eq '!') ^ (eval { $var =~ /$2$3/ }); 295*0Sstevel@tonic-gate} 296*0Sstevel@tonic-gate 297*0Sstevel@tonic-gatesub matchvar { 298*0Sstevel@tonic-gate $_[0] eq $_[1] or 299*0Sstevel@tonic-gate ($_[1] =~ /^([!~])(.)([\x00-\xff]*)/) and 300*0Sstevel@tonic-gate ($1 eq '!') ^ (eval {($_[2] . "::" . $_[0]) =~ /$2$3/}); 301*0Sstevel@tonic-gate} 302*0Sstevel@tonic-gate 303*0Sstevel@tonic-gatesub compactDump { 304*0Sstevel@tonic-gate $compactDump = shift if @_; 305*0Sstevel@tonic-gate $compactDump = 6*80-1 if $compactDump and $compactDump < 2; 306*0Sstevel@tonic-gate $compactDump; 307*0Sstevel@tonic-gate} 308*0Sstevel@tonic-gate 309*0Sstevel@tonic-gatesub veryCompact { 310*0Sstevel@tonic-gate $veryCompact = shift if @_; 311*0Sstevel@tonic-gate compactDump(1) if !$compactDump and $veryCompact; 312*0Sstevel@tonic-gate $veryCompact; 313*0Sstevel@tonic-gate} 314*0Sstevel@tonic-gate 315*0Sstevel@tonic-gatesub unctrlSet { 316*0Sstevel@tonic-gate if (@_) { 317*0Sstevel@tonic-gate my $in = shift; 318*0Sstevel@tonic-gate if ($in eq 'unctrl' or $in eq 'quote') { 319*0Sstevel@tonic-gate $unctrl = $in; 320*0Sstevel@tonic-gate } else { 321*0Sstevel@tonic-gate print "Unknown value for `unctrl'.\n"; 322*0Sstevel@tonic-gate } 323*0Sstevel@tonic-gate } 324*0Sstevel@tonic-gate $unctrl; 325*0Sstevel@tonic-gate} 326*0Sstevel@tonic-gate 327*0Sstevel@tonic-gatesub quote { 328*0Sstevel@tonic-gate if (@_ and $_[0] eq '"') { 329*0Sstevel@tonic-gate $tick = '"'; 330*0Sstevel@tonic-gate $unctrl = 'quote'; 331*0Sstevel@tonic-gate } elsif (@_ and $_[0] eq 'auto') { 332*0Sstevel@tonic-gate $tick = 'auto'; 333*0Sstevel@tonic-gate $unctrl = 'quote'; 334*0Sstevel@tonic-gate } elsif (@_) { # Need to set 335*0Sstevel@tonic-gate $tick = "'"; 336*0Sstevel@tonic-gate $unctrl = 'unctrl'; 337*0Sstevel@tonic-gate } 338*0Sstevel@tonic-gate $tick; 339*0Sstevel@tonic-gate} 340*0Sstevel@tonic-gate 341*0Sstevel@tonic-gatesub dumpglob { 342*0Sstevel@tonic-gate return if $DB::signal; 343*0Sstevel@tonic-gate my ($off,$key, $val, $all, $m) = @_; 344*0Sstevel@tonic-gate local(*entry) = $val; 345*0Sstevel@tonic-gate my $fileno; 346*0Sstevel@tonic-gate if (($key !~ /^_</ or $dumpDBFiles) and defined $entry) { 347*0Sstevel@tonic-gate print( (' ' x $off) . "\$", &unctrl($key), " = " ); 348*0Sstevel@tonic-gate DumpElem $entry, 3+$off, $m; 349*0Sstevel@tonic-gate } 350*0Sstevel@tonic-gate if (($key !~ /^_</ or $dumpDBFiles) and @entry) { 351*0Sstevel@tonic-gate print( (' ' x $off) . "\@$key = (\n" ); 352*0Sstevel@tonic-gate unwrap(\@entry,3+$off,$m) ; 353*0Sstevel@tonic-gate print( (' ' x $off) . ")\n" ); 354*0Sstevel@tonic-gate } 355*0Sstevel@tonic-gate if ($key ne "main::" && $key ne "DB::" && %entry 356*0Sstevel@tonic-gate && ($dumpPackages or $key !~ /::$/) 357*0Sstevel@tonic-gate && ($key !~ /^_</ or $dumpDBFiles) 358*0Sstevel@tonic-gate && !($package eq "dumpvar" and $key eq "stab")) { 359*0Sstevel@tonic-gate print( (' ' x $off) . "\%$key = (\n" ); 360*0Sstevel@tonic-gate unwrap(\%entry,3+$off,$m) ; 361*0Sstevel@tonic-gate print( (' ' x $off) . ")\n" ); 362*0Sstevel@tonic-gate } 363*0Sstevel@tonic-gate if (defined ($fileno = fileno(*entry))) { 364*0Sstevel@tonic-gate print( (' ' x $off) . "FileHandle($key) => fileno($fileno)\n" ); 365*0Sstevel@tonic-gate } 366*0Sstevel@tonic-gate if ($all) { 367*0Sstevel@tonic-gate if (defined &entry) { 368*0Sstevel@tonic-gate dumpsub($off, $key); 369*0Sstevel@tonic-gate } 370*0Sstevel@tonic-gate } 371*0Sstevel@tonic-gate} 372*0Sstevel@tonic-gate 373*0Sstevel@tonic-gatesub dumplex { 374*0Sstevel@tonic-gate return if $DB::signal; 375*0Sstevel@tonic-gate my ($key, $val, $m, @vars) = @_; 376*0Sstevel@tonic-gate return if @vars && !grep( matchlex($key, $_), @vars ); 377*0Sstevel@tonic-gate local %address; 378*0Sstevel@tonic-gate my $off = 0; # It reads better this way 379*0Sstevel@tonic-gate my $fileno; 380*0Sstevel@tonic-gate if (UNIVERSAL::isa($val,'ARRAY')) { 381*0Sstevel@tonic-gate print( (' ' x $off) . "$key = (\n" ); 382*0Sstevel@tonic-gate unwrap($val,3+$off,$m) ; 383*0Sstevel@tonic-gate print( (' ' x $off) . ")\n" ); 384*0Sstevel@tonic-gate } 385*0Sstevel@tonic-gate elsif (UNIVERSAL::isa($val,'HASH')) { 386*0Sstevel@tonic-gate print( (' ' x $off) . "$key = (\n" ); 387*0Sstevel@tonic-gate unwrap($val,3+$off,$m) ; 388*0Sstevel@tonic-gate print( (' ' x $off) . ")\n" ); 389*0Sstevel@tonic-gate } 390*0Sstevel@tonic-gate elsif (UNIVERSAL::isa($val,'IO')) { 391*0Sstevel@tonic-gate print( (' ' x $off) . "FileHandle($key) => fileno($fileno)\n" ); 392*0Sstevel@tonic-gate } 393*0Sstevel@tonic-gate # No lexical subroutines yet... 394*0Sstevel@tonic-gate # elsif (UNIVERSAL::isa($val,'CODE')) { 395*0Sstevel@tonic-gate # dumpsub($off, $$val); 396*0Sstevel@tonic-gate # } 397*0Sstevel@tonic-gate else { 398*0Sstevel@tonic-gate print( (' ' x $off) . &unctrl($key), " = " ); 399*0Sstevel@tonic-gate DumpElem $$val, 3+$off, $m; 400*0Sstevel@tonic-gate } 401*0Sstevel@tonic-gate} 402*0Sstevel@tonic-gate 403*0Sstevel@tonic-gatesub CvGV_name_or_bust { 404*0Sstevel@tonic-gate my $in = shift; 405*0Sstevel@tonic-gate return if $skipCvGV; # Backdoor to avoid problems if XS broken... 406*0Sstevel@tonic-gate $in = \&$in; # Hard reference... 407*0Sstevel@tonic-gate eval {require Devel::Peek; 1} or return; 408*0Sstevel@tonic-gate my $gv = Devel::Peek::CvGV($in) or return; 409*0Sstevel@tonic-gate *$gv{PACKAGE} . '::' . *$gv{NAME}; 410*0Sstevel@tonic-gate} 411*0Sstevel@tonic-gate 412*0Sstevel@tonic-gatesub dumpsub { 413*0Sstevel@tonic-gate my ($off,$sub) = @_; 414*0Sstevel@tonic-gate my $ini = $sub; 415*0Sstevel@tonic-gate my $s; 416*0Sstevel@tonic-gate $sub = $1 if $sub =~ /^\{\*(.*)\}$/; 417*0Sstevel@tonic-gate my $subref = defined $1 ? \&$sub : \&$ini; 418*0Sstevel@tonic-gate my $place = $DB::sub{$sub} || (($s = $subs{"$subref"}) && $DB::sub{$s}) 419*0Sstevel@tonic-gate || (($s = CvGV_name_or_bust($subref)) && $DB::sub{$s}) 420*0Sstevel@tonic-gate || ($subdump && ($s = findsubs("$subref")) && $DB::sub{$s}); 421*0Sstevel@tonic-gate $place = '???' unless defined $place; 422*0Sstevel@tonic-gate $s = $sub unless defined $s; 423*0Sstevel@tonic-gate print( (' ' x $off) . "&$s in $place\n" ); 424*0Sstevel@tonic-gate} 425*0Sstevel@tonic-gate 426*0Sstevel@tonic-gatesub findsubs { 427*0Sstevel@tonic-gate return undef unless %DB::sub; 428*0Sstevel@tonic-gate my ($addr, $name, $loc); 429*0Sstevel@tonic-gate while (($name, $loc) = each %DB::sub) { 430*0Sstevel@tonic-gate $addr = \&$name; 431*0Sstevel@tonic-gate $subs{"$addr"} = $name; 432*0Sstevel@tonic-gate } 433*0Sstevel@tonic-gate $subdump = 0; 434*0Sstevel@tonic-gate $subs{ shift() }; 435*0Sstevel@tonic-gate} 436*0Sstevel@tonic-gate 437*0Sstevel@tonic-gatesub main::dumpvar { 438*0Sstevel@tonic-gate my ($package,$m,@vars) = @_; 439*0Sstevel@tonic-gate local(%address,$key,$val,$^W); 440*0Sstevel@tonic-gate $package .= "::" unless $package =~ /::$/; 441*0Sstevel@tonic-gate *stab = *{"main::"}; 442*0Sstevel@tonic-gate while ($package =~ /(\w+?::)/g){ 443*0Sstevel@tonic-gate *stab = $ {stab}{$1}; 444*0Sstevel@tonic-gate } 445*0Sstevel@tonic-gate local $TotalStrings = 0; 446*0Sstevel@tonic-gate local $Strings = 0; 447*0Sstevel@tonic-gate local $CompleteTotal = 0; 448*0Sstevel@tonic-gate while (($key,$val) = each(%stab)) { 449*0Sstevel@tonic-gate return if $DB::signal; 450*0Sstevel@tonic-gate next if @vars && !grep( matchvar($key, $_), @vars ); 451*0Sstevel@tonic-gate if ($usageOnly) { 452*0Sstevel@tonic-gate globUsage(\$val, $key) 453*0Sstevel@tonic-gate if ($package ne 'dumpvar' or $key ne 'stab') 454*0Sstevel@tonic-gate and ref(\$val) eq 'GLOB'; 455*0Sstevel@tonic-gate } else { 456*0Sstevel@tonic-gate dumpglob(0,$key, $val, 0, $m); 457*0Sstevel@tonic-gate } 458*0Sstevel@tonic-gate } 459*0Sstevel@tonic-gate if ($usageOnly) { 460*0Sstevel@tonic-gate print "String space: $TotalStrings bytes in $Strings strings.\n"; 461*0Sstevel@tonic-gate $CompleteTotal += $TotalStrings; 462*0Sstevel@tonic-gate print "Grand total = $CompleteTotal bytes (1 level deep) + overhead.\n"; 463*0Sstevel@tonic-gate } 464*0Sstevel@tonic-gate} 465*0Sstevel@tonic-gate 466*0Sstevel@tonic-gatesub scalarUsage { 467*0Sstevel@tonic-gate my $size = length($_[0]); 468*0Sstevel@tonic-gate $TotalStrings += $size; 469*0Sstevel@tonic-gate $Strings++; 470*0Sstevel@tonic-gate $size; 471*0Sstevel@tonic-gate} 472*0Sstevel@tonic-gate 473*0Sstevel@tonic-gatesub arrayUsage { # array ref, name 474*0Sstevel@tonic-gate my $size = 0; 475*0Sstevel@tonic-gate map {$size += scalarUsage($_)} @{$_[0]}; 476*0Sstevel@tonic-gate my $len = @{$_[0]}; 477*0Sstevel@tonic-gate print "\@$_[1] = $len item", ($len > 1 ? "s" : ""), 478*0Sstevel@tonic-gate " (data: $size bytes)\n" 479*0Sstevel@tonic-gate if defined $_[1]; 480*0Sstevel@tonic-gate $CompleteTotal += $size; 481*0Sstevel@tonic-gate $size; 482*0Sstevel@tonic-gate} 483*0Sstevel@tonic-gate 484*0Sstevel@tonic-gatesub hashUsage { # hash ref, name 485*0Sstevel@tonic-gate my @keys = keys %{$_[0]}; 486*0Sstevel@tonic-gate my @values = values %{$_[0]}; 487*0Sstevel@tonic-gate my $keys = arrayUsage \@keys; 488*0Sstevel@tonic-gate my $values = arrayUsage \@values; 489*0Sstevel@tonic-gate my $len = @keys; 490*0Sstevel@tonic-gate my $total = $keys + $values; 491*0Sstevel@tonic-gate print "\%$_[1] = $len item", ($len > 1 ? "s" : ""), 492*0Sstevel@tonic-gate " (keys: $keys; values: $values; total: $total bytes)\n" 493*0Sstevel@tonic-gate if defined $_[1]; 494*0Sstevel@tonic-gate $total; 495*0Sstevel@tonic-gate} 496*0Sstevel@tonic-gate 497*0Sstevel@tonic-gatesub globUsage { # glob ref, name 498*0Sstevel@tonic-gate local *name = *{$_[0]}; 499*0Sstevel@tonic-gate $total = 0; 500*0Sstevel@tonic-gate $total += scalarUsage $name if defined $name; 501*0Sstevel@tonic-gate $total += arrayUsage \@name, $_[1] if @name; 502*0Sstevel@tonic-gate $total += hashUsage \%name, $_[1] if %name and $_[1] ne "main::" 503*0Sstevel@tonic-gate and $_[1] ne "DB::"; #and !($package eq "dumpvar" and $key eq "stab")); 504*0Sstevel@tonic-gate $total; 505*0Sstevel@tonic-gate} 506*0Sstevel@tonic-gate 507*0Sstevel@tonic-gatesub packageUsage { 508*0Sstevel@tonic-gate my ($package,@vars) = @_; 509*0Sstevel@tonic-gate $package .= "::" unless $package =~ /::$/; 510*0Sstevel@tonic-gate local *stab = *{"main::"}; 511*0Sstevel@tonic-gate while ($package =~ /(\w+?::)/g){ 512*0Sstevel@tonic-gate *stab = $ {stab}{$1}; 513*0Sstevel@tonic-gate } 514*0Sstevel@tonic-gate local $TotalStrings = 0; 515*0Sstevel@tonic-gate local $CompleteTotal = 0; 516*0Sstevel@tonic-gate my ($key,$val); 517*0Sstevel@tonic-gate while (($key,$val) = each(%stab)) { 518*0Sstevel@tonic-gate next if @vars && !grep($key eq $_,@vars); 519*0Sstevel@tonic-gate globUsage \$val, $key unless $package eq 'dumpvar' and $key eq 'stab'; 520*0Sstevel@tonic-gate } 521*0Sstevel@tonic-gate print "String space: $TotalStrings.\n"; 522*0Sstevel@tonic-gate $CompleteTotal += $TotalStrings; 523*0Sstevel@tonic-gate print "\nGrand total = $CompleteTotal bytes\n"; 524*0Sstevel@tonic-gate} 525*0Sstevel@tonic-gate 526*0Sstevel@tonic-gate1; 527*0Sstevel@tonic-gate 528