X-Git-Url: https://perl5.git.perl.org/perl5.git/blobdiff_plain/d6b7ef8642dbff7f74dde11fd4995a37e8f38c04..a1219b5e0bb6c311848c834f67e70ff7a19c6bf4:/lib/dumpvar.pl diff --git a/lib/dumpvar.pl b/lib/dumpvar.pl index 12c9e91..91153ea 100644 --- a/lib/dumpvar.pl +++ b/lib/dumpvar.pl @@ -1,4 +1,4 @@ -require 5.002; # For (defined ref) +require 5.014; # For more reliable $@ after eval package dumpvar; # Needed for PrettyPrinter only: @@ -30,18 +30,25 @@ sub main::dumpValue { local $^W=0; (print "undef\n"), return unless defined $_[0]; (print &stringify($_[0]), "\n"), return unless ref $_[0]; - dumpvar::unwrap($_[0],0, $_[1]); + push @_, -1 if @_ == 1; + dumpvar::unwrap($_[0], 0, $_[1]); } # This one is good for variable names: sub unctrl { - local($_) = @_; + for (my($dummy) = shift) { local($v) ; return \$_ if ref \$_ eq "GLOB"; - s/([\001-\037\177])/'^'.pack('c',ord($1)^64)/eg; - $_; + if (ord('A') == 193) { # EBCDIC. + # EBCDIC has no concept of "\cA" or "A" being related + # to each other by a linear/boolean mapping. + } else { + s/([\001-\037\177])/'^'.pack('c',ord($1)^64)/eg; + } + return $_; + } } sub uniescape { @@ -51,7 +58,17 @@ sub uniescape { } sub stringify { - local($_,$noticks) = @_; + my $string; + if (eval { $string = _stringify(@_); 1 }) { + return $string; + } + + return "<< value could not be dumped: $@ >>"; +} + +sub _stringify { + (my $__, local $noticks) = @_; + for ($__) { local($v) ; my $tick = $tick; @@ -62,11 +79,19 @@ sub stringify { and %overload:: and defined &{'overload::StrVal'}; if ($tick eq 'auto') { - if (/[\000-\011\013-\037\177]/) { - $tick = '"'; - }else { - $tick = "'"; - } + if (ord('A') == 193) { + if (/[\000-\011]/ or /[\013-\024\31-\037\177]/) { + $tick = '"'; + } else { + $tick = "'"; + } + } else { + if (/[\000-\011\013-\037\177]/) { + $tick = '"'; + } else { + $tick = "'"; + } + } } if ($tick eq "'") { s/([\'\\])/\\$1/g; @@ -79,13 +104,26 @@ sub stringify { } elsif ($unctrl eq 'quote') { s/([\"\\\$\@])/\\$1/g if $tick eq '"'; s/\033/\\e/g; - s/([\000-\037\177])/'\\c'.chr(ord($1)^64)/eg; + if (ord('A') == 193) { # EBCDIC. + s/([\000-\037\177])/'\\c'.chr(193)/eg; # Unfinished. + } else { + s/([\000-\037\177])/'\\c'._escaped_ord($1)/eg; + } } $_ = uniescape($_); s/([\200-\377])/'\\'.sprintf('%3o',ord($1))/eg if $quoteHighBit; - ($noticks || /^\d+(\.\d*)?\Z/) + return ($noticks || /^\d+(\.\d*)?\Z/) ? $_ : $tick . $_ . $tick; + } +} + +# Ensure a resulting \ is escaped to be \\ +sub _escaped_ord { + my $chr = shift; + $chr = chr(ord($chr)^64); + $chr =~ s{\\}{\\\\}g; + return $chr; } sub ShortArray { @@ -115,7 +153,7 @@ sub DumpElem { join("' '", @{$v}[0..$tArrayDepth]) . "'$shortmore"; } else { print "$short\n"; - unwrap($_[0],$_[1],$_[2]); + unwrap($_[0],$_[1],$_[2]) if ref $_[0]; } } @@ -131,12 +169,24 @@ sub unwrap { $sp = " " x $s ; $s += 3 ; + eval { # Check for reused addresses if (ref $v) { my $val = $v; $val = &{'overload::StrVal'}($v) if %overload:: and defined &{'overload::StrVal'}; - ($address) = $val =~ /(0x[0-9a-f]+)\)$/ ; + # Match type and address. + # Unblessed references will look like TYPE(0x...) + # Blessed references will look like Class=TYPE(0x...) + $val =~ s/^.*=//; # suppress the Class part, just keep TYPE(0x...) + ($item_type, $address) = + $val =~ /([^\(]+) # Keep stuff that's + # not an open paren + \( # Skip open paren + (0x[0-9a-f]+) # Save the address + \) # Skip close paren + $/x; # Should be at end now + if (!$dumpReused && defined $address) { $address{$address}++ ; if ( $address{$address} > 1 ) { @@ -145,6 +195,7 @@ sub unwrap { } } } elsif (ref \$v eq 'GLOB') { + # This is a raw glob. Special handling for that. $address = "$v" . ""; # To avoid a bug with globs $address{$address}++ ; if ( $address{$address} > 1 ) { @@ -154,14 +205,16 @@ sub unwrap { } if (ref $v eq 'Regexp') { + # Reformat the regexp to look the standard way. my $re = "$v"; $re =~ s,/,\\/,g; print "$sp-> qr/$re/\n"; return; } - if ( UNIVERSAL::isa($v, 'HASH') ) { - @sortKeys = sort keys(%$v) ; + if ( $item_type eq 'HASH' ) { + # Hash ref or hash-based object. + my @sortKeys = sort keys(%$v) ; undef $more ; $tHashDepth = $#sortKeys ; $tHashDepth = $#sortKeys < $hashDepth-1 ? $#sortKeys : $hashDepth-1 @@ -193,19 +246,24 @@ sub unwrap { } print "$sp empty hash\n" unless @sortKeys; print "$sp$more" if defined $more ; - } elsif ( UNIVERSAL::isa($v, 'ARRAY') ) { + } elsif ( $item_type eq 'ARRAY' ) { + # Array ref or array-based object. Also: undef. + # See how big the array is. $tArrayDepth = $#{$v} ; undef $more ; + # Bigger than the max? $tArrayDepth = $#{$v} < $arrayDepth-1 ? $#{$v} : $arrayDepth-1 if defined $arrayDepth && $arrayDepth ne ''; + # Yep. Don't show it all. $more = "....\n" if $tArrayDepth < $#{$v} ; $shortmore = ""; $shortmore = " ..." if $tArrayDepth < $#{$v} ; + if ($compactDump && !grep(ref $_, @{$v})) { if ($#$v >= 0) { $short = $sp . "0..$#{$v} " . join(" ", - map {exists $v->[$_] ? stringify $v->[$_] : "empty"} ($[..$tArrayDepth) + map {exists $v->[$_] ? stringify $v->[$_] : "empty"} (0..$tArrayDepth) ) . "$shortmore"; } else { $short = $sp . "empty array"; @@ -216,38 +274,60 @@ sub unwrap { # print "$short\n"; # return; #} - for $num ($[ .. $tArrayDepth) { + for $num (0 .. $tArrayDepth) { return if $DB::signal; print "$sp$num "; if (exists $v->[$num]) { - DumpElem $v->[$num], $s, $m-1; + if (defined $v->[$num]) { + DumpElem $v->[$num], $s, $m-1; + } + else { + print "undef\n"; + } } else { print "empty slot\n"; } } print "$sp empty array\n" unless @$v; print "$sp$more" if defined $more ; - } elsif ( UNIVERSAL::isa($v, 'SCALAR') or ref $v eq 'REF' ) { + } elsif ( $item_type eq 'SCALAR' ) { + unless (defined $$v) { + print "$sp-> undef\n"; + return; + } print "$sp-> "; DumpElem $$v, $s, $m-1; - } elsif ( UNIVERSAL::isa($v, 'CODE') ) { + } elsif ( $item_type eq 'REF' ) { + print "$sp-> $$v\n"; + return unless defined $$v; + unwrap($$v, $s+3, $m-1); + } elsif ( $item_type eq 'CODE' ) { + # Code object or reference. print "$sp-> "; dumpsub (0, $v); - } elsif ( UNIVERSAL::isa($v, 'GLOB') ) { + } elsif ( $item_type eq 'GLOB' ) { + # Glob object or reference. print "$sp-> ",&stringify($$v,1),"\n"; if ($globPrint) { $s += 3; dumpglob($s, "{$$v}", $$v, 1, $m-1); - } elsif (defined ($fileno = fileno($v))) { + } elsif (defined ($fileno = eval {fileno($v)})) { print( (' ' x ($s+3)) . "FileHandle({$$v}) => fileno($fileno)\n" ); } } elsif (ref \$v eq 'GLOB') { + # Raw glob (again?) if ($globPrint) { dumpglob($s, "{$v}", $v, 1, $m-1) if $globPrint; - } elsif (defined ($fileno = fileno(\$v))) { + } elsif (defined ($fileno = eval {fileno(\$v)})) { print( (' ' x $s) . "FileHandle({$v}) => fileno($fileno)\n" ); } } + }; + if ($@) { + print( (' ' x $s) . "<< value could not be dumped: $@ >>\n"); + } + + return; } sub matchlex { @@ -281,7 +361,7 @@ sub unctrlSet { if ($in eq 'unctrl' or $in eq 'quote') { $unctrl = $in; } else { - print "Unknown value for `unctrl'.\n"; + print "Unknown value for 'unctrl'.\n"; } } $unctrl; @@ -323,7 +403,7 @@ sub dumpglob { unwrap(\%entry,3+$off,$m) ; print( (' ' x $off) . ")\n" ); } - if (defined ($fileno = fileno(*entry))) { + if (defined ($fileno = eval{fileno(*entry)})) { print( (' ' x $off) . "FileHandle($key) => fileno($fileno)\n" ); } if ($all) {