| 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 |