#!/usr/bin/perl # # recurse2txt routines # # version 1.08, 12-20-12, michael@bizsystems.com # # 10-3-11 updated to bless into calling package # 10-10-11 add SCALAR ref support # 1.06 12-16-12 add hexDumper # 1.07 12-19-12 added wantarray return of data and elements # 1.08 12-20-12 add wantarray to hexDumper # #use strict; #use diagnostics; use overload; # generate a unique signature for a particular hash # # Data::Dumper actually does much more than this, however, it # does not stringify hash's in a consistent manner. i.e. no SORT # # The routine below, while not covering recursion loops, non ascii # characters, etc.... does produce text that can be eval'd and is # consistent with each rendering. # sub hexDumper { if (wantarray) { ($data,$count) = Dumper($_[0]); $data =~ s/(\b\d+)/sprintf("0x%x",$1)/ge; return ($data,$count); } (my $x = Dumper($_[0])) =~ s/(\b\d+)/sprintf("0x%x",$1)/ge; $x; } sub Dumper { unless (defined $_[0]) { return ("undef\n",'undef') if wantarray; return "undef\n"; } my $ref = ref $_[0]; return "not a reference\n" unless $ref; unless ($ref eq 'HASH' or $ref eq 'ARRAY' or $ref eq 'SCALAR') { ($ref) = (overload::StrVal($_[0]) =~ /^(?:.*\=)?([^=]*)\(/); } my $p = { depth => 0, elements => 0, }; (my $pkg = (caller(0))[3]) =~ s/(.+)::Dumper/$1/; bless $p,$pkg; my $data; if ($ref eq 'HASH') { $data = $p->hash_recurse($_[0],"\n"); } elsif ($ref eq 'ARRAY') { $data = $p->array_recurse($_[0]); } else { # return $ref ." unsupported\n"; $data = $p->scalar_recurse($_[0]); } $data =~ s/,\n$/;\n/; return ($data,$p->{elements}) if wantarray; return $p->{elements} ."\t= ". $data; } # input: pointer to scalar, terminator # returns data # sub scalar_recurse { my($p,$ptr,$n) = @_; $n = '' unless $n; my $data = "\\"; $data .= _dump($p,$$ptr); $data .= "\n"; } # input: pointer to hash, terminator # returns: data # sub hash_recurse { my($p,$ptr,$n) = @_; $n = '' unless $n; my $data = "{\n"; foreach my $key (sort keys %$ptr) { $data .= "\t'". $key ."'\t=> "; $data .= _dump($p,$ptr->{$key},"\n"); } $data .= '},'.$n; } # generate a unique signature for a particular array # # input: pointer to array, terminator # returns: data sub array_recurse { my($p,$ptr,$n) = @_; $n = '' unless $n; my $data = '['; foreach my $item (@$ptr) { $data .= _dump($p,$item); } $data .= "],\n"; } # input: self, item, append # return: data # sub _dump { my($p,$item,$n) = @_; $p->{elements}++; $n = '' unless $n; my $ref = ref $item; if ($ref eq 'HASH') { return tabout($p->hash_recurse($item,"\n")); } elsif($ref eq 'ARRAY') { return $p->array_recurse($item,$n); } elsif($ref eq 'SCALAR') { # return q|\$SCALAR,|.$n; return($p->scalar_recurse($item,$n)); } elsif ($ref eq 'GLOB') { my $g = *{$item}; return "\\$g" .','.$n; } elsif(do {my $g = \$item; ref $g eq 'GLOB'}) { return "$item" .','.$n; } elsif($ref eq 'CODE') { return q|sub {'DUMMY'},|.$n; } elsif (defined $item) { return wrap_data($item) .','.$n; } else { return 'undef,'.$n; } } sub tabout { my @data = split(/\n/,shift); my $data = shift @data; $data .= "\n"; foreach(@data) { $data .= "\t$_\n"; } $data; } sub wrap_data { my $data = shift; return ($data =~ /\D/ || $data =~ /^$/) ? q|'|. $data .q|'| : $data; } 1;