line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
# License: Public Domain or CC0 |
2
|
|
|
|
|
|
|
# See https://creativecommons.org/publicdomain/zero/1.0/ |
3
|
|
|
|
|
|
|
# The author, Jim Avera (jim.avera at gmail) has waived all copyright and |
4
|
|
|
|
|
|
|
# related or neighboring rights. Attribution is requested but is not required. |
5
|
|
|
|
|
|
|
|
6
|
|
|
|
|
|
|
##FIXME: Refaddr(1) has no effect inside Blessed structures |
7
|
|
|
|
|
|
|
|
8
|
9
|
|
|
9
|
|
100338
|
use strict; use warnings FATAL => 'all'; use utf8; |
|
9
|
|
|
9
|
|
57
|
|
|
9
|
|
|
9
|
|
304
|
|
|
9
|
|
|
|
|
49
|
|
|
9
|
|
|
|
|
15
|
|
|
9
|
|
|
|
|
289
|
|
|
9
|
|
|
|
|
5608
|
|
|
9
|
|
|
|
|
132
|
|
|
9
|
|
|
|
|
45
|
|
9
|
|
|
|
|
|
|
#use 5.010; # say, state |
10
|
|
|
|
|
|
|
#use 5.011; # cpantester gets warning that 5.11 is the minimum acceptable |
11
|
|
|
|
|
|
|
#use 5.014; # /r for non-destructive substitution |
12
|
9
|
|
|
9
|
|
452
|
use 5.018; # lexical_subs |
|
9
|
|
|
|
|
33
|
|
13
|
9
|
|
|
9
|
|
45
|
use feature qw(say state lexical_subs current_sub); |
|
9
|
|
|
|
|
16
|
|
|
9
|
|
|
|
|
899
|
|
14
|
9
|
|
|
9
|
|
59
|
use feature 'lexical_subs'; |
|
9
|
|
|
|
|
15
|
|
|
9
|
|
|
|
|
245
|
|
15
|
|
|
|
|
|
|
|
16
|
9
|
|
|
9
|
|
54
|
no warnings "experimental::lexical_subs"; |
|
9
|
|
|
|
|
24
|
|
|
9
|
|
|
|
|
702
|
|
17
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
package Data::Dumper::Interp; |
19
|
9
|
|
|
9
|
|
79
|
{ no strict 'refs'; ${__PACKAGE__."::VER"."SION"} = 997.999; } |
|
9
|
|
|
|
|
15
|
|
|
9
|
|
|
|
|
1607
|
|
20
|
|
|
|
|
|
|
our $VERSION = '6.006'; # VERSION from Dist::Zilla::Plugin::OurPkgVersion |
21
|
|
|
|
|
|
|
our $DATE = '2023-09-02'; # DATE from Dist::Zilla::Plugin::OurDate |
22
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
package |
24
|
|
|
|
|
|
|
# newline so Dist::Zilla::Plugin::PkgVersion won't add $VERSION |
25
|
|
|
|
|
|
|
DB { |
26
|
|
|
|
|
|
|
sub DB_Vis_Evalwrapper { |
27
|
1669
|
|
|
1669
|
0
|
284809
|
eval $Data::Dumper::Interp::string_to_eval; ## no critic |
28
|
|
|
|
|
|
|
} |
29
|
|
|
|
|
|
|
} |
30
|
|
|
|
|
|
|
|
31
|
|
|
|
|
|
|
package Data::Dumper::Interp; |
32
|
|
|
|
|
|
|
|
33
|
9
|
|
|
9
|
|
5244
|
use Moose; |
|
9
|
|
|
|
|
4297184
|
|
|
9
|
|
|
|
|
63
|
|
34
|
|
|
|
|
|
|
|
35
|
|
|
|
|
|
|
extends 'Data::Visitor' => { -version => 0.32 }, |
36
|
|
|
|
|
|
|
'Exporter' => { -version => 5.57 }, |
37
|
|
|
|
|
|
|
; |
38
|
|
|
|
|
|
|
|
39
|
9
|
|
|
9
|
|
71363
|
no warnings "experimental::lexical_subs"; # un-do Moose forcing these on!! |
|
9
|
|
|
|
|
23
|
|
|
9
|
|
|
|
|
422
|
|
40
|
|
|
|
|
|
|
|
41
|
9
|
|
|
9
|
|
8032
|
use Data::Dumper (); |
|
9
|
|
|
|
|
69520
|
|
|
9
|
|
|
|
|
286
|
|
42
|
9
|
|
|
9
|
|
71
|
use Carp; |
|
9
|
|
|
|
|
27
|
|
|
9
|
|
|
|
|
740
|
|
43
|
9
|
|
|
9
|
|
4944
|
use POSIX qw(INT_MAX); |
|
9
|
|
|
|
|
62593
|
|
|
9
|
|
|
|
|
65
|
|
44
|
9
|
|
|
9
|
|
13631
|
use Scalar::Util qw(blessed reftype refaddr looks_like_number weaken); |
|
9
|
|
|
|
|
20
|
|
|
9
|
|
|
|
|
749
|
|
45
|
9
|
|
|
9
|
|
82
|
use List::Util 1.45 qw(min max first none all any sum0); |
|
9
|
|
|
|
|
213
|
|
|
9
|
|
|
|
|
875
|
|
46
|
9
|
|
|
9
|
|
4931
|
use Data::Structure::Util qw/circular_off/; |
|
9
|
|
|
|
|
68849
|
|
|
9
|
|
|
|
|
640
|
|
47
|
9
|
|
|
9
|
|
5130
|
use Regexp::Common qw/RE_balanced/; |
|
9
|
|
|
|
|
26043
|
|
|
9
|
|
|
|
|
52
|
|
48
|
9
|
|
|
9
|
|
1473640
|
use Term::ReadKey (); |
|
9
|
|
|
|
|
19172
|
|
|
9
|
|
|
|
|
272
|
|
49
|
9
|
|
|
9
|
|
93
|
use overload (); |
|
9
|
|
|
|
|
21
|
|
|
9
|
|
|
|
|
12813
|
|
50
|
|
|
|
|
|
|
|
51
|
|
|
|
|
|
|
############################ Exports ####################################### |
52
|
|
|
|
|
|
|
# Short-hand functions/methods are generated on demand (i.e. if imported or |
53
|
|
|
|
|
|
|
# called as a method) based on a naming convention. |
54
|
|
|
|
|
|
|
############################################################################ |
55
|
|
|
|
|
|
|
|
56
|
|
|
|
|
|
|
our @EXPORT = qw( visnew |
57
|
|
|
|
|
|
|
vis avis hvis ivis dvis |
58
|
|
|
|
|
|
|
viso aviso hviso iviso dviso |
59
|
|
|
|
|
|
|
visq avisq hvisq ivisq dvisq |
60
|
|
|
|
|
|
|
visr avisr hvisr ivisr dvisr |
61
|
|
|
|
|
|
|
rvis rvisq |
62
|
|
|
|
|
|
|
addrvis addrvisl |
63
|
|
|
|
|
|
|
u quotekey qsh qshlist qshpath |
64
|
|
|
|
|
|
|
); |
65
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
our @EXPORT_OK = qw(addrvis_digits |
67
|
|
|
|
|
|
|
|
68
|
|
|
|
|
|
|
$Debug $MaxStringwidth $Truncsuffix $Objects $Foldwidth |
69
|
|
|
|
|
|
|
$Useqq $Quotekeys $Sortkeys |
70
|
|
|
|
|
|
|
$Maxdepth $Maxrecurse $Deparse $Deepcopy); |
71
|
|
|
|
|
|
|
|
72
|
|
|
|
|
|
|
our %EXPORT_TAGS = ( |
73
|
|
|
|
|
|
|
null => [], |
74
|
|
|
|
|
|
|
); |
75
|
|
|
|
|
|
|
|
76
|
|
|
|
|
|
|
sub _generate_sub($;$); # forward |
77
|
|
|
|
|
|
|
|
78
|
|
|
|
|
|
|
#--------------------------------------------------------------------------- |
79
|
|
|
|
|
|
|
my $sane_cW = $^W; |
80
|
|
|
|
|
|
|
my $sane_cH = $^H; |
81
|
|
|
|
|
|
|
our @save_stack; |
82
|
|
|
|
|
|
|
sub _SaveAndResetPunct() { |
83
|
|
|
|
|
|
|
# Save things which will later be restored |
84
|
7335
|
|
|
7335
|
|
75389
|
push @save_stack, [ $@, $!+0, $^E+0, $,, $/, $\, $?, $^W ]; |
85
|
|
|
|
|
|
|
# Reset sane values |
86
|
7335
|
|
|
|
|
16127
|
$, = ""; # output field separator is null string |
87
|
7335
|
|
|
|
|
19647
|
$/ = "\n"; # input record separator is newline |
88
|
7335
|
|
|
|
|
14358
|
$\ = ""; # output record separator is null string |
89
|
7335
|
|
|
|
|
12677
|
$? = 0; # child process exit status |
90
|
7335
|
|
|
|
|
15643
|
$^W = $sane_cW; # our load-time warnings |
91
|
|
|
|
|
|
|
#$^H = $sane_cH; # our load-time pragmas (strict etc.) |
92
|
|
|
|
|
|
|
} |
93
|
|
|
|
|
|
|
sub _RestorePunct_NoPop() { |
94
|
9004
|
|
|
9004
|
|
16203
|
( $@, $!, $^E, $,, $/, $\, $?, $^W ) = @{ $save_stack[-1] }; |
|
9004
|
|
|
|
|
92590
|
|
95
|
|
|
|
|
|
|
} |
96
|
|
|
|
|
|
|
sub _RestorePunct() { |
97
|
7335
|
|
|
7335
|
|
17016
|
&_RestorePunct_NoPop; |
98
|
7335
|
|
|
|
|
17446
|
pop @save_stack; |
99
|
|
|
|
|
|
|
} |
100
|
|
|
|
|
|
|
#--------------------------------------------------------------------------- |
101
|
|
|
|
|
|
|
|
102
|
|
|
|
|
|
|
our $AUTOLOAD_debug; |
103
|
|
|
|
|
|
|
|
104
|
|
|
|
|
|
|
sub import { |
105
|
9
|
|
|
9
|
|
3366321
|
my $class = shift; |
106
|
9
|
|
|
|
|
46
|
my @args = @_; |
107
|
|
|
|
|
|
|
|
108
|
9
|
|
100
|
|
|
62
|
my $exporting_default = (@args==0 or grep{ /:DEFAULT/ } @args); |
109
|
|
|
|
|
|
|
|
110
|
9
|
|
|
|
|
25
|
our $Debug; |
111
|
9
|
|
|
|
|
30
|
local $Debug = $Debug; |
112
|
9
|
50
|
|
6
|
|
122
|
if (my $tag = first{ /^:debug/i } @args) { |
|
6
|
|
|
|
|
27
|
|
113
|
0
|
|
|
|
|
0
|
@args = grep{ ! /^:debug/i } @args; |
|
0
|
|
|
|
|
0
|
|
114
|
0
|
0
|
|
|
|
0
|
my $level = ($tag =~ /=(\d+)/ ? $1 : 1); |
115
|
0
|
|
|
|
|
0
|
$AUTOLOAD_debug = $Debug = $level; # show generated code |
116
|
|
|
|
|
|
|
} |
117
|
|
|
|
|
|
|
|
118
|
9
|
100
|
|
|
|
58
|
if (grep{ /^:all$/i } @args) { |
|
6
|
|
|
|
|
31
|
|
119
|
2
|
|
|
|
|
6
|
@args = grep{ ! /^:all$/i } @args; |
|
5
|
|
|
|
|
17
|
|
120
|
|
|
|
|
|
|
# Generate all modifiers combinations as suffixes in alphabetical order. |
121
|
2
|
|
|
|
|
6
|
my %already = map{$_ => 1} @args; |
|
3
|
|
|
|
|
11
|
|
122
|
2
|
50
|
|
|
|
16
|
push @args, ":DEFAULT" unless $already{':DEFAULT'}; |
123
|
2
|
|
|
|
|
8
|
for my $v1 (qw/avis hvis vis ivis dvis/) { # avisl hvisl ? |
124
|
10
|
|
|
|
|
17
|
for my $v2 ('1', '2', "") { |
125
|
30
|
|
|
|
|
48
|
for my $v3 ('l', "") { |
126
|
60
|
100
|
100
|
|
|
202
|
next if $v3 && $v1 !~ /^[ah]/; # 'l' only with avis or hvis |
127
|
42
|
|
|
|
|
66
|
for my $v4 ('o', "") { |
128
|
84
|
|
|
|
|
120
|
for my $v5 ('q', "") { |
129
|
168
|
|
|
|
|
237
|
for my $v6 ('r', "") { |
130
|
336
|
|
|
|
|
612
|
my $subname = $v1.$v2.$v3.$v4.$v5.$v6; |
131
|
336
|
50
|
|
|
|
876
|
next if $already{$subname}++; |
132
|
336
|
|
|
|
|
738
|
push @args, $subname; |
133
|
|
|
|
|
|
|
} |
134
|
|
|
|
|
|
|
} |
135
|
|
|
|
|
|
|
} |
136
|
|
|
|
|
|
|
} |
137
|
|
|
|
|
|
|
} |
138
|
|
|
|
|
|
|
} |
139
|
|
|
|
|
|
|
} |
140
|
|
|
|
|
|
|
|
141
|
9
|
100
|
|
|
|
65
|
foreach my $subname (@args, ($exporting_default ? @EXPORT : ())) { |
142
|
552
|
100
|
|
|
|
2456
|
next unless $subname =~ /^[a-zA-Z]/a; # skip :tag or $var |
143
|
549
|
|
|
|
|
1420
|
push @EXPORT_OK, $subname; |
144
|
9
|
|
|
9
|
|
82
|
no strict 'refs'; |
|
9
|
|
|
|
|
20
|
|
|
9
|
|
|
|
|
3190
|
|
145
|
549
|
100
|
|
|
|
2774
|
if (defined(*$subname{CODE})) { |
146
|
58
|
50
|
50
|
|
|
237
|
warn "# $subname ALREADY DEFINED\n" if ($Debug//0) > 1; |
147
|
|
|
|
|
|
|
} else { |
148
|
|
|
|
|
|
|
# Only generate a 'forward' stub to allow prototype checks. |
149
|
|
|
|
|
|
|
# Subs actually called will be defined via AUTOLOAD |
150
|
491
|
|
|
|
|
2144
|
_generate_sub($subname, 1); |
151
|
|
|
|
|
|
|
} |
152
|
|
|
|
|
|
|
} |
153
|
|
|
|
|
|
|
|
154
|
9
|
50
|
66
|
|
|
98
|
@args = (':null') if @_ && !@args; |
155
|
|
|
|
|
|
|
|
156
|
9
|
50
|
|
|
|
47
|
warn "Passing to Exporter::import ",&_dbavis(@args),"\n" |
157
|
|
|
|
|
|
|
if $Debug; |
158
|
|
|
|
|
|
|
|
159
|
9
|
|
|
|
|
207669
|
__PACKAGE__->export_to_level(1, $class, @args); |
160
|
|
|
|
|
|
|
} |
161
|
|
|
|
|
|
|
|
162
|
|
|
|
|
|
|
sub AUTOLOAD { # invoked on call to undefined *method* |
163
|
31
|
|
|
31
|
|
1280563
|
our $AUTOLOAD; |
164
|
31
|
|
|
|
|
144
|
_SaveAndResetPunct(); |
165
|
31
|
|
|
|
|
57
|
our $Debug; |
166
|
31
|
|
|
|
|
101
|
local $Debug = $AUTOLOAD_debug; |
167
|
31
|
50
|
|
|
|
145
|
carp "AUTOLOAD $AUTOLOAD" if $Debug; |
168
|
31
|
|
|
|
|
415
|
_generate_sub($AUTOLOAD); |
169
|
31
|
|
|
|
|
142
|
_RestorePunct(); |
170
|
9
|
|
|
9
|
|
84
|
no strict 'refs'; |
|
9
|
|
|
|
|
36
|
|
|
9
|
|
|
|
|
40173
|
|
171
|
31
|
|
|
|
|
1387
|
goto &$AUTOLOAD; |
172
|
|
|
|
|
|
|
} |
173
|
|
|
|
|
|
|
#sub DESTROY {} #unnecessary: No D::D::Interp objects are ever instantiated |
174
|
|
|
|
|
|
|
|
175
|
|
|
|
|
|
|
############################################################################ |
176
|
|
|
|
|
|
|
# Internal debug-message utilities |
177
|
|
|
|
|
|
|
|
178
|
0
|
|
|
0
|
0
|
0
|
sub oops(@) { @_=("\n".(caller)." oops:\n",@_,"\n"); goto &Carp::confess } |
|
0
|
|
|
|
|
0
|
|
179
|
0
|
|
|
0
|
0
|
0
|
sub btwN($@) { my $N=shift; local $_=join("",@_); s/\n\z//s; printf "%4d: %s\n",(caller($N))[2],$_; } |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
180
|
0
|
|
|
0
|
0
|
0
|
sub btw(@) { unshift @_,0; goto &btwN } |
|
0
|
|
|
|
|
0
|
|
181
|
|
|
|
|
|
|
|
182
|
|
|
|
|
|
|
sub __chop_loc($) { # remove "at ..." from an exception message |
183
|
0
|
|
|
0
|
|
0
|
(local $_ = shift) =~ s/ at \(eval[^\)]*\) line \d+[^\n]*\n?\z//s; |
184
|
0
|
|
|
|
|
0
|
$_ |
185
|
|
|
|
|
|
|
} |
186
|
0
|
0
|
|
0
|
|
0
|
sub _tf($) { $_[0] ? "T" : "F" } |
187
|
0
|
0
|
|
0
|
|
0
|
sub _showfalse(_) { $_[0] ? $_[0] : 0 } |
188
|
|
|
|
|
|
|
sub _dbvisnew($) { |
189
|
800
|
|
|
800
|
|
1197
|
my $v = shift; |
190
|
800
|
|
|
|
|
3043
|
Data::Dumper->new([$v])->Terse(1)->Indent(0)->Quotekeys(0)->Useqq(1) |
191
|
|
|
|
|
|
|
#->Useperl(1) |
192
|
|
|
|
|
|
|
###->Sortkeys(\&__sortkeys)->Pair("=>") |
193
|
|
|
|
|
|
|
} |
194
|
800
|
|
|
800
|
|
7460
|
sub _dbvis(_) {chomp(my $s=_dbvisnew(shift)->Useqq(1)->Dump); $s } |
|
800
|
|
|
|
|
51091
|
|
195
|
0
|
|
|
0
|
|
0
|
sub _dbvisq(_){chomp(my $s=_dbvisnew(shift)->Useqq(0)->Dump); $s } |
|
0
|
|
|
|
|
0
|
|
196
|
0
|
|
|
0
|
|
0
|
sub _dbvis1(_){chomp(my $s=_dbvisnew(shift)->Maxdepth(1)->Useqq(1)->Dump); $s } |
|
0
|
|
|
|
|
0
|
|
197
|
0
|
|
|
0
|
|
0
|
sub _dbvis2(_){chomp(my $s=_dbvisnew(shift)->Maxdepth(3)->Useqq(1)->Dump); $s } |
|
0
|
|
|
|
|
0
|
|
198
|
0
|
|
|
0
|
|
0
|
sub _dbavis(@){ "(" . join(", ", map{_dbvis} @_) . ")" } |
|
0
|
|
|
|
|
0
|
|
199
|
0
|
|
|
0
|
|
0
|
sub _dbavis2(@){ "(" . join(", ", map{_dbvis2} @_) . ")" } |
|
0
|
|
|
|
|
0
|
|
200
|
0
|
0
|
|
0
|
|
0
|
sub _dbrvis(_) { (ref($_[0]) ? addrvis(refaddr $_[0]) : "")._dbvis($_[0]) } |
201
|
0
|
0
|
|
0
|
|
0
|
sub _dbrvis2(_){ (ref($_[0]) ? addrvis(refaddr $_[0]) : "")._dbvis2($_[0]) } |
202
|
0
|
|
|
0
|
|
0
|
sub _dbravis2(@){ "(" . join(", ", map{_dbrvis2} @_) . ")" } |
|
0
|
|
|
|
|
0
|
|
203
|
|
|
|
|
|
|
sub _dbshow(_) { |
204
|
0
|
|
|
0
|
|
0
|
my $v = shift; |
205
|
0
|
0
|
|
|
|
0
|
blessed($v) ? "(".blessed($v).")".$v # stringify with (classname) prefix |
206
|
|
|
|
|
|
|
: _dbvis($v) # something else |
207
|
|
|
|
|
|
|
} |
208
|
|
|
|
|
|
|
our $_dbmaxlen = 300; |
209
|
0
|
0
|
|
0
|
|
0
|
sub _dbrawstr(_) { "«".(length($_[0])>$_dbmaxlen ? substr($_[0],0,$_dbmaxlen-3)."..." : $_[0])."»" } |
210
|
|
|
|
|
|
|
sub _dbstr($) { |
211
|
0
|
|
|
0
|
|
0
|
local $_ = shift; |
212
|
0
|
0
|
|
|
|
0
|
return "undef" if !defined; |
213
|
0
|
|
|
|
|
0
|
s/\x{0a}/\N{U+2424}/sg; # a special NL glyph |
214
|
0
|
|
|
|
|
0
|
s/ /\N{U+00B7}/sg; # space -> Middle Dot |
215
|
0
|
|
|
|
|
0
|
s/[\x{00}-\x{1F}]/ chr( ord($&)+0x2400 ) /aseg; |
|
0
|
|
|
|
|
0
|
|
216
|
0
|
|
|
|
|
0
|
$_ |
217
|
|
|
|
|
|
|
} |
218
|
|
|
|
|
|
|
sub _dbstrposn($$) { |
219
|
0
|
|
|
0
|
|
0
|
local $_ = shift; |
220
|
0
|
|
|
|
|
0
|
my $posn = shift; |
221
|
0
|
|
|
|
|
0
|
local $_dbmaxlen = max($_dbmaxlen+8, $posn+8); |
222
|
0
|
|
|
|
|
0
|
my $visible = _dbstr($_); # simplified 'controlpics' |
223
|
0
|
|
|
|
|
0
|
"posn=$posn shown at '(<<HERE)':" |
224
|
|
|
|
|
|
|
. substr($visible, 0, $posn+1)."(<<HERE)".substr($visible,$posn+1) |
225
|
|
|
|
|
|
|
} |
226
|
|
|
|
|
|
|
############################################################################ |
227
|
|
|
|
|
|
|
|
228
|
|
|
|
|
|
|
|
229
|
|
|
|
|
|
|
#################### Configuration Globals ################# |
230
|
|
|
|
|
|
|
|
231
|
|
|
|
|
|
|
our ($Debug, $MaxStringwidth, $Truncsuffix, $Objects, |
232
|
|
|
|
|
|
|
$Refaddr, $Foldwidth, $Foldwidth1, |
233
|
|
|
|
|
|
|
$Useqq, $Quotekeys, $Sortkeys, |
234
|
|
|
|
|
|
|
$Maxdepth, $Maxrecurse, $Deparse, $Deepcopy); |
235
|
|
|
|
|
|
|
|
236
|
|
|
|
|
|
|
$Debug = 0 unless defined $Debug; |
237
|
|
|
|
|
|
|
$MaxStringwidth = 0 unless defined $MaxStringwidth; |
238
|
|
|
|
|
|
|
$Truncsuffix = "..." unless defined $Truncsuffix; |
239
|
|
|
|
|
|
|
$Objects = 1 unless defined $Objects; |
240
|
|
|
|
|
|
|
$Refaddr = 0 unless defined $Refaddr; |
241
|
|
|
|
|
|
|
$Foldwidth = undef unless defined $Foldwidth; # undef auto-detects |
242
|
|
|
|
|
|
|
$Foldwidth1 = undef unless defined $Foldwidth1; # override for 1st |
243
|
|
|
|
|
|
|
|
244
|
|
|
|
|
|
|
# The following override Data::Dumper defaults |
245
|
|
|
|
|
|
|
# Initial D::D values are captured once when we are first loaded. |
246
|
|
|
|
|
|
|
# |
247
|
|
|
|
|
|
|
#$Useqq = "unicode:controlpic" unless defined $Useqq; |
248
|
|
|
|
|
|
|
$Useqq = "unicode" unless defined $Useqq; |
249
|
|
|
|
|
|
|
$Quotekeys = 0 unless defined $Quotekeys; |
250
|
|
|
|
|
|
|
$Sortkeys = \&__sortkeys unless defined $Sortkeys; |
251
|
|
|
|
|
|
|
$Maxdepth = $Data::Dumper::Maxdepth unless defined $Maxdepth; |
252
|
|
|
|
|
|
|
$Maxrecurse = $Data::Dumper::Maxrecurse unless defined $Maxrecurse; |
253
|
|
|
|
|
|
|
$Deparse = 0 unless defined $Deparse; |
254
|
|
|
|
|
|
|
$Deepcopy = 0 unless defined $Deepcopy; |
255
|
|
|
|
|
|
|
|
256
|
|
|
|
|
|
|
#################### Methods ################# |
257
|
|
|
|
|
|
|
|
258
|
|
|
|
|
|
|
has dd => ( |
259
|
|
|
|
|
|
|
is => 'ro', |
260
|
|
|
|
|
|
|
lazy => 1, |
261
|
|
|
|
|
|
|
default => sub{ |
262
|
|
|
|
|
|
|
my $self = shift; |
263
|
|
|
|
|
|
|
Data::Dumper->new([],[]) |
264
|
|
|
|
|
|
|
->Terse(1) |
265
|
|
|
|
|
|
|
->Indent(0) |
266
|
|
|
|
|
|
|
->Sparseseen(1) |
267
|
|
|
|
|
|
|
->Useqq($Useqq) |
268
|
|
|
|
|
|
|
->Quotekeys($Quotekeys) |
269
|
|
|
|
|
|
|
->Sortkeys($Sortkeys) |
270
|
|
|
|
|
|
|
->Maxdepth($Maxdepth) |
271
|
|
|
|
|
|
|
->Maxrecurse($Maxrecurse) |
272
|
|
|
|
|
|
|
->Deparse($Deparse) |
273
|
|
|
|
|
|
|
->Deepcopy($Deepcopy) |
274
|
|
|
|
|
|
|
}, |
275
|
|
|
|
|
|
|
# This generates pass-through methods which call the dd object |
276
|
|
|
|
|
|
|
handles => [qw/Values Useqq Quotekeys Trailingcomma Pad Varname Quotekeys |
277
|
|
|
|
|
|
|
Maxdepth Maxrecurse Useperl Sortkeys Deparse Deepcopy |
278
|
|
|
|
|
|
|
/], |
279
|
|
|
|
|
|
|
); |
280
|
|
|
|
|
|
|
|
281
|
|
|
|
|
|
|
# Config values which have no counter part in Data::Dumper |
282
|
|
|
|
|
|
|
has Debug => (is=>'rw', default => sub{ $Debug }); |
283
|
|
|
|
|
|
|
has MaxStringwidth => (is=>'rw', default => sub{ $MaxStringwidth }); |
284
|
|
|
|
|
|
|
has Truncsuffix => (is=>'rw', default => sub{ $Truncsuffix }); |
285
|
|
|
|
|
|
|
has Objects => (is=>'rw', default => sub{ $Objects }); |
286
|
|
|
|
|
|
|
has Refaddr => (is=>'rw', default => sub{ $Refaddr }); |
287
|
|
|
|
|
|
|
has Foldwidth => (is=>'rw', default => sub{ |
288
|
|
|
|
|
|
|
$Foldwidth // do{ |
289
|
|
|
|
|
|
|
_set_default_Foldwidth(); |
290
|
|
|
|
|
|
|
$Foldwidth |
291
|
|
|
|
|
|
|
} |
292
|
|
|
|
|
|
|
}); |
293
|
|
|
|
|
|
|
has Foldwidth1 => (is=>'rw', default => sub{ $Foldwidth1 }); |
294
|
|
|
|
|
|
|
has _Listform => (is=>'rw'); |
295
|
|
|
|
|
|
|
|
296
|
|
|
|
|
|
|
# Make "setters" return the outer object $self |
297
|
|
|
|
|
|
|
around [qw/Values Useqq Quotekeys Trailingcomma Pad Varname Quotekeys |
298
|
|
|
|
|
|
|
Maxdepth Maxrecurse Useperl Sortkeys Deparse Deepcopy |
299
|
|
|
|
|
|
|
|
300
|
|
|
|
|
|
|
Debug MaxStringwidth Truncsuffix Objects Refaddr |
301
|
|
|
|
|
|
|
Foldwidth Foldwidth1 _Listform |
302
|
|
|
|
|
|
|
/] => sub{ |
303
|
|
|
|
|
|
|
my $orig = shift; |
304
|
|
|
|
|
|
|
my $self = shift; |
305
|
|
|
|
|
|
|
#Carp::cluck("##around (@_)\n"); |
306
|
|
|
|
|
|
|
if (@_ > 0) { |
307
|
|
|
|
|
|
|
$self->$orig(@_); |
308
|
|
|
|
|
|
|
return $self; |
309
|
|
|
|
|
|
|
} |
310
|
|
|
|
|
|
|
$self->$orig |
311
|
|
|
|
|
|
|
}; |
312
|
|
|
|
|
|
|
|
313
|
|
|
|
|
|
|
############### Utility Functions ################# |
314
|
|
|
|
|
|
|
|
315
|
|
|
|
|
|
|
#--------------------------------------------------------------------------- |
316
|
|
|
|
|
|
|
# Display an address as <decimal:hex> showing only the last few digits. |
317
|
|
|
|
|
|
|
# The number of digits shown increases when collisions occur. |
318
|
|
|
|
|
|
|
# The arg can be a numeric address or a ref from which the addr is taken. |
319
|
|
|
|
|
|
|
# If a ref the result is REFTYPEorOBJTYPE<dec:hex> otherwise just <dec:hex> |
320
|
|
|
|
|
|
|
our $addrvis_ndigits = 3; |
321
|
|
|
|
|
|
|
our $addrvis_seen = {}; # full (decimal) address => undef |
322
|
|
|
|
|
|
|
our $addrvis_dec_abbrs = {}; # abbreviated decimal digits => undef |
323
|
|
|
|
|
|
|
sub _abbr_hex($) { |
324
|
170573
|
|
|
170573
|
|
539106
|
substr(sprintf("%0*x", $addrvis_ndigits, $_[0]), -$addrvis_ndigits) } |
325
|
|
|
|
|
|
|
sub _abbr_dec($) { |
326
|
176946
|
|
|
176946
|
|
554841
|
substr(sprintf("%0*d", $addrvis_ndigits, $_[0]), -$addrvis_ndigits) } |
327
|
|
|
|
|
|
|
sub addrvis(_) { |
328
|
170575
|
|
100
|
170575
|
1
|
3144671
|
my $arg = shift // return("undef"); |
329
|
170573
|
|
|
|
|
247436
|
my $refstr = ref($arg); |
330
|
170573
|
|
|
|
|
219382
|
my $addr; |
331
|
170573
|
100
|
|
|
|
397336
|
if ($refstr ne "") { $addr = refaddr($arg) } |
|
39
|
50
|
|
|
|
86
|
|
332
|
170534
|
|
|
|
|
230697
|
elsif (looks_like_number($arg)) { $addr = $arg } |
333
|
|
|
|
|
|
|
else { |
334
|
0
|
|
|
|
|
0
|
carp("addrvis arg '$arg' is neither a ref or a number\n"); |
335
|
0
|
|
|
|
|
0
|
return "" |
336
|
|
|
|
|
|
|
} |
337
|
|
|
|
|
|
|
|
338
|
170573
|
100
|
|
|
|
361310
|
if (! exists $addrvis_seen->{$addr}) { |
339
|
2168
|
|
|
|
|
3449
|
my $dec_abbr = _abbr_dec($addr); |
340
|
2168
|
|
|
|
|
5397
|
while (exists $addrvis_dec_abbrs->{$dec_abbr}) { |
341
|
3
|
|
|
|
|
7
|
++$addrvis_ndigits; |
342
|
3
|
|
|
|
|
403
|
%$addrvis_dec_abbrs = map{ (_abbr_dec($_) => undef) } keys %$addrvis_seen; |
|
3202
|
|
|
|
|
4771
|
|
343
|
3
|
|
|
|
|
332
|
$dec_abbr = _abbr_dec($addr); |
344
|
|
|
|
|
|
|
} |
345
|
2168
|
|
|
|
|
6400
|
$addrvis_dec_abbrs->{$dec_abbr} = undef; |
346
|
2168
|
|
|
|
|
5061
|
$addrvis_seen->{$addr} = undef; |
347
|
|
|
|
|
|
|
} |
348
|
|
|
|
|
|
|
#$refstr ne "" ? $refstr.'<'._abbr_dec($addr).':'._abbr_hex($addr).'>' |
349
|
|
|
|
|
|
|
# : _abbr_dec($addr).':'._abbr_hex($addr) |
350
|
170573
|
|
|
|
|
295853
|
$refstr.'<'._abbr_dec($addr).':'._abbr_hex($addr).'>' |
351
|
|
|
|
|
|
|
} |
352
|
|
|
|
|
|
|
sub addrvisl(_) { |
353
|
|
|
|
|
|
|
# Return bare "hex:dec" or "Typename hex:dec" |
354
|
2
|
100
|
|
2
|
1
|
8
|
&addrvis =~ s/^([^\<]*)\<(.*)\>$/ $1 ? "$1 $2" : $2 /er or oops |
|
2
|
50
|
|
|
|
42
|
|
355
|
|
|
|
|
|
|
} |
356
|
|
|
|
|
|
|
sub addrvis_digits(;$) { |
357
|
1
|
50
|
|
1
|
0
|
337
|
return $addrvis_ndigits if ! defined $_[0]; # "get" request |
358
|
1
|
50
|
|
|
|
4
|
if ($_[0] <= $addrvis_ndigits) { |
359
|
0
|
|
|
|
|
0
|
return $addrvis_ndigits; # can not decrease |
360
|
|
|
|
|
|
|
} |
361
|
1
|
|
|
|
|
3
|
$addrvis_ndigits = $_[0]; |
362
|
1
|
|
|
|
|
103
|
%$addrvis_dec_abbrs = map{ (_abbr_dec($_) => undef) } keys %$addrvis_seen; |
|
1000
|
|
|
|
|
1502
|
|
363
|
1
|
|
|
|
|
92
|
$addrvis_ndigits; |
364
|
|
|
|
|
|
|
} |
365
|
|
|
|
|
|
|
sub addrvis_forget() { |
366
|
2
|
|
|
2
|
0
|
850
|
$addrvis_seen = {}; |
367
|
2
|
|
|
|
|
296
|
$addrvis_dec_abbrs = {}; |
368
|
2
|
|
|
|
|
8
|
$addrvis_ndigits = 3; |
369
|
|
|
|
|
|
|
} |
370
|
|
|
|
|
|
|
|
371
|
|
|
|
|
|
|
=for Pod::Coverage addrvis_digits addrvis_forget |
372
|
|
|
|
|
|
|
|
373
|
|
|
|
|
|
|
=cut |
374
|
|
|
|
|
|
|
|
375
|
50
|
|
100
|
50
|
1
|
43816
|
sub u(_) { $_[0] // "undef" } |
376
|
|
|
|
|
|
|
sub quotekey(_); # forward. Implemented after regex declarations. |
377
|
|
|
|
|
|
|
|
378
|
|
|
|
|
|
|
sub __stringify($) { |
379
|
29
|
50
|
|
29
|
|
99
|
if (defined(my $class = blessed($_[0]))) { |
380
|
0
|
0
|
|
|
|
0
|
return "$_[0]" if overload::Method($class,'""'); |
381
|
|
|
|
|
|
|
} |
382
|
29
|
|
|
|
|
67
|
$_[0] |
383
|
|
|
|
|
|
|
} |
384
|
|
|
|
|
|
|
|
385
|
9
|
50
|
|
|
|
22539
|
use constant _SHELL_UNSAFE_REGEX => |
386
|
9
|
|
|
9
|
|
94
|
($^O eq "MSWin32" ? qr/[^-=\w_:\.,\\]/ : qr/[^-=\w_\/:\.,]/); |
|
9
|
|
|
|
|
22
|
|
387
|
|
|
|
|
|
|
|
388
|
|
|
|
|
|
|
sub __forceqsh(_) { |
389
|
12
|
|
|
12
|
|
27
|
local $_ = shift; |
390
|
12
|
100
|
|
|
|
40
|
return "undef" if !defined; # undef without quotes |
391
|
11
|
50
|
|
|
|
23
|
$_ = vis($_) if ref; |
392
|
11
|
50
|
|
|
|
35
|
if ($^O eq "MSWin32") { |
393
|
|
|
|
|
|
|
# Backslash usually need not be protected, except: |
394
|
|
|
|
|
|
|
# \" quotes the " whether inside "quoes" or bare (!) |
395
|
|
|
|
|
|
|
# \\ quotes the \ ONLY(?) if immediately followed by \" |
396
|
0
|
|
|
|
|
0
|
s/\\(?=")/\\\\/g; |
397
|
0
|
|
|
|
|
0
|
s/"/\\"/g; |
398
|
0
|
|
|
|
|
0
|
return "\"${_}\""; # 6/7/23: UNtested |
399
|
|
|
|
|
|
|
} else { |
400
|
|
|
|
|
|
|
# Prefer "double quoted" if no shell escapes would be needed. |
401
|
11
|
100
|
|
|
|
27
|
if (/["\$`!\\\x{00}-\x{1F}\x{7F}]/) { |
402
|
|
|
|
|
|
|
# Unlike Perl, /bin/sh does not recognize any backslash escapes in '...' |
403
|
1
|
|
|
|
|
20
|
s/'/'\\''/g; # foo'bar => foo'\''bar |
404
|
1
|
|
|
|
|
16
|
return "'${_}'"; |
405
|
|
|
|
|
|
|
} else { |
406
|
10
|
|
|
|
|
134
|
return "\"${_}\""; |
407
|
|
|
|
|
|
|
} |
408
|
|
|
|
|
|
|
} |
409
|
|
|
|
|
|
|
} |
410
|
|
|
|
|
|
|
sub qsh(_) { |
411
|
20
|
|
|
20
|
1
|
15501
|
local $_ = __stringify(shift()); |
412
|
20
|
100
|
100
|
|
|
257
|
defined && !ref && ($_ !~ _SHELL_UNSAFE_REGEX) |
413
|
|
|
|
|
|
|
&& $_ ne "" && $_ ne "undef" ? $_ : __forceqsh |
414
|
|
|
|
|
|
|
} |
415
|
|
|
|
|
|
|
sub qshpath(_) { # like qsh but does not quote initial ~ or ~username |
416
|
9
|
|
|
9
|
1
|
1134
|
local $_ = __stringify(shift()); |
417
|
9
|
50
|
33
|
|
|
57
|
return qsh($_) if !defined or ref; |
418
|
9
|
50
|
|
|
|
65
|
my ($tilde_prefix, $rest) = /^( (?:\~[^\/\\]*[\/\\]?+)? )(.*)/xs or die; |
419
|
9
|
100
|
|
|
|
44
|
$rest eq "" ? $tilde_prefix : $tilde_prefix.qsh($rest) |
420
|
|
|
|
|
|
|
} |
421
|
|
|
|
|
|
|
|
422
|
|
|
|
|
|
|
# Should this have been called 'aqsh' ? |
423
|
1
|
|
|
1
|
1
|
141
|
sub qshlist(@) { join " ", map{qsh} @_ } |
|
3
|
|
|
|
|
7
|
|
424
|
|
|
|
|
|
|
|
425
|
|
|
|
|
|
|
########### Subs callable as either a Function or Method ############# |
426
|
|
|
|
|
|
|
|
427
|
|
|
|
|
|
|
sub __getself { # Return $self if passed or else create a new object |
428
|
7297
|
|
|
7297
|
|
12239
|
local $@; |
429
|
7297
|
|
|
|
|
14303
|
my $blessed = eval{ blessed($_[0]) }; # In case a tie handler throws |
|
7297
|
|
|
|
|
26884
|
|
430
|
7297
|
50
|
|
|
|
20459
|
croak __chop_loc($@) if $@; |
431
|
7297
|
100
|
100
|
|
|
88333
|
$blessed && $_[0]->isa(__PACKAGE__) ? shift : __PACKAGE__->new() |
432
|
|
|
|
|
|
|
} |
433
|
5564
|
|
|
5564
|
|
12096
|
sub __getself_s { &__getself->Values([$_[0]]) } |
434
|
320
|
|
|
320
|
|
948
|
sub __getself_a { &__getself->Values([[@_]]) } |
435
|
|
|
|
|
|
|
sub __getself_h { |
436
|
140
|
|
|
140
|
|
447
|
my $obj = &__getself; |
437
|
140
|
50
|
|
|
|
4259
|
($#_ % 2)==1 or croak "Uneven arg count for key => val pairs"; |
438
|
140
|
|
|
|
|
1213
|
$obj->Values([{@_}]) |
439
|
|
|
|
|
|
|
} |
440
|
|
|
|
|
|
|
|
441
|
|
|
|
|
|
|
sub _EnabSpacedots { |
442
|
|
|
|
|
|
|
# Append :spacedots to Useqq if Useqq matches the global default |
443
|
|
|
|
|
|
|
# (and if the default used extended options). |
444
|
1201
|
|
|
1201
|
|
406114
|
my $self = shift; |
445
|
1201
|
|
|
|
|
4392
|
my $curr = $self->Useqq; |
446
|
1201
|
50
|
50
|
|
|
50523
|
return $self if length($curr//"") <= 1 or $curr eq $Useqq; |
|
|
|
33
|
|
|
|
|
447
|
0
|
|
|
|
|
0
|
$self->Useqq($curr.":spacedots") |
448
|
|
|
|
|
|
|
} |
449
|
|
|
|
|
|
|
|
450
|
|
|
|
|
|
|
sub _generate_sub($;$) { |
451
|
|
|
|
|
|
|
my ($arg, $proto_only) = @_; |
452
|
|
|
|
|
|
|
(my $methname = $arg) =~ s/.*:://; |
453
|
|
|
|
|
|
|
my sub error($) { |
454
|
|
|
|
|
|
|
confess "Invalid sub/method name '$methname' (@_)\n" |
455
|
|
|
|
|
|
|
} |
456
|
|
|
|
|
|
|
|
457
|
|
|
|
|
|
|
# Method names are ivis, dvis, vis, avis, or hvis with prepended |
458
|
|
|
|
|
|
|
# or appended modifier letters or digits (in any order), with |
459
|
|
|
|
|
|
|
# optional underscore separators. |
460
|
|
|
|
|
|
|
local $_ = $methname; |
461
|
|
|
|
|
|
|
|
462
|
|
|
|
|
|
|
s/alvis/avisl/; # backwards compat. |
463
|
|
|
|
|
|
|
s/hlvis/hvisl/; # backwards compat. |
464
|
|
|
|
|
|
|
|
465
|
|
|
|
|
|
|
s/^[^diha]*\K(?:lvis|visl)/avisl/; # 'visl' same as 'avisl' for bw compat. |
466
|
|
|
|
|
|
|
|
467
|
|
|
|
|
|
|
s/([ahid]?vis)// or error "can not infer the basic function"; |
468
|
|
|
|
|
|
|
my $basename = $1; # avis, hvis, ivis, dvis, or vis |
469
|
|
|
|
|
|
|
my $N = s/(\d+)// ? $1 : undef; |
470
|
|
|
|
|
|
|
my %mod = map{$_ => 1} split //, $_; |
471
|
|
|
|
|
|
|
delete $mod{"_"}; # ignore underscores |
472
|
|
|
|
|
|
|
|
473
|
|
|
|
|
|
|
if (($Debug//0) > 1) { |
474
|
|
|
|
|
|
|
warn "## (D=$Debug) methname=$methname base=$basename \$_=$_\n"; |
475
|
|
|
|
|
|
|
} |
476
|
|
|
|
|
|
|
if ($basename =~ /^[id]/) { |
477
|
|
|
|
|
|
|
error "'$1' is inapplicable to $basename" if /([ahl])/; |
478
|
|
|
|
|
|
|
} |
479
|
|
|
|
|
|
|
error "'$1' mis-placed: Only allowed as '${1}vis'" if /([ahid])/; |
480
|
|
|
|
|
|
|
|
481
|
|
|
|
|
|
|
|
482
|
|
|
|
|
|
|
# All these subs can be called as either or methods or functions. |
483
|
|
|
|
|
|
|
# If the first argument is an object it is used, otherwise a new object |
484
|
|
|
|
|
|
|
# is created; then option-setting methods are called as implied by |
485
|
|
|
|
|
|
|
# the specific sub name. |
486
|
|
|
|
|
|
|
# |
487
|
|
|
|
|
|
|
# Finally the _Do() method is invoked for primatives like 'vis'. |
488
|
|
|
|
|
|
|
# |
489
|
|
|
|
|
|
|
# For ivis/dvis, control jumps to _Interpolate() which uses the object |
490
|
|
|
|
|
|
|
# repeatedly when calling primatives to interpolate values into the string. |
491
|
|
|
|
|
|
|
|
492
|
|
|
|
|
|
|
my $listform = ''; |
493
|
|
|
|
|
|
|
my $signature = $basename =~ /^[ah]/ ? '@' : '_'; # avis(@) ivis(_) vis(_) |
494
|
|
|
|
|
|
|
my $code = "sub $methname($signature)"; |
495
|
|
|
|
|
|
|
if ($proto_only) { |
496
|
|
|
|
|
|
|
$code .= ";"; |
497
|
|
|
|
|
|
|
} else { |
498
|
|
|
|
|
|
|
if ($basename eq "vis") { |
499
|
|
|
|
|
|
|
$code .= " { &__getself_s->_Listform('')"; |
500
|
|
|
|
|
|
|
} |
501
|
|
|
|
|
|
|
elsif ($basename eq "avis") { |
502
|
|
|
|
|
|
|
my $listform = delete($mod{l}) ? 'l' : 'a'; |
503
|
|
|
|
|
|
|
$code .= " { &__getself_a->_Listform('$listform')"; |
504
|
|
|
|
|
|
|
} |
505
|
|
|
|
|
|
|
elsif ($basename eq "hvis") { |
506
|
|
|
|
|
|
|
my $listform = delete($mod{l}) ? 'l' : 'h'; |
507
|
|
|
|
|
|
|
$code .= " { &__getself_h->_Listform('$listform')"; |
508
|
|
|
|
|
|
|
} |
509
|
|
|
|
|
|
|
elsif ($basename eq "ivis") { |
510
|
|
|
|
|
|
|
$code .= " { \@_ = ( &__getself" ; |
511
|
|
|
|
|
|
|
} |
512
|
|
|
|
|
|
|
elsif ($basename eq "dvis") { |
513
|
|
|
|
|
|
|
$code .= " { \@_ = ( &__getself->_EnabSpacedots" ; |
514
|
|
|
|
|
|
|
} |
515
|
|
|
|
|
|
|
else { oops } |
516
|
|
|
|
|
|
|
|
517
|
|
|
|
|
|
|
$code .= "->Maxdepth($N)" if defined($N); |
518
|
|
|
|
|
|
|
$code .= '->Objects(0)' if delete $mod{o}; |
519
|
|
|
|
|
|
|
$code .= '->Useqq(0)' if delete $mod{q}; |
520
|
|
|
|
|
|
|
$code .= '->Useqq("unicode:controlpics")' if delete $mod{c}; |
521
|
|
|
|
|
|
|
$code .= '->Refaddr(1)' if delete $mod{r}; |
522
|
|
|
|
|
|
|
|
523
|
|
|
|
|
|
|
if ($basename =~ /^([id])vis/) { |
524
|
|
|
|
|
|
|
$code .= ", shift, '$1' ); goto &_Interpolate }"; |
525
|
|
|
|
|
|
|
} else { |
526
|
|
|
|
|
|
|
$code .= "->_Do }"; |
527
|
|
|
|
|
|
|
} |
528
|
|
|
|
|
|
|
|
529
|
|
|
|
|
|
|
for (keys %mod) { error "Unknown or inappropriate modifier '$_'" } |
530
|
|
|
|
|
|
|
} |
531
|
|
|
|
|
|
|
|
532
|
|
|
|
|
|
|
# To see the generated code |
533
|
|
|
|
|
|
|
# use Data::Dumper::Interp qw/:debug :DEFAULT/; # or :all |
534
|
|
|
|
|
|
|
if ($Debug) { |
535
|
|
|
|
|
|
|
warn "# generated: $code\n"; |
536
|
|
|
|
|
|
|
} |
537
|
54
|
|
|
54
|
1
|
32977
|
eval "$code"; oops "code=$code\n\$@=$@" if $@; |
|
54
|
|
|
6918
|
1
|
31736
|
|
|
6918
|
|
|
99
|
0
|
637109
|
|
|
1219
|
|
|
129
|
1
|
37250
|
|
|
67
|
|
|
46
|
0
|
33511
|
|
|
67
|
|
|
17
|
0
|
15136
|
|
|
103
|
|
|
17
|
0
|
13778
|
|
|
20
|
|
|
|
|
11109
|
|
|
17
|
|
|
|
|
10948
|
|
|
17
|
|
|
|
|
10688
|
|
538
|
|
|
|
|
|
|
}#_generate_sub |
539
|
|
|
|
|
|
|
|
540
|
|
|
|
|
|
|
|
541
|
41
|
|
|
41
|
1
|
34317
|
sub visnew() { __PACKAGE__->new() } # shorthand |
542
|
|
|
|
|
|
|
|
543
|
|
|
|
|
|
|
|
544
|
|
|
|
|
|
|
############# only internals follow ############ |
545
|
|
|
|
|
|
|
|
546
|
|
|
|
|
|
|
BEGIN { |
547
|
9
|
50
|
|
9
|
|
5079
|
if (! Data::Dumper->can("Maxrecurse")) { |
548
|
|
|
|
|
|
|
# Supply if missing in older Data::Dumper |
549
|
0
|
|
|
|
|
0
|
eval q(sub Data::Dumper::Maxrecurse { |
550
|
|
|
|
|
|
|
my($s, $v) = @_; |
551
|
|
|
|
|
|
|
@_ == 2 ? (($s->{Maxrecurse} = $v), return $s) |
552
|
|
|
|
|
|
|
: $s->{Maxrecurse}//0; |
553
|
|
|
|
|
|
|
}); |
554
|
0
|
0
|
|
|
|
0
|
die $@ if $@; |
555
|
|
|
|
|
|
|
} |
556
|
|
|
|
|
|
|
} |
557
|
|
|
|
|
|
|
|
558
|
|
|
|
|
|
|
sub _get_terminal_width() { # returns undef if unknowable |
559
|
27
|
100
|
|
10
|
|
205
|
if (u($ENV{COLUMNS}) =~ /^[1-9]\d*$/) { |
560
|
2
|
|
|
|
|
36
|
return $ENV{COLUMNS}; # overrides actual terminal width |
561
|
|
|
|
|
|
|
} else { |
562
|
8
|
|
|
|
|
90
|
local *_; # Try to avoid clobbering special filehandle "_" |
563
|
|
|
|
|
|
|
# This does not actualy work; https://github.com/Perl/perl5/issues/19142 |
564
|
|
|
|
|
|
|
|
565
|
|
|
|
|
|
|
my $fh = -t STDERR ? *STDERR : |
566
|
|
|
|
|
|
|
-t STDOUT ? *STDOUT : |
567
|
|
|
|
|
|
|
-t STDIN ? *STDIN : |
568
|
8
|
50
|
|
|
|
171
|
do{my $fh; for("/dev/tty",'CONOUT$') { last if open $fh, $_ } $fh} ; |
|
8
|
50
|
|
|
|
38
|
|
|
8
|
50
|
|
|
|
30
|
|
|
16
|
50
|
|
|
|
686
|
|
|
8
|
|
|
|
|
52
|
|
569
|
8
|
|
|
|
|
50
|
my $wmsg = ""; # Suppress a "didn't work" warning from Term::ReadKey. |
570
|
|
|
|
|
|
|
# On some platforms (different libc?) "stty" directly |
571
|
|
|
|
|
|
|
# outputs "stdin is not a tty" which we can not trap. |
572
|
|
|
|
|
|
|
# Probably this is a Term::Readkey bug where it should |
573
|
|
|
|
|
|
|
# redirect such messages to /dev/null... |
574
|
8
|
|
|
|
|
22
|
my ($width, $height) = do { |
575
|
8
|
|
|
8
|
|
194
|
local $SIG{'__WARN__'} = sub { $wmsg .= $_[0] }; |
|
8
|
|
|
|
|
158826
|
|
576
|
8
|
50
|
|
|
|
148
|
$fh ? Term::ReadKey::GetTerminalSize($fh) : () |
577
|
|
|
|
|
|
|
}; |
578
|
8
|
|
|
|
|
1004
|
return $width; # possibly undef (sometimes seems to be zero ?!?) |
579
|
|
|
|
|
|
|
} |
580
|
|
|
|
|
|
|
} |
581
|
|
|
|
|
|
|
|
582
|
|
|
|
|
|
|
sub _set_default_Foldwidth() { |
583
|
10
|
|
|
10
|
|
60
|
_SaveAndResetPunct(); |
584
|
10
|
|
100
|
|
|
58
|
$Foldwidth = _get_terminal_width || 80; |
585
|
10
|
|
|
|
|
357
|
_RestorePunct(); |
586
|
10
|
|
|
|
|
203
|
undef $Foldwidth1; |
587
|
|
|
|
|
|
|
} |
588
|
|
|
|
|
|
|
|
589
|
9
|
|
|
9
|
|
89
|
use constant _UNIQUE => substr(refaddr \&oops,-5); |
|
9
|
|
|
|
|
28
|
|
|
9
|
|
|
|
|
1956
|
|
590
|
|
|
|
|
|
|
use constant { |
591
|
9
|
|
|
|
|
27
|
_MAGIC_NOQUOTES_PFX => "|NQMagic${\_UNIQUE}|", |
|
9
|
|
|
|
|
28
|
|
592
|
9
|
|
|
|
|
22
|
_MAGIC_KEEPQUOTES_PFX => "|KQMagic${\_UNIQUE}|", |
593
|
9
|
|
|
|
|
19
|
_MAGIC_REFADDR => "|RAMagic${\_UNIQUE}|", |
594
|
9
|
|
|
|
|
9018
|
_MAGIC_ELIDE_NEXT => "|ENMagic${\_UNIQUE}|", |
595
|
9
|
|
|
9
|
|
78
|
}; |
|
9
|
|
|
|
|
21
|
|
596
|
|
|
|
|
|
|
|
597
|
|
|
|
|
|
|
#--------------------------------------------------------------------------- |
598
|
|
|
|
|
|
|
my $my_maxdepth; |
599
|
|
|
|
|
|
|
our $my_visit_depth = 0; |
600
|
|
|
|
|
|
|
|
601
|
|
|
|
|
|
|
my ($maxstringwidth, $truncsuffix, $objects, $opt_refaddr, $listform, $debug); |
602
|
|
|
|
|
|
|
my ($sortkeys); |
603
|
|
|
|
|
|
|
|
604
|
|
|
|
|
|
|
sub _Do { |
605
|
6024
|
50
|
|
6024
|
|
14752
|
oops unless @_ == 1; |
606
|
6024
|
|
|
|
|
9415
|
my $self = $_[0]; |
607
|
|
|
|
|
|
|
|
608
|
6024
|
|
|
|
|
9525
|
local $_; |
609
|
6024
|
|
|
|
|
14200
|
&_SaveAndResetPunct; |
610
|
|
|
|
|
|
|
|
611
|
|
|
|
|
|
|
($maxstringwidth, $truncsuffix, $objects, $opt_refaddr, $listform, $debug) |
612
|
6024
|
|
|
|
|
24239
|
= @$self{qw/MaxStringwidth Truncsuffix Objects Refaddr _Listform Debug/}; |
613
|
6024
|
|
|
|
|
22525
|
$sortkeys = $self->Sortkeys; |
614
|
|
|
|
|
|
|
|
615
|
6024
|
50
|
100
|
|
|
100387
|
$maxstringwidth = 0 if ($maxstringwidth //= 0) >= INT_MAX; |
616
|
6024
|
|
50
|
|
|
14388
|
$truncsuffix //= "..."; |
617
|
6024
|
100
|
100
|
|
|
22570
|
$objects = [ $objects ] unless ref($objects //= []) eq 'ARRAY'; |
618
|
|
|
|
|
|
|
|
619
|
6024
|
|
|
|
|
160350
|
my @orig_values = $self->dd->Values; |
620
|
6024
|
50
|
|
|
|
59459
|
croak "Exactly one item may be in Values" if @orig_values != 1; |
621
|
6024
|
|
|
|
|
12257
|
my $original = $orig_values[0]; |
622
|
6024
|
50
|
|
|
|
12953
|
btw "##ORIGINAL=",u($original),"=",_dbvis($original) if $debug; |
623
|
|
|
|
|
|
|
|
624
|
|
|
|
|
|
|
# Allow one extra level if we wrapped the user's args in __getself_[ah] |
625
|
6024
|
|
100
|
|
|
17572
|
$my_maxdepth = $self->Maxdepth || INT_MAX; |
626
|
6024
|
50
|
66
|
|
|
103646
|
++$my_maxdepth if $listform && $my_maxdepth < INT_MAX; |
627
|
|
|
|
|
|
|
|
628
|
6024
|
50
|
|
|
|
13777
|
oops unless $my_visit_depth == 0; |
629
|
6024
|
|
|
|
|
21794
|
my $modified = $self->visit($original); # see Data::Visitor |
630
|
|
|
|
|
|
|
|
631
|
6024
|
50
|
|
|
|
42623
|
btw "## DD input : ",_dbvis($modified) if $debug; |
632
|
6024
|
|
|
|
|
178040
|
$self->dd->Values([$modified]); |
633
|
|
|
|
|
|
|
|
634
|
|
|
|
|
|
|
# Always call Data::Dumper with Indent(0) and Pad("") to get a single |
635
|
|
|
|
|
|
|
# maximally-compact string, and then manually fold the result to Foldwidth, |
636
|
|
|
|
|
|
|
# inserting the user's Pad before each line *except* the first. |
637
|
|
|
|
|
|
|
# |
638
|
|
|
|
|
|
|
# Also disable Maxdepth because we did it ourself (see visit_ref). |
639
|
6024
|
|
|
|
|
72948
|
my $users_Maxdepth = $self->Maxdepth; # implemented by D::D |
640
|
6024
|
|
|
|
|
88185
|
$self->Maxdepth(0); |
641
|
6024
|
|
|
|
|
16158
|
my $users_pad = $self->Pad(); |
642
|
6024
|
|
|
|
|
88888
|
$self->Pad(""); |
643
|
|
|
|
|
|
|
|
644
|
6024
|
|
|
|
|
10632
|
my ($dd_result, $our_result); |
645
|
6024
|
|
|
|
|
16216
|
my ($sAt, $sQ) = ($@, $?); |
646
|
6024
|
|
|
|
|
9333
|
{ my $dd_warning = ""; |
|
6024
|
|
|
|
|
10405
|
|
647
|
|
|
|
|
|
|
|
648
|
6024
|
|
|
0
|
|
8841
|
{ local $SIG{__WARN__} = sub{ $dd_warning .= $_[0] }; |
|
6024
|
|
|
|
|
40979
|
|
|
0
|
|
|
|
|
0
|
|
649
|
6024
|
|
|
|
|
13524
|
eval{ $dd_result = $self->dd->Dump }; |
|
6024
|
|
|
|
|
164315
|
|
650
|
|
|
|
|
|
|
} |
651
|
6024
|
50
|
33
|
|
|
149795
|
if ($dd_warning || $@) { |
652
|
0
|
0
|
|
|
|
0
|
warn "Data::Dumper complained:\n$dd_warning\n$@" if $debug; |
653
|
0
|
|
|
|
|
0
|
($@, $?) = ($sAt, $sQ); |
654
|
0
|
|
|
|
|
0
|
$our_result = $self->dd->Values([$original])->Dump; |
655
|
|
|
|
|
|
|
} |
656
|
|
|
|
|
|
|
} |
657
|
6024
|
|
|
|
|
17421
|
($@, $?) = ($sAt, $sQ); |
658
|
6024
|
|
|
|
|
21455
|
$self->Pad($users_pad); |
659
|
6024
|
|
|
|
|
19589
|
$self->Maxdepth($users_Maxdepth); |
660
|
|
|
|
|
|
|
|
661
|
6024
|
|
66
|
|
|
103533
|
$our_result //= $self->_postprocess_DD_result($dd_result, $original); |
662
|
|
|
|
|
|
|
|
663
|
|
|
|
|
|
|
# Allow deletion of the possibly-recursive clone |
664
|
6024
|
|
|
|
|
27344
|
circular_off($modified); |
665
|
6024
|
|
|
|
|
251047
|
$self->dd->Values([]); |
666
|
|
|
|
|
|
|
|
667
|
6024
|
|
|
|
|
72869
|
&_RestorePunct; |
668
|
6024
|
|
|
|
|
38231
|
$our_result; |
669
|
|
|
|
|
|
|
} |
670
|
|
|
|
|
|
|
|
671
|
|
|
|
|
|
|
#--------------------------------------------------------------------- |
672
|
|
|
|
|
|
|
# methods called from Data::Visitor when transforming the input |
673
|
|
|
|
|
|
|
|
674
|
|
|
|
|
|
|
sub _object_subst($) { |
675
|
319
|
|
|
319
|
|
653
|
my $item = shift; |
676
|
319
|
|
|
|
|
498
|
my $overload_depth; |
677
|
|
|
|
|
|
|
CHECKObject: { |
678
|
319
|
100
|
|
|
|
547
|
if (my $class = blessed($item)) { |
|
479
|
|
|
|
|
1713
|
|
679
|
319
|
|
|
|
|
522
|
my $enabled; |
680
|
|
|
|
|
|
|
OSPEC: |
681
|
319
|
|
|
|
|
722
|
foreach my $ospec (@$objects) { |
682
|
362
|
100
|
|
|
|
1218
|
if (ref($ospec) eq "Regexp") { |
683
|
46
|
|
|
|
|
104
|
my @stack = ($class); |
684
|
46
|
|
|
|
|
66
|
my %seen; |
685
|
46
|
|
|
|
|
108
|
while (my $c = shift @stack) { |
686
|
78
|
100
|
|
|
|
475
|
$enabled=1, last OSPEC if $c =~ $ospec; |
687
|
48
|
50
|
|
|
|
150
|
last CHECKObject if $seen{$c}++; # circular ISAs ! |
688
|
9
|
|
|
9
|
|
79
|
no strict 'refs'; |
|
9
|
|
|
|
|
18
|
|
|
9
|
|
|
|
|
24233
|
|
689
|
48
|
|
|
|
|
71
|
push @stack, @{"${c}::ISA"}; |
|
48
|
|
|
|
|
265
|
|
690
|
|
|
|
|
|
|
} |
691
|
|
|
|
|
|
|
} else { |
692
|
316
|
100
|
100
|
|
|
1453
|
$enabled=1, last OSPEC if ($ospec eq "1" || $item->isa($ospec)); |
693
|
|
|
|
|
|
|
} |
694
|
|
|
|
|
|
|
} |
695
|
|
|
|
|
|
|
last CHECKObject |
696
|
319
|
100
|
|
|
|
2271
|
unless $enabled; |
697
|
299
|
100
|
|
|
|
1182
|
if (overload::Overloaded($item)) { |
698
|
160
|
50
|
|
|
|
9625
|
btw '@@@repl overloaded ',"\'$class\'" if $debug; |
699
|
|
|
|
|
|
|
# N.B. Overloaded(...) also returns true if it's a NAME of an |
700
|
|
|
|
|
|
|
# overloaded package; should not happen in this case. |
701
|
160
|
50
|
|
|
|
459
|
warn("Recursive overloads on $item ?\n"),last |
702
|
|
|
|
|
|
|
if $overload_depth++ > 10; |
703
|
|
|
|
|
|
|
# Stringify objects which have the stringification operator |
704
|
160
|
100
|
|
|
|
358
|
if (overload::Method($class,'""')) { |
705
|
155
|
50
|
|
|
|
5683
|
my $prefix = _show_as_number($item) ? _MAGIC_NOQUOTES_PFX : ""; |
706
|
155
|
50
|
|
|
|
365
|
btw '@@@repl prefix="',$prefix,'"' if $debug; |
707
|
155
|
|
|
|
|
831
|
$item = $item.""; # stringify; |
708
|
155
|
50
|
|
|
|
9292
|
if ($item !~ /^${class}=REF/) { |
709
|
155
|
|
|
|
|
500
|
$item = "${prefix}($class)$item"; |
710
|
|
|
|
|
|
|
} else { |
711
|
|
|
|
|
|
|
# The "stringification" looks like Perl's default; don't prefix it |
712
|
|
|
|
|
|
|
} |
713
|
155
|
50
|
|
|
|
351
|
btw '@@@repl stringified:',$item if $debug; |
714
|
155
|
|
|
|
|
512
|
redo CHECKObject; |
715
|
|
|
|
|
|
|
} |
716
|
|
|
|
|
|
|
# Substitute the virtual value behind an overloaded deref operator |
717
|
5
|
100
|
|
|
|
163
|
if (overload::Method($class,'@{}')) { |
718
|
1
|
50
|
|
|
|
36
|
btw '@@@repl (overload...)' if $debug; |
719
|
1
|
|
|
|
|
1
|
$item = \@{ $item }; |
|
1
|
|
|
|
|
27
|
|
720
|
1
|
|
|
|
|
18
|
redo CHECKObject; |
721
|
|
|
|
|
|
|
} |
722
|
4
|
100
|
|
|
|
99
|
if (overload::Method($class,'%{}')) { |
723
|
1
|
50
|
|
|
|
35
|
btw '@@@repl (overload...)' if $debug; |
724
|
1
|
|
|
|
|
2
|
$item = \%{ $item }; |
|
1
|
|
|
|
|
33
|
|
725
|
1
|
|
|
|
|
18
|
redo CHECKObject; |
726
|
|
|
|
|
|
|
} |
727
|
3
|
100
|
|
|
|
71
|
if (overload::Method($class,'${}')) { |
728
|
1
|
50
|
|
|
|
33
|
btw '@@@repl (overload...)' if $debug; |
729
|
1
|
|
|
|
|
2
|
$item = \${ $item }; |
|
1
|
|
|
|
|
25
|
|
730
|
1
|
|
|
|
|
7
|
redo CHECKObject; |
731
|
|
|
|
|
|
|
} |
732
|
2
|
100
|
|
|
|
54
|
if (overload::Method($class,'&{}')) { |
733
|
1
|
50
|
|
|
|
44
|
btw '@@@repl (overload...)' if $debug; |
734
|
1
|
|
|
|
|
2
|
$item = \&{ $item }; |
|
1
|
|
|
|
|
25
|
|
735
|
1
|
|
|
|
|
14
|
redo CHECKObject; |
736
|
|
|
|
|
|
|
} |
737
|
1
|
50
|
|
|
|
27
|
if (overload::Method($class,'*{}')) { |
738
|
1
|
50
|
|
|
|
31
|
btw '@@@repl (overload...)' if $debug; |
739
|
1
|
|
|
|
|
2
|
$item = \*{ $item }; |
|
1
|
|
|
|
|
25
|
|
740
|
1
|
|
|
|
|
7
|
redo CHECKObject; |
741
|
|
|
|
|
|
|
} |
742
|
|
|
|
|
|
|
} |
743
|
139
|
100
|
|
|
|
8669
|
if ($class eq 'Regexp') { |
744
|
|
|
|
|
|
|
# D::D will just stringify it, which is fine except actual tabs etc. |
745
|
|
|
|
|
|
|
# will be shown as themselves and not \t etc. |
746
|
|
|
|
|
|
|
# We try to fix that in _postprocess_DD_result; |
747
|
|
|
|
|
|
|
} else { |
748
|
|
|
|
|
|
|
# No overloaded operator (that we care about); |
749
|
|
|
|
|
|
|
# substitute addrvis(obj) |
750
|
1
|
50
|
|
|
|
27
|
btw '@@@repl (no overload repl, not Regexp)' if $debug; |
751
|
1
|
|
|
|
|
14
|
$item = _MAGIC_NOQUOTES_PFX.addrvis($item); |
752
|
|
|
|
|
|
|
} |
753
|
|
|
|
|
|
|
} |
754
|
|
|
|
|
|
|
}#CHECKObject |
755
|
|
|
|
|
|
|
$item |
756
|
319
|
|
|
|
|
1506
|
}#_object_subst |
757
|
|
|
|
|
|
|
|
758
|
|
|
|
|
|
|
sub visit_value { |
759
|
8195
|
|
|
8195
|
1
|
210184
|
my $self = shift; |
760
|
8195
|
50
|
|
|
|
18996
|
say "!V value ",_dbravis2(@_)," depth:$my_visit_depth" if $debug; |
761
|
8195
|
|
|
|
|
12801
|
my $item = shift; |
762
|
|
|
|
|
|
|
# N.B. Not called for hash keys (short-circuited in visit_hash_key) |
763
|
|
|
|
|
|
|
|
764
|
8195
|
100
|
|
|
|
16195
|
return $item |
765
|
|
|
|
|
|
|
if !defined($item); |
766
|
|
|
|
|
|
|
|
767
|
8178
|
100
|
|
|
|
20509
|
return _object_subst($item) |
768
|
|
|
|
|
|
|
if defined(blessed $item); |
769
|
|
|
|
|
|
|
|
770
|
7859
|
100
|
|
|
|
18028
|
return $item |
771
|
|
|
|
|
|
|
if reftype($item); # some other (i.e. not blessed) reference |
772
|
|
|
|
|
|
|
|
773
|
|
|
|
|
|
|
# Prepend a "magic prefix" (later removed) to items which Data::Dumper is |
774
|
|
|
|
|
|
|
# likely to represent wrongly or anyway not how we want: |
775
|
|
|
|
|
|
|
# |
776
|
|
|
|
|
|
|
# 1. Scalars set to strings like "6" will come out as a number 6 rather |
777
|
|
|
|
|
|
|
# than "6" with Useqq(1) or Useperl(1) (string-ness is preserved |
778
|
|
|
|
|
|
|
# with other options). IMO this is a Data::Dumper bug which the |
779
|
|
|
|
|
|
|
# maintainers won't fix it because the difference isn't functionally |
780
|
|
|
|
|
|
|
# relevant to correctly-written Perl code. However we want to help |
781
|
|
|
|
|
|
|
# humans debug their software by showing the representation they |
782
|
|
|
|
|
|
|
# most likely used to create the datum. |
783
|
|
|
|
|
|
|
# |
784
|
|
|
|
|
|
|
# 2. Floating point values come out as "strings" to avoid some |
785
|
|
|
|
|
|
|
# cross-platform issue. For our purposes we want all numbers |
786
|
|
|
|
|
|
|
# to appear unquoted. |
787
|
|
|
|
|
|
|
# |
788
|
7857
|
100
|
66
|
|
|
43285
|
if (looks_like_number($item) && $item !~ /^0\d/) { |
|
|
100
|
66
|
|
|
|
|
|
|
|
100
|
|
|
|
|
789
|
2998
|
100
|
|
|
|
7053
|
my $prefix = _show_as_number($item) ? _MAGIC_NOQUOTES_PFX |
790
|
|
|
|
|
|
|
: _MAGIC_KEEPQUOTES_PFX ; |
791
|
2998
|
|
|
|
|
7824
|
$item = $prefix.$item; |
792
|
2998
|
50
|
|
|
|
7773
|
btw '@@@repl prefixed item:',$item if $debug; |
793
|
|
|
|
|
|
|
} |
794
|
|
|
|
|
|
|
|
795
|
|
|
|
|
|
|
# Truncacte overly-long strings |
796
|
|
|
|
|
|
|
elsif ($maxstringwidth && !_show_as_number($item) |
797
|
|
|
|
|
|
|
&& length($item) > $maxstringwidth + length($truncsuffix)) { |
798
|
9
|
50
|
|
|
|
22
|
btw '@@@repl truncating ',substr($item,0,10),"..." if $debug; |
799
|
9
|
|
|
|
|
26
|
$item = "".substr($item,0,$maxstringwidth).$truncsuffix; |
800
|
|
|
|
|
|
|
} |
801
|
|
|
|
|
|
|
$item |
802
|
7857
|
|
|
|
|
26827
|
}#visit_value |
803
|
|
|
|
|
|
|
|
804
|
|
|
|
|
|
|
sub visit_hash_key { |
805
|
1518
|
|
|
1518
|
1
|
12449
|
my ($self, $item) = @_; |
806
|
1518
|
50
|
|
|
|
3220
|
say "!V visit_hash_key ",_dbravis2($item)," depth:$my_visit_depth" if $debug; |
807
|
1518
|
|
|
|
|
4316
|
return $item; # don't truncate or otherwise munge |
808
|
|
|
|
|
|
|
} |
809
|
|
|
|
|
|
|
|
810
|
|
|
|
|
|
|
sub _prefix_refaddr($;$) { |
811
|
1998
|
|
|
1998
|
|
3759
|
my ($item, $original) = @_; |
812
|
|
|
|
|
|
|
# If enabled by Refaddr(true): |
813
|
|
|
|
|
|
|
# |
814
|
|
|
|
|
|
|
# Prefix (the formatted representation of) a ref with it's abbreviated |
815
|
|
|
|
|
|
|
# address. This is done by wrapping the ref in a temporary [array] with the |
816
|
|
|
|
|
|
|
# prefix, and unwrapping the Data::Dumper result in _postprocess_DD_result(). |
817
|
|
|
|
|
|
|
# |
818
|
|
|
|
|
|
|
# However don't do this if $item already has an addrvis() substituted, |
819
|
|
|
|
|
|
|
# which happens if an object does not stringify or provide another overload |
820
|
|
|
|
|
|
|
# replacement -- see _object_subst(). |
821
|
1998
|
100
|
66
|
|
|
5584
|
return $item |
|
|
|
100
|
|
|
|
|
822
|
|
|
|
|
|
|
unless $opt_refaddr && (!$listform || $my_visit_depth > 0); |
823
|
37
|
|
33
|
|
|
133
|
my $pfx = addrvis(refaddr($original//$item)); |
824
|
37
|
|
|
|
|
106
|
my $ix = index($item,$pfx); |
825
|
37
|
50
|
|
|
|
337
|
say "_prefix_refaddr: pfx=$pfx ix=$ix original=",_dbvis1($original)," item=$item" if $debug; |
826
|
37
|
50
|
|
|
|
82
|
return $item if $ix >= 0; |
827
|
37
|
|
|
|
|
188
|
$item = [ _MAGIC_REFADDR.$pfx, $item, _MAGIC_ELIDE_NEXT, ]; |
828
|
37
|
50
|
|
|
|
90
|
btwN 1, '@@@addrvis-prefixed object:',_dbvis2($item) if $debug; |
829
|
37
|
|
|
|
|
75
|
$item |
830
|
|
|
|
|
|
|
}#_prefix_refaddr |
831
|
|
|
|
|
|
|
|
832
|
|
|
|
|
|
|
sub visit_object { |
833
|
319
|
|
|
319
|
1
|
11170
|
my $self = shift; |
834
|
319
|
|
|
|
|
580
|
my $item = shift; |
835
|
319
|
50
|
|
|
|
788
|
say "!V object a=",addrvis(refaddr $item)," depth:$my_visit_depth"," item=",_dbvis1($item) if $debug; |
836
|
319
|
|
|
|
|
653
|
my $original = $item; |
837
|
|
|
|
|
|
|
|
838
|
319
|
|
|
|
|
593
|
local $my_visit_depth = $my_visit_depth + 1; |
839
|
|
|
|
|
|
|
# FIXME: with Objects(0) we should visit object internals so $my_maxdepth |
840
|
|
|
|
|
|
|
# can be applied correctly. Currently we just leave object refs as-is |
841
|
|
|
|
|
|
|
# for D::D to expand, and Maxdepth will be handled incorrectly if the |
842
|
|
|
|
|
|
|
# is underneath a magic_refaddr wrapper or avis/hvis top wrapper. |
843
|
|
|
|
|
|
|
|
844
|
|
|
|
|
|
|
# First register the ref (to detect duplicates); |
845
|
|
|
|
|
|
|
# this calls visit_seen() which usually substitutes something |
846
|
319
|
|
|
|
|
1028
|
my $nitem = $self->SUPER::visit_object($item); |
847
|
319
|
50
|
|
|
|
3816
|
say "! (obj) new: ",_dbvis1($item), " --> ",_dbrvis2($nitem) if $debug; |
848
|
319
|
|
|
|
|
760
|
$item = $nitem; |
849
|
|
|
|
|
|
|
|
850
|
319
|
|
|
|
|
703
|
$item = _prefix_refaddr($item, $original); |
851
|
319
|
|
|
|
|
1282
|
$item |
852
|
|
|
|
|
|
|
}#visit_object |
853
|
|
|
|
|
|
|
|
854
|
|
|
|
|
|
|
sub visit_ref { |
855
|
1679
|
|
|
1679
|
1
|
57691
|
my ($self, $item) = @_; |
856
|
1679
|
100
|
|
|
|
4169
|
if (ref($item) eq 'ARRAY') { |
857
|
546
|
50
|
|
|
|
1476
|
say "!V ref A=",addrvis(refaddr $item)," depth:$my_visit_depth max:$my_maxdepth item=",_dbavis2(@$item) if $debug; |
858
|
|
|
|
|
|
|
} else { |
859
|
1133
|
50
|
|
|
|
2673
|
say "!V ref a=",addrvis(refaddr $item)," depth:$my_visit_depth max:$my_maxdepth item=",_dbvis1($item) if $debug; |
860
|
|
|
|
|
|
|
} |
861
|
1679
|
|
|
|
|
2550
|
my $original = $item; |
862
|
|
|
|
|
|
|
|
863
|
|
|
|
|
|
|
# The Refaddr option introduces [...] wrappers in the tree and so |
864
|
|
|
|
|
|
|
# Data::Dumper's Maxdepth() option will not work as we intend. |
865
|
|
|
|
|
|
|
# Therefore we implement Maxdepth ourself |
866
|
1679
|
50
|
|
|
|
3582
|
if ($my_visit_depth >= $my_maxdepth) { |
867
|
0
|
0
|
|
|
|
0
|
oops unless $my_visit_depth == $my_maxdepth; |
868
|
0
|
|
|
|
|
0
|
$item = _MAGIC_NOQUOTES_PFX.addrvis($item); |
869
|
0
|
0
|
|
|
|
0
|
say "! maxdepth reached, returning ",_dbvis2($item) if $debug; |
870
|
0
|
|
|
|
|
0
|
return $item |
871
|
|
|
|
|
|
|
} |
872
|
|
|
|
|
|
|
|
873
|
|
|
|
|
|
|
# First descend into the structure, probably returning a clone |
874
|
1679
|
|
|
|
|
2893
|
local $my_visit_depth = $my_visit_depth + 1; |
875
|
1679
|
|
|
|
|
4871
|
my $nitem = $self->SUPER::visit_ref($item); |
876
|
1679
|
50
|
|
|
|
33557
|
say "! (ref) new: ",_dbvis2($item), " --> ",_dbvis2($nitem) if $debug; |
877
|
1679
|
|
|
|
|
2701
|
$item = $nitem; |
878
|
|
|
|
|
|
|
|
879
|
|
|
|
|
|
|
# Prepend the original address to whatever the representation is now |
880
|
1679
|
|
|
|
|
3540
|
$item = _prefix_refaddr($item, $original); |
881
|
|
|
|
|
|
|
|
882
|
1679
|
|
|
|
|
5142
|
$item |
883
|
|
|
|
|
|
|
} |
884
|
|
|
|
|
|
|
sub visit_hash_entries { |
885
|
561
|
|
|
561
|
1
|
21645
|
my ($self, $hash) = @_; |
886
|
|
|
|
|
|
|
# Visit in sorted order |
887
|
1518
|
|
|
|
|
9994
|
return map { $self->visit_hash_entry( $_, $hash->{$_}, $hash ) } |
888
|
561
|
100
|
|
|
|
1534
|
(ref($sortkeys) ? @{ $sortkeys->($hash) } : (sort keys %$hash)); |
|
553
|
|
|
|
|
1224
|
|
889
|
|
|
|
|
|
|
} |
890
|
|
|
|
|
|
|
|
891
|
|
|
|
|
|
|
sub visit_glob { |
892
|
3
|
|
|
3
|
1
|
88
|
my ($self, $item) = @_; |
893
|
3
|
50
|
|
|
|
10
|
say "!V glob ref()=",ref($item)," depth:$my_visit_depth"," item=",_dbravis2($item) if $debug; |
894
|
|
|
|
|
|
|
# By default Data::Visitor will create a new anon glob in the output tree. |
895
|
|
|
|
|
|
|
# Instead, put the original into the output so the user can recognize |
896
|
|
|
|
|
|
|
# it e.g. "*main::STDOUT" instead of an anonymous from Symbol::gensym |
897
|
3
|
|
|
|
|
10
|
return $item |
898
|
|
|
|
|
|
|
} |
899
|
|
|
|
|
|
|
|
900
|
|
|
|
|
|
|
sub visit_seen { |
901
|
18
|
|
|
18
|
1
|
585
|
my ($self, $data, $first_result) = @_; |
902
|
18
|
50
|
|
|
|
42
|
say "!V seen orig=",_dbrvis2($data)," depth:$my_visit_depth"," 1stres=",_dbrvis2($first_result) |
903
|
|
|
|
|
|
|
if $debug; |
904
|
|
|
|
|
|
|
|
905
|
|
|
|
|
|
|
# $data is a ref which has been visited before, i.e. there is a circularity. |
906
|
|
|
|
|
|
|
# Data::Dumper will display a $VAR->... expression. |
907
|
|
|
|
|
|
|
# With the Refaddr option the $VAR index may be incorrect due to the |
908
|
|
|
|
|
|
|
# temporary [...] wrappers inserted into the cloned tree. |
909
|
|
|
|
|
|
|
# |
910
|
|
|
|
|
|
|
# Therefore if Refaddr is in effect substitute an addrvis() string |
911
|
|
|
|
|
|
|
# which the user will be able to match with other refs to the same thing. |
912
|
18
|
100
|
|
|
|
43
|
if ($opt_refaddr) { |
913
|
7
|
|
|
|
|
21
|
my $t = ref($data); |
914
|
7
|
100
|
|
|
|
28
|
return _MAGIC_NOQUOTES_PFX.addrvis(refaddr $data)."[...]" if $t eq "ARRAY"; |
915
|
5
|
100
|
|
|
|
37
|
return _MAGIC_NOQUOTES_PFX.addrvis(refaddr $data)."{...}" if $t eq "HASH"; |
916
|
3
|
100
|
|
|
|
19
|
return _MAGIC_NOQUOTES_PFX.addrvis(refaddr $data)."\\..." if $t eq "SCALAR"; |
917
|
1
|
|
|
|
|
5
|
return _MAGIC_NOQUOTES_PFX.addrvis($data); |
918
|
|
|
|
|
|
|
} |
919
|
|
|
|
|
|
|
|
920
|
|
|
|
|
|
|
$first_result |
921
|
11
|
|
|
|
|
27
|
} |
922
|
|
|
|
|
|
|
|
923
|
|
|
|
|
|
|
#--------------------------------------------------------------------- |
924
|
|
|
|
|
|
|
sub _preprocess { # Modify the cloned data |
925
|
9
|
|
|
9
|
|
88
|
no warnings 'recursion'; |
|
9
|
|
|
|
|
35
|
|
|
9
|
|
|
|
|
9029
|
|
926
|
0
|
|
|
0
|
|
0
|
my ($self, $cloned_itemref, $orig_itemref) = @_; |
927
|
0
|
|
|
|
|
0
|
my ($debug, $seenhash) = @$self{qw/Debug Seenhash/}; |
928
|
|
|
|
|
|
|
|
929
|
0
|
0
|
|
|
|
0
|
btw '##pp AAA cloned=",addrvis($cloned_itemref)," -> ',_dbvis($$cloned_itemref) if $debug; |
930
|
0
|
0
|
|
|
|
0
|
btw '## orig=",addrvis($orig_itemref)," -> ",_dbvis($$orig_itemref)' if $debug; |
931
|
|
|
|
|
|
|
|
932
|
|
|
|
|
|
|
# Pop back if this item was visited previously |
933
|
0
|
0
|
|
|
|
0
|
if ($seenhash->{ refaddr($cloned_itemref) }++) { |
934
|
0
|
0
|
|
|
|
0
|
btw ' Seen already' if $debug; |
935
|
|
|
|
|
|
|
return |
936
|
0
|
|
|
|
|
0
|
} |
937
|
|
|
|
|
|
|
|
938
|
|
|
|
|
|
|
# About TIED VARIABLES: |
939
|
|
|
|
|
|
|
# We must never modify a tied variable because of user-defined side-effects. |
940
|
|
|
|
|
|
|
# So when we want to replace a tied variable we untie it first, if possible. |
941
|
|
|
|
|
|
|
# N.B. The whole structure was cloned, so this does not untie the |
942
|
|
|
|
|
|
|
# user's variables. |
943
|
|
|
|
|
|
|
# |
944
|
|
|
|
|
|
|
# All modifications (untie and over-writing) is done in eval{...} in case |
945
|
|
|
|
|
|
|
# the data is read-only or an UNTIE handler throws -- in which case we leave |
946
|
|
|
|
|
|
|
# the cloned item as it is. This occurs e.g. with the 'Readonly' module; |
947
|
|
|
|
|
|
|
# I tried using Readonly::Clone (insterad of Clone::clone) to copy the input, |
948
|
|
|
|
|
|
|
# since it is supposed to make a mutable copy; but it has bugs with refs to |
949
|
|
|
|
|
|
|
# other refs, and doesn't actually make everything mutable; it was a big mess |
950
|
|
|
|
|
|
|
# so now taking the simple way out. |
951
|
|
|
|
|
|
|
|
952
|
|
|
|
|
|
|
# Side note: Taking a ref to a member of a tied container, |
953
|
|
|
|
|
|
|
# e.g. \$tiedhash{key}, actually returns an overloaded object or some other |
954
|
|
|
|
|
|
|
# magical thing which, every time it is de-referenced, FETCHes the datum |
955
|
|
|
|
|
|
|
# into a temporary. |
956
|
|
|
|
|
|
|
# |
957
|
|
|
|
|
|
|
# There is a bug somewhere which makes it unsafe to store these fake |
958
|
|
|
|
|
|
|
# references inside tied variables because after the variable is 'untie'd |
959
|
|
|
|
|
|
|
# bad things can happen (refcount problems?). So after a lot of mucking |
960
|
|
|
|
|
|
|
# around I gave up trying to do anything intelligent about tied data. |
961
|
|
|
|
|
|
|
# I still have to untie variables before over-writing them with substitute |
962
|
|
|
|
|
|
|
# content. |
963
|
|
|
|
|
|
|
|
964
|
|
|
|
|
|
|
# Note: Our Item is only ever a scalar, either the top-level item from the |
965
|
|
|
|
|
|
|
# user or a member of a container we unroll below. In either case the |
966
|
|
|
|
|
|
|
# scalar could be either a ref to something or a non-ref value. |
967
|
|
|
|
|
|
|
|
968
|
0
|
|
|
|
|
0
|
eval { |
969
|
0
|
0
|
|
|
|
0
|
if (tied($$cloned_itemref)) { |
970
|
0
|
0
|
|
|
|
0
|
btw ' Item itself is tied' if $debug; |
971
|
0
|
|
|
|
|
0
|
my $copy = $$cloned_itemref; |
972
|
0
|
|
|
|
|
0
|
untie $$cloned_itemref; |
973
|
0
|
|
|
|
|
0
|
$$cloned_itemref = $copy; # n.b. $copy might be a ref to a tied variable |
974
|
0
|
0
|
|
|
|
0
|
oops if tied($$cloned_itemref); |
975
|
|
|
|
|
|
|
} |
976
|
|
|
|
|
|
|
|
977
|
0
|
|
0
|
|
|
0
|
my $rt = reftype($$cloned_itemref) // ""; # "" if item is not a ref |
978
|
0
|
0
|
|
|
|
0
|
if (reftype($cloned_itemref) eq "SCALAR") { |
979
|
0
|
0
|
|
|
|
0
|
oops if $rt; |
980
|
0
|
0
|
|
|
|
0
|
btw '##pp item is non-ref scalar; stop.' if $debug; |
981
|
|
|
|
|
|
|
return |
982
|
0
|
|
|
|
|
0
|
} |
983
|
|
|
|
|
|
|
|
984
|
|
|
|
|
|
|
# Item is some kind of ref |
985
|
0
|
0
|
|
|
|
0
|
oops unless reftype($cloned_itemref) eq "REF"; |
986
|
0
|
0
|
|
|
|
0
|
oops unless reftype($orig_itemref) eq "REF"; |
987
|
|
|
|
|
|
|
|
988
|
0
|
0
|
0
|
|
|
0
|
if ($rt eq "SCALAR" || $rt eq "LVALUE" || $rt eq "REF") { |
|
|
0
|
0
|
|
|
|
|
|
|
0
|
|
|
|
|
|
989
|
0
|
0
|
|
|
|
0
|
btw '##pp dereferencing ref-to-scalarish $rt' if $debug; |
990
|
0
|
|
|
|
|
0
|
$self->_preprocess($$cloned_itemref, $$orig_itemref); |
991
|
|
|
|
|
|
|
} |
992
|
|
|
|
|
|
|
elsif ($rt eq "ARRAY") { |
993
|
0
|
0
|
|
|
|
0
|
btw '##pp ARRAY ref' if $debug; |
994
|
0
|
0
|
|
|
|
0
|
if (tied @$$cloned_itemref) { |
995
|
0
|
0
|
|
|
|
0
|
btw ' aref to *tied* ARRAY' if $debug; |
996
|
0
|
|
|
|
|
0
|
my $copy = [ @$$cloned_itemref ]; # only 1 level |
997
|
0
|
|
|
|
|
0
|
untie @$$cloned_itemref; |
998
|
0
|
|
|
|
|
0
|
@$$cloned_itemref = @$copy; |
999
|
|
|
|
|
|
|
} |
1000
|
0
|
|
|
|
|
0
|
for my $ix (0..$#{$$cloned_itemref}) { |
|
0
|
|
|
|
|
0
|
|
1001
|
0
|
|
|
|
|
0
|
$self->_preprocess(\$$cloned_itemref->[$ix], \$$orig_itemref->[$ix]); |
1002
|
|
|
|
|
|
|
} |
1003
|
|
|
|
|
|
|
} |
1004
|
|
|
|
|
|
|
elsif ($rt eq "HASH") { |
1005
|
0
|
0
|
|
|
|
0
|
btw '##pp HASH ref' if $debug; |
1006
|
0
|
0
|
|
|
|
0
|
if (tied %$$cloned_itemref) { |
1007
|
0
|
0
|
|
|
|
0
|
btw ' href to *tied* HASH' if $debug; |
1008
|
0
|
|
|
|
|
0
|
my $copy = { %$$cloned_itemref }; # only 1 level |
1009
|
0
|
|
|
|
|
0
|
untie %$$cloned_itemref; |
1010
|
0
|
|
|
|
|
0
|
%$$cloned_itemref = %$copy; |
1011
|
0
|
0
|
|
|
|
0
|
die if tied %$$cloned_itemref; |
1012
|
|
|
|
|
|
|
} |
1013
|
|
|
|
|
|
|
#For easier debugging, do in sorted order |
1014
|
0
|
0
|
|
|
|
0
|
btw ' #### iterating hash values...' if $debug; |
1015
|
0
|
|
|
|
|
0
|
for my $key (sort keys %$$cloned_itemref) { |
1016
|
0
|
|
|
|
|
0
|
$self->_preprocess(\$$cloned_itemref->{$key}, \$$orig_itemref->{$key}); |
1017
|
|
|
|
|
|
|
} |
1018
|
|
|
|
|
|
|
} |
1019
|
|
|
|
|
|
|
};#eval |
1020
|
0
|
0
|
|
|
|
0
|
if ($@) { |
1021
|
0
|
0
|
|
|
|
0
|
btw "*EXCEPTION*, just returning\n$@\n" if $debug; |
1022
|
|
|
|
|
|
|
} |
1023
|
|
|
|
|
|
|
} |
1024
|
|
|
|
|
|
|
|
1025
|
|
|
|
|
|
|
sub _show_as_number(_) { |
1026
|
4009
|
|
|
4009
|
|
270729
|
my $value = shift; |
1027
|
|
|
|
|
|
|
|
1028
|
|
|
|
|
|
|
# IMPORTANT: We must not do any numeric ops or comparisions |
1029
|
|
|
|
|
|
|
# on $value because that may set some magic which defeats our attempt |
1030
|
|
|
|
|
|
|
# to try bitstring unary & below (after a numeric compare, $value is |
1031
|
|
|
|
|
|
|
# apparently assumed to be numeric or dual-valued even if it |
1032
|
|
|
|
|
|
|
# is/was just a "string"). |
1033
|
|
|
|
|
|
|
|
1034
|
4009
|
100
|
|
|
|
9024
|
return 0 if !defined $value; |
1035
|
|
|
|
|
|
|
|
1036
|
|
|
|
|
|
|
# if the utf8 flag is on, it almost certainly started as a string |
1037
|
4008
|
100
|
100
|
|
|
15997
|
return 0 if (ref($value) eq "") && utf8::is_utf8($value); |
1038
|
|
|
|
|
|
|
|
1039
|
|
|
|
|
|
|
# There was a Perl bug where looks_like_number() provoked a warning from |
1040
|
|
|
|
|
|
|
# BigRat.pm if it is called under 'use bigrat;' so we must not do that. |
1041
|
|
|
|
|
|
|
# https://github.com/Perl/perl5/issues/20685 |
1042
|
|
|
|
|
|
|
#return 0 unless looks_like_number($value); |
1043
|
|
|
|
|
|
|
|
1044
|
|
|
|
|
|
|
# JSON::PP uses these tricks: |
1045
|
|
|
|
|
|
|
# string & "" -> "" # bitstring AND, truncating to shortest operand |
1046
|
|
|
|
|
|
|
# number & "" -> 0 (with warning) |
1047
|
|
|
|
|
|
|
# number * 0 -> 0 unless number is nan or inf |
1048
|
|
|
|
|
|
|
|
1049
|
|
|
|
|
|
|
# Attempt uniary & with "string" and see what happens |
1050
|
3993
|
|
|
|
|
7275
|
my $uand_str_result = eval { |
1051
|
9
|
|
|
9
|
|
80
|
use warnings "FATAL" => "all"; # Convert warnings into exceptions |
|
9
|
|
|
|
|
24
|
|
|
9
|
|
|
|
|
1105
|
|
1052
|
|
|
|
|
|
|
# 'bitwise' is the default only in newer perls. So disable. |
1053
|
|
|
|
|
|
|
BEGIN { |
1054
|
9
|
|
|
9
|
|
34
|
eval { # "no feature 'bitwise'" won't compile on Perl 5.20 |
1055
|
9
|
|
|
|
|
401
|
feature->unimport( 'bitwise' ); |
1056
|
9
|
|
|
|
|
167
|
warnings->unimport("experimental::bitwise"); |
1057
|
|
|
|
|
|
|
}; |
1058
|
9
|
|
|
|
|
284
|
$@ = ""; |
1059
|
|
|
|
|
|
|
} |
1060
|
9
|
|
|
9
|
|
90
|
no warnings "once"; |
|
9
|
|
|
|
|
42
|
|
|
9
|
|
|
|
|
9756
|
|
1061
|
|
|
|
|
|
|
# Use FF... so we can see what $value was in debug messages below |
1062
|
3993
|
|
|
|
|
46781
|
my $dummy = ($value & "\x{FF}\x{FF}\x{FF}\x{FF}\x{FF}\x{FF}\x{FF}\x{FF}"); |
1063
|
|
|
|
|
|
|
}; |
1064
|
3993
|
50
|
|
|
|
104451
|
btw '##_san $value \$@=$@' if $Debug; |
1065
|
3993
|
100
|
100
|
|
|
9527
|
if ($@) { |
|
|
100
|
|
|
|
|
|
1066
|
3019
|
50
|
|
|
|
18201
|
if ($@ =~ /".*" isn't numeric/) { |
1067
|
3019
|
|
|
|
|
8989
|
return 1; # Ergo $value must be numeric |
1068
|
|
|
|
|
|
|
} |
1069
|
0
|
0
|
|
|
|
0
|
if ($@ =~ /\& not supported/) { |
1070
|
|
|
|
|
|
|
# If it is an object then it probably (but not necessarily) |
1071
|
|
|
|
|
|
|
# is numeric but just doesn't support bitwise operators, |
1072
|
|
|
|
|
|
|
# for example BigRat. |
1073
|
0
|
0
|
|
|
|
0
|
return 1 if defined blessed($value); |
1074
|
|
|
|
|
|
|
} |
1075
|
0
|
0
|
|
|
|
0
|
if ($@ =~ /no method found/) { # overloaded but does not do '&' |
1076
|
|
|
|
|
|
|
# It must use overloads, but does not implement '&' |
1077
|
|
|
|
|
|
|
# Assume it is string-ish |
1078
|
0
|
0
|
|
|
|
0
|
return 0 if defined blessed($value); # else our mistake, isn't overloaded |
1079
|
|
|
|
|
|
|
} |
1080
|
0
|
0
|
|
|
|
0
|
warn "# ".__PACKAGE__." : value=",_dbshow($value), |
1081
|
|
|
|
|
|
|
"\n Unhandled warn/exception from unary & :$@\n" |
1082
|
|
|
|
|
|
|
if $Debug; |
1083
|
|
|
|
|
|
|
# Unknown problem, treat as a string |
1084
|
0
|
|
|
|
|
0
|
return 0; |
1085
|
|
|
|
|
|
|
} |
1086
|
|
|
|
|
|
|
elsif (ref($uand_str_result) ne "" && $uand_str_result =~ /NaN|Inf/) { |
1087
|
|
|
|
|
|
|
# unary & returned an object representing Nan or Inf |
1088
|
|
|
|
|
|
|
# (e.g. Math::BigFloat) so $value must be numberish. |
1089
|
140
|
|
|
|
|
3327
|
return 1; |
1090
|
|
|
|
|
|
|
} |
1091
|
834
|
50
|
|
|
|
2323
|
warn "# ".__PACKAGE__." : (value & \"...\") succeeded\n", |
1092
|
|
|
|
|
|
|
" value=", _dbshow($value), "\n", |
1093
|
|
|
|
|
|
|
" uand_str_result=", _dbvis($uand_str_result),"\n" |
1094
|
|
|
|
|
|
|
if $Debug; |
1095
|
|
|
|
|
|
|
# Sigh. With Perl 5.32 (at least) $value & "..." stringifies $value |
1096
|
|
|
|
|
|
|
# or so it seems. |
1097
|
834
|
100
|
|
|
|
2247
|
if (blessed($value)) { |
1098
|
|
|
|
|
|
|
# +42 might throw if object is not numberish e.g. a DateTime |
1099
|
28
|
50
|
|
|
|
59
|
if (blessed(eval{ $value + 42 })) { |
|
28
|
|
|
|
|
86
|
|
1100
|
28
|
50
|
|
|
|
20683
|
warn " Object and value+42 is still an object, so probably numberish\n" |
1101
|
|
|
|
|
|
|
if $Debug; |
1102
|
28
|
|
|
|
|
150
|
return 1 |
1103
|
|
|
|
|
|
|
} else { |
1104
|
0
|
0
|
|
|
|
0
|
warn " Object and value+42 is NOT an object, so it must be stringish\n" |
1105
|
|
|
|
|
|
|
if $Debug; |
1106
|
0
|
|
|
|
|
0
|
return 0 |
1107
|
|
|
|
|
|
|
} |
1108
|
|
|
|
|
|
|
} else { |
1109
|
806
|
50
|
|
|
|
1474
|
warn " NOT an object, so must be a string\n", |
1110
|
|
|
|
|
|
|
if $Debug; |
1111
|
806
|
|
|
|
|
1758
|
return 0; |
1112
|
|
|
|
|
|
|
} |
1113
|
|
|
|
|
|
|
}# _show_as_number |
1114
|
|
|
|
|
|
|
|
1115
|
|
|
|
|
|
|
# Split keys into "components" (e.g. 2_16.A has 3 components) and sort |
1116
|
|
|
|
|
|
|
# components containing only digits numerically. |
1117
|
|
|
|
|
|
|
sub __sortkeys { |
1118
|
1118
|
|
|
1118
|
|
8030
|
my $hash = shift; |
1119
|
|
|
|
|
|
|
my $r = [ |
1120
|
1118
|
|
|
|
|
5357
|
sort { my @a = split /(?<=\d)(?=\D)|(?<=\D)(?=\d)/,$a; |
|
4621
|
|
|
|
|
26124
|
|
1121
|
4621
|
|
|
|
|
26228
|
my @b = split /(?<=\d)(?=\D)|(?<=\D)(?=\d)/,$b; |
1122
|
4621
|
|
|
|
|
10109
|
for (my $i=0; $i <= $#a; ++$i) { |
1123
|
4236
|
100
|
|
|
|
7865
|
return 1 if $i > $#b; # a is longer |
1124
|
3829
|
50
|
33
|
|
|
11768
|
my $r = ($a[$i] =~ /^\d+$/ && $b[$i] =~ /^\d+$/) |
1125
|
|
|
|
|
|
|
? ($a[$i] <=> $b[$i]) : ($a[$i] cmp $b[$i]) ; |
1126
|
3829
|
50
|
|
|
|
11191
|
return $r if $r != 0; |
1127
|
|
|
|
|
|
|
} |
1128
|
385
|
50
|
|
|
|
1209
|
return -1 if $#a < $#b; # a is shorter |
1129
|
0
|
|
|
|
|
0
|
return 0; |
1130
|
|
|
|
|
|
|
} |
1131
|
|
|
|
|
|
|
keys %$hash |
1132
|
|
|
|
|
|
|
]; |
1133
|
1118
|
|
|
|
|
13124
|
$r |
1134
|
|
|
|
|
|
|
} |
1135
|
|
|
|
|
|
|
|
1136
|
|
|
|
|
|
|
my $balanced_re = RE_balanced(-parens=>'{}[]()'); |
1137
|
|
|
|
|
|
|
|
1138
|
|
|
|
|
|
|
# cf man perldata |
1139
|
|
|
|
|
|
|
my $userident_re = qr/ (?: (?=\p{Word})\p{XID_Start} | _ ) |
1140
|
|
|
|
|
|
|
(?: (?=\p{Word})\p{XID_Continue} )* /x; |
1141
|
|
|
|
|
|
|
|
1142
|
|
|
|
|
|
|
my $pkgname_re = qr/ ${userident_re} (?: :: ${userident_re} )* /x; |
1143
|
|
|
|
|
|
|
|
1144
|
|
|
|
|
|
|
our $curlies_re = RE_balanced(-parens=>'{}'); |
1145
|
|
|
|
|
|
|
our $parens_re = RE_balanced(-parens=>'()'); |
1146
|
|
|
|
|
|
|
our $curliesorsquares_re = RE_balanced(-parens=>'{}[]'); |
1147
|
|
|
|
|
|
|
|
1148
|
|
|
|
|
|
|
my $anyvname_re = |
1149
|
|
|
|
|
|
|
qr/ ${pkgname_re} | [0-9]+ | \^[A-Z] |
1150
|
|
|
|
|
|
|
| [-+!\$\&\;i"'().,\@\/:<>?\[\]\~\^\\] /x; |
1151
|
|
|
|
|
|
|
|
1152
|
|
|
|
|
|
|
my $anyvname_or_refexpr_re = qr/ ${anyvname_re} | ${curlies_re} /x; |
1153
|
|
|
|
|
|
|
|
1154
|
|
|
|
|
|
|
my $addrvis_re = qr/\<\d+:[\da-fA-F]+\>/; |
1155
|
|
|
|
|
|
|
|
1156
|
|
|
|
|
|
|
sub __unmagic_atom() { # edits $_ |
1157
|
|
|
|
|
|
|
## # FIXME this probably could omit the ([^'"]*?) bc there is never anything |
1158
|
|
|
|
|
|
|
## # between the open quote and the _MAGIC_NOQUOTES_PFX |
1159
|
|
|
|
|
|
|
## s/(['"])([^'"]*?) |
1160
|
|
|
|
|
|
|
## (?:\Q${\_MAGIC_NOQUOTES_PFX}\E) |
1161
|
|
|
|
|
|
|
## (.*?)(\1)/$2$3/xgs; |
1162
|
|
|
|
|
|
|
|
1163
|
17145
|
|
|
17145
|
|
24078
|
s/(['"]) |
1164
|
17145
|
|
|
|
|
67701
|
(?:\Q${\_MAGIC_NOQUOTES_PFX}\E) (.*?) |
1165
|
3160
|
|
|
|
|
5742
|
(\1)/do{ local $_ = $2; |
|
3160
|
|
|
|
|
6935
|
|
1166
|
3160
|
|
|
|
|
5816
|
s!\\(.)!$1!g; # undo double-quotish backslash escapes |
1167
|
3160
|
|
|
|
|
9929
|
$_ }/xegs; |
1168
|
|
|
|
|
|
|
|
1169
|
17145
|
|
|
|
|
28946
|
s/\Q${\_MAGIC_KEEPQUOTES_PFX}\E//gs; |
|
17145
|
|
|
|
|
36617
|
|
1170
|
|
|
|
|
|
|
} |
1171
|
|
|
|
|
|
|
|
1172
|
|
|
|
|
|
|
sub __unesc_unicode() { # edits $_ |
1173
|
15024
|
100
|
|
15024
|
|
36355
|
if (/^"/) { |
1174
|
|
|
|
|
|
|
# Data::Dumper with Useqq(1) outputs wide characters as hex escapes |
1175
|
|
|
|
|
|
|
# Note that a BOM is the ZERO WIDTH NO-BREAK SPACE character and |
1176
|
|
|
|
|
|
|
# so is considered "Graphical", but we want to see it as hex rather |
1177
|
|
|
|
|
|
|
# than "", and probably any other "Format" category Unicode characters. |
1178
|
|
|
|
|
|
|
|
1179
|
3498
|
|
|
|
|
8040
|
s/ |
1180
|
|
|
|
|
|
|
\G (?: [^\\]++ | \\[^x] )*+ \K (?<w> \\x\x{7B} (?<hex>[a-fA-F0-9]+) \x{7D} ) |
1181
|
|
|
|
|
|
|
/ |
1182
|
9
|
|
|
9
|
|
37966
|
my $orig = $+{w}; |
|
9
|
|
|
|
|
4241
|
|
|
9
|
|
|
|
|
949
|
|
|
312
|
|
|
|
|
1391
|
|
1183
|
312
|
100
|
|
|
|
1780
|
local $_ = hex( length($+{hex}) > 6 ? '0' : $+{hex} ); |
1184
|
312
|
100
|
|
|
|
938
|
$_ = $_ > 0x10FFFF ? "\0" : chr($_); # 10FFFF is Unicode limit |
1185
|
|
|
|
|
|
|
# Using 'lc' so regression tests do not depend on Data::Dumper's |
1186
|
|
|
|
|
|
|
# choice of case when escaping wide characters. |
1187
|
312
|
100
|
66
|
|
|
2587
|
(m<\P{XPosixGraph}|[\0-\177]> |
1188
|
|
|
|
|
|
|
|| m<\p{General_Category=Format}>) ? lc($orig) : $_ |
1189
|
|
|
|
|
|
|
/xesg; |
1190
|
|
|
|
|
|
|
} |
1191
|
|
|
|
|
|
|
} |
1192
|
|
|
|
|
|
|
|
1193
|
|
|
|
|
|
|
sub __change_quotechars($) { # edits $_ |
1194
|
1653
|
50
|
|
1653
|
|
7634
|
if (s/^"//) { |
1195
|
1653
|
50
|
|
|
|
8148
|
oops unless s/"$//; |
1196
|
1653
|
|
|
|
|
7141
|
s/\\"/"/g; |
1197
|
1653
|
50
|
|
|
|
6545
|
my ($l, $r) = split //, $_[0]; oops unless $r; |
|
1653
|
|
|
|
|
4108
|
|
1198
|
1653
|
|
|
|
|
34707
|
s/([\Q$l$r\E])/\\$1/g; |
1199
|
1653
|
|
|
|
|
7221
|
$_ = "qq".$l.$_.$r; |
1200
|
|
|
|
|
|
|
} |
1201
|
|
|
|
|
|
|
} |
1202
|
|
|
|
|
|
|
|
1203
|
|
|
|
|
|
|
my %qqesc2controlpic = ( |
1204
|
9
|
|
|
9
|
|
17844
|
'\0' => "\N{SYMBOL FOR NULL}", |
|
9
|
|
|
|
|
23
|
|
|
9
|
|
|
|
|
135
|
|
1205
|
|
|
|
|
|
|
'\a' => "\N{SYMBOL FOR BELL}", |
1206
|
|
|
|
|
|
|
'\b' => "\N{SYMBOL FOR BACKSPACE}", |
1207
|
|
|
|
|
|
|
'\e' => "\N{SYMBOL FOR ESCAPE}", |
1208
|
|
|
|
|
|
|
'\f' => "\N{SYMBOL FOR FORM FEED}", |
1209
|
|
|
|
|
|
|
'\n' => "\N{SYMBOL FOR NEWLINE}", |
1210
|
|
|
|
|
|
|
'\r' => "\N{SYMBOL FOR CARRIAGE RETURN}", |
1211
|
|
|
|
|
|
|
'\t' => "\N{SYMBOL FOR HORIZONTAL TABULATION}", |
1212
|
|
|
|
|
|
|
); |
1213
|
|
|
|
|
|
|
my %char2controlpic = ( |
1214
|
|
|
|
|
|
|
map{ |
1215
|
|
|
|
|
|
|
my $cp = $qqesc2controlpic{$_}; |
1216
|
|
|
|
|
|
|
my $char = eval(qq("$_")) // die; |
1217
|
|
|
|
|
|
|
die "XX<<$_>> YY<<$char>>" unless length($char) == 1; |
1218
|
|
|
|
|
|
|
($char => $cp) |
1219
|
|
|
|
|
|
|
} keys %qqesc2controlpic |
1220
|
|
|
|
|
|
|
); |
1221
|
|
|
|
|
|
|
sub __subst_controlpic_backesc() { # edits $_ |
1222
|
|
|
|
|
|
|
# Replace '\t' '\n' etc. escapes with "control picture" characters |
1223
|
551
|
50
|
|
551
|
|
2150
|
return unless/^"/; |
1224
|
551
|
|
|
|
|
4290
|
s{ \G (?: [^\\]++ | \\[^0abefnrt] )*+ \K ( \\[abefnrt] | \\0(?![0-7]) ) |
1225
|
|
|
|
|
|
|
}{ |
1226
|
1623
|
|
33
|
|
|
11799
|
$qqesc2controlpic{$1} // $1 |
1227
|
|
|
|
|
|
|
}xesg; |
1228
|
|
|
|
|
|
|
} |
1229
|
|
|
|
|
|
|
sub __subst_spacedots() { # edits $_ |
1230
|
0
|
0
|
|
0
|
|
0
|
if (/^"/) { |
1231
|
0
|
|
|
|
|
0
|
s{\N{MIDDLE DOT}}{\N{BLACK LARGE CIRCLE}}g; |
1232
|
0
|
|
|
|
|
0
|
s{ }{\N{MIDDLE DOT}}g; |
1233
|
|
|
|
|
|
|
} |
1234
|
|
|
|
|
|
|
} |
1235
|
|
|
|
|
|
|
|
1236
|
|
|
|
|
|
|
my $indent_unit; |
1237
|
|
|
|
|
|
|
|
1238
|
|
|
|
|
|
|
sub _mycallloc(;@) { |
1239
|
0
|
|
|
0
|
|
0
|
my ($lno, $subcalled) = (caller(1))[2,3]; |
1240
|
0
|
0
|
|
|
|
0
|
":".$lno.(@_ ? _dbavis(@_) : "")." " |
1241
|
|
|
|
|
|
|
} |
1242
|
|
|
|
|
|
|
|
1243
|
|
|
|
|
|
|
use constant { |
1244
|
9
|
|
|
|
|
756
|
_WRAP_ALWAYS => 1, |
1245
|
|
|
|
|
|
|
_WRAP_ALLHASH => 2, |
1246
|
9
|
|
|
9
|
|
31729
|
}; |
|
9
|
|
|
|
|
27
|
|
1247
|
9
|
|
|
9
|
|
69
|
use constant _WRAP_STYLE => (_WRAP_ALLHASH); |
|
9
|
|
|
|
|
18
|
|
|
9
|
|
|
|
|
1062
|
|
1248
|
|
|
|
|
|
|
|
1249
|
|
|
|
|
|
|
sub _postprocess_DD_result { |
1250
|
|
|
|
|
|
|
(my $self, local $_, my $original) = @_; |
1251
|
9
|
|
|
9
|
|
78
|
no warnings 'recursion'; |
|
9
|
|
|
|
|
19
|
|
|
9
|
|
|
|
|
36236
|
|
1252
|
|
|
|
|
|
|
my ($debug, $listform, $foldwidth, $foldwidth1) |
1253
|
|
|
|
|
|
|
= @$self{qw/Debug _Listform Foldwidth Foldwidth1/}; |
1254
|
|
|
|
|
|
|
my $useqq = $self->Useqq(); |
1255
|
|
|
|
|
|
|
my $unesc_unicode = $useqq =~ /utf|unic/; |
1256
|
|
|
|
|
|
|
my $controlpics = $useqq =~ /pic/; |
1257
|
|
|
|
|
|
|
my $spacedots = $useqq =~ /space/; |
1258
|
|
|
|
|
|
|
my $qq = $useqq =~ /qq(?:=(..))?/ ? ($1//'{}') : ''; |
1259
|
|
|
|
|
|
|
my $pad = $self->Pad() // ""; |
1260
|
|
|
|
|
|
|
|
1261
|
|
|
|
|
|
|
$indent_unit = 2; # make configurable? |
1262
|
|
|
|
|
|
|
|
1263
|
|
|
|
|
|
|
my $maxlinelen = $foldwidth1 || $foldwidth || INT_MAX; |
1264
|
|
|
|
|
|
|
my $maxlineNlen = ($foldwidth // INT_MAX) - length($pad); |
1265
|
|
|
|
|
|
|
|
1266
|
|
|
|
|
|
|
if ($debug) { |
1267
|
|
|
|
|
|
|
our $_dbmaxlen = INT_MAX; |
1268
|
|
|
|
|
|
|
btw "## DD result: fw1=",u($foldwidth1)," fw=",u($foldwidth)," pad='${pad}' maxll=$maxlinelen maxlNl=$maxlineNlen\n result=",_dbrawstr($_); |
1269
|
|
|
|
|
|
|
} |
1270
|
|
|
|
|
|
|
|
1271
|
|
|
|
|
|
|
my $top = { tlen => 0, children => [] }; |
1272
|
|
|
|
|
|
|
my $context = $top; |
1273
|
|
|
|
|
|
|
my $prepending = ""; |
1274
|
|
|
|
|
|
|
|
1275
|
|
|
|
|
|
|
my sub atom($;$) { |
1276
|
|
|
|
|
|
|
(local $_, my $mode) = @_; |
1277
|
|
|
|
|
|
|
$mode //= ""; |
1278
|
|
|
|
|
|
|
|
1279
|
|
|
|
|
|
|
__unmagic_atom ; |
1280
|
|
|
|
|
|
|
__unesc_unicode if $unesc_unicode; |
1281
|
|
|
|
|
|
|
__subst_controlpic_backesc if $controlpics; |
1282
|
|
|
|
|
|
|
__subst_spacedots if $spacedots; |
1283
|
|
|
|
|
|
|
__change_quotechars($qq) if $qq; |
1284
|
|
|
|
|
|
|
|
1285
|
|
|
|
|
|
|
if ($prepending) { $_ = $prepending . $_; $prepending = ""; } |
1286
|
|
|
|
|
|
|
|
1287
|
|
|
|
|
|
|
btw "###atom",_mycallloc(), _dbrawstr($_),"($mode)" |
1288
|
|
|
|
|
|
|
,"\n context:",_dbvisnew($context)->Sortkeys(sub{[grep{exists $_[0]->{$_}} qw/O C tlen children CLOSE_AFTER_NEXT/]})->Dump() |
1289
|
|
|
|
|
|
|
if $debug; |
1290
|
|
|
|
|
|
|
if ($mode eq "prepend_to_next") { |
1291
|
|
|
|
|
|
|
$prepending .= $_; |
1292
|
|
|
|
|
|
|
} else { |
1293
|
|
|
|
|
|
|
if ($mode eq "") { |
1294
|
|
|
|
|
|
|
push @{ $context->{children} }, $_; |
1295
|
|
|
|
|
|
|
} |
1296
|
|
|
|
|
|
|
elsif ($mode eq "open") { |
1297
|
|
|
|
|
|
|
my $child = { |
1298
|
|
|
|
|
|
|
O => $_, |
1299
|
|
|
|
|
|
|
tlen => 0, # incremented below |
1300
|
|
|
|
|
|
|
children => [], |
1301
|
|
|
|
|
|
|
C => undef, |
1302
|
|
|
|
|
|
|
parent => $context, |
1303
|
|
|
|
|
|
|
}; |
1304
|
|
|
|
|
|
|
weaken( $child->{parent} ); |
1305
|
|
|
|
|
|
|
push @{ $context->{children} }, $child; |
1306
|
|
|
|
|
|
|
$context = $child; |
1307
|
|
|
|
|
|
|
} |
1308
|
|
|
|
|
|
|
elsif ($mode eq "close") { |
1309
|
|
|
|
|
|
|
oops if defined($context->{C}); |
1310
|
|
|
|
|
|
|
$context->{C} = $_; |
1311
|
|
|
|
|
|
|
$context->{tlen} += length; |
1312
|
|
|
|
|
|
|
$context = $context->{parent}; # undef if closing the top item |
1313
|
|
|
|
|
|
|
} |
1314
|
|
|
|
|
|
|
elsif ($mode eq "append_to_prev") { |
1315
|
|
|
|
|
|
|
my $prev = $context; |
1316
|
|
|
|
|
|
|
{ #block for 'redo' |
1317
|
|
|
|
|
|
|
oops "No previous!" unless @{$prev->{children}} > 0; |
1318
|
|
|
|
|
|
|
if (ref($prev->{children}->[-1] // oops)) { |
1319
|
|
|
|
|
|
|
$prev = $prev->{children}->[-1]; |
1320
|
|
|
|
|
|
|
if (! $prev->{C}) { # empty or not-yet-read closer? |
1321
|
|
|
|
|
|
|
redo; # *** |
1322
|
|
|
|
|
|
|
} |
1323
|
|
|
|
|
|
|
$prev->{C} .= $_; |
1324
|
|
|
|
|
|
|
} else { |
1325
|
|
|
|
|
|
|
$prev->{children}->[-1] .= $_; |
1326
|
|
|
|
|
|
|
} |
1327
|
|
|
|
|
|
|
} |
1328
|
|
|
|
|
|
|
} |
1329
|
|
|
|
|
|
|
else { |
1330
|
|
|
|
|
|
|
oops "mode=",_dbvis($mode); |
1331
|
|
|
|
|
|
|
} |
1332
|
|
|
|
|
|
|
my $c = $context; |
1333
|
|
|
|
|
|
|
while(defined $c) { |
1334
|
|
|
|
|
|
|
$c->{tlen} += length($_); |
1335
|
|
|
|
|
|
|
$c = $c->{parent}; |
1336
|
|
|
|
|
|
|
} |
1337
|
|
|
|
|
|
|
if ($context->{CLOSE_AFTER_NEXT}) { |
1338
|
|
|
|
|
|
|
oops(_dbvis($context)) if defined($context->{C}); |
1339
|
|
|
|
|
|
|
$context->{C} = ""; |
1340
|
|
|
|
|
|
|
$context = $context->{parent}; |
1341
|
|
|
|
|
|
|
} |
1342
|
|
|
|
|
|
|
} |
1343
|
|
|
|
|
|
|
}#atom |
1344
|
|
|
|
|
|
|
|
1345
|
|
|
|
|
|
|
my sub fat_arrow($) { # => |
1346
|
|
|
|
|
|
|
my $lhs = $context->{children}->[-1] // oops; |
1347
|
|
|
|
|
|
|
oops if ref($lhs); |
1348
|
|
|
|
|
|
|
my $newchild = { |
1349
|
|
|
|
|
|
|
O => "", |
1350
|
|
|
|
|
|
|
tlen => length($lhs), |
1351
|
|
|
|
|
|
|
children => [ $lhs ], |
1352
|
|
|
|
|
|
|
C => undef, |
1353
|
|
|
|
|
|
|
parent => $context, |
1354
|
|
|
|
|
|
|
}; |
1355
|
|
|
|
|
|
|
weaken($newchild->{parent}); |
1356
|
|
|
|
|
|
|
$context->{children}->[-1] = $newchild; |
1357
|
|
|
|
|
|
|
$context = $newchild; |
1358
|
|
|
|
|
|
|
atom($_[0]); # the " => " |
1359
|
|
|
|
|
|
|
oops unless $context == $newchild; |
1360
|
|
|
|
|
|
|
$context->{CLOSE_AFTER_NEXT} = 1; |
1361
|
|
|
|
|
|
|
} |
1362
|
|
|
|
|
|
|
|
1363
|
|
|
|
|
|
|
# There is a trade-off between compactness (e.g. want a single line when |
1364
|
|
|
|
|
|
|
# possible), and ease of reading large structures. |
1365
|
|
|
|
|
|
|
# |
1366
|
|
|
|
|
|
|
# At any nesting level, if everything (including any nested levels) fits |
1367
|
|
|
|
|
|
|
# on a single line, then that part is output without folding; |
1368
|
|
|
|
|
|
|
# |
1369
|
|
|
|
|
|
|
# 4/25/2023: Now controlled by constant _WRAP_STYLE: |
1370
|
|
|
|
|
|
|
# |
1371
|
|
|
|
|
|
|
# (_WRAP_STYLE == _WRAP_ALWAYS): |
1372
|
|
|
|
|
|
|
# If folding is necessary, then *every* member of the folded block |
1373
|
|
|
|
|
|
|
# appears on a separate line, so members all vertically align. |
1374
|
|
|
|
|
|
|
# |
1375
|
|
|
|
|
|
|
# *(_WRAP_STYLE & _WRAP_ALLHASH): Members of a hash (key => value) |
1376
|
|
|
|
|
|
|
# are shown on separate lines, but not members of an array. |
1377
|
|
|
|
|
|
|
# |
1378
|
|
|
|
|
|
|
# Otherwise: |
1379
|
|
|
|
|
|
|
# |
1380
|
|
|
|
|
|
|
# When folding is necessary, every member appears on a separate |
1381
|
|
|
|
|
|
|
# line if ANY of them will not fit on a single line; however if |
1382
|
|
|
|
|
|
|
# they all fit individually, then shorter members will be run |
1383
|
|
|
|
|
|
|
# together on the same line. For example: |
1384
|
|
|
|
|
|
|
# |
1385
|
|
|
|
|
|
|
# [aaa,bbb,[ccc,ddd,[eee,fff,hhhhhhhhhhhhhhhhhhhhh,{key => value}]]] |
1386
|
|
|
|
|
|
|
# |
1387
|
|
|
|
|
|
|
# might be shown as |
1388
|
|
|
|
|
|
|
# [ aaa,bbb, # N.B. space inserted before aaa to line up with next level |
1389
|
|
|
|
|
|
|
# [ ccc,ddd, # packed because all siblings fit individually |
1390
|
|
|
|
|
|
|
# [eee,fff,hhhhhhhhhhhhhhhhhhhhh,{key => value}] # entirely fits |
1391
|
|
|
|
|
|
|
# ] |
1392
|
|
|
|
|
|
|
# ] |
1393
|
|
|
|
|
|
|
# but if Foldwidth is smaller then like this: |
1394
|
|
|
|
|
|
|
# [ aaa,bbb, |
1395
|
|
|
|
|
|
|
# [ ccc, # sibs vertically-aligned because not all of them fit |
1396
|
|
|
|
|
|
|
# ddd, |
1397
|
|
|
|
|
|
|
# [ eee,fff, # but within this level, all siblings fit |
1398
|
|
|
|
|
|
|
# hhhhhhhhhhhhhhhhhhhhh, |
1399
|
|
|
|
|
|
|
# {key => value} |
1400
|
|
|
|
|
|
|
# ] |
1401
|
|
|
|
|
|
|
# ] |
1402
|
|
|
|
|
|
|
# ] |
1403
|
|
|
|
|
|
|
# or if Foldwidth is very small then: |
1404
|
|
|
|
|
|
|
# [ aaa, |
1405
|
|
|
|
|
|
|
# bbb, |
1406
|
|
|
|
|
|
|
# [ ccc, |
1407
|
|
|
|
|
|
|
# ddd, |
1408
|
|
|
|
|
|
|
# [ eee, |
1409
|
|
|
|
|
|
|
# fff, |
1410
|
|
|
|
|
|
|
# hhhhhhhhhhhhhhhhhhhhh, |
1411
|
|
|
|
|
|
|
# { key |
1412
|
|
|
|
|
|
|
# => |
1413
|
|
|
|
|
|
|
# value |
1414
|
|
|
|
|
|
|
# } |
1415
|
|
|
|
|
|
|
# ] |
1416
|
|
|
|
|
|
|
# ] |
1417
|
|
|
|
|
|
|
# ] |
1418
|
|
|
|
|
|
|
# |
1419
|
|
|
|
|
|
|
# Note: Indentation is done regardless of Foldwidth, so deeply nested |
1420
|
|
|
|
|
|
|
# structures may extend beyond Foldwidth even if all elements are short. |
1421
|
|
|
|
|
|
|
|
1422
|
|
|
|
|
|
|
my $outstr; |
1423
|
|
|
|
|
|
|
my $linelen; |
1424
|
|
|
|
|
|
|
our $level; |
1425
|
|
|
|
|
|
|
my sub expand_children($) { |
1426
|
|
|
|
|
|
|
my $parent = shift; |
1427
|
|
|
|
|
|
|
# $level is already set appropriately for $parent->{children}, |
1428
|
|
|
|
|
|
|
# and the parent's {opener} is at the end of $outstr. |
1429
|
|
|
|
|
|
|
# |
1430
|
|
|
|
|
|
|
# Intially we are called with a fake parent ($top) containing |
1431
|
|
|
|
|
|
|
# no {opener} and the top-most item as its only child, with $level==0; |
1432
|
|
|
|
|
|
|
# this puts the top item at the left margin. |
1433
|
|
|
|
|
|
|
# |
1434
|
|
|
|
|
|
|
# If all children individually fit then run them all together, |
1435
|
|
|
|
|
|
|
# wrapping only between siblings; otherwise start each sibling on |
1436
|
|
|
|
|
|
|
# it's own line so they line up vertically. |
1437
|
|
|
|
|
|
|
# [4/25/2023: Now controlled by _WRAP_STYLE] |
1438
|
|
|
|
|
|
|
|
1439
|
|
|
|
|
|
|
my $available = $maxlinelen - $linelen; |
1440
|
|
|
|
|
|
|
my $indent_width = $level * $indent_unit; |
1441
|
|
|
|
|
|
|
|
1442
|
|
|
|
|
|
|
my $run_together = |
1443
|
|
|
|
|
|
|
(_WRAP_STYLE & _WRAP_ALWAYS)==0 |
1444
|
|
|
|
|
|
|
&& |
1445
|
|
|
|
|
|
|
all{ (ref() ? $_->{tlen} : length) <= $available } @{$parent->{children}} |
1446
|
|
|
|
|
|
|
; |
1447
|
|
|
|
|
|
|
|
1448
|
|
|
|
|
|
|
if (!$run_together |
1449
|
|
|
|
|
|
|
&& @{$parent->{children}}==3 |
1450
|
|
|
|
|
|
|
&& !ref(my $item=$parent->{children}->[1])) { |
1451
|
|
|
|
|
|
|
# Concatenate (key,=>) if possible |
1452
|
|
|
|
|
|
|
if ($item =~ /\A *=> *\z/) { |
1453
|
|
|
|
|
|
|
$run_together = 1; |
1454
|
|
|
|
|
|
|
btw "# (level $level): Running together $parent->{children}->[0] => value" if $debug; |
1455
|
|
|
|
|
|
|
} |
1456
|
|
|
|
|
|
|
} |
1457
|
|
|
|
|
|
|
|
1458
|
|
|
|
|
|
|
my $indent = ' ' x $indent_width; |
1459
|
|
|
|
|
|
|
|
1460
|
|
|
|
|
|
|
btw "###expand",_mycallloc(), "level $level, avail=$available", |
1461
|
|
|
|
|
|
|
" rt=",_tf($run_together), |
1462
|
|
|
|
|
|
|
" indw=$indent_width ll=$linelen maxll=$maxlinelen : ", |
1463
|
|
|
|
|
|
|
#"{ tlen=",$parent->{tlen}," }", |
1464
|
|
|
|
|
|
|
" p=",_dbvisnew($parent)->Sortkeys(sub{[grep{exists $_[0]->{$_}} qw/O C tlen CLOSE_AFTER_NEXT/]})->Dump(), |
1465
|
|
|
|
|
|
|
"\n os=",_dbstr($outstr) if $debug; |
1466
|
|
|
|
|
|
|
|
1467
|
|
|
|
|
|
|
#oops(_dbavis($linelen,$indent_width)) unless $linelen >= $indent_width; |
1468
|
|
|
|
|
|
|
|
1469
|
|
|
|
|
|
|
my $first = 1; |
1470
|
|
|
|
|
|
|
for my $child (@{$parent->{children}}) { |
1471
|
|
|
|
|
|
|
my $child_len = ref($child) ? $child->{tlen} : length($child); |
1472
|
|
|
|
|
|
|
my $fits = ($child_len <= $available) || 0; |
1473
|
|
|
|
|
|
|
|
1474
|
|
|
|
|
|
|
if ($first) { |
1475
|
|
|
|
|
|
|
} else { |
1476
|
|
|
|
|
|
|
if(!$fits && !ref($child)) { |
1477
|
|
|
|
|
|
|
if ($child =~ /( +)\z/ && ($child_len-length($1)) <= $available) { |
1478
|
|
|
|
|
|
|
# remove trailing space(s) e.g. in ' => ' |
1479
|
|
|
|
|
|
|
substr($child,-length($1),INT_MAX,""); |
1480
|
|
|
|
|
|
|
$child_len -= length($1); |
1481
|
|
|
|
|
|
|
oops unless $child_len <= $available; |
1482
|
|
|
|
|
|
|
$fits = 2; |
1483
|
|
|
|
|
|
|
btw "# (level $level): Chopped ",_dbstr($1)," from child" if $debug; |
1484
|
|
|
|
|
|
|
} |
1485
|
|
|
|
|
|
|
if (!$fits && $linelen <= $indent_width && $run_together) { |
1486
|
|
|
|
|
|
|
# If we wrap we'll end up at the same or worse position after |
1487
|
|
|
|
|
|
|
# indenting, so don't bother wrapping if running together |
1488
|
|
|
|
|
|
|
$fits = 3; |
1489
|
|
|
|
|
|
|
btw "# (level $level): Wrap would not help" if $debug |
1490
|
|
|
|
|
|
|
} |
1491
|
|
|
|
|
|
|
} |
1492
|
|
|
|
|
|
|
if (!$fits || !$run_together) { |
1493
|
|
|
|
|
|
|
# start a second+ line |
1494
|
|
|
|
|
|
|
$outstr =~ s/ +\z//; |
1495
|
|
|
|
|
|
|
$outstr .= "\n$indent"; |
1496
|
|
|
|
|
|
|
$linelen = $indent_width; |
1497
|
|
|
|
|
|
|
$maxlinelen = $maxlineNlen; |
1498
|
|
|
|
|
|
|
|
1499
|
|
|
|
|
|
|
# elide any initial spaces after wrapping, e.g. in " => " |
1500
|
|
|
|
|
|
|
$child =~ s/^ +// unless ref($child); |
1501
|
|
|
|
|
|
|
|
1502
|
|
|
|
|
|
|
$available = $maxlinelen - $linelen; |
1503
|
|
|
|
|
|
|
$child_len = ref($child) ? $child->{tlen} : length($child); |
1504
|
|
|
|
|
|
|
$fits = ($child_len <= $available); |
1505
|
|
|
|
|
|
|
btw "# (level $level): 2nd+ Pre-WRAP; ",_dbstr($child)," cl=$child_len av=$available ll=$linelen f=$fits rt=",_tf($run_together)," os=",_dbstr($outstr) if $debug; |
1506
|
|
|
|
|
|
|
} else { |
1507
|
|
|
|
|
|
|
btw "# (level $level): (no 2nd+ pre-wrap); ",_dbstr($child)," cl=$child_len av=$available ll=$linelen f=$fits rt=",_tf($run_together) if $debug; |
1508
|
|
|
|
|
|
|
} |
1509
|
|
|
|
|
|
|
} |
1510
|
|
|
|
|
|
|
|
1511
|
|
|
|
|
|
|
if (ref($child)) { |
1512
|
|
|
|
|
|
|
++$level; |
1513
|
|
|
|
|
|
|
$outstr .= $child->{O}; |
1514
|
|
|
|
|
|
|
$linelen += length($child->{O}); |
1515
|
|
|
|
|
|
|
if (! $fits && $child->{O} ne "") { |
1516
|
|
|
|
|
|
|
# Wrap before first child, if there is a real opener (not for '=>') |
1517
|
|
|
|
|
|
|
$outstr =~ s/ +\z//; |
1518
|
|
|
|
|
|
|
$outstr .= "\n$indent" . (' ' x $indent_unit); |
1519
|
|
|
|
|
|
|
$linelen = $indent_width + $indent_unit; |
1520
|
|
|
|
|
|
|
$maxlinelen = $maxlineNlen; |
1521
|
|
|
|
|
|
|
btw "# (l $level): Wrap after opener: os=",_dbstr($outstr) if $debug; |
1522
|
|
|
|
|
|
|
} |
1523
|
|
|
|
|
|
|
__SUB__->($child); |
1524
|
|
|
|
|
|
|
if (! $fits && $child->{O} ne "") { |
1525
|
|
|
|
|
|
|
# Wrap before closer if we wrapped after opener |
1526
|
|
|
|
|
|
|
$outstr =~ s/ +\z//; |
1527
|
|
|
|
|
|
|
$outstr .= "\n$indent"; |
1528
|
|
|
|
|
|
|
$linelen = $indent_width; |
1529
|
|
|
|
|
|
|
$maxlinelen = $maxlineNlen; |
1530
|
|
|
|
|
|
|
btw "# (l $level): Wrap after closer; ll=$linelen os=",_dbstr($outstr) if $debug; |
1531
|
|
|
|
|
|
|
} |
1532
|
|
|
|
|
|
|
$outstr .= $child->{C}; |
1533
|
|
|
|
|
|
|
$linelen += length($child->{C}); |
1534
|
|
|
|
|
|
|
--$level; |
1535
|
|
|
|
|
|
|
} else { |
1536
|
|
|
|
|
|
|
$outstr .= $child; |
1537
|
|
|
|
|
|
|
$linelen += length($child); |
1538
|
|
|
|
|
|
|
btw "# (level $level): appended SCALAR ",_dbstr($child)," os=",_dbstr($outstr) if $debug; |
1539
|
|
|
|
|
|
|
} |
1540
|
|
|
|
|
|
|
$available = $maxlinelen - $linelen; |
1541
|
|
|
|
|
|
|
$first = 0; |
1542
|
|
|
|
|
|
|
} |
1543
|
|
|
|
|
|
|
}#expand_children |
1544
|
|
|
|
|
|
|
|
1545
|
|
|
|
|
|
|
# Remove the magic wrapper created by _prefix_refaddr(). The original $ref |
1546
|
|
|
|
|
|
|
# was replaced by |
1547
|
|
|
|
|
|
|
# |
1548
|
|
|
|
|
|
|
# [ _MAGIC_REFADDR.addrvis($ref), $ref, _MAGIC_ELIDE_NEXT, ]; |
1549
|
|
|
|
|
|
|
# |
1550
|
|
|
|
|
|
|
# Data::Dumper formatted the magic* items as "quoted strings" |
1551
|
|
|
|
|
|
|
# |
1552
|
|
|
|
|
|
|
s/\[\s*(["'])\Q${\_MAGIC_REFADDR}\E(.*?)\1,\s*/$2/gs; |
1553
|
|
|
|
|
|
|
s/,\s*(["'])\Q${\_MAGIC_ELIDE_NEXT}\E\1,?\s*\]//gs |
1554
|
|
|
|
|
|
|
&& $debug && btw "Unwrapped addrvis:",_dbvis($_); |
1555
|
|
|
|
|
|
|
|
1556
|
|
|
|
|
|
|
while ((pos()//0) < length) { |
1557
|
|
|
|
|
|
|
if (/\G[\\\*\!]/gc) { atom($&, "prepend_to_next") } |
1558
|
|
|
|
|
|
|
elsif (/\G[,;]/gc) { atom($&, "append_to_prev") } |
1559
|
|
|
|
|
|
|
elsif (/\G"(?:[^"\\]++|\\.)*+"/gsc) { atom($&) } # "quoted" |
1560
|
|
|
|
|
|
|
elsif (/\G'(?:[^'\\]++|\\.)*+'/gsc) { atom($&) } # 'quoted' |
1561
|
|
|
|
|
|
|
elsif (m(\Gqr/(?:[^\\\/]++|\\.)*+/[a-z]*)gsc){ # Regexp |
1562
|
|
|
|
|
|
|
local $_ = $&; |
1563
|
|
|
|
|
|
|
# Data::Dumper just stringifies a compiled regex, and Perl (v5.34) |
1564
|
|
|
|
|
|
|
# does not stringify actual tab as \t etc. probably because the result |
1565
|
|
|
|
|
|
|
# would be ambiguous if preceeded by another backslash, e.g. |
1566
|
|
|
|
|
|
|
# \<tab> -> \\t would be wrong (backslash character + 't'). |
1567
|
|
|
|
|
|
|
# |
1568
|
|
|
|
|
|
|
# If 'controlpics' is enabled, they are always substituted and then |
1569
|
|
|
|
|
|
|
# a preceding backslash is not a problem; otherwise \-escapes are |
1570
|
|
|
|
|
|
|
# substituted only if not preceded by another backslash. |
1571
|
|
|
|
|
|
|
if ($controlpics) { |
1572
|
|
|
|
|
|
|
s{([\x{0}\a\b\e\f\n\r\t])}{ $char2controlpic{$1} // $1 }esg; |
1573
|
|
|
|
|
|
|
} else { |
1574
|
|
|
|
|
|
|
if (/[\x{0}\a\b\e\f\n\r\t]/) { |
1575
|
|
|
|
|
|
|
s/(?<!\\)\x{0}/\\0/g; |
1576
|
|
|
|
|
|
|
s/(?<!\\)[\b]/\N{SYMBOL FOR BACKSPACE}/; # Bare \b matches boundaries |
1577
|
|
|
|
|
|
|
s/(?<!\\)\e/\\e/g; |
1578
|
|
|
|
|
|
|
s/(?<!\\)\f/\\f/g; |
1579
|
|
|
|
|
|
|
s/(?<!\\)\x{0A}/\\n/g; |
1580
|
|
|
|
|
|
|
s/(?<!\\)\x{0D}/\\r/g; |
1581
|
|
|
|
|
|
|
s/(?<!\\)\t/\\t/g; |
1582
|
|
|
|
|
|
|
} |
1583
|
|
|
|
|
|
|
} |
1584
|
|
|
|
|
|
|
atom($_) |
1585
|
|
|
|
|
|
|
} |
1586
|
|
|
|
|
|
|
elsif (/\G${addrvis_re}/gsc) { atom($&, "prepend_to_next") } |
1587
|
|
|
|
|
|
|
|
1588
|
|
|
|
|
|
|
# With Deparse(1) the body has arbitrary Perl code, which we can't parse |
1589
|
|
|
|
|
|
|
elsif (/\Gsub\s*${curlies_re}/gc) { atom($&) } # sub{...} |
1590
|
|
|
|
|
|
|
|
1591
|
|
|
|
|
|
|
# $VAR1->[ix] $VAR1->{key} or just $varname |
1592
|
|
|
|
|
|
|
elsif (/\G(?:my\s+)?\$(?:${userident_re}|\s*->\s*|${balanced_re}+)++/gsc) { atom($&) } |
1593
|
|
|
|
|
|
|
|
1594
|
|
|
|
|
|
|
elsif (/\G\b[A-Za-z_][A-Za-z0-9_]*+\b/gc) { atom($&) } # bareword? |
1595
|
|
|
|
|
|
|
elsif (/\G-?\d[\deE\.]*+\b/gc) { atom($&) } # number |
1596
|
|
|
|
|
|
|
elsif (/\G\s*=>\s*/gc) { fat_arrow($&) } |
1597
|
|
|
|
|
|
|
elsif (/\G\s*=(?=[\w\s'"])\s*/gc) { atom($&) } |
1598
|
|
|
|
|
|
|
elsif (/\G:*${pkgname_re}/gc) { atom($&) } |
1599
|
|
|
|
|
|
|
elsif (/\G[\[\{\(]/gc) { atom($&, "open") } |
1600
|
|
|
|
|
|
|
elsif (/\G[\]\}\)]/gc) { atom($&, "close") } |
1601
|
|
|
|
|
|
|
elsif (/\G\s+/sgc) { } |
1602
|
|
|
|
|
|
|
else { |
1603
|
|
|
|
|
|
|
my $remnant = substr($_,pos//0); |
1604
|
|
|
|
|
|
|
Carp::cluck "UNPARSED ",_dbstr(substr($remnant,0,30)."...")," ",_dbstrposn($_,pos()//0),"\nFULL STRING:",_dbstr($_),"\n(Using remainder as-is)\n" ; |
1605
|
|
|
|
|
|
|
atom($remnant); |
1606
|
|
|
|
|
|
|
while (defined $context->{parent}) { atom("", "close"); } |
1607
|
|
|
|
|
|
|
last; |
1608
|
|
|
|
|
|
|
} |
1609
|
|
|
|
|
|
|
} |
1610
|
|
|
|
|
|
|
oops "Dangling prepend ",_dbstr($prepending) if $prepending; |
1611
|
|
|
|
|
|
|
|
1612
|
0
|
|
|
0
|
|
0
|
btw "--------top-------\n",_dbvisnew($top)->Sortkeys(sub{[qw/O C tlen children/]})->Dump,"\n-----------------" if $debug; |
1613
|
|
|
|
|
|
|
|
1614
|
|
|
|
|
|
|
$outstr = ""; |
1615
|
|
|
|
|
|
|
$linelen = 0; |
1616
|
|
|
|
|
|
|
$level = 0; |
1617
|
|
|
|
|
|
|
expand_children($top); |
1618
|
|
|
|
|
|
|
|
1619
|
|
|
|
|
|
|
if (index($listform,'a') >= 0) { |
1620
|
|
|
|
|
|
|
# show [...] as (val1,val2,...) array initializer |
1621
|
|
|
|
|
|
|
# Remove any initial Addrvis prefix |
1622
|
|
|
|
|
|
|
$outstr =~ s/\A(?:${addrvis_re})?\[/(/ && $outstr =~ s/\]\z/)/s or oops _dbvis($outstr); |
1623
|
|
|
|
|
|
|
} |
1624
|
|
|
|
|
|
|
elsif (index($listform,'h') >= 0) { |
1625
|
|
|
|
|
|
|
# show {...} as (key => val, ...) hash initializer |
1626
|
|
|
|
|
|
|
$outstr =~ s/\A(?:${addrvis_re})?\{/(/ && $outstr =~ s/\}\z/)/s or oops; |
1627
|
|
|
|
|
|
|
} |
1628
|
|
|
|
|
|
|
elsif (index($listform,'l') >= 0) { |
1629
|
|
|
|
|
|
|
# show as a bare list without brackets |
1630
|
|
|
|
|
|
|
$outstr =~ s/\A(?:${addrvis_re})?[\[\{]// && $outstr =~ s/[\]\}]\z//s or oops; |
1631
|
|
|
|
|
|
|
} |
1632
|
|
|
|
|
|
|
|
1633
|
|
|
|
|
|
|
# Insert user-specified padding after each embedded newline |
1634
|
|
|
|
|
|
|
if ($pad) { |
1635
|
|
|
|
|
|
|
$outstr =~ s/\n\K(?=[^\n])/$pad/g; |
1636
|
|
|
|
|
|
|
} |
1637
|
|
|
|
|
|
|
|
1638
|
|
|
|
|
|
|
$outstr |
1639
|
|
|
|
|
|
|
} #_postprocess_DD_result { |
1640
|
|
|
|
|
|
|
|
1641
|
|
|
|
|
|
|
sub _Interpolate { |
1642
|
1273
|
|
|
1273
|
|
3886
|
my ($self, $input, $i_or_d) = @_; |
1643
|
1273
|
100
|
|
|
|
3982
|
return "<undef arg>" if ! defined $input; |
1644
|
|
|
|
|
|
|
|
1645
|
1270
|
|
|
|
|
3633
|
&_SaveAndResetPunct; |
1646
|
|
|
|
|
|
|
|
1647
|
1270
|
|
|
|
|
5511
|
my $debug = $self->Debug; |
1648
|
1270
|
|
|
|
|
4025
|
my $useqq = $self->Useqq; |
1649
|
|
|
|
|
|
|
|
1650
|
1270
|
100
|
|
|
|
20471
|
my $q = $useqq ? "" : "q"; |
1651
|
1270
|
|
|
|
|
3767
|
my $funcname = $i_or_d . "vis" .$q; |
1652
|
|
|
|
|
|
|
|
1653
|
1270
|
|
|
|
|
2289
|
my @pieces; # list of [visfuncname or 'p' or 'e', inputstring] |
1654
|
1270
|
|
|
|
|
2117
|
{ local $_ = $input; |
|
1270
|
|
|
|
|
2680
|
|
1655
|
1270
|
50
|
|
|
|
4016
|
if (/\b((?:ARRAY|HASH)\(0x[a-fA-F0-9]+\))/) { |
1656
|
0
|
|
|
|
|
0
|
state $warned=0; |
1657
|
0
|
0
|
|
|
|
0
|
carp("Warning: String passed to $funcname may have been interpolated by Perl\n(use 'single quotes' to avoid this)\n") unless $warned++; |
1658
|
|
|
|
|
|
|
} |
1659
|
1270
|
|
|
|
|
3009
|
while ( |
1660
|
|
|
|
|
|
|
/\G ( |
1661
|
|
|
|
|
|
|
# Stuff without variable references (might include \n etc. escapes) |
1662
|
|
|
|
|
|
|
|
1663
|
|
|
|
|
|
|
#This gets "recursion limit exceeded" |
1664
|
|
|
|
|
|
|
#( (?: [^\\\$\@\%] | \\[^\$\@\%] )++ ) |
1665
|
|
|
|
|
|
|
#| |
1666
|
|
|
|
|
|
|
|
1667
|
|
|
|
|
|
|
(?: [^\\\$\@\%]++ ) |
1668
|
|
|
|
|
|
|
| |
1669
|
|
|
|
|
|
|
#(?: (?: \\[^\$\@\%] )++ ) |
1670
|
|
|
|
|
|
|
(?: (?: \\. )++ ) |
1671
|
|
|
|
|
|
|
| |
1672
|
|
|
|
|
|
|
|
1673
|
|
|
|
|
|
|
# $#arrayvar $#$$...refvarname $#{aref expr} $#$$...{ref2ref expr} |
1674
|
|
|
|
|
|
|
# |
1675
|
|
|
|
|
|
|
(?: \$\#\$*+\K ${anyvname_or_refexpr_re} ) |
1676
|
|
|
|
|
|
|
| |
1677
|
|
|
|
|
|
|
|
1678
|
|
|
|
|
|
|
# $scalarvar $$$...refvarname ${sref expr} $$$...{ref2ref expr} |
1679
|
|
|
|
|
|
|
# followed by [] {} ->[] ->{} ->method() ... «zero or more» |
1680
|
|
|
|
|
|
|
# EXCEPT $$<punctchar> is parsed as $$ followed by <punctchar> |
1681
|
|
|
|
|
|
|
|
1682
|
|
|
|
|
|
|
(?: |
1683
|
|
|
|
|
|
|
(?: \$\$++ ${pkgname_re} \K | \$ ${anyvname_or_refexpr_re} \K ) |
1684
|
|
|
|
|
|
|
(?: |
1685
|
|
|
|
|
|
|
(?: ->\K(?: ${curliesorsquares_re}|${userident_re}${parens_re}? )) |
1686
|
|
|
|
|
|
|
| |
1687
|
|
|
|
|
|
|
${curliesorsquares_re} |
1688
|
|
|
|
|
|
|
)* |
1689
|
|
|
|
|
|
|
) |
1690
|
|
|
|
|
|
|
| |
1691
|
|
|
|
|
|
|
|
1692
|
|
|
|
|
|
|
# @arrayvar @$$...varname @{aref expr} @$$...{ref2ref expr} |
1693
|
|
|
|
|
|
|
# followed by [] {} «zero or one» |
1694
|
|
|
|
|
|
|
# |
1695
|
4374
|
|
|
|
|
58478
|
(?: \@\$*+\K ${anyvname_or_refexpr_re} ${$curliesorsquares_re}? ) |
1696
|
|
|
|
|
|
|
| |
1697
|
|
|
|
|
|
|
# %hash %$hrefvar %{href expr} %$$...sref2hrefvar «no follow-ons» |
1698
|
|
|
|
|
|
|
(?: \%\$*+\K ${anyvname_or_refexpr_re} ) |
1699
|
|
|
|
|
|
|
) /xsgc) |
1700
|
|
|
|
|
|
|
{ |
1701
|
3104
|
50
|
|
|
|
37655
|
local $_ = $1; oops unless length() > 0; |
|
3104
|
|
|
|
|
7117
|
|
1702
|
3104
|
100
|
|
|
|
8958
|
if (/^[\$\@\%]/) { |
1703
|
1207
|
|
|
|
|
3285
|
my $sigl = substr($_,0,1); |
1704
|
1207
|
100
|
|
|
|
3122
|
if ($i_or_d eq 'd') { |
1705
|
|
|
|
|
|
|
# Inject a "plain text" fragment containing the "expr=" prefix, |
1706
|
|
|
|
|
|
|
# omitting the '$' sigl if the expr is a plain '$name'. |
1707
|
1178
|
100
|
|
|
|
9486
|
push @pieces, ['p', (/^\$(?!_)(${userident_re})\z/ ? $1 : $_)."="]; |
1708
|
|
|
|
|
|
|
} |
1709
|
1207
|
100
|
|
|
|
5671
|
if ($sigl eq '$') { |
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
1710
|
939
|
|
|
|
|
3639
|
push @pieces, ["vis", $_]; |
1711
|
|
|
|
|
|
|
} |
1712
|
|
|
|
|
|
|
elsif ($sigl eq '@') { |
1713
|
203
|
|
|
|
|
903
|
push @pieces, ["avis", $_]; |
1714
|
|
|
|
|
|
|
} |
1715
|
|
|
|
|
|
|
elsif ($sigl eq '%') { |
1716
|
65
|
|
|
|
|
340
|
push @pieces, ["hvis", $_]; |
1717
|
|
|
|
|
|
|
} |
1718
|
0
|
|
|
|
|
0
|
else { confess "BUG:sigl='$sigl'"; } |
1719
|
|
|
|
|
|
|
} else { |
1720
|
1897
|
50
|
|
|
|
6428
|
if (/^.+?(?<!\\)([\$\@\%])/) { confess __PACKAGE__." bug: Missed '$1' in «$_»" } |
|
0
|
|
|
|
|
0
|
|
1721
|
|
|
|
|
|
|
# Due to the need to simplify the big regexp above, \x{abcd} is now |
1722
|
|
|
|
|
|
|
# split into "\x" and "{abcd}". Combine consecutive pass-thrus |
1723
|
|
|
|
|
|
|
# into a single passthru ('p') and convert later to 'e' if |
1724
|
|
|
|
|
|
|
# an eval if needed. |
1725
|
1897
|
100
|
100
|
|
|
7912
|
if (@pieces && $pieces[-1]->[0] eq 'p') { |
1726
|
107
|
|
|
|
|
284
|
$pieces[-1]->[1] .= $_; |
1727
|
|
|
|
|
|
|
} else { |
1728
|
1790
|
|
|
|
|
7291
|
push @pieces, [ 'p', $_ ]; |
1729
|
|
|
|
|
|
|
} |
1730
|
|
|
|
|
|
|
} |
1731
|
|
|
|
|
|
|
} |
1732
|
1270
|
50
|
33
|
|
|
6603
|
if (!defined(pos) || pos() < length($_)) { |
1733
|
0
|
|
0
|
|
|
0
|
my $leftover = substr($_,pos()//0); |
1734
|
0
|
|
|
|
|
0
|
my $e; |
1735
|
|
|
|
|
|
|
# Try to recognize user syntax errors |
1736
|
0
|
0
|
|
|
|
0
|
if ($leftover =~ /^[\$\@\%][\s\%\@]/) { |
1737
|
0
|
|
|
|
|
0
|
$e = "Invalid expression syntax starting at '$leftover' in $funcname arg" |
1738
|
|
|
|
|
|
|
} else { |
1739
|
|
|
|
|
|
|
# Otherwise we may have a parser bug |
1740
|
0
|
|
|
|
|
0
|
$e = "Invalid expression (or ".__PACKAGE__." bug):\n«$leftover»"; |
1741
|
|
|
|
|
|
|
} |
1742
|
0
|
|
|
|
|
0
|
carp "$e\n"; |
1743
|
0
|
|
|
|
|
0
|
push @pieces, ['p',"<INVALID EXPRESSION>".$leftover]; |
1744
|
|
|
|
|
|
|
} |
1745
|
1270
|
|
|
|
|
3284
|
foreach (@pieces) { |
1746
|
4175
|
|
|
|
|
8609
|
my ($meth, $str) = @$_; |
1747
|
4175
|
100
|
100
|
|
|
16309
|
next unless $meth eq 'p' && $str =~ /\\[abtnfrexXN0-7]/; |
1748
|
462
|
|
|
|
|
1294
|
$str =~ s/([()\$\@\%])/\\$1/g; # don't hide \-escapes to be interpolated! |
1749
|
462
|
|
|
|
|
970
|
$str =~ s/\$\\/\$\\\\/g; |
1750
|
462
|
|
|
|
|
1219
|
$_->[1] = "qq(" . $str . ")"; |
1751
|
462
|
|
|
|
|
1427
|
$_->[0] = 'e'; |
1752
|
|
|
|
|
|
|
} |
1753
|
|
|
|
|
|
|
} #local $_ |
1754
|
|
|
|
|
|
|
|
1755
|
1270
|
|
|
|
|
4513
|
@_ = ($self, $funcname, \@pieces); |
1756
|
1270
|
|
|
|
|
5393
|
goto &DB::DB_Vis_Interpolate |
1757
|
|
|
|
|
|
|
} |
1758
|
|
|
|
|
|
|
|
1759
|
|
|
|
|
|
|
sub quotekey(_) { # Quote a hash key if not a valid bareword |
1760
|
0
|
0
|
0
|
0
|
1
|
0
|
$_[0] =~ /\A${userident_re}\z/s ? $_[0] : |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
1761
|
|
|
|
|
|
|
$_[0] =~ /(?!.*')["\$\@]/ ? visq("$_[0]") : |
1762
|
|
|
|
|
|
|
$_[0] =~ /\W/ && !looks_like_number($_[0]) ? vis("$_[0]") : |
1763
|
|
|
|
|
|
|
"\"$_[0]\"" |
1764
|
|
|
|
|
|
|
} |
1765
|
|
|
|
|
|
|
|
1766
|
|
|
|
|
|
|
package |
1767
|
|
|
|
|
|
|
DB; |
1768
|
|
|
|
|
|
|
|
1769
|
|
|
|
|
|
|
sub DB_Vis_Interpolate { |
1770
|
1270
|
|
|
1270
|
0
|
3226
|
my ($self, $funcname, $pieces) = @_; |
1771
|
1270
|
|
|
|
|
2486
|
my $result = ""; |
1772
|
1270
|
|
|
|
|
2740
|
foreach my $p (@$pieces) { |
1773
|
4175
|
|
|
|
|
9013
|
my ($methname, $arg) = @$p; |
1774
|
4175
|
100
|
|
|
|
9604
|
if ($methname eq 'p') { |
|
|
100
|
|
|
|
|
|
1775
|
2506
|
|
|
|
|
5597
|
$result .= $arg; |
1776
|
|
|
|
|
|
|
} |
1777
|
|
|
|
|
|
|
elsif ($methname eq 'e') { |
1778
|
462
|
|
|
|
|
1515
|
$result .= DB::DB_Vis_Eval($funcname, $arg); |
1779
|
|
|
|
|
|
|
} else { |
1780
|
|
|
|
|
|
|
# Reduce width before first wrap to account for stuff already on the line |
1781
|
1207
|
|
|
|
|
3459
|
my $leftwid = length($result) - rindex($result,"\n") - 1; |
1782
|
1207
|
|
|
|
|
2574
|
my $foldwidth = $self->{Foldwidth}; |
1783
|
1207
|
|
66
|
|
|
5662
|
local $self->{Foldwidth1} = $self->{Foldwidth1} // $foldwidth; |
1784
|
1207
|
100
|
|
|
|
2859
|
if ($foldwidth) { |
1785
|
|
|
|
|
|
|
$self->{Foldwidth1} -= $leftwid if $leftwid < $self->{Foldwidth1} |
1786
|
1121
|
50
|
|
|
|
3258
|
} |
1787
|
1207
|
|
|
|
|
3406
|
$result .= $self->$methname( DB::DB_Vis_Eval($funcname, $arg) ); |
1788
|
|
|
|
|
|
|
} |
1789
|
|
|
|
|
|
|
} |
1790
|
|
|
|
|
|
|
|
1791
|
1270
|
|
|
|
|
3318
|
&Data::Dumper::Interp::_RestorePunct; # saved in _Interpolate |
1792
|
1270
|
|
|
|
|
24373
|
$result |
1793
|
|
|
|
|
|
|
}# DB_Vis_Interpolate |
1794
|
|
|
|
|
|
|
|
1795
|
|
|
|
|
|
|
# eval a string in the user's context and return the result. The nearest |
1796
|
|
|
|
|
|
|
# non-DB frame must be the original user's call; this is accomplished by |
1797
|
|
|
|
|
|
|
# dvis(), and friends using "goto &_Interpolate", which in turn |
1798
|
|
|
|
|
|
|
# does "goto &DB::DB_Vis_Interpolate" to enter package DB. |
1799
|
|
|
|
|
|
|
sub DB_Vis_Eval($$) { |
1800
|
1669
|
|
|
1669
|
0
|
3747
|
my ($label_for_errmsg, $evalarg) = @_; |
1801
|
1669
|
50
|
|
|
|
3847
|
Carp::confess("Data::Dumper::Interp bug:empty evalarg") if $evalarg eq ""; |
1802
|
|
|
|
|
|
|
# Inspired perl5db.pl but at this point has been rewritten |
1803
|
|
|
|
|
|
|
|
1804
|
|
|
|
|
|
|
# Find the closest non-DB caller. The eval will be done in that package. |
1805
|
|
|
|
|
|
|
# Find the next caller further up which has arguments (i.e. wasn't doing |
1806
|
|
|
|
|
|
|
# "&subname;"), and make @_ contain those arguments. |
1807
|
1669
|
|
|
|
|
3235
|
my ($distance, $pkg, $fname, $lno); |
1808
|
1669
|
|
|
|
|
3229
|
for ($distance = 0 ; ; $distance++) { |
1809
|
3338
|
|
|
|
|
77326
|
($pkg, $fname, $lno) = caller($distance); |
1810
|
3338
|
100
|
|
|
|
15872
|
last if $pkg ne "DB"; |
1811
|
|
|
|
|
|
|
} |
1812
|
1669
|
|
|
|
|
4867
|
local *_ = []; |
1813
|
1669
|
|
|
|
|
2885
|
while() { |
1814
|
3304
|
|
|
|
|
4569
|
$distance++; |
1815
|
3304
|
|
|
|
|
18376
|
my ($p, $hasargs) = (caller($distance))[0,4]; |
1816
|
3304
|
100
|
|
|
|
11194
|
if (! defined $p){ |
1817
|
44
|
|
|
|
|
117
|
*_ = [ '<@_ is not defined in the outer block>' ]; |
1818
|
|
|
|
|
|
|
last |
1819
|
44
|
|
|
|
|
83
|
} |
1820
|
3260
|
100
|
|
|
|
6848
|
if ($hasargs) { |
1821
|
1625
|
|
|
|
|
4484
|
*_ = [ @DB::args ]; # copy in case of recursion |
1822
|
|
|
|
|
|
|
last |
1823
|
1625
|
|
|
|
|
3461
|
} |
1824
|
|
|
|
|
|
|
} |
1825
|
|
|
|
|
|
|
|
1826
|
1669
|
|
|
|
|
2593
|
my @result = do { |
1827
|
1669
|
|
|
|
|
2935
|
local @Data::Dumper::Interp::result; |
1828
|
1669
|
|
|
|
|
5969
|
local $Data::Dumper::Interp::string_to_eval = |
1829
|
|
|
|
|
|
|
"package $pkg; " |
1830
|
|
|
|
|
|
|
# N.B. eval first clears $@ so we must restore $@ inside the eval |
1831
|
|
|
|
|
|
|
.' &Data::Dumper::Interp::_RestorePunct_NoPop;' # saved in _Interpolate |
1832
|
|
|
|
|
|
|
# In case something carps or croaks (e.g. because of ${\(somefunc())} |
1833
|
|
|
|
|
|
|
# or a tie handler), force a full backtrace so the user's call location |
1834
|
|
|
|
|
|
|
# is visible. Unfortunately there is no way to make carp() show only |
1835
|
|
|
|
|
|
|
# the location of the user's call because we must force the eval'd |
1836
|
|
|
|
|
|
|
# string into in e.g. package main so user functions can be found. |
1837
|
|
|
|
|
|
|
.' local $Carp::Verbose = 1;' |
1838
|
|
|
|
|
|
|
.' @Data::Dumper::Interp::result = '.$evalarg.';' |
1839
|
|
|
|
|
|
|
.' $Data::Dumper::Interp::save_stack[-1]->[0] = $@;' # possibly changed by a tie handler |
1840
|
|
|
|
|
|
|
; |
1841
|
1669
|
|
|
|
|
4761
|
&DB_Vis_Evalwrapper; |
1842
|
|
|
|
|
|
|
@Data::Dumper::Interp::result |
1843
|
1669
|
|
|
|
|
14079
|
}; |
1844
|
1669
|
|
|
|
|
3797
|
my $errmsg = $@; |
1845
|
|
|
|
|
|
|
|
1846
|
1669
|
50
|
|
|
|
4412
|
if ($errmsg) { |
1847
|
0
|
|
|
|
|
0
|
$errmsg = Data::Dumper::Interp::__chop_loc($errmsg); |
1848
|
0
|
|
|
|
|
0
|
Carp::carp("${label_for_errmsg}: Error interpolating '$evalarg':\n$errmsg\n"); |
1849
|
0
|
0
|
|
|
|
0
|
@result = ( (defined($result[0]) ? $result[0] : "")."<invalid/error>" ); |
1850
|
|
|
|
|
|
|
} |
1851
|
|
|
|
|
|
|
|
1852
|
1669
|
50
|
|
|
|
35314
|
wantarray ? @result : (do{die "bug" if @result>1}, $result[0]) |
|
462
|
100
|
|
|
|
3678
|
|
1853
|
|
|
|
|
|
|
}# DB_Vis_Eval |
1854
|
|
|
|
|
|
|
|
1855
|
|
|
|
|
|
|
1; |
1856
|
|
|
|
|
|
|
__END__ |
1857
|
|
|
|
|
|
|
|
1858
|
|
|
|
|
|
|
=pod |
1859
|
|
|
|
|
|
|
|
1860
|
|
|
|
|
|
|
=encoding UTF-8 |
1861
|
|
|
|
|
|
|
|
1862
|
|
|
|
|
|
|
=head1 NAME |
1863
|
|
|
|
|
|
|
|
1864
|
|
|
|
|
|
|
Data::Dumper::Interp - interpolate Data::Dumper output into strings for human consumption |
1865
|
|
|
|
|
|
|
|
1866
|
|
|
|
|
|
|
=head1 SYNOPSIS |
1867
|
|
|
|
|
|
|
|
1868
|
|
|
|
|
|
|
use open IO => ':locale'; |
1869
|
|
|
|
|
|
|
use Data::Dumper::Interp; |
1870
|
|
|
|
|
|
|
|
1871
|
|
|
|
|
|
|
@ARGV = ('-i', '/file/path'); |
1872
|
|
|
|
|
|
|
my %hash = (abc => [1,2,3,4,5], def => undef); |
1873
|
|
|
|
|
|
|
my $ref = \%hash; |
1874
|
|
|
|
|
|
|
my $obj = bless {}, "Foo::Bar"; |
1875
|
|
|
|
|
|
|
|
1876
|
|
|
|
|
|
|
# Interpolate variables in strings with Data::Dumper output |
1877
|
|
|
|
|
|
|
say ivis 'FYI ref is $ref\nThat hash is: %hash\nArgs are @ARGV'; |
1878
|
|
|
|
|
|
|
|
1879
|
|
|
|
|
|
|
# -->FYI ref is {abc => [1,2,3,4,5], def => undef} |
1880
|
|
|
|
|
|
|
# That hash is: (abc => [1,2,3,4,5], def => undef) |
1881
|
|
|
|
|
|
|
# Args are ("-i","/file/path") |
1882
|
|
|
|
|
|
|
|
1883
|
|
|
|
|
|
|
# Label interpolated values with "expr=" |
1884
|
|
|
|
|
|
|
say dvis '$ref\nand @ARGV'; |
1885
|
|
|
|
|
|
|
|
1886
|
|
|
|
|
|
|
# -->ref={abc => [1,2,3,4,5], def => undef} |
1887
|
|
|
|
|
|
|
# and @ARGV=("-i","/file/path") |
1888
|
|
|
|
|
|
|
|
1889
|
|
|
|
|
|
|
# Functions to format one thing |
1890
|
|
|
|
|
|
|
say vis $ref; #prints {abc => [1,2,3,4,5], def => undef} |
1891
|
|
|
|
|
|
|
say vis \@ARGV; #prints ["-i", "/file/path"] # any scalar |
1892
|
|
|
|
|
|
|
say avis @ARGV; #prints ("-i", "/file/path") |
1893
|
|
|
|
|
|
|
say hvis %hash; #prints (abc => [1,2,3,4,5], def => undef) |
1894
|
|
|
|
|
|
|
|
1895
|
|
|
|
|
|
|
# Format a reference with abbreviated referent address |
1896
|
|
|
|
|
|
|
say visr $href; #prints HASH<457:1c9>{abc => [1,2,3,4,5], ...} |
1897
|
|
|
|
|
|
|
|
1898
|
|
|
|
|
|
|
# Just abbreviate a referent address or arbitrary number |
1899
|
|
|
|
|
|
|
say addrvis refaddr($ref); # 457:1c9 |
1900
|
|
|
|
|
|
|
say addrvis $ref; # HASH<457:1c9> |
1901
|
|
|
|
|
|
|
say addrvis $obj; # Foo::Bar<984:ef8> |
1902
|
|
|
|
|
|
|
|
1903
|
|
|
|
|
|
|
# Stringify objects |
1904
|
|
|
|
|
|
|
{ use bigint; |
1905
|
|
|
|
|
|
|
my $struct = { debt => 999_999_999_999_999_999.02 }; |
1906
|
|
|
|
|
|
|
say vis $struct; |
1907
|
|
|
|
|
|
|
# --> {debt => (Math::BigFloat)999999999999999999.02} |
1908
|
|
|
|
|
|
|
|
1909
|
|
|
|
|
|
|
# But if you do want to see object internals... |
1910
|
|
|
|
|
|
|
# |
1911
|
|
|
|
|
|
|
say visnew->Objects(0)->vis($struct); |
1912
|
|
|
|
|
|
|
# --> {debt => bless({...lots of stuff...},'Math::BigInt')} |
1913
|
|
|
|
|
|
|
|
1914
|
|
|
|
|
|
|
# or, equivalently |
1915
|
|
|
|
|
|
|
{ local $Data::Dumper::Interp::Objects=0; say vis $struct; } |
1916
|
|
|
|
|
|
|
|
1917
|
|
|
|
|
|
|
# yet another equivalent way |
1918
|
|
|
|
|
|
|
say viso $struct; # not exported by default |
1919
|
|
|
|
|
|
|
} |
1920
|
|
|
|
|
|
|
|
1921
|
|
|
|
|
|
|
# Wide characters are readable |
1922
|
|
|
|
|
|
|
use utf8; |
1923
|
|
|
|
|
|
|
my $h = {msg => "My language is not ASCII ☻ ☺ 😊 \N{U+2757}!"}; |
1924
|
|
|
|
|
|
|
say dvis '$h' ; |
1925
|
|
|
|
|
|
|
# --> h={msg => "My language is not ASCII ☻ ☺ 😊 ❗"} |
1926
|
|
|
|
|
|
|
|
1927
|
|
|
|
|
|
|
#-------- OO API -------- |
1928
|
|
|
|
|
|
|
|
1929
|
|
|
|
|
|
|
say Data::Dumper::Interp->new() |
1930
|
|
|
|
|
|
|
->MaxStringwidth(50)->Maxdepth($levels)->vis($datum); |
1931
|
|
|
|
|
|
|
|
1932
|
|
|
|
|
|
|
say visnew->MaxStringwidth(50)->Maxdepth($levels)->vis($datum); |
1933
|
|
|
|
|
|
|
|
1934
|
|
|
|
|
|
|
#-------- UTILITY FUNCTIONS -------- |
1935
|
|
|
|
|
|
|
say u($might_be_undef); # $_[0] // "undef" |
1936
|
|
|
|
|
|
|
say quotekey($string); # quote hash key if not a valid bareword |
1937
|
|
|
|
|
|
|
say qsh($string); # quote if needed for /bin/sh |
1938
|
|
|
|
|
|
|
say qshpath($pathname); # shell quote excepting ~ or ~username prefix |
1939
|
|
|
|
|
|
|
say "Runing this: ", qshlist(@command_and_args); |
1940
|
|
|
|
|
|
|
|
1941
|
|
|
|
|
|
|
system "ls -ld ".join(" ",map{ qshpath } |
1942
|
|
|
|
|
|
|
("/tmp", "~sally/My Documents", "~")); |
1943
|
|
|
|
|
|
|
|
1944
|
|
|
|
|
|
|
|
1945
|
|
|
|
|
|
|
=head1 DESCRIPTION |
1946
|
|
|
|
|
|
|
|
1947
|
|
|
|
|
|
|
This Data::Dumper wrapper optimizes output for human consumption |
1948
|
|
|
|
|
|
|
and avoids side-effects which interfere with debugging. |
1949
|
|
|
|
|
|
|
|
1950
|
|
|
|
|
|
|
The namesake feature is interpolating Data::Dumper output |
1951
|
|
|
|
|
|
|
into strings, but simple functions are also provided |
1952
|
|
|
|
|
|
|
to format a scalar, array, or hash. |
1953
|
|
|
|
|
|
|
|
1954
|
|
|
|
|
|
|
Internally, Data::Dumper is called to visualize (i.e. format) data |
1955
|
|
|
|
|
|
|
with pre- and post-processing to "improve" the results: |
1956
|
|
|
|
|
|
|
|
1957
|
|
|
|
|
|
|
=over 2 |
1958
|
|
|
|
|
|
|
|
1959
|
|
|
|
|
|
|
=item * Output is 1 line if possible, |
1960
|
|
|
|
|
|
|
otherwise folded at your terminal width, WITHOUT a trailing newline. |
1961
|
|
|
|
|
|
|
|
1962
|
|
|
|
|
|
|
=item * Printable Unicode characters appear as themselves. |
1963
|
|
|
|
|
|
|
|
1964
|
|
|
|
|
|
|
=item * Object internals are not shown by default; Math:BigInt etc. are stringified. |
1965
|
|
|
|
|
|
|
|
1966
|
|
|
|
|
|
|
=item * "virtual" values behind overloaded deref operators are shown. |
1967
|
|
|
|
|
|
|
|
1968
|
|
|
|
|
|
|
=item * Data::Dumper bugs^H^H^H^Hquirks are circumvented. |
1969
|
|
|
|
|
|
|
|
1970
|
|
|
|
|
|
|
=back |
1971
|
|
|
|
|
|
|
|
1972
|
|
|
|
|
|
|
See "DIFFERENCES FROM Data::Dumper". |
1973
|
|
|
|
|
|
|
|
1974
|
|
|
|
|
|
|
A few utilities are also provided to quote strings for /bin/sh. |
1975
|
|
|
|
|
|
|
|
1976
|
|
|
|
|
|
|
=head1 FUNCTIONS |
1977
|
|
|
|
|
|
|
|
1978
|
|
|
|
|
|
|
=head2 ivis 'string to be interpolated' |
1979
|
|
|
|
|
|
|
|
1980
|
|
|
|
|
|
|
Returns the argument with variable references and escapes interpolated |
1981
|
|
|
|
|
|
|
as in in Perl double-quotish strings, but using Data::Dumper to |
1982
|
|
|
|
|
|
|
format variable values. |
1983
|
|
|
|
|
|
|
|
1984
|
|
|
|
|
|
|
C<$var> is replaced by its value, |
1985
|
|
|
|
|
|
|
C<@var> is replaced by "(comma, sparated, list)", |
1986
|
|
|
|
|
|
|
and C<%hash> by "(key => value, ...)" . |
1987
|
|
|
|
|
|
|
Complex expressions with indexing, dereferences, slices |
1988
|
|
|
|
|
|
|
and method calls are also recognized. |
1989
|
|
|
|
|
|
|
|
1990
|
|
|
|
|
|
|
Expressions are evaluated in the caller's context using Perl's debugger |
1991
|
|
|
|
|
|
|
hooks, and may refer to almost any lexical or global visible at |
1992
|
|
|
|
|
|
|
the point of call (see "LIMITATIONS"). |
1993
|
|
|
|
|
|
|
|
1994
|
|
|
|
|
|
|
IMPORTANT: The argument must be single-quoted to prevent Perl |
1995
|
|
|
|
|
|
|
from interpolating it beforehand. |
1996
|
|
|
|
|
|
|
|
1997
|
|
|
|
|
|
|
=head2 dvis 'string to be interpolated' |
1998
|
|
|
|
|
|
|
|
1999
|
|
|
|
|
|
|
Like C<ivis> but interpolations are prefixed with a "expr=" label |
2000
|
|
|
|
|
|
|
and spaces are shown visibly as '·'. |
2001
|
|
|
|
|
|
|
|
2002
|
|
|
|
|
|
|
The 'd' in 'dvis' stands for B<d>ebugging messages, a frequent use case where |
2003
|
|
|
|
|
|
|
brevity of typing is needed. |
2004
|
|
|
|
|
|
|
|
2005
|
|
|
|
|
|
|
=head2 vis [SCALAREXPR] |
2006
|
|
|
|
|
|
|
|
2007
|
|
|
|
|
|
|
=head2 avis LIST |
2008
|
|
|
|
|
|
|
|
2009
|
|
|
|
|
|
|
=head2 hvis EVENLIST |
2010
|
|
|
|
|
|
|
|
2011
|
|
|
|
|
|
|
C<vis> formats a single scalar ($_ if no argument is given) |
2012
|
|
|
|
|
|
|
and returns the resulting string. |
2013
|
|
|
|
|
|
|
|
2014
|
|
|
|
|
|
|
C<avis> formats an array (or any list) as comma-separated values in parenthesis. |
2015
|
|
|
|
|
|
|
|
2016
|
|
|
|
|
|
|
C<hvis> formats key => value pairs in parenthesis. |
2017
|
|
|
|
|
|
|
|
2018
|
|
|
|
|
|
|
=head2 FUNCTION (and METHOD) VARIATIONS |
2019
|
|
|
|
|
|
|
|
2020
|
|
|
|
|
|
|
Variations of the above five functions have extra characters |
2021
|
|
|
|
|
|
|
in their names to imply certain options. |
2022
|
|
|
|
|
|
|
For example C<visq> is like C<vis> but |
2023
|
|
|
|
|
|
|
shows strings in single-quoted form (implied by the 'B<q>' suffix). |
2024
|
|
|
|
|
|
|
|
2025
|
|
|
|
|
|
|
There are no fixed function names; you can use any combination of |
2026
|
|
|
|
|
|
|
characters in any order, prefixed or suffixed to the primary name |
2027
|
|
|
|
|
|
|
with optional '_' separators. |
2028
|
|
|
|
|
|
|
The function will be I<generated> when it is imported* or called as a method. |
2029
|
|
|
|
|
|
|
|
2030
|
|
|
|
|
|
|
The available modifier characters are: |
2031
|
|
|
|
|
|
|
|
2032
|
|
|
|
|
|
|
=over 2 |
2033
|
|
|
|
|
|
|
|
2034
|
|
|
|
|
|
|
B<l> - omit parenthesis to return a bare list (only with "avis" or "hvis") |
2035
|
|
|
|
|
|
|
|
2036
|
|
|
|
|
|
|
B<o> - show object internals |
2037
|
|
|
|
|
|
|
|
2038
|
|
|
|
|
|
|
=over |
2039
|
|
|
|
|
|
|
|
2040
|
|
|
|
|
|
|
Calling B<< Objects(0) >> using the OO api has the same effect. |
2041
|
|
|
|
|
|
|
|
2042
|
|
|
|
|
|
|
=back |
2043
|
|
|
|
|
|
|
|
2044
|
|
|
|
|
|
|
B<q> - show strings 'single quoted' if possible |
2045
|
|
|
|
|
|
|
|
2046
|
|
|
|
|
|
|
=over |
2047
|
|
|
|
|
|
|
|
2048
|
|
|
|
|
|
|
Internally, Data::Dumper is called with C<Useqq(0)>, but depending |
2049
|
|
|
|
|
|
|
on the version of Data::Dumper the result may be "double quoted" |
2050
|
|
|
|
|
|
|
anyway if wide characters are present. |
2051
|
|
|
|
|
|
|
|
2052
|
|
|
|
|
|
|
=back |
2053
|
|
|
|
|
|
|
|
2054
|
|
|
|
|
|
|
B<r> - show abbreviated addresses of objects and other refs |
2055
|
|
|
|
|
|
|
|
2056
|
|
|
|
|
|
|
=over |
2057
|
|
|
|
|
|
|
|
2058
|
|
|
|
|
|
|
Calling B<< Reftype(1) >> using the OO api has the same effect. |
2059
|
|
|
|
|
|
|
|
2060
|
|
|
|
|
|
|
=back |
2061
|
|
|
|
|
|
|
|
2062
|
|
|
|
|
|
|
B<NUMBER> - limit nested structure depth to NUMBER levels |
2063
|
|
|
|
|
|
|
|
2064
|
|
|
|
|
|
|
=over |
2065
|
|
|
|
|
|
|
|
2066
|
|
|
|
|
|
|
Calling B<< Maxdepth(NUMBER) >> using the OO api has the same effect. |
2067
|
|
|
|
|
|
|
|
2068
|
|
|
|
|
|
|
=back |
2069
|
|
|
|
|
|
|
|
2070
|
|
|
|
|
|
|
=back |
2071
|
|
|
|
|
|
|
|
2072
|
|
|
|
|
|
|
If you call a function directly it must be explicitly listed |
2073
|
|
|
|
|
|
|
in the C<< S<use Data::Dumper::Interp ... ;> >> statement |
2074
|
|
|
|
|
|
|
unless it is imported by default (list shown below) |
2075
|
|
|
|
|
|
|
or created via the :all tag. |
2076
|
|
|
|
|
|
|
|
2077
|
|
|
|
|
|
|
To avoid having to specify functions in advance, you can |
2078
|
|
|
|
|
|
|
use them as methods and import only the C<visnew> function: |
2079
|
|
|
|
|
|
|
|
2080
|
|
|
|
|
|
|
use Spreadsheet::Edit::Interp qw/visnew/; |
2081
|
|
|
|
|
|
|
... |
2082
|
|
|
|
|
|
|
say visnew->vis($struct); |
2083
|
|
|
|
|
|
|
say visnew->visrq($my_object); |
2084
|
|
|
|
|
|
|
say visnew->avis(@ARGV); |
2085
|
|
|
|
|
|
|
say visnew->avis2lrq(@ARGV); |
2086
|
|
|
|
|
|
|
etc. |
2087
|
|
|
|
|
|
|
|
2088
|
|
|
|
|
|
|
(C<visnew> creates a new object. Non-existent methods are auto-generated when |
2089
|
|
|
|
|
|
|
first called via the AUTOLOAD mechanism). |
2090
|
|
|
|
|
|
|
|
2091
|
|
|
|
|
|
|
=head2 Functions imported by default |
2092
|
|
|
|
|
|
|
|
2093
|
|
|
|
|
|
|
ivis dvis vis avis hvis |
2094
|
|
|
|
|
|
|
|
2095
|
|
|
|
|
|
|
ivisq dvisq visq avisq hvisq rvis rvisq |
2096
|
|
|
|
|
|
|
|
2097
|
|
|
|
|
|
|
visnew |
2098
|
|
|
|
|
|
|
addrvis addrvisl |
2099
|
|
|
|
|
|
|
u quotekey qsh qshlist qshpath |
2100
|
|
|
|
|
|
|
|
2101
|
|
|
|
|
|
|
=head2 The :all import tag |
2102
|
|
|
|
|
|
|
Z<> Z<> |
2103
|
|
|
|
|
|
|
|
2104
|
|
|
|
|
|
|
use Data::Dumper::Interp qw/:all/; |
2105
|
|
|
|
|
|
|
|
2106
|
|
|
|
|
|
|
This generates and imports all possible variations (with NUMBER <= 2). |
2107
|
|
|
|
|
|
|
that have suffix characters in alphabetical order, without underscores. |
2108
|
|
|
|
|
|
|
There are 119 variations, too many to remember. |
2109
|
|
|
|
|
|
|
|
2110
|
|
|
|
|
|
|
But you only really need to remember the five standard names |
2111
|
|
|
|
|
|
|
|
2112
|
|
|
|
|
|
|
ivis, dvis, vis, avis, and hvis |
2113
|
|
|
|
|
|
|
|
2114
|
|
|
|
|
|
|
and the possible suffixes and their order (I<NUMBER>,l,o,q,r). |
2115
|
|
|
|
|
|
|
|
2116
|
|
|
|
|
|
|
For example, one function is C<avis2lq>, which |
2117
|
|
|
|
|
|
|
|
2118
|
|
|
|
|
|
|
* Formats multiple arguments as an array ('avis') |
2119
|
|
|
|
|
|
|
* Decends at most 2 levels into structures ('2') |
2120
|
|
|
|
|
|
|
* Returns a comma-separated list *without* parenthesis ('l') |
2121
|
|
|
|
|
|
|
* Shows strings in single-quoted form ('q') |
2122
|
|
|
|
|
|
|
|
2123
|
|
|
|
|
|
|
You could equally well have made up different names like C<avis2ql>, |
2124
|
|
|
|
|
|
|
C<q2avisl>, C<q_2_avis_l> etc. |
2125
|
|
|
|
|
|
|
for the same function if you explicitly imported those alternate |
2126
|
|
|
|
|
|
|
names or called them as methods. |
2127
|
|
|
|
|
|
|
|
2128
|
|
|
|
|
|
|
* To save memory, only stub declarations for prototype |
2129
|
|
|
|
|
|
|
checking are generated for imported functions. |
2130
|
|
|
|
|
|
|
The body will be generated when a function is actually used |
2131
|
|
|
|
|
|
|
via the AUTOLOAD mechanism. The C<:debug> import tag |
2132
|
|
|
|
|
|
|
prints messages as these events occur. |
2133
|
|
|
|
|
|
|
|
2134
|
|
|
|
|
|
|
=head1 Showing Abbreviated Addresses |
2135
|
|
|
|
|
|
|
|
2136
|
|
|
|
|
|
|
=head2 addrvis REF_or_NUMBER |
2137
|
|
|
|
|
|
|
|
2138
|
|
|
|
|
|
|
This function returns a string showing an address in both decimal and |
2139
|
|
|
|
|
|
|
hexadecimal, but abbreviated to only the last few digits. |
2140
|
|
|
|
|
|
|
|
2141
|
|
|
|
|
|
|
The number of digits starts at 3 and increases over time if necessary |
2142
|
|
|
|
|
|
|
to keep new results unambiguous. |
2143
|
|
|
|
|
|
|
|
2144
|
|
|
|
|
|
|
For REFs, the result is like I<< "HASHE<lt>457:1c9E<gt>" >> |
2145
|
|
|
|
|
|
|
or, for blessed objects, I<< "Package::NameE<lt>457:1c9E<gt>" >>. |
2146
|
|
|
|
|
|
|
|
2147
|
|
|
|
|
|
|
If the argument is a plain number, just the abbreviated decimal:hex address |
2148
|
|
|
|
|
|
|
is returned, e.g. I<< "E<lt>457:1c9E<gt>" >>. |
2149
|
|
|
|
|
|
|
|
2150
|
|
|
|
|
|
|
I<"undef"> is returned if the argument is undefined. |
2151
|
|
|
|
|
|
|
Croaks if the argument is defined but not a ref. |
2152
|
|
|
|
|
|
|
|
2153
|
|
|
|
|
|
|
C<addrvis_digits(NUMBER)> forces a minimum width |
2154
|
|
|
|
|
|
|
and C<addrvis_forget()> discards past values and resets to 3 digits. |
2155
|
|
|
|
|
|
|
|
2156
|
|
|
|
|
|
|
=head2 addrvisl REF_or_NUMBER |
2157
|
|
|
|
|
|
|
|
2158
|
|
|
|
|
|
|
Like C<addrvis> but omits the <angle brackets>. |
2159
|
|
|
|
|
|
|
|
2160
|
|
|
|
|
|
|
=head1 OBJECT-ORIENTED API |
2161
|
|
|
|
|
|
|
|
2162
|
|
|
|
|
|
|
=head2 Data::Dumper::Interp->new() |
2163
|
|
|
|
|
|
|
|
2164
|
|
|
|
|
|
|
=head2 visnew() |
2165
|
|
|
|
|
|
|
|
2166
|
|
|
|
|
|
|
These create an object initialized from the global configuration |
2167
|
|
|
|
|
|
|
variables listed below. C<visnew> is simply a shorthand wrapper. |
2168
|
|
|
|
|
|
|
|
2169
|
|
|
|
|
|
|
No arguments are permitted. |
2170
|
|
|
|
|
|
|
|
2171
|
|
|
|
|
|
|
B<All the functions described above> including all possible variations |
2172
|
|
|
|
|
|
|
may be called as I<methods> on an object |
2173
|
|
|
|
|
|
|
(when not called as a method the functions create a new object internally). |
2174
|
|
|
|
|
|
|
|
2175
|
|
|
|
|
|
|
For example: |
2176
|
|
|
|
|
|
|
|
2177
|
|
|
|
|
|
|
$msg = visnew->Foldwidth(40)->avis(@ARGV); |
2178
|
|
|
|
|
|
|
|
2179
|
|
|
|
|
|
|
returns the same string as |
2180
|
|
|
|
|
|
|
|
2181
|
|
|
|
|
|
|
local $Data::Dumper::Interp::Foldwidth = 40; |
2182
|
|
|
|
|
|
|
$msg = avis @ARGV; |
2183
|
|
|
|
|
|
|
|
2184
|
|
|
|
|
|
|
Any "variation" can be called, for example |
2185
|
|
|
|
|
|
|
|
2186
|
|
|
|
|
|
|
$msg = visnew->vis_r2($x); # show addresses; Maxdepth 2 |
2187
|
|
|
|
|
|
|
|
2188
|
|
|
|
|
|
|
=head1 Configuration Variables / Methods |
2189
|
|
|
|
|
|
|
|
2190
|
|
|
|
|
|
|
These work the same way as variables/methods in Data::Dumper. |
2191
|
|
|
|
|
|
|
|
2192
|
|
|
|
|
|
|
Each config method has a corresponding global variable |
2193
|
|
|
|
|
|
|
in package C<Data::Dumper::Interp> which provides the default value. |
2194
|
|
|
|
|
|
|
|
2195
|
|
|
|
|
|
|
When a config method is called without arguments the current value is returned, |
2196
|
|
|
|
|
|
|
and when called with an argument the value is changed and |
2197
|
|
|
|
|
|
|
the object is returned so that calls can be chained. |
2198
|
|
|
|
|
|
|
|
2199
|
|
|
|
|
|
|
=head2 MaxStringwidth(INTEGER) |
2200
|
|
|
|
|
|
|
|
2201
|
|
|
|
|
|
|
=head2 Truncsuffix("...") |
2202
|
|
|
|
|
|
|
|
2203
|
|
|
|
|
|
|
Longer strings are truncated and I<Truncsuffix> appended. |
2204
|
|
|
|
|
|
|
MaxStringwidth=0 (the default) means no limit. |
2205
|
|
|
|
|
|
|
|
2206
|
|
|
|
|
|
|
=head2 Foldwidth(INTEGER) |
2207
|
|
|
|
|
|
|
|
2208
|
|
|
|
|
|
|
Defaults to the terminal width at the time of first use. |
2209
|
|
|
|
|
|
|
|
2210
|
|
|
|
|
|
|
=head2 Objects(BOOL); |
2211
|
|
|
|
|
|
|
|
2212
|
|
|
|
|
|
|
=head2 Objects("classname") |
2213
|
|
|
|
|
|
|
|
2214
|
|
|
|
|
|
|
=head2 Objects([ list of classnames ]) |
2215
|
|
|
|
|
|
|
|
2216
|
|
|
|
|
|
|
A I<false> value disables special handling of objects |
2217
|
|
|
|
|
|
|
(that is, blessed things) and internals are shown as with Data::Dumper. |
2218
|
|
|
|
|
|
|
|
2219
|
|
|
|
|
|
|
A "1" (the default) enables for all objects, |
2220
|
|
|
|
|
|
|
otherwise only for the specified class name(s) [or derived classes]. |
2221
|
|
|
|
|
|
|
|
2222
|
|
|
|
|
|
|
When enabled, object internals are never shown. |
2223
|
|
|
|
|
|
|
The class and abbreviated address are shown as with C<addrvis> |
2224
|
|
|
|
|
|
|
e.g. "Foo::Bar<392:0f0>", unless the object overloads |
2225
|
|
|
|
|
|
|
the stringification ('""') operator, |
2226
|
|
|
|
|
|
|
or array-, hash-, scalar-, or glob- deref operators; |
2227
|
|
|
|
|
|
|
in that case the first overloaded operator found will be evaluated, |
2228
|
|
|
|
|
|
|
the object replaced by the result, and the check repeated. |
2229
|
|
|
|
|
|
|
|
2230
|
|
|
|
|
|
|
=head2 Sortkeys(subref) |
2231
|
|
|
|
|
|
|
|
2232
|
|
|
|
|
|
|
The default sorts numeric substrings in keys by numerical |
2233
|
|
|
|
|
|
|
value, e.g. "A.20" sorts before "A.100". See C<Data::Dumper> documentation. |
2234
|
|
|
|
|
|
|
|
2235
|
|
|
|
|
|
|
=head2 Useqq |
2236
|
|
|
|
|
|
|
|
2237
|
|
|
|
|
|
|
0 means generate 'single quoted' strings when possible. |
2238
|
|
|
|
|
|
|
|
2239
|
|
|
|
|
|
|
1 means generate "double quoted" strings as-is from Data::Dumper. |
2240
|
|
|
|
|
|
|
Non-ASCII charcters will be shown as hex escapes. |
2241
|
|
|
|
|
|
|
|
2242
|
|
|
|
|
|
|
Otherwise generate "double quoted" strings enhanced according to option |
2243
|
|
|
|
|
|
|
keywords given as a :-separated list, e.g. Useqq("unicode:controlpics"). |
2244
|
|
|
|
|
|
|
The avilable options are: |
2245
|
|
|
|
|
|
|
|
2246
|
|
|
|
|
|
|
=over 4 |
2247
|
|
|
|
|
|
|
|
2248
|
|
|
|
|
|
|
=item "unicode" |
2249
|
|
|
|
|
|
|
|
2250
|
|
|
|
|
|
|
Printable ("graphic") |
2251
|
|
|
|
|
|
|
characters are shown as themselves rather than hex escapes, and |
2252
|
|
|
|
|
|
|
'\n', '\t', etc. are shown for ASCII control codes. |
2253
|
|
|
|
|
|
|
|
2254
|
|
|
|
|
|
|
=item "controlpics" |
2255
|
|
|
|
|
|
|
|
2256
|
|
|
|
|
|
|
Show ASCII control characters using single "control picture" characters: |
2257
|
|
|
|
|
|
|
'' is shown for newline instead of '\n', and |
2258
|
|
|
|
|
|
|
similarly ␀ ␇ ␈ ␛ ␌ ␍ ␉ for \0 \a \b \e \f \r \t. |
2259
|
|
|
|
|
|
|
|
2260
|
|
|
|
|
|
|
Every character occupies the same space with a fixed-width font, but |
2261
|
|
|
|
|
|
|
the tiny "control picures" can be hard to read; |
2262
|
|
|
|
|
|
|
to see traditional \n etc. while still seeing wide characters as themselves, |
2263
|
|
|
|
|
|
|
set C<Useqq> to just "unicode"; |
2264
|
|
|
|
|
|
|
|
2265
|
|
|
|
|
|
|
=item "spacedots" |
2266
|
|
|
|
|
|
|
|
2267
|
|
|
|
|
|
|
Space characters are shown as '·' (Middle Dot). |
2268
|
|
|
|
|
|
|
|
2269
|
|
|
|
|
|
|
=item "qq" |
2270
|
|
|
|
|
|
|
|
2271
|
|
|
|
|
|
|
=item "qq=XY" |
2272
|
|
|
|
|
|
|
|
2273
|
|
|
|
|
|
|
Show using Perl's qq{...} syntax, or qqX...Y if delimiters are specified, |
2274
|
|
|
|
|
|
|
rather than "...". |
2275
|
|
|
|
|
|
|
|
2276
|
|
|
|
|
|
|
=back |
2277
|
|
|
|
|
|
|
|
2278
|
|
|
|
|
|
|
The default is C<Useqq('unicode')> except for |
2279
|
|
|
|
|
|
|
functions/methods with 'q' in their name, which force C<Useqq(0)>. |
2280
|
|
|
|
|
|
|
|
2281
|
|
|
|
|
|
|
=head2 Quotekeys |
2282
|
|
|
|
|
|
|
|
2283
|
|
|
|
|
|
|
=head2 Maxdepth |
2284
|
|
|
|
|
|
|
|
2285
|
|
|
|
|
|
|
=head2 Maxrecurse |
2286
|
|
|
|
|
|
|
|
2287
|
|
|
|
|
|
|
=head2 Deparse |
2288
|
|
|
|
|
|
|
|
2289
|
|
|
|
|
|
|
=head2 Deepcopy |
2290
|
|
|
|
|
|
|
|
2291
|
|
|
|
|
|
|
See C<Data::Dumper> documentation. |
2292
|
|
|
|
|
|
|
|
2293
|
|
|
|
|
|
|
=head1 |
2294
|
|
|
|
|
|
|
|
2295
|
|
|
|
|
|
|
=head1 UTILITY FUNCTIONS |
2296
|
|
|
|
|
|
|
|
2297
|
|
|
|
|
|
|
=head2 u |
2298
|
|
|
|
|
|
|
|
2299
|
|
|
|
|
|
|
=head2 u SCALAR |
2300
|
|
|
|
|
|
|
|
2301
|
|
|
|
|
|
|
Returns the argument ($_ by default) if it is defined, otherwise |
2302
|
|
|
|
|
|
|
the string "undef". |
2303
|
|
|
|
|
|
|
|
2304
|
|
|
|
|
|
|
=head2 quotekey |
2305
|
|
|
|
|
|
|
|
2306
|
|
|
|
|
|
|
=head2 quotekey SCALAR |
2307
|
|
|
|
|
|
|
|
2308
|
|
|
|
|
|
|
Returns the argument ($_ by default) if it is a valid bareword, |
2309
|
|
|
|
|
|
|
otherwise a "quoted string". |
2310
|
|
|
|
|
|
|
|
2311
|
|
|
|
|
|
|
=head2 qsh [$string] |
2312
|
|
|
|
|
|
|
|
2313
|
|
|
|
|
|
|
The string ($_ by default) is quoted if necessary for parsing |
2314
|
|
|
|
|
|
|
by the shell (/bin/sh), which has different quoting rules than Perl. |
2315
|
|
|
|
|
|
|
On Win32 quoting is for cmd.com. |
2316
|
|
|
|
|
|
|
|
2317
|
|
|
|
|
|
|
If the string contains only "shell-safe" ASCII characters |
2318
|
|
|
|
|
|
|
it is returned as-is, without quotes. |
2319
|
|
|
|
|
|
|
|
2320
|
|
|
|
|
|
|
If the argument is a ref but is not an object which stringifies, |
2321
|
|
|
|
|
|
|
then vis() is called and the resulting string quoted. |
2322
|
|
|
|
|
|
|
An undefined value is shown as C<undef> without quotes; |
2323
|
|
|
|
|
|
|
as a special case to avoid ambiguity the string 'undef' is always "quoted". |
2324
|
|
|
|
|
|
|
|
2325
|
|
|
|
|
|
|
=head2 qshpath [$might_have_tilde_prefix] |
2326
|
|
|
|
|
|
|
|
2327
|
|
|
|
|
|
|
Similar to C<qsh> except that an initial ~ or ~username is left |
2328
|
|
|
|
|
|
|
unquoted. Useful with bash or csh. |
2329
|
|
|
|
|
|
|
|
2330
|
|
|
|
|
|
|
=head2 qshlist @items |
2331
|
|
|
|
|
|
|
|
2332
|
|
|
|
|
|
|
Format e.g. a shell command and arguments, quoting when necessary. |
2333
|
|
|
|
|
|
|
|
2334
|
|
|
|
|
|
|
Returns a string with the items separated by spaces. |
2335
|
|
|
|
|
|
|
|
2336
|
|
|
|
|
|
|
=head1 LIMITATIONS |
2337
|
|
|
|
|
|
|
|
2338
|
|
|
|
|
|
|
=over 2 |
2339
|
|
|
|
|
|
|
|
2340
|
|
|
|
|
|
|
=item Interpolated Strings |
2341
|
|
|
|
|
|
|
|
2342
|
|
|
|
|
|
|
C<ivis> and C<dvis> evaluate expressions in the user's context |
2343
|
|
|
|
|
|
|
using Perl's debugger support ('eval' in package DB -- see I<perlfunc>). |
2344
|
|
|
|
|
|
|
This mechanism has some limitations: |
2345
|
|
|
|
|
|
|
|
2346
|
|
|
|
|
|
|
@_ will appear to have the original arguments to a sub even if "shift" |
2347
|
|
|
|
|
|
|
has been executed. However if @_ is entirely replaced, the correct values |
2348
|
|
|
|
|
|
|
will be displayed. |
2349
|
|
|
|
|
|
|
|
2350
|
|
|
|
|
|
|
A lexical ("my") sub creates a closure, and variables in visible scopes |
2351
|
|
|
|
|
|
|
which are not actually referenced by your code may not exist in the closure; |
2352
|
|
|
|
|
|
|
an attempt to display them with C<ivis> will fail. For example: |
2353
|
|
|
|
|
|
|
|
2354
|
|
|
|
|
|
|
our $global; |
2355
|
|
|
|
|
|
|
sub outerfunc { |
2356
|
|
|
|
|
|
|
my sub inner { |
2357
|
|
|
|
|
|
|
say dvis '$global'; # croaks with "Error interpolating '$global'" |
2358
|
|
|
|
|
|
|
# my $x = $global; # ... unless this is un-commented |
2359
|
|
|
|
|
|
|
} |
2360
|
|
|
|
|
|
|
&inner(); |
2361
|
|
|
|
|
|
|
} |
2362
|
|
|
|
|
|
|
&outerfunc; |
2363
|
|
|
|
|
|
|
|
2364
|
|
|
|
|
|
|
|
2365
|
|
|
|
|
|
|
=item Multiply-referenced items |
2366
|
|
|
|
|
|
|
|
2367
|
|
|
|
|
|
|
If a structure contains several refs to the same item, |
2368
|
|
|
|
|
|
|
the first ref will be visualized by showing the referenced item |
2369
|
|
|
|
|
|
|
as you might expect. |
2370
|
|
|
|
|
|
|
|
2371
|
|
|
|
|
|
|
However subsequent refs will look like C<< $VAR1->place >> |
2372
|
|
|
|
|
|
|
where C<place> is the location of the first ref in the overall structure. |
2373
|
|
|
|
|
|
|
This is how Data::Dumper indicates that the ref is a copy of the first |
2374
|
|
|
|
|
|
|
ref and thus points to the same datum. |
2375
|
|
|
|
|
|
|
"$VAR1" is an artifact of how Data::Dumper would generate code |
2376
|
|
|
|
|
|
|
using its "Purity" feature. Data::Dumper::Interp does nothing |
2377
|
|
|
|
|
|
|
special and simply passes through these annotations. |
2378
|
|
|
|
|
|
|
|
2379
|
|
|
|
|
|
|
=item The special "_" stat filehandle may not be preserved |
2380
|
|
|
|
|
|
|
|
2381
|
|
|
|
|
|
|
Data::Dumper::Interp queries the operating |
2382
|
|
|
|
|
|
|
system to obtain the window size to initialize C<$Foldwidth>, if it |
2383
|
|
|
|
|
|
|
is not already defined; this may change the "_" filehandle. |
2384
|
|
|
|
|
|
|
After the first call (or if you pre-set C<$Foldwidth>), |
2385
|
|
|
|
|
|
|
the "_" filehandle will not change across calls. |
2386
|
|
|
|
|
|
|
|
2387
|
|
|
|
|
|
|
=back |
2388
|
|
|
|
|
|
|
|
2389
|
|
|
|
|
|
|
=head1 DIFFERENCES FROM Data::Dumper |
2390
|
|
|
|
|
|
|
|
2391
|
|
|
|
|
|
|
Results differ from plain C<Data::Dumper> output in the following ways |
2392
|
|
|
|
|
|
|
(most substitutions can be disabled via Config options): |
2393
|
|
|
|
|
|
|
|
2394
|
|
|
|
|
|
|
=over 2 |
2395
|
|
|
|
|
|
|
|
2396
|
|
|
|
|
|
|
=item * |
2397
|
|
|
|
|
|
|
|
2398
|
|
|
|
|
|
|
A final newline is I<never> included. |
2399
|
|
|
|
|
|
|
|
2400
|
|
|
|
|
|
|
Everything is shown on a single line if possible, otherwise wrapped to |
2401
|
|
|
|
|
|
|
your terminal width (or C<$Foldwidth>), with indented structure levels. |
2402
|
|
|
|
|
|
|
|
2403
|
|
|
|
|
|
|
=item * |
2404
|
|
|
|
|
|
|
|
2405
|
|
|
|
|
|
|
Printable Unicode characters appear as themselves instead of \x{ABCD}. |
2406
|
|
|
|
|
|
|
|
2407
|
|
|
|
|
|
|
Note: If your data contains 'wide characters', you should |
2408
|
|
|
|
|
|
|
C<< use open IO => ':locale'; >> or otherwise arrange to |
2409
|
|
|
|
|
|
|
encode the output for your terminal. |
2410
|
|
|
|
|
|
|
You'll also want C<< use utf8; >> if your Perl source |
2411
|
|
|
|
|
|
|
contains characters outside the ASCII range. |
2412
|
|
|
|
|
|
|
|
2413
|
|
|
|
|
|
|
Undecoded binary octets (e.g. data read from a 'binmode' file) |
2414
|
|
|
|
|
|
|
will still be escaped as individual bytes. |
2415
|
|
|
|
|
|
|
|
2416
|
|
|
|
|
|
|
=item * |
2417
|
|
|
|
|
|
|
|
2418
|
|
|
|
|
|
|
Depending on options, spaces·may·be·shown·visibly |
2419
|
|
|
|
|
|
|
and '' may be shown for newline (and similarly for other ASCII controls). |
2420
|
|
|
|
|
|
|
|
2421
|
|
|
|
|
|
|
"White space" characters in qr/compiled regex/ are shown as \t, \n etc. |
2422
|
|
|
|
|
|
|
|
2423
|
|
|
|
|
|
|
=item * |
2424
|
|
|
|
|
|
|
|
2425
|
|
|
|
|
|
|
The internals of objects are not shown by default. |
2426
|
|
|
|
|
|
|
|
2427
|
|
|
|
|
|
|
If stringifcation is overloaded it is used to obtain the object's |
2428
|
|
|
|
|
|
|
representation. For example, C<bignum> and C<bigrat> numbers are shown as easily |
2429
|
|
|
|
|
|
|
readable values rather than S<"bless( {...}, 'Math::...')">. |
2430
|
|
|
|
|
|
|
|
2431
|
|
|
|
|
|
|
Stingified objects are prefixed with "(classname)" to make clear what |
2432
|
|
|
|
|
|
|
happened. |
2433
|
|
|
|
|
|
|
|
2434
|
|
|
|
|
|
|
The "virtual" value of objects which overload a dereference operator |
2435
|
|
|
|
|
|
|
(C<@{}> or C<%{}>) is displayed instead of the object's internals. |
2436
|
|
|
|
|
|
|
|
2437
|
|
|
|
|
|
|
=item * |
2438
|
|
|
|
|
|
|
|
2439
|
|
|
|
|
|
|
Hash keys are sorted treating numeric "components" numerically. |
2440
|
|
|
|
|
|
|
For example "A.20" sorts before "A.100". |
2441
|
|
|
|
|
|
|
|
2442
|
|
|
|
|
|
|
=item * |
2443
|
|
|
|
|
|
|
|
2444
|
|
|
|
|
|
|
Punctuation variables such as $@, $!, and $?, are preserved over calls. |
2445
|
|
|
|
|
|
|
|
2446
|
|
|
|
|
|
|
=item * |
2447
|
|
|
|
|
|
|
|
2448
|
|
|
|
|
|
|
Numbers and strings which look like numbers are kept distinct when displayed, |
2449
|
|
|
|
|
|
|
i.e. "0" does not become 0 or vice-versa. Floating-point values are shown |
2450
|
|
|
|
|
|
|
as numbers not 'quoted strings' and similarly for stringified objects. |
2451
|
|
|
|
|
|
|
|
2452
|
|
|
|
|
|
|
Although such differences might be immaterial to Perl during execution, |
2453
|
|
|
|
|
|
|
they may be important when communicating to a human. |
2454
|
|
|
|
|
|
|
|
2455
|
|
|
|
|
|
|
=back |
2456
|
|
|
|
|
|
|
|
2457
|
|
|
|
|
|
|
=head1 SEE ALSO |
2458
|
|
|
|
|
|
|
|
2459
|
|
|
|
|
|
|
Data::Dumper |
2460
|
|
|
|
|
|
|
|
2461
|
|
|
|
|
|
|
=head1 AUTHOR |
2462
|
|
|
|
|
|
|
|
2463
|
|
|
|
|
|
|
Jim Avera (jim.avera AT gmail) |
2464
|
|
|
|
|
|
|
|
2465
|
|
|
|
|
|
|
=head1 LICENSE |
2466
|
|
|
|
|
|
|
|
2467
|
|
|
|
|
|
|
Public Domain or CC0. |
2468
|
|
|
|
|
|
|
|
2469
|
|
|
|
|
|
|
=for nobody Foldwidth1 is currently an undocumented experimental method |
2470
|
|
|
|
|
|
|
=for nobody which sets a different fold width for the first line only. |
2471
|
|
|
|
|
|
|
=for nobody The Debug method is for author's debugging, and not documented. |
2472
|
|
|
|
|
|
|
=for nobody |
2473
|
|
|
|
|
|
|
=for nobody oops and btw btwN are internal debugging functions |
2474
|
|
|
|
|
|
|
|
2475
|
|
|
|
|
|
|
=for Pod::Coverage Foldwidth1 oops btw btwN Debug |
2476
|
|
|
|
|
|
|
|
2477
|
|
|
|
|
|
|
=cut |