| line | stmt | bran | cond | sub | pod | time | code | 
| 1 |  |  |  |  |  |  | package Data::Denter; | 
| 2 |  |  |  |  |  |  |  | 
| 3 | 1 |  |  | 1 |  | 241811 | use strict; | 
|  | 1 |  |  |  |  | 3 |  | 
|  | 1 |  |  |  |  | 49 |  | 
| 4 | 1 |  |  | 1 |  | 78 | use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS); | 
|  | 1 |  |  |  |  | 2 |  | 
|  | 1 |  |  |  |  | 101 |  | 
| 5 | 1 |  |  | 1 |  | 5 | use vars qw($Width $Comma $Level $TabWidth $Sort $MaxLines $HashMode); | 
|  | 1 |  |  |  |  | 8 |  | 
|  | 1 |  |  |  |  | 373 |  | 
| 6 |  |  |  |  |  |  | require Exporter; | 
| 7 |  |  |  |  |  |  | @ISA = qw(Exporter); | 
| 8 |  |  |  |  |  |  | @EXPORT = qw(Indent Undent Denter); | 
| 9 |  |  |  |  |  |  | @EXPORT_OK = qw(Dumper); | 
| 10 |  |  |  |  |  |  | %EXPORT_TAGS = (all => [@EXPORT, @EXPORT_OK]); | 
| 11 |  |  |  |  |  |  | $VERSION = '0.15'; | 
| 12 | 1 |  |  | 1 |  | 7 | use Carp; | 
|  | 1 |  |  |  |  | 2 |  | 
|  | 1 |  |  |  |  | 5556 |  | 
| 13 |  |  |  |  |  |  |  | 
| 14 |  |  |  |  |  |  | sub Indent { | 
| 15 | 10 | 100 |  | 10 | 1 | 1769 | $Sort = 1 unless defined $Sort; | 
| 16 | 10 |  | 50 |  |  | 175 | Data::Denter->new(width => $Width || 4, | 
|  |  |  | 50 |  |  |  |  | 
|  |  |  | 50 |  |  |  |  | 
|  |  |  | 50 |  |  |  |  | 
|  |  |  | 100 |  |  |  |  | 
| 17 |  |  |  |  |  |  | level => $Level || 0, | 
| 18 |  |  |  |  |  |  | comma => $Comma || " => ", | 
| 19 |  |  |  |  |  |  | sort => $Sort, | 
| 20 |  |  |  |  |  |  | maxlines => $MaxLines || 0, | 
| 21 |  |  |  |  |  |  | hashmode => $HashMode || 0, | 
| 22 |  |  |  |  |  |  | )->indent(@_); | 
| 23 |  |  |  |  |  |  | }; | 
| 24 |  |  |  |  |  |  | *Denter = \&Indent; | 
| 25 |  |  |  |  |  |  | *Dumper = \&Indent; | 
| 26 |  |  |  |  |  |  |  | 
| 27 |  |  |  |  |  |  | sub Undent { | 
| 28 | 10 |  | 50 | 10 | 1 | 216 | Data::Denter->new(width => $Width || 4, | 
|  |  |  | 50 |  |  |  |  | 
|  |  |  | 50 |  |  |  |  | 
|  |  |  | 100 |  |  |  |  | 
| 29 |  |  |  |  |  |  | tabwidth => $TabWidth || 8, | 
| 30 |  |  |  |  |  |  | comma => $Comma || " => ", | 
| 31 |  |  |  |  |  |  | hashmode => $HashMode || 0, | 
| 32 |  |  |  |  |  |  | )->undent(@_); | 
| 33 |  |  |  |  |  |  | }; | 
| 34 |  |  |  |  |  |  |  | 
| 35 |  |  |  |  |  |  | # General error messages | 
| 36 |  |  |  |  |  |  | sub invalid_usage { | 
| 37 | 0 |  |  | 0 | 0 | 0 | "Invalid usage of the $_[0] method\n"; | 
| 38 |  |  |  |  |  |  | } | 
| 39 |  |  |  |  |  |  |  | 
| 40 |  |  |  |  |  |  | # Indent error messages | 
| 41 |  |  |  |  |  |  | sub invalid_name_level { | 
| 42 | 0 |  |  | 0 | 0 | 0 | "Can't indent a typeglob name at indentation level $_[0]\n"; | 
| 43 |  |  |  |  |  |  | } | 
| 44 |  |  |  |  |  |  |  | 
| 45 |  |  |  |  |  |  | sub invalid_hashmode_key { | 
| 46 | 0 |  |  | 0 | 0 | 0 | my $key = shift; | 
| 47 | 0 |  |  |  |  | 0 | < | 
| 48 |  |  |  |  |  |  | You are using Data::Denter and you have specified a "key" that is invalid: | 
| 49 |  |  |  |  |  |  | "$key" | 
| 50 |  |  |  |  |  |  | The keys must be string values containing only word characters. | 
| 51 |  |  |  |  |  |  | END | 
| 52 |  |  |  |  |  |  | } | 
| 53 |  |  |  |  |  |  |  | 
| 54 |  |  |  |  |  |  | # Undent error messages | 
| 55 |  |  |  |  |  |  | sub invalid_indent_width { | 
| 56 | 0 |  |  | 0 | 0 | 0 | my $o = shift; | 
| 57 | 0 |  |  |  |  | 0 | "Invalid indent width detected at line $o->{line}\n"; | 
| 58 |  |  |  |  |  |  | } | 
| 59 |  |  |  |  |  |  |  | 
| 60 |  |  |  |  |  |  | sub no_key_end_marker { | 
| 61 | 0 |  |  | 0 | 0 | 0 | my ($marker, $line) = @_; | 
| 62 | 0 |  |  |  |  | 0 | "No terminating marker '$marker' found for key at line $line\n"; | 
| 63 |  |  |  |  |  |  | } | 
| 64 |  |  |  |  |  |  |  | 
| 65 |  |  |  |  |  |  | sub no_value_end_marker { | 
| 66 | 0 |  |  | 0 | 0 | 0 | my ($marker, $line) = @_; | 
| 67 | 0 |  |  |  |  | 0 | "No terminating marker '$marker' found for value at line $line\n"; | 
| 68 |  |  |  |  |  |  | } | 
| 69 |  |  |  |  |  |  |  | 
| 70 |  |  |  |  |  |  | sub mismatched_quotes { | 
| 71 | 0 |  |  | 0 | 0 | 0 | my $o = shift; | 
| 72 | 0 |  |  |  |  | 0 | "Mismatched double quotes for value at line $o->{line}\n"; | 
| 73 |  |  |  |  |  |  | } | 
| 74 |  |  |  |  |  |  |  | 
| 75 |  |  |  |  |  |  | sub invalid_key_value { | 
| 76 | 0 |  |  | 0 | 0 | 0 | my $o = shift; | 
| 77 | 0 |  |  |  |  | 0 | "Missing or invalid hash key/value pair at $o->{line}\n"; | 
| 78 |  |  |  |  |  |  | } | 
| 79 |  |  |  |  |  |  |  | 
| 80 |  |  |  |  |  |  | sub invalid_indent_level { | 
| 81 | 0 |  |  | 0 | 0 | 0 | my $o = shift; | 
| 82 | 0 |  |  |  |  | 0 | "Invalid indentation level at $o->{line}\n"; | 
| 83 |  |  |  |  |  |  | } | 
| 84 |  |  |  |  |  |  |  | 
| 85 |  |  |  |  |  |  | sub invalid_scalar_value { | 
| 86 | 0 |  |  | 0 | 0 | 0 | my $o = shift; | 
| 87 | 0 |  |  |  |  | 0 | "Invalid value for scalar ref context at $o->{line}\n"; | 
| 88 |  |  |  |  |  |  | } | 
| 89 |  |  |  |  |  |  |  | 
| 90 |  |  |  |  |  |  | sub no_such_ref { | 
| 91 | 0 |  |  | 0 | 0 | 0 | my $ref = shift; | 
| 92 | 0 |  |  |  |  | 0 | "Cannot dereference '$ref'. Not previously defined\n"; | 
| 93 |  |  |  |  |  |  | } | 
| 94 |  |  |  |  |  |  |  | 
| 95 |  |  |  |  |  |  | sub new { | 
| 96 | 20 |  |  | 20 | 0 | 34 | my $class = shift; | 
| 97 | 20 |  |  |  |  | 82 | my %args = @_; | 
| 98 | 20 | 100 |  |  |  | 59 | $args{sort} = 1 unless defined $args{sort}; | 
| 99 | 20 |  | 50 |  |  | 431 | bless {__DATA__DENTER__ => 1, | 
|  |  |  | 50 |  |  |  |  | 
|  |  |  | 50 |  |  |  |  | 
|  |  |  | 100 |  |  |  |  | 
|  |  |  | 50 |  |  |  |  | 
|  |  |  | 100 |  |  |  |  | 
| 100 |  |  |  |  |  |  | width => $args{width} || 4, | 
| 101 |  |  |  |  |  |  | comma => $args{comma} || " => ", | 
| 102 |  |  |  |  |  |  | level => $args{level} || 0, | 
| 103 |  |  |  |  |  |  | tabwidth => $args{tabwidth} || 8, | 
| 104 |  |  |  |  |  |  | sort => $args{sort}, | 
| 105 |  |  |  |  |  |  | maxlines => $args{maxlines} || 0, | 
| 106 |  |  |  |  |  |  | hashmode => $args{hashmode} || 0, | 
| 107 |  |  |  |  |  |  | }, $class; | 
| 108 |  |  |  |  |  |  | } | 
| 109 |  |  |  |  |  |  |  | 
| 110 |  |  |  |  |  |  | sub indent { | 
| 111 | 10 |  |  | 10 | 0 | 13 | my $o = shift; | 
| 112 | 10 | 50 |  |  |  | 31 | croak invalid_usage('indent') unless $o->{__DATA__DENTER__}; | 
| 113 | 10 |  |  |  |  | 20 | my $package = caller; | 
| 114 | 10 | 50 |  |  |  | 33 | $package = caller(1) if $package eq 'Data::Denter'; | 
| 115 | 10 |  |  |  |  | 17 | my $stream = ''; | 
| 116 | 10 |  |  |  |  | 20 | $o->{key} = ''; | 
| 117 | 10 |  |  |  |  | 28 | while (@_) { | 
| 118 | 11 |  |  |  |  | 16 | $_ = shift; | 
| 119 | 11 | 100 |  |  |  | 26 | if ($o->{hashmode}) { | 
| 120 | 2 | 50 | 33 |  |  | 19 | croak invalid_hashmode_key($_) | 
| 121 |  |  |  |  |  |  | if (ref or not /^\w+$/); | 
| 122 | 2 |  |  |  |  | 14 | $stream .= $o->_indent_name("*${package}::$_", shift); | 
| 123 | 2 |  |  |  |  | 6 | next; | 
| 124 |  |  |  |  |  |  | } | 
| 125 | 9 | 100 |  |  |  | 83 | $stream .= $o->_indent_name($_, shift), next | 
| 126 |  |  |  |  |  |  | if (/^\*$package\::\w+$/); | 
| 127 | 8 |  |  |  |  | 21 | $stream .= $o->_indent_data($_); | 
| 128 |  |  |  |  |  |  | } | 
| 129 | 10 |  |  |  |  | 96 | $o->_resolve(\$stream); | 
| 130 | 10 |  |  |  |  | 43 | return $stream; | 
| 131 |  |  |  |  |  |  | } | 
| 132 |  |  |  |  |  |  |  | 
| 133 |  |  |  |  |  |  | sub _indent_data { | 
| 134 | 35 |  |  | 35 |  | 55 | my $o = shift; | 
| 135 | 35 |  |  |  |  | 52 | $_ = shift; | 
| 136 | 35 | 100 |  |  |  | 72 | return $o->_indent_undef($_) | 
| 137 |  |  |  |  |  |  | if not defined; | 
| 138 | 34 | 100 |  |  |  | 93 | return $o->_indent_value($_) | 
| 139 |  |  |  |  |  |  | if (not ref); | 
| 140 | 24 | 100 | 66 |  |  | 189 | return $o->_indent_hash($_) | 
|  |  |  | 100 |  |  |  |  | 
| 141 |  |  |  |  |  |  | if (ref eq 'HASH' and not /=/ or /=HASH/); | 
| 142 | 21 | 100 | 66 |  |  | 149 | return $o->_indent_array($_) | 
|  |  |  | 66 |  |  |  |  | 
| 143 |  |  |  |  |  |  | if (ref eq 'ARRAY' and not /=/ or /=ARRAY/); | 
| 144 | 16 | 100 | 66 |  |  | 166 | return $o->_indent_ref($_, $1) | 
| 145 |  |  |  |  |  |  | if (ref eq 'REF' and /^(SCALAR|REF)\(/); | 
| 146 | 2 | 50 | 33 |  |  | 25 | return $o->_indent_scalar($_) | 
|  |  |  | 33 |  |  |  |  | 
| 147 |  |  |  |  |  |  | if (ref eq 'SCALAR' and not /=/ or /=SCALAR/); | 
| 148 | 0 |  |  |  |  | 0 | return "$_\n"; | 
| 149 |  |  |  |  |  |  | } | 
| 150 |  |  |  |  |  |  |  | 
| 151 |  |  |  |  |  |  | sub _indent_value { | 
| 152 | 10 |  |  | 10 |  | 17 | my ($o, $data) = @_; | 
| 153 | 10 |  |  |  |  | 13 | my $stream; | 
| 154 | 10 | 100 | 33 |  |  | 341 | if ($data =~ /\n/) { | 
|  |  | 100 | 66 |  |  |  |  | 
|  |  |  | 66 |  |  |  |  | 
| 155 | 1 |  |  |  |  | 3 | my $marker = 'EOV'; | 
| 156 | 1 |  |  |  |  | 19 | $marker++ while $data =~ /^$marker$/m; | 
| 157 | 1 | 50 |  |  |  | 9 | my $chomp = ($data =~ s/\n\Z//) ? '' : '-'; | 
| 158 | 1 |  |  |  |  | 4 | $stream = "<<$marker$chomp\n"; | 
| 159 | 1 | 50 |  |  |  | 5 | $stream .= $o->{key}, $o->{key} = '' if $o->{key}; | 
| 160 | 1 |  |  |  |  | 6 | my @data = split /\n/, $data, -1; | 
| 161 | 1 |  |  |  |  | 3 | $data = ''; | 
| 162 | 1 | 50 | 33 |  |  | 7 | if ($o->{maxlines} and @data > $o->{maxlines}) { | 
| 163 | 0 |  |  |  |  | 0 | my $notshown = @data - $o->{maxlines}; | 
| 164 | 0 |  |  |  |  | 0 | $#data = $o->{maxlines} - 1; | 
| 165 | 0 |  |  |  |  | 0 | push @data, "*** $notshown lines not displayed ***"; | 
| 166 |  |  |  |  |  |  | } | 
| 167 | 1 |  |  |  |  | 2 | for (@data) { | 
| 168 | 3 |  |  |  |  | 10 | s/([\x00-\x08\x0b-\x1f%\x7f-\xff])/'%'.sprintf('%02x',ord($1))/eg; | 
|  | 2 |  |  |  |  | 12 |  | 
| 169 | 3 |  |  |  |  | 13 | $data .= "$_\n"; | 
| 170 |  |  |  |  |  |  | } | 
| 171 | 1 |  |  |  |  | 3 | chomp $data; | 
| 172 | 1 |  |  |  |  | 5 | $stream .= "$data\n$marker\n"; | 
| 173 |  |  |  |  |  |  | } | 
| 174 |  |  |  |  |  |  | elsif ($data =~ /^[\s\%\@\$\\?\"]|\s$/ or | 
| 175 |  |  |  |  |  |  | $data =~ /\Q$o->{comma}\E/ or | 
| 176 |  |  |  |  |  |  | $data =~ /([\x00-\x1f\x7f-\xff])/ or | 
| 177 |  |  |  |  |  |  | $data eq '') { | 
| 178 | 1 |  |  |  |  | 8 | $data =~ s/([\x00-\x1f%\x7f-\xff])/'%'.sprintf('%02x',ord($1))/eg; | 
|  | 3 |  |  |  |  | 17 |  | 
| 179 | 1 |  |  |  |  | 4 | $stream = qq{"$data"\n}; | 
| 180 | 1 | 50 |  |  |  | 6 | $stream .= $o->{key}, $o->{key} = '' if $o->{key}; | 
| 181 |  |  |  |  |  |  | } | 
| 182 |  |  |  |  |  |  | else { | 
| 183 | 8 |  |  |  |  | 10 | $stream = "$data\n"; | 
| 184 | 8 | 50 |  |  |  | 24 | $stream .= $o->{key}, $o->{key} = '' if $o->{key}; | 
| 185 |  |  |  |  |  |  | } | 
| 186 | 10 |  |  |  |  | 36 | return $stream; | 
| 187 |  |  |  |  |  |  | } | 
| 188 |  |  |  |  |  |  |  | 
| 189 |  |  |  |  |  |  | sub _indent_hash { | 
| 190 | 3 |  |  | 3 |  | 5 | my ($o, $data) = @_; | 
| 191 | 3 |  |  |  |  | 12 | my $stream = $o->_print_ref($data, '%', 'HASH'); | 
| 192 | 3 | 50 |  |  |  | 10 | return $$stream if ref $stream; | 
| 193 | 3 |  |  |  |  | 11 | my $indent = ++$o->{level} * $o->{width}; | 
| 194 | 3 | 50 |  |  |  | 16 | for my $key ($o->{sort} ? | 
| 195 |  |  |  |  |  |  | (sort keys %$data) : | 
| 196 |  |  |  |  |  |  | (keys %$data) | 
| 197 |  |  |  |  |  |  | ) { | 
| 198 | 2 |  |  |  |  | 4 | my $key_out = $key; | 
| 199 | 2 | 50 | 33 |  |  | 52 | if ($key =~ /\n/ or | 
|  |  | 50 | 33 |  |  |  |  | 
| 200 |  |  |  |  |  |  | $key =~ /\Q$o->{comma}\E/) { | 
| 201 | 0 |  |  |  |  | 0 | my $marker = 'EOK'; | 
| 202 | 0 |  |  |  |  | 0 | $marker++ while $key =~ /^$marker$/m; | 
| 203 | 0 | 0 |  |  |  | 0 | my $chomp = (($o->{key} = $key) =~ s/\n\Z//m) ? '' : '-'; | 
| 204 | 0 |  |  |  |  | 0 | $o->{key} .= "\n$marker\n"; | 
| 205 | 0 |  |  |  |  | 0 | $key_out = "<<$marker$chomp"; | 
| 206 |  |  |  |  |  |  | } | 
| 207 |  |  |  |  |  |  | elsif ($key =~ /^[\s\%\@\$\\?\"]|\s$/ | 
| 208 |  |  |  |  |  |  | or $key eq '') { | 
| 209 | 0 |  |  |  |  | 0 | $key_out = qq{"$key"}; | 
| 210 |  |  |  |  |  |  | } | 
| 211 | 2 |  |  |  |  | 10 | $stream .= ' ' x $indent . $key_out . $o->{comma}; | 
| 212 | 2 |  |  |  |  | 13 | $stream .= $o->_indent_data($data->{$key}); | 
| 213 |  |  |  |  |  |  | } | 
| 214 | 3 |  |  |  |  | 6 | $o->{level}--; | 
| 215 | 3 |  |  |  |  | 17 | return $stream; | 
| 216 |  |  |  |  |  |  | } | 
| 217 |  |  |  |  |  |  |  | 
| 218 |  |  |  |  |  |  | sub _indent_array { | 
| 219 | 5 |  |  | 5 |  | 9 | my ($o, $data) = @_; | 
| 220 | 5 |  |  |  |  | 16 | my $stream = $o->_print_ref($data, '@', 'ARRAY'); | 
| 221 | 5 | 100 |  |  |  | 18 | return $$stream if ref $stream; | 
| 222 | 4 |  |  |  |  | 12 | my $indent = ++$o->{level} * $o->{width}; | 
| 223 | 4 |  |  |  |  | 9 | for my $datum (@$data) { | 
| 224 | 10 |  |  |  |  | 25 | $stream .= ' ' x $indent; | 
| 225 | 10 |  |  |  |  | 26 | $stream .= $o->_indent_data($datum); | 
| 226 |  |  |  |  |  |  | } | 
| 227 | 4 |  |  |  |  | 9 | $o->{level}--; | 
| 228 | 4 |  |  |  |  | 26 | return $stream; | 
| 229 |  |  |  |  |  |  | } | 
| 230 |  |  |  |  |  |  |  | 
| 231 |  |  |  |  |  |  | sub _indent_scalar { | 
| 232 | 2 |  |  | 2 |  | 6 | my ($o, $data) = @_; | 
| 233 | 2 |  |  |  |  | 10 | my $stream = $o->_print_ref($data, q{$}, 'SCALAR'); | 
| 234 | 2 | 50 |  |  |  | 8 | return $$stream if ref $stream; | 
| 235 | 2 |  |  |  |  | 9 | my $indent = ($o->{level} + 1) * $o->{width}; | 
| 236 | 2 |  |  |  |  | 6 | $stream .= ' ' x $indent; | 
| 237 | 2 |  |  |  |  | 11 | $stream .= $o->_indent_data($$data); | 
| 238 | 2 |  |  |  |  | 18 | return $stream; | 
| 239 |  |  |  |  |  |  | } | 
| 240 |  |  |  |  |  |  |  | 
| 241 |  |  |  |  |  |  | sub _indent_ref { | 
| 242 | 14 |  |  | 14 |  | 34 | my ($o, $data, $type) = @_; | 
| 243 | 14 |  |  |  |  | 34 | my $stream = $o->_print_ref($data, '\\', $type); | 
| 244 | 14 | 100 |  |  |  | 54 | return $$stream if ref $stream; | 
| 245 | 10 |  |  |  |  | 16 | chomp $stream; | 
| 246 | 10 |  |  |  |  | 33 | return $stream . $o->_indent_data($$data); | 
| 247 |  |  |  |  |  |  | } | 
| 248 |  |  |  |  |  |  |  | 
| 249 |  |  |  |  |  |  | sub _indent_undef { | 
| 250 | 1 |  |  | 1 |  | 3 | my ($o, $data) = @_; | 
| 251 | 1 |  |  |  |  | 3 | my $stream = "?\n"; | 
| 252 | 1 | 50 |  |  |  | 4 | $stream .= $o->{key}, $o->{key} = '' if $o->{key}; | 
| 253 | 1 |  |  |  |  | 5 | return $stream; | 
| 254 |  |  |  |  |  |  | } | 
| 255 |  |  |  |  |  |  |  | 
| 256 |  |  |  |  |  |  | sub _indent_name { | 
| 257 | 3 |  |  | 3 |  | 7 | my ($o, $name, $value) = @_; | 
| 258 | 3 |  |  |  |  | 23 | $name =~ s/^.*:://; | 
| 259 | 3 | 50 |  |  |  | 13 | croak invalid_name_level($o->{level}) if $o->{level} != 0; | 
| 260 | 3 |  |  |  |  | 7 | my $stream = $name . $o->{comma}; | 
| 261 | 3 |  |  |  |  | 11 | $stream .= $o->_indent_data($value); | 
| 262 | 3 |  |  |  |  | 14 | return $stream; | 
| 263 |  |  |  |  |  |  | } | 
| 264 |  |  |  |  |  |  |  | 
| 265 |  |  |  |  |  |  | sub _print_ref { | 
| 266 | 24 |  |  | 24 |  | 52 | my ($o, $data, $symbol, $type) = @_; | 
| 267 | 24 | 50 |  |  |  | 4147 | $data =~ /^(([\w:]+)=)?$type\(0x([0-9a-f]+)\)$/ | 
| 268 |  |  |  |  |  |  | or croak "Invalid reference: $data, for type $type\n"; | 
| 269 | 24 |  |  |  |  | 167 | my $stream = $symbol; | 
| 270 | 24 | 100 |  |  |  | 70 | $stream .= $2 if defined $2; | 
| 271 | 24 |  |  |  |  | 92 | $o->{xref}{$3}++; | 
| 272 | 24 | 100 |  |  |  | 83 | if ($o->{xref}{$3} > 1) { | 
| 273 | 5 |  |  |  |  | 16 | $stream .= "(*$3)\n"; | 
| 274 | 5 | 50 |  |  |  | 17 | $stream .= $o->{key}, $o->{key} = '' if $o->{key}; | 
| 275 | 5 |  |  |  |  | 13 | return \$stream; | 
| 276 |  |  |  |  |  |  | } | 
| 277 | 19 |  |  |  |  | 21 | push @{$o->{refs}}, $3; | 
|  | 19 |  |  |  |  | 64 |  | 
| 278 | 19 |  |  |  |  | 98 | $stream .= "($3)\n"; | 
| 279 | 19 | 50 |  |  |  | 48 | $stream .= $o->{key}, $o->{key} = '' if $o->{key}; | 
| 280 | 19 |  |  |  |  | 82 | return $stream; | 
| 281 |  |  |  |  |  |  | } | 
| 282 |  |  |  |  |  |  |  | 
| 283 |  |  |  |  |  |  | sub _resolve { | 
| 284 | 10 |  |  | 10 |  | 19 | my ($o, $stream_ref) = @_; | 
| 285 | 10 |  |  |  |  | 15 | my $ref_label = 'REF00000'; | 
| 286 | 10 |  |  |  |  | 31 | local $^W; | 
| 287 | 10 |  |  |  |  | 22 | for my $ref (@{$o->{refs}}) { | 
|  | 10 |  |  |  |  | 28 |  | 
| 288 | 19 | 100 |  |  |  | 59 | if ($o->{xref}{$ref} == 1) { | 
| 289 | 14 |  |  |  |  | 509 | $$stream_ref =~ s/(?:(\\)\($ref\)([\\\%\@\$])|\($ref\)\s*$)/$1$2/m; | 
| 290 |  |  |  |  |  |  | } | 
| 291 |  |  |  |  |  |  | else { | 
| 292 | 5 |  |  |  |  | 10 | $ref_label++; | 
| 293 | 5 |  |  |  |  | 11 | local $^W; | 
| 294 | 5 |  |  |  |  | 162 | $$stream_ref =~ | 
| 295 |  |  |  |  |  |  | s/(?:(\\)\($ref\)([\\\%\@\$])|\($ref\)\s*$)/$1($ref_label)$2/m; | 
| 296 | 5 |  |  |  |  | 13 | my $i = 0; | 
| 297 | 5 |  |  |  |  | 73 | $$stream_ref =~ | 
| 298 | 5 |  |  |  |  | 31 | s/\(\*$ref\)$/ "(*$ref_label" . '-' . ++$i . ')' /gem; | 
| 299 |  |  |  |  |  |  |  | 
| 300 |  |  |  |  |  |  | } | 
| 301 |  |  |  |  |  |  | } | 
| 302 | 10 | 100 |  |  |  | 65 | $$stream_ref .= "\n" unless $$stream_ref =~ /\n\Z/; | 
| 303 |  |  |  |  |  |  | } | 
| 304 |  |  |  |  |  |  |  | 
| 305 |  |  |  |  |  |  | sub undent { | 
| 306 | 10 |  |  | 10 | 0 | 41 | local $/ = "\n"; | 
| 307 | 10 |  |  |  |  | 19 | my ($o, $text) = @_; | 
| 308 | 10 |  |  |  |  | 19 | my ($comma) = $o->{comma}; | 
| 309 | 10 | 50 |  |  |  | 24 | croak invalid_usage('undent') unless $o->{__DATA__DENTER__}; | 
| 310 | 10 |  |  |  |  | 20 | my $package = caller; | 
| 311 | 10 | 50 |  |  |  | 33 | $package = caller(1) if $package eq 'Data::Denter'; | 
| 312 | 10 |  |  |  |  | 13 | %{$o->{xref}} = (); | 
|  | 10 |  |  |  |  | 29 |  | 
| 313 | 10 |  |  |  |  | 13 | @{$o->{objects}} = (); | 
|  | 10 |  |  |  |  | 23 |  | 
| 314 | 10 |  |  |  |  | 13 | @{$o->{context}} = (); | 
|  | 10 |  |  |  |  | 23 |  | 
| 315 | 10 |  |  |  |  | 15 | my $glob = ''; | 
| 316 | 10 |  |  |  |  | 19 | chomp $text; | 
| 317 | 10 |  |  |  |  | 47 | @{$o->{lines}} = split $/, $text; | 
|  | 10 |  |  |  |  | 33 |  | 
| 318 | 10 |  |  |  |  | 20 | $o->{level} = 0; | 
| 319 | 10 |  | 50 |  |  | 50 | $o->{line} ||= 1; | 
| 320 | 10 |  |  |  |  | 27 | $o->_setup_line; | 
| 321 | 10 |  |  |  |  | 27 | while (not $o->{done}) { | 
| 322 | 11 | 100 | 66 |  |  | 110 | if ($o->{level} == 0 and | 
| 323 |  |  |  |  |  |  | $o->{content} =~ /^(.+?)\s*$comma\s*(.*)$/) { | 
| 324 | 3 |  |  |  |  | 8 | $o->{content} = $2; | 
| 325 | 1 |  |  | 1 |  | 12 | no strict 'refs'; | 
|  | 1 |  |  |  |  | 2 |  | 
|  | 1 |  |  |  |  | 5341 |  | 
| 326 | 3 |  |  |  |  | 13 | push @{$o->{objects}}, | 
|  | 1 |  |  |  |  | 8 |  | 
| 327 | 3 | 100 |  |  |  | 5 | $o->{hashmode} ? $1 : *{"${package}::$1"}; | 
| 328 |  |  |  |  |  |  | } | 
| 329 | 11 |  |  |  |  | 15 | push @{$o->{objects}}, $o->_undent_data; | 
|  | 11 |  |  |  |  | 38 |  | 
| 330 |  |  |  |  |  |  | } | 
| 331 | 10 | 100 |  |  |  | 22 | return wantarray ? @{$o->{objects}} : ${$o->{objects}}[-1]; | 
|  | 9 |  |  |  |  | 71 |  | 
|  | 1 |  |  |  |  | 8 |  | 
| 332 |  |  |  |  |  |  | } | 
| 333 |  |  |  |  |  |  |  | 
| 334 |  |  |  |  |  |  | sub _undent_data { | 
| 335 | 23 |  |  | 23 |  | 29 | my $o = shift; | 
| 336 | 23 |  |  |  |  | 35 | my ($obj, $class) = ('god', ''); | 
| 337 | 23 |  |  |  |  | 25 | my @refs; | 
| 338 |  |  |  |  |  |  | my %refs; | 
| 339 | 23 |  |  |  |  | 57 | local $^W; | 
| 340 | 23 |  |  |  |  | 108 | while ($o->{content} =~ s/^\\(?:\((\w+)\))?((\%|\@|\$|\\\(\*|\\).*)/$2/) { | 
| 341 | 10 |  |  |  |  | 24 | push @refs, $1; | 
| 342 | 10 |  |  |  |  | 24 | $refs{$1} = scalar @refs; | 
| 343 | 10 | 100 |  |  |  | 58 | last if $3 eq '\\(*'; | 
| 344 |  |  |  |  |  |  | } | 
| 345 | 23 | 100 |  |  |  | 130 | if ($o->{content} =~ /^([\%\@\$]) | 
|  |  | 100 |  |  |  |  |  | 
|  |  | 50 |  |  |  |  |  | 
| 346 |  |  |  |  |  |  | (\w(?:\w|::)*)? | 
| 347 |  |  |  |  |  |  | (?:\((\*)?(\w+)(?:-\d+)?\))? | 
| 348 |  |  |  |  |  |  | \s*$/x | 
| 349 |  |  |  |  |  |  | ) { | 
| 350 | 10 |  |  |  |  | 13 | my $foo; | 
| 351 | 10 | 100 |  |  |  | 41 | $obj = ($1 eq '%') ? {} : ($1 eq '@') ? [] : \$foo; | 
|  |  | 100 |  |  |  |  |  | 
| 352 | 10 |  | 100 |  |  | 47 | $class = $2 || ''; | 
| 353 | 10 | 100 |  |  |  | 25 | if ($3) { | 
| 354 | 1 | 50 |  |  |  | 5 | croak no_such_ref($4) unless defined $o->{xref}{$4}; | 
| 355 | 1 |  |  |  |  | 3 | $obj = $o->{xref}{$4}; | 
| 356 | 1 |  |  |  |  | 5 | $o->_next_line; | 
| 357 | 1 |  |  |  |  | 12 | $o->_setup_line; | 
| 358 |  |  |  |  |  |  | } | 
| 359 |  |  |  |  |  |  | else { | 
| 360 | 9 |  |  |  |  | 29 | $o->{xref}{$4} = $obj; | 
| 361 | 9 | 100 |  |  |  | 32 | if ($1 eq '%') { | 
|  |  | 100 |  |  |  |  |  | 
| 362 | 3 |  |  |  |  | 16 | %$obj = $o->_undent_hash; | 
| 363 |  |  |  |  |  |  | } | 
| 364 |  |  |  |  |  |  | elsif ($1 eq '@') { | 
| 365 | 4 |  |  |  |  | 15 | @$obj = $o->_undent_array; | 
| 366 |  |  |  |  |  |  | } | 
| 367 |  |  |  |  |  |  | else { | 
| 368 | 2 |  |  |  |  | 10 | $$obj = $o->_undent_scalar; | 
| 369 |  |  |  |  |  |  | } | 
| 370 | 9 | 100 |  |  |  | 32 | bless $obj, $class if length $class; | 
| 371 |  |  |  |  |  |  | } | 
| 372 |  |  |  |  |  |  | } | 
| 373 |  |  |  |  |  |  | elsif ($o->{content} =~ /^\\\(\*(\w+)-\d+\)\s*$/ | 
| 374 |  |  |  |  |  |  | ) { | 
| 375 | 4 |  |  |  |  | 6 | my $refs = @refs; | 
| 376 | 4 |  |  |  |  | 13 | while (@refs) { | 
| 377 | 4 |  |  |  |  | 7 | my $ref = pop @refs; | 
| 378 | 4 |  |  |  |  | 5 | my $copy = $obj; | 
| 379 | 4 |  |  |  |  | 7 | $obj = \ $copy; | 
| 380 | 4 | 100 |  |  |  | 19 | $o->{xref}{$ref} = $obj if $ref; | 
| 381 |  |  |  |  |  |  | } | 
| 382 | 4 | 50 |  |  |  | 15 | croak no_such_ref($1) unless defined $o->{xref}{$1}; | 
| 383 | 4 |  |  |  |  | 276 | eval("\$" x $refs . '$obj = $o->{xref}{$1}'); | 
| 384 | 4 |  |  |  |  | 19 | $o->_next_line; | 
| 385 | 4 |  |  |  |  | 10 | $o->_setup_line; | 
| 386 |  |  |  |  |  |  | } | 
| 387 |  |  |  |  |  |  | elsif ($o->{content} =~ /^\?\s*$/) { | 
| 388 | 0 |  |  |  |  | 0 | $obj = $o->_undent_undef; | 
| 389 |  |  |  |  |  |  | } | 
| 390 |  |  |  |  |  |  | else { | 
| 391 | 9 |  |  |  |  | 21 | $obj = $o->_undent_value; | 
| 392 |  |  |  |  |  |  | } | 
| 393 | 23 |  |  |  |  | 55 | while (@refs) { | 
| 394 | 6 |  |  |  |  | 10 | my $ref = pop @refs; | 
| 395 | 6 |  |  |  |  | 9 | my $copy = $obj; | 
| 396 | 6 |  |  |  |  | 9 | $obj = \ $copy; | 
| 397 | 6 | 100 |  |  |  | 22 | $o->{xref}{$ref} = $obj if $ref; | 
| 398 |  |  |  |  |  |  | } | 
| 399 | 23 |  |  |  |  | 127 | return $obj; | 
| 400 |  |  |  |  |  |  | } | 
| 401 |  |  |  |  |  |  |  | 
| 402 |  |  |  |  |  |  | sub _undent_value { | 
| 403 | 10 |  |  | 10 |  | 15 | my $o = shift; | 
| 404 | 10 |  |  |  |  | 15 | my $value = ''; | 
| 405 | 10 | 100 |  |  |  | 43 | if ($o->{content} =~ /^\<\<(\w+)(\-?)\s*$/) { | 
|  |  | 100 |  |  |  |  |  | 
| 406 | 1 |  |  |  |  | 4 | my ($marker, $chomp) = ($1, $2); | 
| 407 | 1 |  |  |  |  | 3 | my $line = $o->{line}; | 
| 408 | 1 |  |  |  |  | 5 | $o->_next_line; | 
| 409 | 1 |  | 66 |  |  | 11 | while (not $o->{done} and | 
| 410 |  |  |  |  |  |  | $o->{lines}[0] ne $marker) { | 
| 411 | 3 |  |  |  |  | 8 | $value .= $o->{lines}[0] . "\n"; | 
| 412 | 3 |  |  |  |  | 9 | $o->_next_line; | 
| 413 |  |  |  |  |  |  | } | 
| 414 | 1 | 50 |  |  |  | 5 | croak no_value_end_marker($marker, $line) if $o->{done}; | 
| 415 | 1 |  |  |  |  | 6 | $value =~ s/(%([0-9a-fA-F]{2}))/pack("H2","$2")/eg; | 
|  | 2 |  |  |  |  | 11 |  | 
| 416 | 1 | 50 |  |  |  | 6 | chomp $value if $chomp; | 
| 417 |  |  |  |  |  |  | } | 
| 418 |  |  |  |  |  |  | elsif ($o->{content} =~ /^\"/) { | 
| 419 | 1 | 50 |  |  |  | 10 | croak $o->mismatched_quotes unless $o->{content} =~ /^\".*\"\s*$/; | 
| 420 | 1 |  |  |  |  | 10 | ($value = $o->{content}) =~ s/^\"|\"\s*$//g; | 
| 421 | 1 |  |  |  |  | 7 | $value =~ s/(%([0-9a-fA-F]{2}))/pack("H2","$2")/eg; | 
|  | 3 |  |  |  |  | 19 |  | 
| 422 |  |  |  |  |  |  | } | 
| 423 |  |  |  |  |  |  | else { | 
| 424 | 8 |  |  |  |  | 17 | $value = $o->{content}; | 
| 425 |  |  |  |  |  |  | } | 
| 426 | 10 |  |  |  |  | 23 | $o->_next_line; | 
| 427 | 10 |  |  |  |  | 21 | $o->_setup_line; | 
| 428 | 10 |  |  |  |  | 28 | return $value; | 
| 429 |  |  |  |  |  |  | } | 
| 430 |  |  |  |  |  |  |  | 
| 431 |  |  |  |  |  |  | sub _undent_hash { | 
| 432 | 3 |  |  | 3 |  | 6 | my @values; | 
| 433 | 3 |  |  |  |  | 5 | my $o = shift; | 
| 434 | 3 |  |  |  |  | 7 | my $level = $o->{level} + 1; | 
| 435 | 3 |  |  |  |  | 11 | $o->_next_line; | 
| 436 | 3 |  |  |  |  | 9 | $o->_setup_line; | 
| 437 | 3 |  |  |  |  | 12 | while ($o->{level} == $level) { | 
| 438 | 2 |  |  |  |  | 21 | my ($key, $value) = split $o->{comma}, $o->{content}; | 
| 439 | 2 | 50 | 33 |  |  | 14 | croak $o->invalid_key_value unless (defined $key and defined $value); | 
| 440 | 2 |  |  |  |  | 4 | $o->{content} = $value; | 
| 441 | 2 |  |  |  |  | 11 | push @values, $o->_get_key($key), $o->_undent_data;; | 
| 442 |  |  |  |  |  |  | } | 
| 443 | 3 | 50 |  |  |  | 9 | croak $o->invalid_indent_level if $o->{level} > $level; | 
| 444 | 3 |  |  |  |  | 11 | return @values; | 
| 445 |  |  |  |  |  |  | } | 
| 446 |  |  |  |  |  |  |  | 
| 447 |  |  |  |  |  |  | sub _get_key { | 
| 448 | 2 |  |  | 2 |  | 5 | my ($o, $key) = @_; | 
| 449 | 2 |  |  |  |  | 6 | $key =~ s/^"(.*)"$/$1/; | 
| 450 | 2 | 50 |  |  |  | 18 | return $key unless $key =~ /^\<\<(\w+)(\-?)/; | 
| 451 | 0 |  |  |  |  | 0 | my ($marker, $chomp) = ($1, $2); | 
| 452 | 0 |  |  |  |  | 0 | $key = ''; | 
| 453 | 0 |  |  |  |  | 0 | my $line = $o->{line}; | 
| 454 | 0 |  |  |  |  | 0 | $o->_next_line; | 
| 455 | 0 |  | 0 |  |  | 0 | while (not $o->{done} and | 
| 456 |  |  |  |  |  |  | $o->{lines}[0] ne $marker) { | 
| 457 | 0 |  |  |  |  | 0 | $key .= $o->{lines}[0] . "\n"; | 
| 458 | 0 |  |  |  |  | 0 | $o->_next_line; | 
| 459 |  |  |  |  |  |  | } | 
| 460 | 0 | 0 |  |  |  | 0 | croak no_key_end_marker($marker, $line) if $o->{done}; | 
| 461 | 0 | 0 |  |  |  | 0 | chomp $key if $chomp; | 
| 462 | 0 |  |  |  |  | 0 | $o->_next_line; | 
| 463 | 0 |  |  |  |  | 0 | $o->_setup_line; | 
| 464 | 0 |  |  |  |  | 0 | return $key; | 
| 465 |  |  |  |  |  |  | } | 
| 466 |  |  |  |  |  |  |  | 
| 467 |  |  |  |  |  |  | sub _undent_array { | 
| 468 | 4 |  |  | 4 |  | 5 | my @values; | 
| 469 | 4 |  |  |  |  | 7 | my $o = shift; | 
| 470 | 4 |  |  |  |  | 11 | my $level = $o->{level} + 1; | 
| 471 | 4 |  |  |  |  | 12 | $o->_next_line; | 
| 472 | 4 |  |  |  |  | 10 | $o->_setup_line; | 
| 473 | 4 |  |  |  |  | 41 | while ($o->{level} == $level) { | 
| 474 | 10 |  |  |  |  | 26 | push @values, $o->_undent_data; | 
| 475 |  |  |  |  |  |  | } | 
| 476 | 4 | 50 |  |  |  | 15 | croak $o->invalid_indent_level if $o->{level} > $level; | 
| 477 | 4 |  |  |  |  | 16 | return @values; | 
| 478 |  |  |  |  |  |  | } | 
| 479 |  |  |  |  |  |  |  | 
| 480 |  |  |  |  |  |  | sub _undent_scalar { | 
| 481 | 2 |  |  | 2 |  | 3 | my $values; | 
| 482 | 2 |  |  |  |  | 5 | my $o = shift; | 
| 483 | 2 |  |  |  |  | 5 | my $level = $o->{level} + 1; | 
| 484 | 2 |  |  |  |  | 6 | $o->_next_line; | 
| 485 | 2 |  |  |  |  | 7 | $o->_setup_line; | 
| 486 | 2 | 50 |  |  |  | 9 | croak $o->invalid_indent_level if $o->{level} != $level; | 
| 487 | 2 | 50 |  |  |  | 9 | croak $o->invalid_scalar_value if $o->{content} =~ /^[\%\@\$\\]/; | 
| 488 | 2 | 100 |  |  |  | 16 | return $o->_undent_undef if $o->{content} =~ /^\?/; | 
| 489 | 1 |  |  |  |  | 4 | return $o->_undent_value; | 
| 490 |  |  |  |  |  |  | } | 
| 491 |  |  |  |  |  |  |  | 
| 492 |  |  |  |  |  |  | sub _undent_undef { | 
| 493 | 1 |  |  | 1 |  | 3 | my $o = shift; | 
| 494 | 1 |  |  |  |  | 4 | $o->_next_line; | 
| 495 | 1 |  |  |  |  | 4 | $o->_setup_line; | 
| 496 | 1 |  |  |  |  | 3 | return undef; | 
| 497 |  |  |  |  |  |  | } | 
| 498 |  |  |  |  |  |  |  | 
| 499 |  |  |  |  |  |  | sub _next_line { | 
| 500 | 29 |  |  | 29 |  | 38 | my $o = shift; | 
| 501 | 29 | 50 |  |  |  | 35 | $o->{done}++, $o->{level} = -1, return unless @{$o->{lines}}; | 
|  | 29 |  |  |  |  | 78 |  | 
| 502 | 29 |  |  |  |  | 35 | $_ = shift @{$o->{lines}}; | 
|  | 29 |  |  |  |  | 57 |  | 
| 503 | 29 |  |  |  |  | 72 | $o->{line}++; | 
| 504 |  |  |  |  |  |  | } | 
| 505 |  |  |  |  |  |  |  | 
| 506 |  |  |  |  |  |  | sub _setup_line { | 
| 507 | 35 |  |  | 35 |  | 44 | my $o = shift; | 
| 508 | 35 | 100 |  |  |  | 40 | $o->{done}++, $o->{level} = -1, return unless @{$o->{lines}}; | 
|  | 35 |  |  |  |  | 145 |  | 
| 509 | 25 |  |  |  |  | 32 | my ($width, $tabwidth) = @{$o}{qw(width tabwidth)}; | 
|  | 25 |  |  |  |  | 60 |  | 
| 510 | 25 |  |  |  |  | 31 | while (1) { | 
| 511 | 25 |  |  |  |  | 47 | $_ = $o->{lines}[0]; | 
| 512 |  |  |  |  |  |  | # expand tabs in leading whitespace; | 
| 513 | 25 | 50 |  |  |  | 87 | $o->_next_line, next if /^(\s*$|\#)/; # skip comments and blank lines | 
| 514 | 25 |  |  |  |  | 68 | while (s{^( *)(\t+)} | 
| 515 | 0 |  |  |  |  | 0 | {' ' x (length($1) + length($2) * $tabwidth - | 
| 516 |  |  |  |  |  |  | length($1) % $tabwidth)}e){} | 
| 517 | 25 | 50 |  |  |  | 231 | croak $o->invalid_indent_width unless /^(( {$width})*)(\S.*)$/; | 
| 518 | 25 |  |  |  |  | 80 | $o->{level} = length($1) / $width; | 
| 519 | 25 |  |  |  |  | 56 | $o->{content} = $3; | 
| 520 | 25 |  |  |  |  | 49 | last; | 
| 521 |  |  |  |  |  |  | } | 
| 522 |  |  |  |  |  |  | } | 
| 523 |  |  |  |  |  |  |  | 
| 524 |  |  |  |  |  |  | 1; | 
| 525 |  |  |  |  |  |  |  | 
| 526 |  |  |  |  |  |  | __END__ |