use vars
qw(@EXPORT_OK $VERSION $DEBUG);
*import = \&Exporter::import;
$VERSION = "1.02"; # $Date: 2003/12/18 09:27:35 $
use vars
qw(%seen %refcnt @dump @fixup %require);
my %is_perl_keyword = map { $_ => 1 }
qw( __FILE__ __LINE__ __PACKAGE__ __DATA__ __END__ AUTOLOAD BEGIN CORE
DESTROY END EQ GE GT INIT LE LT NE abs accept alarm and atan2 bind
binmode bless caller chdir chmod chomp chop chown chr chroot close
closedir cmp connect continue cos crypt dbmclose dbmopen defined
delete die do dump each else elsif endgrent endhostent endnetent
endprotoent endpwent endservent eof eq eval exec exists exit exp fcntl
fileno flock for foreach fork format formline ge getc getgrent
getgrgid getgrnam gethostbyaddr gethostbyname gethostent getlogin
getnetbyaddr getnetbyname getnetent getpeername getpgrp getppid
getpriority getprotobyname getprotobynumber getprotoent getpwent
getpwnam getpwuid getservbyname getservbyport getservent getsockname
getsockopt glob gmtime goto grep gt hex if index int ioctl join keys
kill last lc lcfirst le length link listen local localtime lock log
lstat lt m map mkdir msgctl msgget msgrcv msgsnd my ne next no not oct
open opendir or ord pack package pipe pop pos print printf prototype
push q qq qr quotemeta qw qx rand read readdir readline readlink
readpipe recv redo ref rename require reset return reverse rewinddir
rindex rmdir s scalar seek seekdir select semctl semget semop send
setgrent sethostent setnetent setpgrp setpriority setprotoent setpwent
setservent setsockopt shift shmctl shmget shmread shmwrite shutdown
sin sleep socket socketpair sort splice split sprintf sqrt srand stat
study sub substr symlink syscall sysopen sysread sysseek system
syswrite tell telldir tie tied time times tr truncate uc ucfirst umask
undef unless unlink unpack unshift untie until use utime values vec
wait waitpid wantarray warn while write x xor y);
my $val = _dump
($_, $name, []);
push(@dump, [$name, $val]);
for (sort keys %require) {
# output all those with refcounts first
$out .= "my \$$name = $_->[1];\n";
my $paren = (@dump != 1);
$out .= format_list
($paren,
map {defined($_->[1]) ?
$_->[1] : "\$".$_->[0]}
if (%refcnt || %require) {
$out =~ s/^/ /gm; # indent
#use Data::Dumper; print Dumper(\%refcnt);
#use Data::Dumper; print Dumper(\%seen);
print STDERR
"$out\n" unless defined wantarray;
my $rval = $ref ?
$_[0] : \
$_[0];
if (overload
::StrVal
($rval) =~ /^(?:([^=]+)=)?([A-Z]+)\(0x([^\)]+)\)$/) {
die "Can't parse " . overload
::StrVal
($rval);
warn "$name-(@$idx) $class $type $id ($ref)" if $DEBUG;
if (my $s = $seen{$id}) {
my $sref = fullname
($sname, $sidx,
($ref && $type eq "SCALAR"));
warn "SEEN: [$name/@$idx] => [$sname/@$sidx] ($ref,$sref)" if $DEBUG;
return $sref unless $sname eq $name;
push(@fixup, fullname
($name,$idx)." = $sref");
$seen{$id} = [$name, $idx];
if ($type eq "SCALAR" || $type eq "REF") {
if ($class && $class eq "Regexp") {
if ($v =~ /^\(\?([msix-]+):([\x00-\xFF]*)\)\z/) {
my $sep_count = ($v =~ tr/\///);
# see if we can find a better one
for ('|', ',', ':', '#') {
my $c = eval "\$v =~ tr/\Q$_\E//";
#print "SEP $_ $c $sep_count\n";
$v =~ s/\Q$sep\E/\\$sep/g;
$out = "qr$sep$v$sep$mod";
delete $seen{$id}; # will be seen again shortly
my $val = _dump
($$rval, $name, [@
$idx, "\$"]);
$out = $class ?
"do{\\(my \$o = $val)}" : "\\$val";
elsif ($$rval =~ /^-?[1-9]\d{0,8}$/ || $$rval eq "0") {
# Separate thousands by _ to make it more readable
$out =~ s/(\d\d\d)(?=\d)/$1_/g;
# Top is an object, not a reference to one as perl needs
my $obj = fullname
($name, $idx);
push(@fixup, "bless \\$obj, $cl");
elsif ($type eq "GLOB") {
my $val = _dump
($$rval, $name, [@
$idx, "*"]);
if ($out =~ /^\\\*Symbol::/) {
$out = "Symbol::gensym()";
for my $k (qw(SCALAR ARRAY HASH)) {
next unless defined $gval;
next if $k eq "SCALAR" && ! defined $$gval; # always there
push(@fixup, "RESERVED"); # overwritten after _dump() below
$gval = _dump
($gval, $name, [@
$idx, "*{$k}"]);
my $gname = fullname
($name, $idx);
$fixup[$f] = "$gname = $gval"; #XXX indent $gval
elsif ($type eq "ARRAY") {
push(@vals, _dump
($_, $name, [@
$idx, "[$i]"]));
$out = "[" . format_list
(1, @vals) . "]";
elsif ($type eq "HASH") {
# statistics to determine variation in key lengths
my @orig_keys = keys %$rval;
$text_keys++, last unless $_ eq "0" || /^[-+]?[1-9]\d*(?:.\d+)?\z/;
@orig_keys = sort @orig_keys;
@orig_keys = sort { $a <=> $b } @orig_keys;
for my $key (@orig_keys) {
my $val = \
$rval->{$key};
$key = quote
($key) if $is_perl_keyword{$key} ||
!($key =~ /^[a-zA-Z_]\w{0,19}\z/ ||
$key =~ /^-?[1-9]\d{0,8}\z/
$kstat_max = length($key) if length($key) > $kstat_max;
$kstat_sum += length($key);
$kstat_sum2 += length($key)*length($key);
push(@vals, _dump
($$val, $name, [@
$idx, "{$key}"]));
if (length($tmp) > 60 || $tmp =~ /\n/) {
# Determine what padding to add
my $stddev = sqrt(($kstat_sum2 - $n * $avg * $avg) / ($n - 1));
# I am not actually very happy with this heuristics
if ($stddev / $kstat_max < 0.25) {
push(@vals, sprintf("%.2f (%d/%.1f/%.1f)",
$kstat_max, $avg, $stddev));
my $pad = " " x
($klen_pad + 6);
$key = " $key" . " " x
($klen_pad - length($key)) if $nl;
$out .= " $key => $val,$nl";
$out =~ s/,$/ / unless $nl;
elsif ($type eq "CODE") {
warn "Can't handle $type data";
$out = "bless($out, " . quote
($class) . ")";
my($name, $idx, $ref) = @_;
substr($name, 0, 0) = "\$";
my @i = @
$idx; # need copy in order to not modify @$idx
if ($ref && @i && $i[0] eq "\$") {
shift(@i); # remove one deref
while (@i && $i[0] eq "\$") {
if ($i eq "*" || $i eq "\$") {
} elsif ($i =~ s/^\*//) {
$name .= "->" unless $last_was_index++;
$name = "\\$name" if $ref;
my $indent_lim = $paren ?
0 : 1;
if (@_ > $indent_lim && (length($tmp) > 60 || $tmp =~ /\n/)) {
for (@elem) { s/^/ /gm; } # indent
return "\n" . join(",\n", @elem, "");
# put a string value in double quotes
# Check for repeated string
if (/^(.{1,5}?)(\1*)$/s) {
my $repeat = length($2)/length($1) + 1;
return "($base x $repeat)";
# If there are many '"' we might want to use qq() instead
return qq("$_") unless /[^\040-\176]/; # fast exit
s/([\a\b\t\n\f\r\e])/$esc{$1}/g;
# no need for 3 digits in escape for these
s/([\0-\037])(?!\d)/'\\'.sprintf('%o',ord($1))/eg;
s/([\0-\037\177])/'\\'.sprintf('%03o',ord($1))/eg;
if ($high eq "iso8859") {
s/[\200-\240]/'\\'.sprintf('%o',ord($1))/eg;
} elsif ($high eq "utf8") {
# $str =~ s/([^\040-\176])/sprintf "\\x{%04x}", ord($1)/ge;
s/([\0-\037\177-\377])/'\\'.sprintf('%03o',ord($1))/eg;
if (length($_) > 40 && length($_) > (length($_[0]) * 2)) {
# too much binary data, better to represent as a hex string?
# Base64 is more compact than hex when string is longer than
# 17 bytes (not counting any require statement needed).
# But on the other hand, hex is much more readable.
if (length($_[0]) > 50 && eval { require MIME
::Base64
}) {
# XXX Perhaps we should just use unpack("u",...) instead.
$require{"MIME::Base64"}++;
return "MIME::Base64::decode(\"" .
MIME
::Base64
::encode
($_[0],"") .
return "pack(\"H*\",\"" . unpack("H*", $_[0]) . "\")";
Data::Dump - Pretty printing of data structures
@copy_of_list = eval $str;
This module provides a single function called dump() that takes a list
of values as its argument and produces a string as its result. The string
contains Perl code that, when C<eval>ed, produces a deep copy of the
original arguments. The string is formatted for easy reading.
If dump() is called in a void context, then the dump is printed on
STDERR instead of being returned.
If you don't like importing a function that overrides Perl's
not-so-useful builtin, then you can also import the same function as
pp(), mnemonic for "pretty-print".
The C<Data::Dump> module grew out of frustration with Sarathy's
in-most-cases-excellent C<Data::Dumper>. Basic ideas and some code are shared
The C<Data::Dump> module provides a much simpler interface than
C<Data::Dumper>. No OO interface is available and there are no
configuration options to worry about (yet :-). The other benefit is
that the dump produced does not try to set any variables. It only
returns what is needed to produce a copy of the arguments. This means
that C<dump("foo")> simply returns C<"foo">, and C<dump(1..5)> simply
returns C<(1, 2, 3, 4, 5)>.
L<Data::Dumper>, L<Storable>
The C<Data::Dump> module is written by Gisle Aas <gisle@aas.no>, based
on C<Data::Dumper> by Gurusamy Sarathy <gsar@umich.edu>.
Copyright 1998-2000,2003 Gisle Aas.
Copyright 1996-1998 Gurusamy Sarathy.
This library is free software; you can redistribute it and/or
modify it under the same terms as Perl itself.