home *** CD-ROM | disk | FTP | other *** search
/ Acorn User 10 / AU_CD10.iso / Updates / Perl / Non-RPC / !Perl / lib / zip / dumpvar.pl < prev    next >
Perl Script  |  1998-08-02  |  11KB  |  418 lines

  1. require 5.002;            # For (defined ref)
  2. package dumpvar;
  3.  
  4. # Needed for PrettyPrinter only:
  5.  
  6. # require 5.001;  # Well, it coredumps anyway undef DB in 5.000 (not now)
  7.  
  8. # translate control chars to ^X - Randal Schwartz
  9. # Modifications to print types by Peter Gordon v1.0
  10.  
  11. # Ilya Zakharevich -- patches after 5.001 (and some before ;-)
  12.  
  13. # Won't dump symbol tables and contents of debugged files by default
  14.  
  15. $winsize = 80 unless defined $winsize;
  16.  
  17.  
  18. # Defaults
  19.  
  20. # $globPrint = 1;
  21. $printUndef = 1 unless defined $printUndef;
  22. $tick = "auto" unless defined $tick;
  23. $unctrl = 'quote' unless defined $unctrl;
  24. $subdump = 1;
  25. $dumpReused = 0 unless defined $dumpReused;
  26. $bareStringify = 1 unless defined $bareStringify;
  27.  
  28. sub main::dumpValue {
  29.   local %address;
  30.   local $^W=0;
  31.   (print "undef\n"), return unless defined $_[0];
  32.   (print &stringify($_[0]), "\n"), return unless ref $_[0];
  33.   dumpvar::unwrap($_[0],0);
  34. }
  35.  
  36. # This one is good for variable names:
  37.  
  38. sub unctrl {
  39.     local($_) = @_;
  40.     local($v) ; 
  41.  
  42.     return \$_ if ref \$_ eq "GLOB";
  43.     s/([\001-\037\177])/'^'.pack('c',ord($1)^64)/eg;
  44.     $_;
  45. }
  46.  
  47. sub stringify {
  48.     local($_,$noticks) = @_;
  49.     local($v) ; 
  50.     my $tick = $tick;
  51.  
  52.     return 'undef' unless defined $_ or not $printUndef;
  53.     return $_ . "" if ref \$_ eq 'GLOB';
  54.     $_ = &{'overload::StrVal'}($_) 
  55.       if $bareStringify and ref $_ 
  56.         and defined %overload:: and defined &{'overload::StrVal'};
  57.     
  58.     if ($tick eq 'auto') {
  59.       if (/[\000-\011\013-\037\177]/) {
  60.         $tick = '"';
  61.       }else {
  62.         $tick = "'";
  63.       }
  64.     }
  65.     if ($tick eq "'") {
  66.       s/([\'\\])/\\$1/g;
  67.     } elsif ($unctrl eq 'unctrl') {
  68.       s/([\"\\])/\\$1/g ;
  69.       s/([\000-\037\177])/'^'.pack('c',ord($1)^64)/eg;
  70.       s/([\200-\377])/'\\0x'.sprintf('%2X',ord($1))/eg 
  71.         if $quoteHighBit;
  72.     } elsif ($unctrl eq 'quote') {
  73.       s/([\"\\\$\@])/\\$1/g if $tick eq '"';
  74.       s/\033/\\e/g;
  75.       s/([\000-\037\177])/'\\c'.chr(ord($1)^64)/eg;
  76.     }
  77.     s/([\200-\377])/'\\'.sprintf('%3o',ord($1))/eg if $quoteHighBit;
  78.     ($noticks || /^\d+(\.\d*)?\Z/) 
  79.       ? $_ 
  80.       : $tick . $_ . $tick;
  81. }
  82.  
  83. sub ShortArray {
  84.   my $tArrayDepth = $#{$_[0]} ; 
  85.   $tArrayDepth = $#{$_[0]} < $arrayDepth-1 ? $#{$_[0]} : $arrayDepth-1 
  86.     unless  $arrayDepth eq '' ; 
  87.   my $shortmore = "";
  88.   $shortmore = " ..." if $tArrayDepth < $#{$_[0]} ;
  89.   if (!grep(ref $_, @{$_[0]})) {
  90.     $short = "0..$#{$_[0]}  '" . 
  91.       join("' '", @{$_[0]}[0..$tArrayDepth]) . "'$shortmore";
  92.     return $short if length $short <= $compactDump;
  93.   }
  94.   undef;
  95. }
  96.  
  97. sub DumpElem {
  98.   my $short = &stringify($_[0], ref $_[0]);
  99.   if ($veryCompact && ref $_[0]
  100.       && (ref $_[0] eq 'ARRAY' and !grep(ref $_, @{$_[0]}) )) {
  101.     my $end = "0..$#{$v}  '" . 
  102.       join("' '", @{$_[0]}[0..$tArrayDepth]) . "'$shortmore";
  103.   } elsif ($veryCompact && ref $_[0]
  104.       && (ref $_[0] eq 'HASH') and !grep(ref $_, values %{$_[0]})) {
  105.     my $end = 1;
  106.       $short = $sp . "0..$#{$v}  '" . 
  107.         join("' '", @{$v}[0..$tArrayDepth]) . "'$shortmore";
  108.   } else {
  109.     print "$short\n";
  110.     unwrap($_[0],$_[1]);
  111.   }
  112. }
  113.  
  114. sub unwrap {
  115.     return if $DB::signal;
  116.     local($v) = shift ; 
  117.     local($s) = shift ; # extra no of spaces
  118.     local(%v,@v,$sp,$value,$key,@sortKeys,$more,$shortmore,$short) ;
  119.     local($tHashDepth,$tArrayDepth) ;
  120.  
  121.     $sp = " " x $s ;
  122.     $s += 3 ; 
  123.  
  124.     # Check for reused addresses
  125.     if (ref $v) { 
  126.       my $val = $v;
  127.       $val = &{'overload::StrVal'}($v) 
  128.     if defined %overload:: and defined &{'overload::StrVal'};
  129.       ($address) = $val =~ /(0x[0-9a-f]+)\)$/ ; 
  130.       if (!$dumpReused && defined $address) { 
  131.     $address{$address}++ ;
  132.     if ( $address{$address} > 1 ) { 
  133.       print "${sp}-> REUSED_ADDRESS\n" ; 
  134.       return ; 
  135.     } 
  136.       }
  137.     } elsif (ref \$v eq 'GLOB') {
  138.       $address = "$v" . "";    # To avoid a bug with globs
  139.       $address{$address}++ ;
  140.       if ( $address{$address} > 1 ) { 
  141.     print "${sp}*DUMPED_GLOB*\n" ; 
  142.     return ; 
  143.       } 
  144.     }
  145.  
  146.     if ( UNIVERSAL::isa($v, 'HASH') ) { 
  147.     @sortKeys = sort keys(%$v) ;
  148.     undef $more ; 
  149.     $tHashDepth = $#sortKeys ; 
  150.     $tHashDepth = $#sortKeys < $hashDepth-1 ? $#sortKeys : $hashDepth-1
  151.       unless $hashDepth eq '' ; 
  152.     $more = "....\n" if $tHashDepth < $#sortKeys ; 
  153.     $shortmore = "";
  154.     $shortmore = ", ..." if $tHashDepth < $#sortKeys ; 
  155.     $#sortKeys = $tHashDepth ; 
  156.     if ($compactDump && !grep(ref $_, values %{$v})) {
  157.       #$short = $sp . 
  158.       #  (join ', ', 
  159. # Next row core dumps during require from DB on 5.000, even with map {"_"}
  160.       #   map {&stringify($_) . " => " . &stringify($v->{$_})} 
  161.       #   @sortKeys) . "'$shortmore";
  162.       $short = $sp;
  163.       my @keys;
  164.       for (@sortKeys) {
  165.         push @keys, &stringify($_) . " => " . &stringify($v->{$_});
  166.       }
  167.       $short .= join ', ', @keys;
  168.       $short .= $shortmore;
  169.       (print "$short\n"), return if length $short <= $compactDump;
  170.     }
  171.     for $key (@sortKeys) {
  172.         return if $DB::signal;
  173.         $value = $ {$v}{$key} ;
  174.         print "$sp", &stringify($key), " => ";
  175.         DumpElem $value, $s;
  176.     }
  177.     print "$sp  empty hash\n" unless @sortKeys;
  178.     print "$sp$more" if defined $more ;
  179.     } elsif ( UNIVERSAL::isa($v, 'ARRAY') ) { 
  180.     $tArrayDepth = $#{$v} ; 
  181.     undef $more ; 
  182.     $tArrayDepth = $#{$v} < $arrayDepth-1 ? $#{$v} : $arrayDepth-1 
  183.       unless  $arrayDepth eq '' ; 
  184.     $more = "....\n" if $tArrayDepth < $#{$v} ; 
  185.     $shortmore = "";
  186.     $shortmore = " ..." if $tArrayDepth < $#{$v} ;
  187.     if ($compactDump && !grep(ref $_, @{$v})) {
  188.       if ($#$v >= 0) {
  189.         $short = $sp . "0..$#{$v}  " . 
  190.           join(" ", 
  191.            map {stringify $_} @{$v}[0..$tArrayDepth])
  192.         . "$shortmore";
  193.       } else {
  194.         $short = $sp . "empty array";
  195.       }
  196.       (print "$short\n"), return if length $short <= $compactDump;
  197.     }
  198.     #if ($compactDump && $short = ShortArray($v)) {
  199.     #  print "$short\n";
  200.     #  return;
  201.     #}
  202.     for $num ($[ .. $tArrayDepth) {
  203.         return if $DB::signal;
  204.         print "$sp$num  ";
  205.         DumpElem $v->[$num], $s;
  206.     }
  207.     print "$sp  empty array\n" unless @$v;
  208.     print "$sp$more" if defined $more ;  
  209.     } elsif (  UNIVERSAL::isa($v, 'SCALAR') or ref $v eq 'REF' ) { 
  210.         print "$sp-> ";
  211.         DumpElem $$v, $s;
  212.     } elsif ( UNIVERSAL::isa($v, 'CODE') ) { 
  213.         print "$sp-> ";
  214.         dumpsub (0, $v);
  215.     } elsif ( UNIVERSAL::isa($v, 'GLOB') ) {
  216.       print "$sp-> ",&stringify($$v,1),"\n";
  217.       if ($globPrint) {
  218.     $s += 3;
  219.     dumpglob($s, "{$$v}", $$v, 1);
  220.       } elsif (defined ($fileno = fileno($v))) {
  221.     print( (' ' x ($s+3)) .  "FileHandle({$$v}) => fileno($fileno)\n" );
  222.       }
  223.     } elsif (ref \$v eq 'GLOB') {
  224.       if ($globPrint) {
  225.     dumpglob($s, "{$v}", $v, 1) if $globPrint;
  226.       } elsif (defined ($fileno = fileno(\$v))) {
  227.     print( (' ' x $s) .  "FileHandle({$v}) => fileno($fileno)\n" );
  228.       }
  229.     }
  230. }
  231.  
  232. sub matchvar {
  233.   $_[0] eq $_[1] or 
  234.     ($_[1] =~ /^([!~])(.)([\x00-\xff]*)/) and 
  235.       ($1 eq '!') ^ (eval {($_[2] . "::" . $_[0]) =~ /$2$3/});
  236. }
  237.  
  238. sub compactDump {
  239.   $compactDump = shift if @_;
  240.   $compactDump = 6*80-1 if $compactDump and $compactDump < 2;
  241.   $compactDump;
  242. }
  243.  
  244. sub veryCompact {
  245.   $veryCompact = shift if @_;
  246.   compactDump(1) if !$compactDump and $veryCompact;
  247.   $veryCompact;
  248. }
  249.  
  250. sub unctrlSet {
  251.   if (@_) {
  252.     my $in = shift;
  253.     if ($in eq 'unctrl' or $in eq 'quote') {
  254.       $unctrl = $in;
  255.     } else {
  256.       print "Unknown value for `unctrl'.\n";
  257.     }
  258.   }
  259.   $unctrl;
  260. }
  261.  
  262. sub quote {
  263.   if (@_ and $_[0] eq '"') {
  264.     $tick = '"';
  265.     $unctrl = 'quote';
  266.   } elsif (@_ and $_[0] eq 'auto') {
  267.     $tick = 'auto';
  268.     $unctrl = 'quote';
  269.   } elsif (@_) {        # Need to set
  270.     $tick = "'";
  271.     $unctrl = 'unctrl';
  272.   }
  273.   $tick;
  274. }
  275.  
  276. sub dumpglob {
  277.     return if $DB::signal;
  278.     my ($off,$key, $val, $all) = @_;
  279.     local(*entry) = $val;
  280.     my $fileno;
  281.     if (($key !~ /^_</ or $dumpDBFiles) and defined $entry) {
  282.       print( (' ' x $off) . "\$", &unctrl($key), " = " );
  283.       DumpElem $entry, 3+$off;
  284.     }
  285.     if (($key !~ /^_</ or $dumpDBFiles) and defined @entry) {
  286.       print( (' ' x $off) . "\@$key = (\n" );
  287.       unwrap(\@entry,3+$off) ;
  288.       print( (' ' x $off) .  ")\n" );
  289.     }
  290.     if ($key ne "main::" && $key ne "DB::" && defined %entry
  291.     && ($dumpPackages or $key !~ /::$/)
  292.     && ($key !~ /^_</ or $dumpDBFiles)
  293.     && !($package eq "dumpvar" and $key eq "stab")) {
  294.       print( (' ' x $off) . "\%$key = (\n" );
  295.       unwrap(\%entry,3+$off) ;
  296.       print( (' ' x $off) .  ")\n" );
  297.     }
  298.     if (defined ($fileno = fileno(*entry))) {
  299.       print( (' ' x $off) .  "FileHandle($key) => fileno($fileno)\n" );
  300.     }
  301.     if ($all) {
  302.       if (defined &entry) {
  303.     dumpsub($off, $key);
  304.       }
  305.     }
  306. }
  307.  
  308. sub dumpsub {
  309.     my ($off,$sub) = @_;
  310.     $sub = $1 if $sub =~ /^\{\*(.*)\}$/;
  311.     my $subref = \&$sub;
  312.     my $place = $DB::sub{$sub} || (($sub = $subs{"$subref"}) && $DB::sub{$sub})
  313.       || ($subdump && ($sub = findsubs("$subref")) && $DB::sub{$sub});
  314.     $place = '???' unless defined $place;
  315.     print( (' ' x $off) .  "&$sub in $place\n" );
  316. }
  317.  
  318. sub findsubs {
  319.   return undef unless defined %DB::sub;
  320.   my ($addr, $name, $loc);
  321.   while (($name, $loc) = each %DB::sub) {
  322.     $addr = \&$name;
  323.     $subs{"$addr"} = $name;
  324.   }
  325.   $subdump = 0;
  326.   $subs{ shift() };
  327. }
  328.  
  329. sub main::dumpvar {
  330.     my ($package,@vars) = @_;
  331.     local(%address,$key,$val,$^W);
  332.     $package .= "::" unless $package =~ /::$/;
  333.     *stab = *{"main::"};
  334.     while ($package =~ /(\w+?::)/g){
  335.       *stab = $ {stab}{$1};
  336.     }
  337.     local $TotalStrings = 0;
  338.     local $Strings = 0;
  339.     local $CompleteTotal = 0;
  340.     while (($key,$val) = each(%stab)) {
  341.       return if $DB::signal;
  342.       next if @vars && !grep( matchvar($key, $_), @vars );
  343.       if ($usageOnly) {
  344.     globUsage(\$val, $key) unless $package eq 'dumpvar' and $key eq 'stab';
  345.       } else {
  346.     dumpglob(0,$key, $val);
  347.       }
  348.     }
  349.     if ($usageOnly) {
  350.       print "String space: $TotalStrings bytes in $Strings strings.\n";
  351.       $CompleteTotal += $TotalStrings;
  352.       print "Grand total = $CompleteTotal bytes (1 level deep) + overhead.\n";
  353.     }
  354. }
  355.  
  356. sub scalarUsage {
  357.   my $size = length($_[0]);
  358.   $TotalStrings += $size;
  359.   $Strings++;
  360.   $size;
  361. }
  362.  
  363. sub arrayUsage {        # array ref, name
  364.   my $size = 0;
  365.   map {$size += scalarUsage($_)} @{$_[0]};
  366.   my $len = @{$_[0]};
  367.   print "\@$_[1] = $len item", ($len > 1 ? "s" : ""),
  368.     " (data: $size bytes)\n"
  369.       if defined $_[1];
  370.   $CompleteTotal +=  $size;
  371.   $size;
  372. }
  373.  
  374. sub hashUsage {        # hash ref, name
  375.   my @keys = keys %{$_[0]};
  376.   my @values = values %{$_[0]};
  377.   my $keys = arrayUsage \@keys;
  378.   my $values = arrayUsage \@values;
  379.   my $len = @keys;
  380.   my $total = $keys + $values;
  381.   print "\%$_[1] = $len item", ($len > 1 ? "s" : ""),
  382.     " (keys: $keys; values: $values; total: $total bytes)\n"
  383.       if defined $_[1];
  384.   $total;
  385. }
  386.  
  387. sub globUsage {            # glob ref, name
  388.   local *name = *{$_[0]};
  389.   $total = 0;
  390.   $total += scalarUsage $name if defined $name;
  391.   $total += arrayUsage \@name, $_[1] if defined @name;
  392.   $total += hashUsage \%name, $_[1] if defined %name and $_[1] ne "main::" 
  393.     and $_[1] ne "DB::";   #and !($package eq "dumpvar" and $key eq "stab"));
  394.   $total;
  395. }
  396.  
  397. sub packageUsage {
  398.   my ($package,@vars) = @_;
  399.   $package .= "::" unless $package =~ /::$/;
  400.   local *stab = *{"main::"};
  401.   while ($package =~ /(\w+?::)/g){
  402.     *stab = $ {stab}{$1};
  403.   }
  404.   local $TotalStrings = 0;
  405.   local $CompleteTotal = 0;
  406.   my ($key,$val);
  407.   while (($key,$val) = each(%stab)) {
  408.     next if @vars && !grep($key eq $_,@vars);
  409.     globUsage \$val, $key unless $package eq 'dumpvar' and $key eq 'stab';
  410.   }
  411.   print "String space: $TotalStrings.\n";
  412.   $CompleteTotal += $TotalStrings;
  413.   print "\nGrand total = $CompleteTotal bytes\n";
  414. }
  415.  
  416. 1;
  417.  
  418.