Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

417 lines
11 KiB

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