Filename | /usr/share/perl5/Data/Dump.pm |
Statements | Executed 23 statements in 3.79ms |
Calls | P | F | Exclusive Time |
Inclusive Time |
Subroutine |
---|---|---|---|---|---|
1 | 1 | 1 | 178µs | 185µs | BEGIN@5 | Data::Dump::
1 | 1 | 1 | 11µs | 40µs | BEGIN@232 | Data::Dump::
1 | 1 | 1 | 10µs | 13µs | BEGIN@3 | Data::Dump::
1 | 1 | 1 | 9µs | 44µs | BEGIN@4 | Data::Dump::
1 | 1 | 1 | 6µs | 64µs | BEGIN@16 | Data::Dump::
1 | 1 | 1 | 5µs | 5µs | BEGIN@15 | Data::Dump::
0 | 0 | 0 | 0s | 0s | __ANON__[:156] | Data::Dump::
0 | 0 | 0 | 0s | 0s | _dump | Data::Dump::
0 | 0 | 0 | 0s | 0s | dd | Data::Dump::
0 | 0 | 0 | 0s | 0s | ddx | Data::Dump::
0 | 0 | 0 | 0s | 0s | dump | Data::Dump::
0 | 0 | 0 | 0s | 0s | dumpf | Data::Dump::
0 | 0 | 0 | 0s | 0s | format_list | Data::Dump::
0 | 0 | 0 | 0s | 0s | fullname | Data::Dump::
0 | 0 | 0 | 0s | 0s | quote | Data::Dump::
0 | 0 | 0 | 0s | 0s | str | Data::Dump::
0 | 0 | 0 | 0s | 0s | tied_str | Data::Dump::
Line | State ments |
Time on line |
Calls | Time in subs |
Code |
---|---|---|---|---|---|
1 | package Data::Dump; | ||||
2 | |||||
3 | 2 | 24µs | 2 | 15µs | # spent 13µs (10+2) within Data::Dump::BEGIN@3 which was called:
# once (10µs+2µs) by RBM::BEGIN@23 at line 3 # spent 13µs making 1 call to Data::Dump::BEGIN@3
# spent 2µs making 1 call to strict::import |
4 | 2 | 28µs | 2 | 79µs | # spent 44µs (9+35) within Data::Dump::BEGIN@4 which was called:
# once (9µs+35µs) by RBM::BEGIN@23 at line 4 # spent 44µs making 1 call to Data::Dump::BEGIN@4
# spent 35µs making 1 call to vars::import |
5 | 2 | 230µs | 2 | 193µs | # spent 185µs (178+7) within Data::Dump::BEGIN@5 which was called:
# once (178µs+7µs) by RBM::BEGIN@23 at line 5 # spent 185µs making 1 call to Data::Dump::BEGIN@5
# spent 8µs making 1 call to subs::import |
6 | |||||
7 | 1 | 600ns | require Exporter; | ||
8 | 1 | 1µs | *import = \&Exporter::import; | ||
9 | 1 | 900ns | @EXPORT = qw(dd ddx); | ||
10 | 1 | 500ns | @EXPORT_OK = qw(dump pp dumpf quote); | ||
11 | |||||
12 | 1 | 100ns | $VERSION = "1.23"; | ||
13 | 1 | 100ns | $DEBUG = 0; | ||
14 | |||||
15 | 2 | 25µs | 1 | 5µs | # spent 5µs within Data::Dump::BEGIN@15 which was called:
# once (5µs+0s) by RBM::BEGIN@23 at line 15 # spent 5µs making 1 call to Data::Dump::BEGIN@15 |
16 | 2 | 1.30ms | 2 | 123µs | # spent 64µs (6+59) within Data::Dump::BEGIN@16 which was called:
# once (6µs+59µs) by RBM::BEGIN@23 at line 16 # spent 64µs making 1 call to Data::Dump::BEGIN@16
# spent 59µs making 1 call to vars::import |
17 | |||||
18 | 1 | 200ns | $TRY_BASE64 = 50 unless defined $TRY_BASE64; | ||
19 | 1 | 200ns | $INDENT = " " unless defined $INDENT; | ||
20 | |||||
21 | sub dump | ||||
22 | { | ||||
23 | local %seen; | ||||
24 | local %refcnt; | ||||
25 | local %require; | ||||
26 | local @fixup; | ||||
27 | |||||
28 | require Data::Dump::FilterContext if @FILTERS; | ||||
29 | |||||
30 | my $name = "a"; | ||||
31 | my @dump; | ||||
32 | |||||
33 | for my $v (@_) { | ||||
34 | my $val = _dump($v, $name, [], tied($v)); | ||||
35 | push(@dump, [$name, $val]); | ||||
36 | } continue { | ||||
37 | $name++; | ||||
38 | } | ||||
39 | |||||
40 | my $out = ""; | ||||
41 | if (%require) { | ||||
42 | for (sort keys %require) { | ||||
43 | $out .= "require $_;\n"; | ||||
44 | } | ||||
45 | } | ||||
46 | if (%refcnt) { | ||||
47 | # output all those with refcounts first | ||||
48 | for (@dump) { | ||||
49 | my $name = $_->[0]; | ||||
50 | if ($refcnt{$name}) { | ||||
51 | $out .= "my \$$name = $_->[1];\n"; | ||||
52 | undef $_->[1]; | ||||
53 | } | ||||
54 | } | ||||
55 | for (@fixup) { | ||||
56 | $out .= "$_;\n"; | ||||
57 | } | ||||
58 | } | ||||
59 | |||||
60 | my $paren = (@dump != 1); | ||||
61 | $out .= "(" if $paren; | ||||
62 | $out .= format_list($paren, undef, | ||||
63 | map {defined($_->[1]) ? $_->[1] : "\$".$_->[0]} | ||||
64 | @dump | ||||
65 | ); | ||||
66 | $out .= ")" if $paren; | ||||
67 | |||||
68 | if (%refcnt || %require) { | ||||
69 | $out .= ";\n"; | ||||
70 | $out =~ s/^/$INDENT/gm; | ||||
71 | $out = "do {\n$out}"; | ||||
72 | } | ||||
73 | |||||
74 | print STDERR "$out\n" unless defined wantarray; | ||||
75 | $out; | ||||
76 | } | ||||
77 | |||||
78 | 1 | 400ns | *pp = \&dump; | ||
79 | |||||
80 | sub dd { | ||||
81 | print dump(@_), "\n"; | ||||
82 | } | ||||
83 | |||||
84 | sub ddx { | ||||
85 | my(undef, $file, $line) = caller; | ||||
86 | $file =~ s,.*[\\/],,; | ||||
87 | my $out = "$file:$line: " . dump(@_) . "\n"; | ||||
88 | $out =~ s/^/# /gm; | ||||
89 | print $out; | ||||
90 | } | ||||
91 | |||||
92 | sub dumpf { | ||||
93 | require Data::Dump::Filtered; | ||||
94 | goto &Data::Dump::Filtered::dump_filtered; | ||||
95 | } | ||||
96 | |||||
97 | sub _dump | ||||
98 | { | ||||
99 | my $ref = ref $_[0]; | ||||
100 | my $rval = $ref ? $_[0] : \$_[0]; | ||||
101 | shift; | ||||
102 | |||||
103 | my($name, $idx, $dont_remember, $pclass, $pidx) = @_; | ||||
104 | |||||
105 | my($class, $type, $id); | ||||
106 | my $strval = overload::StrVal($rval); | ||||
107 | # Parse $strval without using regexps, in order not to clobber $1, $2,... | ||||
108 | if ((my $i = rindex($strval, "=")) >= 0) { | ||||
109 | $class = substr($strval, 0, $i); | ||||
110 | $strval = substr($strval, $i+1); | ||||
111 | } | ||||
112 | if ((my $i = index($strval, "(0x")) >= 0) { | ||||
113 | $type = substr($strval, 0, $i); | ||||
114 | $id = substr($strval, $i + 2, -1); | ||||
115 | } | ||||
116 | else { | ||||
117 | die "Can't parse " . overload::StrVal($rval); | ||||
118 | } | ||||
119 | if ($] < 5.008 && $type eq "SCALAR") { | ||||
120 | $type = "REF" if $ref eq "REF"; | ||||
121 | } | ||||
122 | warn "\$$name(@$idx) $class $type $id ($ref)" if $DEBUG; | ||||
123 | |||||
124 | my $out; | ||||
125 | my $comment; | ||||
126 | my $hide_keys; | ||||
127 | if (@FILTERS) { | ||||
128 | my $pself = ""; | ||||
129 | $pself = fullname("self", [@$idx[$pidx..(@$idx - 1)]]) if $pclass; | ||||
130 | my $ctx = Data::Dump::FilterContext->new($rval, $class, $type, $ref, $pclass, $pidx, $idx); | ||||
131 | my @bless; | ||||
132 | for my $filter (@FILTERS) { | ||||
133 | if (my $f = $filter->($ctx, $rval)) { | ||||
134 | if (my $v = $f->{object}) { | ||||
135 | local @FILTERS; | ||||
136 | $out = _dump($v, $name, $idx, 1); | ||||
137 | $dont_remember++; | ||||
138 | } | ||||
139 | if (defined(my $c = $f->{bless})) { | ||||
140 | push(@bless, $c); | ||||
141 | } | ||||
142 | if (my $c = $f->{comment}) { | ||||
143 | $comment = $c; | ||||
144 | } | ||||
145 | if (defined(my $c = $f->{dump})) { | ||||
146 | $out = $c; | ||||
147 | $dont_remember++; | ||||
148 | } | ||||
149 | if (my $h = $f->{hide_keys}) { | ||||
150 | if (ref($h) eq "ARRAY") { | ||||
151 | $hide_keys = sub { | ||||
152 | for my $k (@$h) { | ||||
153 | return 1 if $k eq $_[0]; | ||||
154 | } | ||||
155 | return 0; | ||||
156 | }; | ||||
157 | } | ||||
158 | } | ||||
159 | } | ||||
160 | } | ||||
161 | push(@bless, "") if defined($out) && !@bless; | ||||
162 | if (@bless) { | ||||
163 | $class = shift(@bless); | ||||
164 | warn "More than one filter callback tried to bless object" if @bless; | ||||
165 | } | ||||
166 | } | ||||
167 | |||||
168 | unless ($dont_remember) { | ||||
169 | if (my $s = $seen{$id}) { | ||||
170 | my($sname, $sidx) = @$s; | ||||
171 | $refcnt{$sname}++; | ||||
172 | my $sref = fullname($sname, $sidx, | ||||
173 | ($ref && $type eq "SCALAR")); | ||||
174 | warn "SEEN: [\$$name(@$idx)] => [\$$sname(@$sidx)] ($ref,$sref)" if $DEBUG; | ||||
175 | return $sref unless $sname eq $name; | ||||
176 | $refcnt{$name}++; | ||||
177 | push(@fixup, fullname($name,$idx)." = $sref"); | ||||
178 | return "do{my \$fix}" if @$idx && $idx->[-1] eq '$'; | ||||
179 | return "'fix'"; | ||||
180 | } | ||||
181 | $seen{$id} = [$name, $idx]; | ||||
182 | } | ||||
183 | |||||
184 | if ($class) { | ||||
185 | $pclass = $class; | ||||
186 | $pidx = @$idx; | ||||
187 | } | ||||
188 | |||||
189 | if (defined $out) { | ||||
190 | # keep it | ||||
191 | } | ||||
192 | elsif ($type eq "SCALAR" || $type eq "REF" || $type eq "REGEXP") { | ||||
193 | if ($ref) { | ||||
194 | if ($class && $class eq "Regexp") { | ||||
195 | my $v = "$rval"; | ||||
196 | |||||
197 | my $mod = ""; | ||||
198 | if ($v =~ /^\(\?\^?([msix-]*):([\x00-\xFF]*)\)\z/) { | ||||
199 | $mod = $1; | ||||
200 | $v = $2; | ||||
201 | $mod =~ s/-.*//; | ||||
202 | } | ||||
203 | |||||
204 | my $sep = '/'; | ||||
205 | my $sep_count = ($v =~ tr/\///); | ||||
206 | if ($sep_count) { | ||||
207 | # see if we can find a better one | ||||
208 | for ('|', ',', ':', '#') { | ||||
209 | my $c = eval "\$v =~ tr/\Q$_\E//"; | ||||
210 | #print "SEP $_ $c $sep_count\n"; | ||||
211 | if ($c < $sep_count) { | ||||
212 | $sep = $_; | ||||
213 | $sep_count = $c; | ||||
214 | last if $sep_count == 0; | ||||
215 | } | ||||
216 | } | ||||
217 | } | ||||
218 | $v =~ s/\Q$sep\E/\\$sep/g; | ||||
219 | |||||
220 | $out = "qr$sep$v$sep$mod"; | ||||
221 | undef($class); | ||||
222 | } | ||||
223 | else { | ||||
224 | delete $seen{$id} if $type eq "SCALAR"; # will be seen again shortly | ||||
225 | my $val = _dump($$rval, $name, [@$idx, "\$"], 0, $pclass, $pidx); | ||||
226 | $out = $class ? "do{\\(my \$o = $val)}" : "\\$val"; | ||||
227 | } | ||||
228 | } else { | ||||
229 | if (!defined $$rval) { | ||||
230 | $out = "undef"; | ||||
231 | } | ||||
232 | 2 | 2.17ms | 2 | 70µs | # spent 40µs (11+29) within Data::Dump::BEGIN@232 which was called:
# once (11µs+29µs) by RBM::BEGIN@23 at line 232 # spent 40µs making 1 call to Data::Dump::BEGIN@232
# spent 29µs making 1 call to warnings::unimport |
233 | $out = $$rval; | ||||
234 | } | ||||
235 | else { | ||||
236 | $out = str($$rval); | ||||
237 | } | ||||
238 | if ($class && !@$idx) { | ||||
239 | # Top is an object, not a reference to one as perl needs | ||||
240 | $refcnt{$name}++; | ||||
241 | my $obj = fullname($name, $idx); | ||||
242 | my $cl = quote($class); | ||||
243 | push(@fixup, "bless \\$obj, $cl"); | ||||
244 | } | ||||
245 | } | ||||
246 | } | ||||
247 | elsif ($type eq "GLOB") { | ||||
248 | if ($ref) { | ||||
249 | delete $seen{$id}; | ||||
250 | my $val = _dump($$rval, $name, [@$idx, "*"], 0, $pclass, $pidx); | ||||
251 | $out = "\\$val"; | ||||
252 | if ($out =~ /^\\\*Symbol::/) { | ||||
253 | $require{Symbol}++; | ||||
254 | $out = "Symbol::gensym()"; | ||||
255 | } | ||||
256 | } else { | ||||
257 | my $val = "$$rval"; | ||||
258 | $out = "$$rval"; | ||||
259 | |||||
260 | for my $k (qw(SCALAR ARRAY HASH)) { | ||||
261 | my $gval = *$$rval{$k}; | ||||
262 | next unless defined $gval; | ||||
263 | next if $k eq "SCALAR" && ! defined $$gval; # always there | ||||
264 | my $f = scalar @fixup; | ||||
265 | push(@fixup, "RESERVED"); # overwritten after _dump() below | ||||
266 | $gval = _dump($gval, $name, [@$idx, "*{$k}"], 0, $pclass, $pidx); | ||||
267 | $refcnt{$name}++; | ||||
268 | my $gname = fullname($name, $idx); | ||||
269 | $fixup[$f] = "$gname = $gval"; #XXX indent $gval | ||||
270 | } | ||||
271 | } | ||||
272 | } | ||||
273 | elsif ($type eq "ARRAY") { | ||||
274 | my @vals; | ||||
275 | my $tied = tied_str(tied(@$rval)); | ||||
276 | my $i = 0; | ||||
277 | for my $v (@$rval) { | ||||
278 | push(@vals, _dump($v, $name, [@$idx, "[$i]"], $tied, $pclass, $pidx)); | ||||
279 | $i++; | ||||
280 | } | ||||
281 | $out = "[" . format_list(1, $tied, @vals) . "]"; | ||||
282 | } | ||||
283 | elsif ($type eq "HASH") { | ||||
284 | my(@keys, @vals); | ||||
285 | my $tied = tied_str(tied(%$rval)); | ||||
286 | |||||
287 | # statistics to determine variation in key lengths | ||||
288 | my $kstat_max = 0; | ||||
289 | my $kstat_sum = 0; | ||||
290 | my $kstat_sum2 = 0; | ||||
291 | |||||
292 | my @orig_keys = keys %$rval; | ||||
293 | if ($hide_keys) { | ||||
294 | @orig_keys = grep !$hide_keys->($_), @orig_keys; | ||||
295 | } | ||||
296 | my $text_keys = 0; | ||||
297 | for (@orig_keys) { | ||||
298 | $text_keys++, last unless /^[-+]?(?:0|[1-9]\d*)(?:\.\d+)?\z/; | ||||
299 | } | ||||
300 | |||||
301 | if ($text_keys) { | ||||
302 | @orig_keys = sort { lc($a) cmp lc($b) } @orig_keys; | ||||
303 | } | ||||
304 | else { | ||||
305 | @orig_keys = sort { $a <=> $b } @orig_keys; | ||||
306 | } | ||||
307 | |||||
308 | my $quote; | ||||
309 | for my $key (@orig_keys) { | ||||
310 | next if $key =~ /^-?[a-zA-Z_]\w*\z/; | ||||
311 | next if $key =~ /^-?[1-9]\d{0,8}\z/; | ||||
312 | $quote++; | ||||
313 | last; | ||||
314 | } | ||||
315 | |||||
316 | for my $key (@orig_keys) { | ||||
317 | my $val = \$rval->{$key}; # capture value before we modify $key | ||||
318 | $key = quote($key) if $quote; | ||||
319 | $kstat_max = length($key) if length($key) > $kstat_max; | ||||
320 | $kstat_sum += length($key); | ||||
321 | $kstat_sum2 += length($key)*length($key); | ||||
322 | |||||
323 | push(@keys, $key); | ||||
324 | push(@vals, _dump($$val, $name, [@$idx, "{$key}"], $tied, $pclass, $pidx)); | ||||
325 | } | ||||
326 | my $nl = ""; | ||||
327 | my $klen_pad = 0; | ||||
328 | my $tmp = "@keys @vals"; | ||||
329 | if (length($tmp) > 60 || $tmp =~ /\n/ || $tied) { | ||||
330 | $nl = "\n"; | ||||
331 | |||||
332 | # Determine what padding to add | ||||
333 | if ($kstat_max < 4) { | ||||
334 | $klen_pad = $kstat_max; | ||||
335 | } | ||||
336 | elsif (@keys >= 2) { | ||||
337 | my $n = @keys; | ||||
338 | my $avg = $kstat_sum/$n; | ||||
339 | my $stddev = sqrt(($kstat_sum2 - $n * $avg * $avg) / ($n - 1)); | ||||
340 | |||||
341 | # I am not actually very happy with this heuristics | ||||
342 | if ($stddev / $kstat_max < 0.25) { | ||||
343 | $klen_pad = $kstat_max; | ||||
344 | } | ||||
345 | if ($DEBUG) { | ||||
346 | push(@keys, "__S"); | ||||
347 | push(@vals, sprintf("%.2f (%d/%.1f/%.1f)", | ||||
348 | $stddev / $kstat_max, | ||||
349 | $kstat_max, $avg, $stddev)); | ||||
350 | } | ||||
351 | } | ||||
352 | } | ||||
353 | $out = "{$nl"; | ||||
354 | $out .= "$INDENT# $tied$nl" if $tied; | ||||
355 | while (@keys) { | ||||
356 | my $key = shift @keys; | ||||
357 | my $val = shift @vals; | ||||
358 | my $vpad = $INDENT . (" " x ($klen_pad ? $klen_pad + 4 : 0)); | ||||
359 | $val =~ s/\n/\n$vpad/gm; | ||||
360 | my $kpad = $nl ? $INDENT : " "; | ||||
361 | $key .= " " x ($klen_pad - length($key)) if $nl && $klen_pad > length($key); | ||||
362 | $out .= "$kpad$key => $val,$nl"; | ||||
363 | } | ||||
364 | $out =~ s/,$/ / unless $nl; | ||||
365 | $out .= "}"; | ||||
366 | } | ||||
367 | elsif ($type eq "CODE") { | ||||
368 | $out = 'sub { ... }'; | ||||
369 | } | ||||
370 | elsif ($type eq "VSTRING") { | ||||
371 | $out = sprintf +($ref ? '\v%vd' : 'v%vd'), $$rval; | ||||
372 | } | ||||
373 | else { | ||||
374 | warn "Can't handle $type data"; | ||||
375 | $out = "'#$type#'"; | ||||
376 | } | ||||
377 | |||||
378 | if ($class && $ref) { | ||||
379 | $out = "bless($out, " . quote($class) . ")"; | ||||
380 | } | ||||
381 | if ($comment) { | ||||
382 | $comment =~ s/^/# /gm; | ||||
383 | $comment .= "\n" unless $comment =~ /\n\z/; | ||||
384 | $comment =~ s/^#[ \t]+\n/\n/; | ||||
385 | $out = "$comment$out"; | ||||
386 | } | ||||
387 | return $out; | ||||
388 | } | ||||
389 | |||||
390 | sub tied_str { | ||||
391 | my $tied = shift; | ||||
392 | if ($tied) { | ||||
393 | if (my $tied_ref = ref($tied)) { | ||||
394 | $tied = "tied $tied_ref"; | ||||
395 | } | ||||
396 | else { | ||||
397 | $tied = "tied"; | ||||
398 | } | ||||
399 | } | ||||
400 | return $tied; | ||||
401 | } | ||||
402 | |||||
403 | sub fullname | ||||
404 | { | ||||
405 | my($name, $idx, $ref) = @_; | ||||
406 | substr($name, 0, 0) = "\$"; | ||||
407 | |||||
408 | my @i = @$idx; # need copy in order to not modify @$idx | ||||
409 | if ($ref && @i && $i[0] eq "\$") { | ||||
410 | shift(@i); # remove one deref | ||||
411 | $ref = 0; | ||||
412 | } | ||||
413 | while (@i && $i[0] eq "\$") { | ||||
414 | shift @i; | ||||
415 | $name = "\$$name"; | ||||
416 | } | ||||
417 | |||||
418 | my $last_was_index; | ||||
419 | for my $i (@i) { | ||||
420 | if ($i eq "*" || $i eq "\$") { | ||||
421 | $last_was_index = 0; | ||||
422 | $name = "$i\{$name}"; | ||||
423 | } elsif ($i =~ s/^\*//) { | ||||
424 | $name .= $i; | ||||
425 | $last_was_index++; | ||||
426 | } else { | ||||
427 | $name .= "->" unless $last_was_index++; | ||||
428 | $name .= $i; | ||||
429 | } | ||||
430 | } | ||||
431 | $name = "\\$name" if $ref; | ||||
432 | $name; | ||||
433 | } | ||||
434 | |||||
435 | sub format_list | ||||
436 | { | ||||
437 | my $paren = shift; | ||||
438 | my $comment = shift; | ||||
439 | my $indent_lim = $paren ? 0 : 1; | ||||
440 | if (@_ > 3) { | ||||
441 | # can we use range operator to shorten the list? | ||||
442 | my $i = 0; | ||||
443 | while ($i < @_) { | ||||
444 | my $j = $i + 1; | ||||
445 | my $v = $_[$i]; | ||||
446 | while ($j < @_) { | ||||
447 | # XXX allow string increment too? | ||||
448 | if ($v eq "0" || $v =~ /^-?[1-9]\d{0,9}\z/) { | ||||
449 | $v++; | ||||
450 | } | ||||
451 | elsif ($v =~ /^"([A-Za-z]{1,3}\d*)"\z/) { | ||||
452 | $v = $1; | ||||
453 | $v++; | ||||
454 | $v = qq("$v"); | ||||
455 | } | ||||
456 | else { | ||||
457 | last; | ||||
458 | } | ||||
459 | last if $_[$j] ne $v; | ||||
460 | $j++; | ||||
461 | } | ||||
462 | if ($j - $i > 3) { | ||||
463 | splice(@_, $i, $j - $i, "$_[$i] .. $_[$j-1]"); | ||||
464 | } | ||||
465 | $i++; | ||||
466 | } | ||||
467 | } | ||||
468 | my $tmp = "@_"; | ||||
469 | if ($comment || (@_ > $indent_lim && (length($tmp) > 60 || $tmp =~ /\n/))) { | ||||
470 | my @elem = @_; | ||||
471 | for (@elem) { s/^/$INDENT/gm; } | ||||
472 | return "\n" . ($comment ? "$INDENT# $comment\n" : "") . | ||||
473 | join(",\n", @elem, ""); | ||||
474 | } else { | ||||
475 | return join(", ", @_); | ||||
476 | } | ||||
477 | } | ||||
478 | |||||
479 | sub str { | ||||
480 | if (length($_[0]) > 20) { | ||||
481 | for ($_[0]) { | ||||
482 | # Check for repeated string | ||||
483 | if (/^(.)\1\1\1/s) { | ||||
484 | # seems to be a repeating sequence, let's check if it really is | ||||
485 | # without backtracking | ||||
486 | unless (/[^\Q$1\E]/) { | ||||
487 | my $base = quote($1); | ||||
488 | my $repeat = length; | ||||
489 | return "($base x $repeat)" | ||||
490 | } | ||||
491 | } | ||||
492 | # Length protection because the RE engine will blow the stack [RT#33520] | ||||
493 | if (length($_) < 16 * 1024 && /^(.{2,5}?)\1*\z/s) { | ||||
494 | my $base = quote($1); | ||||
495 | my $repeat = length($_)/length($1); | ||||
496 | return "($base x $repeat)"; | ||||
497 | } | ||||
498 | } | ||||
499 | } | ||||
500 | |||||
501 | local $_ = "e; | ||||
502 | |||||
503 | if (length($_) > 40 && !/\\x\{/ && length($_) > (length($_[0]) * 2)) { | ||||
504 | # too much binary data, better to represent as a hex/base64 string | ||||
505 | |||||
506 | # Base64 is more compact than hex when string is longer than | ||||
507 | # 17 bytes (not counting any require statement needed). | ||||
508 | # But on the other hand, hex is much more readable. | ||||
509 | if ($TRY_BASE64 && length($_[0]) > $TRY_BASE64 && | ||||
510 | (defined &utf8::is_utf8 && !utf8::is_utf8($_[0])) && | ||||
511 | eval { require MIME::Base64 }) | ||||
512 | { | ||||
513 | $require{"MIME::Base64"}++; | ||||
514 | return "MIME::Base64::decode(\"" . | ||||
515 | MIME::Base64::encode($_[0],"") . | ||||
516 | "\")"; | ||||
517 | } | ||||
518 | return "pack(\"H*\",\"" . unpack("H*", $_[0]) . "\")"; | ||||
519 | } | ||||
520 | |||||
521 | return $_; | ||||
522 | } | ||||
523 | |||||
524 | 1 | 4µs | my %esc = ( | ||
525 | "\a" => "\\a", | ||||
526 | "\b" => "\\b", | ||||
527 | "\t" => "\\t", | ||||
528 | "\n" => "\\n", | ||||
529 | "\f" => "\\f", | ||||
530 | "\r" => "\\r", | ||||
531 | "\e" => "\\e", | ||||
532 | ); | ||||
533 | |||||
534 | # put a string value in double quotes | ||||
535 | sub quote { | ||||
536 | local($_) = $_[0]; | ||||
537 | # If there are many '"' we might want to use qq() instead | ||||
538 | s/([\\\"\@\$])/\\$1/g; | ||||
539 | return qq("$_") unless /[^\040-\176]/; # fast exit | ||||
540 | |||||
541 | s/([\a\b\t\n\f\r\e])/$esc{$1}/g; | ||||
542 | |||||
543 | # no need for 3 digits in escape for these | ||||
544 | s/([\0-\037])(?!\d)/sprintf('\\%o',ord($1))/eg; | ||||
545 | |||||
546 | s/([\0-\037\177-\377])/sprintf('\\x%02X',ord($1))/eg; | ||||
547 | s/([^\040-\176])/sprintf('\\x{%X}',ord($1))/eg; | ||||
548 | |||||
549 | return qq("$_"); | ||||
550 | } | ||||
551 | |||||
552 | 1 | 9µs | 1; | ||
553 | |||||
554 | __END__ |