line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
# ABSTRACT: Debug::Statements provides an easy way to insert and enable debug statements. |
2
|
|
|
|
|
|
|
package Debug::Statements; |
3
|
1
|
|
|
1
|
|
68954
|
use warnings; |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
36
|
|
4
|
1
|
|
|
1
|
|
4
|
use strict; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
22
|
|
5
|
1
|
|
|
1
|
|
3
|
use Carp; |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
49
|
|
6
|
1
|
|
|
1
|
|
4
|
use Time::HiRes qw(gettimeofday); |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
6
|
|
7
|
1
|
|
|
1
|
|
529
|
use Dumpvalue; |
|
1
|
|
|
|
|
4196
|
|
|
1
|
|
|
|
|
40
|
|
8
|
1
|
|
|
1
|
|
552
|
use Data::Dumper; |
|
1
|
|
|
|
|
5450
|
|
|
1
|
|
|
|
|
57
|
|
9
|
|
|
|
|
|
|
$Data::Dumper::Terse = 1; # eliminate the $VAR1 |
10
|
|
|
|
|
|
|
|
11
|
1
|
|
|
1
|
|
7
|
use Exporter; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
47
|
|
12
|
1
|
|
|
1
|
|
7
|
use base qw( Exporter ); |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
3406
|
|
13
|
|
|
|
|
|
|
our @EXPORT = qw( d d0 d2 d3 D ); |
14
|
|
|
|
|
|
|
our @EXPORT_OK = qw( d d0 d1 d2 d3 ls D ); |
15
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
my $VERSION = '1.005'; |
17
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
my $printdebug = "DEBUG: "; # print statement begins with this |
19
|
|
|
|
|
|
|
my $id = 0; # for debugging this module, turn on with d('', 10) |
20
|
|
|
|
|
|
|
my $flag = '$d'; # choose another variable besides '$d' |
21
|
|
|
|
|
|
|
my $disable = 0; # disable all functionality (for performance) |
22
|
1
|
|
|
1
|
|
427
|
if ( not eval "use PadWalker; 1" ) { ## no critic |
|
1
|
|
|
|
|
522
|
|
|
1
|
|
|
|
|
28
|
|
23
|
|
|
|
|
|
|
$disable = 1; |
24
|
|
|
|
|
|
|
print "Did not find PadWalker so disabling Debug::Statements - d()\n"; |
25
|
|
|
|
|
|
|
print " Please install PadWalker from CPAN\n"; |
26
|
|
|
|
|
|
|
eval 'sub d {}; sub d0 {}; sub d1 {} ; sub d2 {} ; sub d3 {} ; sub D {} ; sub ls {}'; ## no critic |
27
|
|
|
|
|
|
|
} |
28
|
|
|
|
|
|
|
my $truncateLines = 10; |
29
|
|
|
|
|
|
|
my $globalPrintCounter = 0; |
30
|
|
|
|
|
|
|
my $evalcounter = 0; |
31
|
|
|
|
|
|
|
my %globalOpt; |
32
|
|
|
|
|
|
|
$globalOpt{printSub} = 1; # print name of subroutine 'b' |
33
|
|
|
|
|
|
|
#$globalOpt{compress} = 1; # compress array and hash 'z' |
34
|
|
|
|
|
|
|
my $optionsTable = { |
35
|
|
|
|
|
|
|
'b' => 'printSub', |
36
|
|
|
|
|
|
|
'c' => 'Chomp', |
37
|
|
|
|
|
|
|
'e' => 'Elements', |
38
|
|
|
|
|
|
|
'n' => 'LineNumber', |
39
|
|
|
|
|
|
|
'q' => 'text', |
40
|
|
|
|
|
|
|
'r' => 'tRuncate', |
41
|
|
|
|
|
|
|
's' => 'Sort', |
42
|
|
|
|
|
|
|
't' => 'Timestamp', |
43
|
|
|
|
|
|
|
'x' => 'die', |
44
|
|
|
|
|
|
|
'z' => 'compress' |
45
|
|
|
|
|
|
|
}; |
46
|
|
|
|
|
|
|
|
47
|
|
|
|
|
|
|
sub disable { |
48
|
1
|
|
|
1
|
1
|
775
|
$disable = 1; |
49
|
1
|
|
|
|
|
2
|
return; |
50
|
|
|
|
|
|
|
} |
51
|
|
|
|
|
|
|
|
52
|
|
|
|
|
|
|
sub enable { |
53
|
1
|
|
|
1
|
0
|
646
|
$disable = 0; |
54
|
1
|
|
|
|
|
3
|
return; |
55
|
|
|
|
|
|
|
} |
56
|
|
|
|
|
|
|
|
57
|
|
|
|
|
|
|
sub setPrintDebug { |
58
|
5
|
|
|
5
|
0
|
2435
|
$printdebug = shift; |
59
|
5
|
|
|
|
|
8
|
return; |
60
|
|
|
|
|
|
|
} |
61
|
|
|
|
|
|
|
|
62
|
|
|
|
|
|
|
sub setFlag { |
63
|
2
|
|
|
2
|
0
|
1266
|
$flag = shift; |
64
|
2
|
|
|
|
|
4
|
return; |
65
|
|
|
|
|
|
|
} |
66
|
|
|
|
|
|
|
|
67
|
|
|
|
|
|
|
sub setTruncate { |
68
|
2
|
|
|
2
|
0
|
1282
|
$truncateLines = shift; |
69
|
2
|
|
|
|
|
4
|
return; |
70
|
|
|
|
|
|
|
} |
71
|
|
|
|
|
|
|
|
72
|
|
|
|
|
|
|
sub d { |
73
|
185
|
|
|
185
|
1
|
230595
|
my ( $var, $options ) = @_; |
74
|
185
|
100
|
|
|
|
451
|
return if $disable; |
75
|
182
|
100
|
|
|
|
369
|
$options = "" if !$options; |
76
|
182
|
|
50
|
|
|
968
|
my $caller = ( caller(1) )[3] || ""; |
77
|
182
|
|
|
|
|
464
|
dx( $caller, $var, "$options" ); |
78
|
181
|
|
|
|
|
668
|
return; |
79
|
|
|
|
|
|
|
} |
80
|
|
|
|
|
|
|
|
81
|
|
|
|
|
|
|
sub d0 { |
82
|
8
|
|
|
8
|
0
|
8793
|
my ( $var, $options ) = @_; |
83
|
8
|
50
|
|
|
|
20
|
return if $disable; |
84
|
8
|
50
|
|
|
|
16
|
$options = "" if !$options; |
85
|
8
|
|
50
|
|
|
35
|
my $caller = ( caller(1) )[3] || ""; |
86
|
8
|
|
|
|
|
24
|
dx( $caller, $var, "0$options" ); |
87
|
8
|
|
|
|
|
28
|
return; |
88
|
|
|
|
|
|
|
} |
89
|
|
|
|
|
|
|
|
90
|
|
|
|
|
|
|
sub D { |
91
|
|
|
|
|
|
|
# same as d0 |
92
|
5
|
|
|
5
|
0
|
5444
|
my ( $var, $options ) = @_; |
93
|
5
|
50
|
|
|
|
14
|
return if $disable; |
94
|
5
|
50
|
|
|
|
11
|
$options = "" if !$options; |
95
|
5
|
|
50
|
|
|
20
|
my $caller = ( caller(1) )[3] || ""; |
96
|
5
|
|
|
|
|
16
|
dx( $caller, $var, "0$options" ); |
97
|
5
|
|
|
|
|
18
|
return; |
98
|
|
|
|
|
|
|
} |
99
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
sub d1 { |
101
|
4
|
|
|
4
|
0
|
5042
|
my ( $var, $options ) = @_; |
102
|
4
|
50
|
|
|
|
13
|
return if $disable; |
103
|
4
|
50
|
|
|
|
15
|
$options = "" if !$options; |
104
|
4
|
|
50
|
|
|
21
|
my $caller = ( caller(1) )[3] || ""; |
105
|
4
|
|
|
|
|
14
|
dx( $caller, $var, "1$options" ); |
106
|
4
|
|
|
|
|
17
|
return; |
107
|
|
|
|
|
|
|
} |
108
|
|
|
|
|
|
|
|
109
|
|
|
|
|
|
|
sub d2 { |
110
|
6
|
|
|
6
|
0
|
6863
|
my ( $var, $options ) = @_; |
111
|
6
|
50
|
|
|
|
16
|
return if $disable; |
112
|
6
|
50
|
|
|
|
17
|
$options = "" if !$options; |
113
|
6
|
|
50
|
|
|
28
|
my $caller = ( caller(1) )[3] || ""; |
114
|
6
|
|
|
|
|
17
|
dx( $caller, $var, "2$options" ); |
115
|
6
|
|
|
|
|
22
|
return; |
116
|
|
|
|
|
|
|
} |
117
|
|
|
|
|
|
|
|
118
|
|
|
|
|
|
|
sub d3 { |
119
|
3
|
|
|
3
|
0
|
3291
|
my ( $var, $options ) = @_; |
120
|
3
|
50
|
|
|
|
8
|
return if $disable; |
121
|
3
|
50
|
|
|
|
8
|
$options = "" if !$options; |
122
|
3
|
|
50
|
|
|
13
|
my $caller = ( caller(1) )[3] || ""; |
123
|
3
|
|
|
|
|
9
|
dx( $caller, $var, "3$options" ); |
124
|
3
|
|
|
|
|
11
|
return; |
125
|
|
|
|
|
|
|
} |
126
|
|
|
|
|
|
|
|
127
|
|
|
|
|
|
|
sub checkLevel { |
128
|
|
|
|
|
|
|
# Return if debug level is not high enough |
129
|
211
|
|
|
211
|
0
|
208
|
my ( $h, $level ) = @_; |
130
|
211
|
50
|
|
|
|
306
|
if ($id) { print "sub checkLevel()\n" } |
|
0
|
|
|
|
|
0
|
|
131
|
211
|
50
|
|
|
|
290
|
if ($id) { print "\n\ninternaldebug checkLevel: Dumping \$h:\n"; Dumpvalue->new->dumpValue($h) } |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
132
|
|
|
|
|
|
|
|
133
|
211
|
|
|
|
|
220
|
my $D; |
134
|
211
|
50
|
|
|
|
357
|
if ($id) { print "internaldebug checkLevel: \$flag = '$flag'\n" } |
|
0
|
|
|
|
|
0
|
|
135
|
211
|
50
|
|
|
|
441
|
if ( $flag =~ /\S+::\S+/ ) { ## problems here |
136
|
0
|
0
|
|
|
|
0
|
if ($id) { print "internaldebug checkLevel: \$D is controlled by package variable $flag\n" } |
|
0
|
|
|
|
|
0
|
|
137
|
0
|
0
|
|
|
|
0
|
if ( !defined $flag ) { |
138
|
0
|
0
|
|
|
|
0
|
if ($id) { print "internaldebug checkLevel: \$flag is not defined\n" } |
|
0
|
|
|
|
|
0
|
|
139
|
0
|
|
|
|
|
0
|
$D = 0; |
140
|
|
|
|
|
|
|
} else { |
141
|
0
|
|
|
|
|
0
|
$D = evlwrapper( $h, $flag, 'checkLevel $flag' ); |
142
|
|
|
|
|
|
|
} |
143
|
|
|
|
|
|
|
} else { |
144
|
211
|
50
|
|
|
|
436
|
if ( !defined $h->{$flag} ) { |
|
211
|
100
|
|
|
|
371
|
|
145
|
0
|
0
|
|
|
|
0
|
if ($id) { print "internaldebug checkLevel: \$h->{$flag} is not defined\n" } |
|
0
|
|
|
|
|
0
|
|
146
|
0
|
|
|
|
|
0
|
$D = 0; |
147
|
|
|
|
|
|
|
} elsif ( !defined ${ $h->{$flag} } ) { |
148
|
12
|
50
|
|
|
|
19
|
if ($id) { print "internaldebug checkLevel: \$h->{$flag} is defined but \${\$h->{$flag}} is not defined\n" } |
|
0
|
|
|
|
|
0
|
|
149
|
12
|
|
|
|
|
12
|
$D = 0; |
150
|
|
|
|
|
|
|
} else { |
151
|
|
|
|
|
|
|
# This is the expected case |
152
|
199
|
|
|
|
|
162
|
$D = ${ $h->{$flag} }; |
|
199
|
|
|
|
|
269
|
|
153
|
|
|
|
|
|
|
} |
154
|
|
|
|
|
|
|
} |
155
|
211
|
50
|
|
|
|
445
|
if ( !defined $D ) { |
156
|
0
|
0
|
|
|
|
0
|
if ($id) { print "internaldebug checkLevel: \$D is undef\n" } |
|
0
|
|
|
|
|
0
|
|
157
|
0
|
|
|
|
|
0
|
$D = 0; |
158
|
|
|
|
|
|
|
} |
159
|
|
|
|
|
|
|
|
160
|
211
|
50
|
|
|
|
327
|
if ($id) { print "internaldebug checkLevel: \$D = '$D'\n" } |
|
0
|
|
|
|
|
0
|
|
161
|
|
|
|
|
|
|
|
162
|
|
|
|
|
|
|
# If $d is negative, turn on $id (internal debug flag), and use the absolute value of $d |
163
|
211
|
50
|
|
|
|
286
|
if ( $D < 0 ) { |
164
|
0
|
0
|
|
|
|
0
|
if ( !$id ) { print "internaldebug checkLevel: Turning on \$id with negative value\n" } |
|
0
|
|
|
|
|
0
|
|
165
|
0
|
|
|
|
|
0
|
$D = abs($D); |
166
|
0
|
|
|
|
|
0
|
$id = 1; |
167
|
|
|
|
|
|
|
} else { |
168
|
211
|
50
|
|
|
|
284
|
if ($id) { print "internaldebug checkLevel: Turning off \$id with positive value\n" } |
|
0
|
|
|
|
|
0
|
|
169
|
211
|
|
|
|
|
176
|
$id = 0; |
170
|
|
|
|
|
|
|
} |
171
|
|
|
|
|
|
|
|
172
|
211
|
100
|
|
|
|
342
|
if ( $D >= $level ) { |
173
|
192
|
|
|
|
|
459
|
return 1; |
174
|
|
|
|
|
|
|
} else { |
175
|
19
|
50
|
|
|
|
42
|
if ($id) { print "internaldebug checkLevel: Returning because \$D < \$level\n" } |
|
0
|
|
|
|
|
0
|
|
176
|
19
|
|
|
|
|
148
|
return 0; |
177
|
|
|
|
|
|
|
} |
178
|
|
|
|
|
|
|
} |
179
|
|
|
|
|
|
|
|
180
|
|
|
|
|
|
|
sub dx { |
181
|
208
|
|
|
208
|
0
|
270
|
my ( $caller, $vars, $options ) = @_; |
182
|
|
|
|
|
|
|
|
183
|
208
|
50
|
|
|
|
328
|
if ($id) { print "\n\n\n\n\n\n\n\n--------------- sub dx() ---------------\n" } |
|
0
|
|
|
|
|
0
|
|
184
|
208
|
50
|
|
|
|
285
|
if ($id) { print "internaldebug: \@_ = '@_'\n" } |
|
0
|
|
|
|
|
0
|
|
185
|
|
|
|
|
|
|
|
186
|
208
|
|
|
|
|
4369
|
my $h = PadWalker::peek_my(2); |
187
|
208
|
50
|
|
|
|
341
|
if ($id) { print "\n\ninternaldebug: Dumping \$h:\n"; Dumpvalue->new->dumpValue($h) } |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
188
|
|
|
|
|
|
|
|
189
|
|
|
|
|
|
|
# Parse options |
190
|
208
|
|
|
|
|
524
|
my %opt = %globalOpt; |
191
|
208
|
|
|
|
|
350
|
$opt{level} = 1; |
192
|
208
|
50
|
|
|
|
328
|
if ($id) { print "internaldebug: \$options = '$options'\n" } |
|
0
|
|
|
|
|
0
|
|
193
|
208
|
|
|
|
|
544
|
for my $o ( split //, $options ) { |
194
|
85
|
100
|
|
|
|
382
|
if ( $o =~ /([0-9])/ ) { |
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
195
|
40
|
|
|
|
|
131
|
$opt{level} = $1; |
196
|
|
|
|
|
|
|
} elsif ( $o =~ /[bcenqrstxz]/ ) { |
197
|
20
|
|
|
|
|
56
|
$opt{ $optionsTable->{$o} } = 1; |
198
|
|
|
|
|
|
|
} elsif ( $o =~ /[BCENQRSTXZ]/ ) { |
199
|
8
|
|
|
|
|
20
|
$opt{ $optionsTable->{ lc($o) } } = 0; |
200
|
|
|
|
|
|
|
} elsif ( $o eq '*' ) { |
201
|
17
|
|
|
|
|
62
|
%globalOpt = %opt; |
202
|
|
|
|
|
|
|
} else { |
203
|
0
|
|
|
|
|
0
|
print "WARNING: Debug::Statements::d('variable', 'options) does not understand your option '$o'\n"; |
204
|
|
|
|
|
|
|
} |
205
|
|
|
|
|
|
|
} |
206
|
208
|
50
|
|
|
|
343
|
if ($id) { print "\n\ninternaldebug: Dumping \%opt:\n"; Dumpvalue->new->dumpValue( \%opt ) } |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
207
|
208
|
50
|
|
|
|
282
|
if ($id) { print "\n\ninternaldebug: Dumping \%globalOpt:\n"; Dumpvalue->new->dumpValue( \%globalOpt ) } |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
208
|
|
|
|
|
|
|
|
209
|
208
|
100
|
|
|
|
359
|
return if not checkLevel( $h, $opt{level} ); |
210
|
|
|
|
|
|
|
|
211
|
189
|
100
|
|
|
|
290
|
if ( !$globalPrintCounter ) { |
212
|
1
|
|
|
|
|
35
|
print "DEBUG: Debug::Statements::d() is printing debug statements\n"; |
213
|
1
|
50
|
|
|
|
8
|
my $windows = ($^O =~ /Win/) ? 1 : 0; |
214
|
1
|
|
|
|
|
1
|
my $originalCmdLine; |
215
|
1
|
50
|
|
|
|
3
|
if ($windows) { |
216
|
|
|
|
|
|
|
# Don't know how to do this on Windows |
217
|
|
|
|
|
|
|
} else { |
218
|
1
|
|
|
|
|
5525
|
$originalCmdLine = qx/ps -o args $$/; |
219
|
1
|
|
|
|
|
22
|
$originalCmdLine =~ s/COMMAND\n//; |
220
|
1
|
|
|
|
|
6
|
chomp($originalCmdLine); |
221
|
1
|
|
|
|
|
28
|
print "DEBUG: The debugged script was run as $originalCmdLine\n"; |
222
|
|
|
|
|
|
|
} |
223
|
|
|
|
|
|
|
} |
224
|
|
|
|
|
|
|
|
225
|
189
|
|
|
|
|
190
|
$globalPrintCounter++; |
226
|
|
|
|
|
|
|
|
227
|
189
|
50
|
|
|
|
312
|
if ($id) { print "internaldebug: \$caller = '$caller'\n" } |
|
0
|
|
|
|
|
0
|
|
228
|
|
|
|
|
|
|
|
229
|
189
|
|
|
|
|
128
|
if ( 0 == 1 ) { dumperTests($h) } |
230
|
|
|
|
|
|
|
|
231
|
189
|
50
|
|
|
|
309
|
if ( !defined $vars ) { |
232
|
0
|
|
|
|
|
0
|
print "WARNING: Debug::Statements::d() was given a bare reference to an undefined variable instead of a single-quoted string\n"; |
233
|
0
|
|
|
|
|
0
|
return; |
234
|
|
|
|
|
|
|
} |
235
|
|
|
|
|
|
|
|
236
|
|
|
|
|
|
|
# Remove parens at beginning/end of $vars |
237
|
189
|
50
|
|
|
|
263
|
if ($id) { print "\ninternaldebug: \$vars = '$vars'\n" } |
|
0
|
|
|
|
|
0
|
|
238
|
189
|
|
|
|
|
231
|
my $ovars = $vars; |
239
|
189
|
|
|
|
|
271
|
$vars =~ s/^\(//; |
240
|
189
|
|
|
|
|
210
|
$vars =~ s/\)$//; |
241
|
189
|
50
|
|
|
|
286
|
if ($id) { print "internaldebug: \$vars = '$vars'\n" } |
|
0
|
|
|
|
|
0
|
|
242
|
|
|
|
|
|
|
|
243
|
|
|
|
|
|
|
# Strip out prefix and suffix - d('\n$scalarvar @array\n\n') |
244
|
189
|
|
|
|
|
202
|
my ( $prefix, $suffix ) = ( "", "" ); |
245
|
189
|
100
|
|
|
|
683
|
if ( $vars =~ s/^([^\$\@\%]+)(.*)/$2/ ) { |
246
|
12
|
|
|
|
|
25
|
$prefix = $1; |
247
|
|
|
|
|
|
|
} |
248
|
189
|
100
|
|
|
|
1033
|
if ( $vars =~ s/(.*[\$\@\%][^\s\\]+)(.*)$/$1/ ) { # avoid spaces and \n |
249
|
182
|
|
|
|
|
249
|
$suffix = $2; |
250
|
|
|
|
|
|
|
} |
251
|
189
|
50
|
|
|
|
328
|
if ($id) { print "internaldebug: \$prefix = '$prefix'\n" } |
|
0
|
|
|
|
|
0
|
|
252
|
189
|
50
|
|
|
|
264
|
if ($id) { print "internaldebug: \$vars = '$vars'\n" } |
|
0
|
|
|
|
|
0
|
|
253
|
189
|
50
|
|
|
|
276
|
if ($id) { print "internaldebug: \$suffix = '$suffix'\n" } |
|
0
|
|
|
|
|
0
|
|
254
|
|
|
|
|
|
|
# Recover from problem while stripping prefix???? Try removing this |
255
|
189
|
|
|
|
|
437
|
while ( $prefix =~ s/([\$\@\%]\S+)\s*$// ) { |
256
|
0
|
|
|
|
|
0
|
$vars = "$1 $vars"; |
257
|
|
|
|
|
|
|
} |
258
|
189
|
50
|
|
|
|
301
|
if ($id) { print "internaldebug: \$prefix = '$prefix'\n" } |
|
0
|
|
|
|
|
0
|
|
259
|
189
|
50
|
|
|
|
257
|
if ($id) { print "internaldebug: \$vars = '$vars'\n" } |
|
0
|
|
|
|
|
0
|
|
260
|
|
|
|
|
|
|
|
261
|
|
|
|
|
|
|
# Convert \n to newline |
262
|
|
|
|
|
|
|
#eval("\$prefix = \"$prefix\""); # too dangerous |
263
|
|
|
|
|
|
|
#eval("\$suffix = \"$suffix\""); |
264
|
189
|
|
|
|
|
293
|
$prefix = expandEscapes($prefix); |
265
|
189
|
|
|
|
|
210
|
$prefix =~ s/[ \t]+$//; |
266
|
189
|
|
|
|
|
202
|
$suffix = expandEscapes($suffix); |
267
|
189
|
50
|
|
|
|
306
|
if ($id) { print "internaldebug: \$prefix = '$prefix'\n" } |
|
0
|
|
|
|
|
0
|
|
268
|
189
|
50
|
|
|
|
251
|
if ($id) { print "internaldebug: \$suffix = '$suffix'\n" } |
|
0
|
|
|
|
|
0
|
|
269
|
|
|
|
|
|
|
|
270
|
|
|
|
|
|
|
# Print each $var |
271
|
189
|
|
|
|
|
539
|
my @vars = split /[, ]+/, $vars; |
272
|
189
|
50
|
|
|
|
272
|
if ($id) { print "internaldebug: \@vars = '@vars'\n" } |
|
0
|
|
|
|
|
0
|
|
273
|
189
|
100
|
100
|
|
|
748
|
if ( @vars and not $opt{text} ) { |
274
|
181
|
50
|
|
|
|
285
|
if ($id) { print "internaldebug: Iterating through vars\n" } |
|
0
|
|
|
|
|
0
|
|
275
|
181
|
|
|
|
|
346
|
for my $i ( 0 .. $#vars ) { |
276
|
|
|
|
|
|
|
# Print prefix only on 1st var, print suffix only on last var |
277
|
193
|
100
|
|
|
|
322
|
my $p = $i == 0 ? $prefix : ""; |
278
|
193
|
50
|
|
|
|
281
|
if ($id) { print "internaldebug: \$p = '$p'\n" } |
|
0
|
|
|
|
|
0
|
|
279
|
193
|
100
|
|
|
|
321
|
my $s = $i == $#vars ? $suffix : ""; |
280
|
193
|
50
|
|
|
|
271
|
if ($id) { print "internaldebug: \$s = '$s'\n" } |
|
0
|
|
|
|
|
0
|
|
281
|
|
|
|
|
|
|
#chomp($vars[$i]); |
282
|
193
|
50
|
|
|
|
283
|
if ($id) { print "internaldebug: \$vars[$i] = '$vars[$i]'\n" } |
|
0
|
|
|
|
|
0
|
|
283
|
193
|
|
|
|
|
391
|
my $dump = dumpvar( $h, $caller, $vars[$i], \%opt ); |
284
|
193
|
50
|
33
|
|
|
370
|
if ( $id and defined $dump ) { print "internaldebug: \$dump = '$dump'\n" } |
|
0
|
|
|
|
|
0
|
|
285
|
193
|
100
|
|
|
|
654
|
printdebugsub( $caller, $opt{level}, $vars[$i], $dump, $p, $s, \%opt ) if defined $dump; |
286
|
|
|
|
|
|
|
} |
287
|
|
|
|
|
|
|
} else { |
288
|
8
|
50
|
|
|
|
20
|
if ($id) { print "internaldebug: Just printing everything as text\n" } |
|
0
|
|
|
|
|
0
|
|
289
|
|
|
|
|
|
|
# No variables, just a print |
290
|
|
|
|
|
|
|
# SCALAR(0x6484b8) |
291
|
8
|
50
|
|
|
|
25
|
if ( $prefix =~ /^(SCALAR|ARRAY|HASH|REF|CODE|GLOB)\(0x/ ) { |
292
|
0
|
|
|
|
|
0
|
print "WARNING: Debug::Statements::d() was given a reference to a variable instead of a single-quoted string\n"; |
293
|
0
|
|
|
|
|
0
|
return; |
294
|
|
|
|
|
|
|
} |
295
|
|
|
|
|
|
|
#printdebugsub($caller, $opt{level}, "", "", $prefix, $suffix, \%opt); #07/12/13 |
296
|
8
|
|
|
|
|
30
|
printdebugsub( $caller, $opt{level}, "", "", "", $ovars, \%opt ); |
297
|
|
|
|
|
|
|
} |
298
|
188
|
|
|
|
|
1334
|
return; |
299
|
|
|
|
|
|
|
} |
300
|
|
|
|
|
|
|
|
301
|
|
|
|
|
|
|
# Find value of each variable (and checking for special vars) |
302
|
|
|
|
|
|
|
sub dumpvar { |
303
|
193
|
|
|
193
|
0
|
252
|
my ( $h, $caller, $var, $opt ) = @_; |
304
|
193
|
50
|
|
|
|
286
|
if ($id) { print "sub dumpvar()\n" } |
|
0
|
|
|
|
|
0
|
|
305
|
|
|
|
|
|
|
|
306
|
|
|
|
|
|
|
# Convert ${var} to ${var} |
307
|
193
|
50
|
|
|
|
264
|
if ($id) { print "internaldebug dumpvar: \$vvar = '$var'\n" } |
|
0
|
|
|
|
|
0
|
|
308
|
193
|
|
|
|
|
274
|
$var =~ s/^([\$\@\%]){(\S+)}$/$1$2/; |
309
|
193
|
50
|
|
|
|
256
|
if ($id) { print "internaldebug dumpvar: \$vvar = '$var'\n" } |
|
0
|
|
|
|
|
0
|
|
310
|
|
|
|
|
|
|
|
311
|
|
|
|
|
|
|
# Convert $h->{'$listvar[0]'} to $h->{'@listvar'}[0] |
312
|
|
|
|
|
|
|
# Convert $h->{'$hashvar{one}'} to $h->{'%hashvar'}{one} |
313
|
|
|
|
|
|
|
# Convert $h->{'$listref->[1]'} to ${$h->{'$listref'}}->[1] |
314
|
|
|
|
|
|
|
# Convert $h->{'$hashref->{one}'} to ${$h->{'$hashref'}}->{'one'} |
315
|
|
|
|
|
|
|
|
316
|
193
|
|
|
|
|
503
|
my $sigil = ( split //, $var )[0]; |
317
|
193
|
50
|
|
|
|
354
|
if ($id) { print "internaldebug dumpvar: \$sigil = '$sigil'\n" } |
|
0
|
|
|
|
|
0
|
|
318
|
193
|
|
|
|
|
172
|
my $newsigil = $sigil; |
319
|
193
|
|
|
|
|
148
|
my $reference; |
320
|
|
|
|
|
|
|
|
321
|
|
|
|
|
|
|
# Ugly way to handle these: $hash{$key} and $hash{$key}{$key2} |
322
|
|
|
|
|
|
|
# Will not work for more complicated cases like $hash{$hash2{$key}} |
323
|
193
|
|
|
|
|
445
|
while ( $var =~ /^(\$.*)(\$[a-zA-Z_]\w*)(.*)$/ ) { |
324
|
2
|
|
|
|
|
7
|
my ( $pre, $internalvar, $post ) = ( $1, $2, $3 ); |
325
|
2
|
50
|
|
|
|
4
|
if ($id) { print "internaldebug dumpvar: \$internalvar = $internalvar\n" } |
|
0
|
|
|
|
|
0
|
|
326
|
2
|
|
|
|
|
5
|
my $e = "\$h->{'$internalvar'}"; |
327
|
2
|
50
|
|
|
|
12
|
if ($id) { print "internaldebug dumpvar: \$e = $e\n" } |
|
0
|
|
|
|
|
0
|
|
328
|
2
|
|
|
|
|
4
|
my $reference = evlwrapper( $h, $e, 'dumpvar $hash{$key}' ); |
329
|
2
|
50
|
|
|
|
9
|
if ($id) { print "internaldebug dumpvar: \$reference = $reference\n" } |
|
0
|
|
|
|
|
0
|
|
330
|
|
|
|
|
|
|
#my $dump = cleanDump( $reference, undef ); |
331
|
2
|
|
|
|
|
5
|
my $dump = Dumper($reference); |
332
|
2
|
|
|
|
|
86
|
$dump =~ s/^\\//; |
333
|
2
|
|
|
|
|
4
|
chomp $dump; |
334
|
2
|
50
|
|
|
|
4
|
if ($id) { print "internaldebug dumpvar: \$dump = '$dump'\n" } |
|
0
|
|
|
|
|
0
|
|
335
|
2
|
|
|
|
|
6
|
$var = $pre . $dump . $post; |
336
|
2
|
50
|
|
|
|
8
|
if ($id) { print "internaldebug dumpvar: \$var = '$var'\n" } |
|
0
|
|
|
|
|
0
|
|
337
|
|
|
|
|
|
|
} |
338
|
|
|
|
|
|
|
|
339
|
|
|
|
|
|
|
# sig varbase open elem close |
340
|
193
|
100
|
|
|
|
536
|
if ( $var =~ /^(\$)([^\[\{\]\}]+)([\[\{])(\S+)([\]\}])$/ ) { |
341
|
|
|
|
|
|
|
# array or hash element starting with $ |
342
|
31
|
|
|
|
|
124
|
my ( $sigil, $varbase, $opened, $element, $closed ) = ( $1, $2, $3, $4, $5 ); |
343
|
31
|
50
|
|
|
|
63
|
if ($id) { print "internaldebug dumpvar: (\$sigil, \$varbase, \$opened, \$element, \$closed) = ($sigil, $varbase, $opened, $element, $closed)\n" } |
|
0
|
|
|
|
|
0
|
|
344
|
|
|
|
|
|
|
|
345
|
31
|
50
|
|
|
|
52
|
if ($id) { print "internaldebug: \$varbase = $varbase\n" } |
|
0
|
|
|
|
|
0
|
|
346
|
|
|
|
|
|
|
|
347
|
31
|
100
|
66
|
|
|
154
|
if ( $opened eq '[' and $closed eq ']' ) { |
|
|
50
|
33
|
|
|
|
|
348
|
14
|
50
|
|
|
|
25
|
if ($id) { print "internaldebug: Found array\n" } |
|
0
|
|
|
|
|
0
|
|
349
|
|
|
|
|
|
|
#$reference = $h->{'@'.$varbase}[$element]; |
350
|
|
|
|
|
|
|
#my $e = "\$h->{'\@'.\"$varbase\"}[$element]"; |
351
|
|
|
|
|
|
|
#if ($id) { print "internaldebug: \$e = $e\n" } |
352
|
|
|
|
|
|
|
#$reference = eval($e); |
353
|
14
|
100
|
|
|
|
50
|
if ( $element =~ /:/ ) { |
|
|
100
|
|
|
|
|
|
354
|
1
|
|
|
|
|
35
|
print "DEBUG sub $caller: d() cannot be used on an array slice! Found $var\n"; |
355
|
1
|
|
|
|
|
6
|
return; |
356
|
|
|
|
|
|
|
} elsif ( $element =~ /[^-\d\[\]]/ ) { |
357
|
1
|
|
|
|
|
35
|
print "DEBUG sub $caller: d() cannot be used on an array element with non-digits! Found $var\n"; |
358
|
1
|
|
|
|
|
5
|
return; |
359
|
|
|
|
|
|
|
} else { |
360
|
12
|
|
|
|
|
17
|
$newsigil = '@'; |
361
|
|
|
|
|
|
|
} |
362
|
|
|
|
|
|
|
} elsif ( $opened eq '{' and $closed eq '}' ) { |
363
|
17
|
50
|
|
|
|
28
|
if ($id) { print "internaldebug dumpvar: Found hash\n" } |
|
0
|
|
|
|
|
0
|
|
364
|
17
|
|
|
|
|
24
|
$element =~ s/"//g; |
365
|
|
|
|
|
|
|
#$reference = $h->{'%'.$varbase}{$element}; |
366
|
|
|
|
|
|
|
#my $e = "\$h->{'\%'.\"$varbase\"}{$element}"; |
367
|
|
|
|
|
|
|
#if ($id) { print "internaldebug: \$e = $e\n" } |
368
|
|
|
|
|
|
|
#$reference = eval($e); |
369
|
17
|
|
|
|
|
20
|
$newsigil = '%'; |
370
|
|
|
|
|
|
|
} else { |
371
|
0
|
|
|
|
|
0
|
print "DEBUG sub $caller: WARNING: Debug::Statements::d() did not understand opening/closing brackets $opened and $closed on $var\n"; |
372
|
0
|
|
|
|
|
0
|
return; |
373
|
|
|
|
|
|
|
} |
374
|
29
|
50
|
|
|
|
50
|
if ($id) { print "internaldebug dumpvar: \$newsigil = '$newsigil'\n" } |
|
0
|
|
|
|
|
0
|
|
375
|
29
|
|
|
|
|
24
|
my $e; |
376
|
|
|
|
|
|
|
|
377
|
29
|
100
|
|
|
|
70
|
if ( $varbase =~ s/->// ) { |
378
|
|
|
|
|
|
|
# ${$h->{'$listref'}}->[1] |
379
|
|
|
|
|
|
|
# ${$h->{'$hashref'}}->{'one'} |
380
|
13
|
|
|
|
|
32
|
$e = "\${\$h->{'\$$varbase'}}->$opened$element$closed"; |
381
|
13
|
50
|
|
|
|
21
|
if ($id) { print "internaldebug dumpvar: \$e = $e\n" } |
|
0
|
|
|
|
|
0
|
|
382
|
|
|
|
|
|
|
} else { |
383
|
|
|
|
|
|
|
#internaldebug: $e = $h->{'@listvar'}[10] |
384
|
|
|
|
|
|
|
#internaldebug: $e = $h->{'%hashvar'}{ten} |
385
|
|
|
|
|
|
|
#internaldebug: $e = $h->{'@listvar'}[0] |
386
|
|
|
|
|
|
|
#internaldebug: $e = $h->{'@nestedlist'}[1] |
387
|
|
|
|
|
|
|
#internaldebug: $e = $h->{'@nestedlist'}[1][1] |
388
|
|
|
|
|
|
|
#internaldebug: $e = $h->{'%hashvar'}{one} |
389
|
|
|
|
|
|
|
#internaldebug: $e = $h->{'%hashvar'}{one} |
390
|
|
|
|
|
|
|
#internaldebug: $e = $h->{'%nestedhash'}{flintstones} |
391
|
|
|
|
|
|
|
#internaldebug: $e = $h->{'%nestedhash'}{flintstones}{pal |
392
|
16
|
|
|
|
|
40
|
$e = "\$h->{'$newsigil$varbase'}$opened$element$closed"; |
393
|
|
|
|
|
|
|
} |
394
|
|
|
|
|
|
|
|
395
|
29
|
50
|
|
|
|
46
|
if ($id) { print "internaldebug dumpvar: \$e = $e\n" } |
|
0
|
|
|
|
|
0
|
|
396
|
29
|
|
|
|
|
55
|
$reference = evlwrapper( $h, $e, 'dumpvar $e' ); |
397
|
|
|
|
|
|
|
|
398
|
|
|
|
|
|
|
} else { |
399
|
|
|
|
|
|
|
# $_ @_ $1 $& |
400
|
162
|
100
|
100
|
|
|
1701
|
if ( $var =~ /^(\$_|\@_|\$[1-9]\d*|\$\&)$/ ) { |
|
|
100
|
66
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
401
|
4
|
|
|
|
|
11
|
( my $var2 = $var ) =~ s/^([\$\@\%])//; |
402
|
|
|
|
|
|
|
#my $sigil = $1; |
403
|
4
|
|
|
|
|
104
|
print "DEBUG sub $caller: WARNING: Debug::Statements::d() does not support Special variables such as $var\n"; |
404
|
4
|
|
|
|
|
54
|
print "DEBUG sub $caller: Use double-quotes as a workaround: d(\"$var2 = $var\")\n"; |
405
|
4
|
|
|
|
|
10
|
return; |
406
|
|
|
|
|
|
|
} |
407
|
|
|
|
|
|
|
# Special variables |
408
|
|
|
|
|
|
|
# Package variables |
409
|
|
|
|
|
|
|
elsif (( $var =~ /^(\$0|\$\$|\$\?|\$\.|\@ARGV|\$LIST_SEPARATOR|\$PROCESS_ID|\$PID|\$PROGRAM_NAME|\$REAL_GROUP_ID|\$GID|\$EFFECTIVE_GROUP_ID|\$EGID\|\$REAL_USER_ID|\$UID|\$EFFECTIVE_USER_ID|\$EID|\$SUBSCRIPT_SEPARATOR|\$SUBSEP|\%ENV|\@INC|\$INPLACE_EDIT|\$OSNAME|\%SIG|\$BASETIME|\$PERL_VERSION|\$EXECUTABLE_NAME|\$MATCH|\$PREMATCH|\$POSTMATCH|\$ARGV|\@ARGV|\$OUTPUT_FIELD_SEPARATOR|\$INPUT_LINE_NUMBER|\$NR|\$INPUT_RECORD_SEPARATOR|\$RS|\$OUTPUT_RECORD_SEPARATOR|\$ORS|\$OUTPUT_AUTOFLUSH)$/ ) |
410
|
|
|
|
|
|
|
or ( $var =~ /^[\$\@\%]{?[a-zA-Z_][\w:{}\[\]]*$/ and $var =~ /::/ ) ) |
411
|
|
|
|
|
|
|
{ |
412
|
9
|
|
|
|
|
19
|
return handlelocalvar( $var, $opt ); |
413
|
|
|
|
|
|
|
} |
414
|
|
|
|
|
|
|
# $list[1..3] |
415
|
|
|
|
|
|
|
elsif ( $var =~ /^(\@)([^\[\{\]\}]+)([\[\{])(\S*:\S*)([\]\}])$/ ) { |
416
|
1
|
|
|
|
|
35
|
print "DEBUG sub $caller: d() cannot be used on an array slice! Found $var\n"; |
417
|
1
|
|
|
|
|
5
|
return; |
418
|
|
|
|
|
|
|
} |
419
|
|
|
|
|
|
|
# $scalar @list %hash |
420
|
|
|
|
|
|
|
elsif ( $var =~ /^[\$\@\%]{?[a-zA-Z_][\w{}\[\]]*$/ ) { |
421
|
|
|
|
|
|
|
# normal variable |
422
|
147
|
|
|
|
|
226
|
$reference = $h->{$var}; |
423
|
|
|
|
|
|
|
} |
424
|
|
|
|
|
|
|
# $#list |
425
|
|
|
|
|
|
|
elsif ( $var =~ /^\$#/ ) { |
426
|
1
|
|
|
|
|
5
|
( my $var2 = $var ) =~ s/^[\$\@\%]//; |
427
|
1
|
|
|
|
|
33
|
print "DEBUG sub $caller: WARNING: Debug::Statements::d() does not support \$# used in $var\n"; |
428
|
1
|
|
|
|
|
39
|
print "DEBUG sub $caller: Use double-quotes as a workaround: d(\"$var2 = $var\")\n"; |
429
|
1
|
|
|
|
|
6
|
return; |
430
|
|
|
|
|
|
|
} |
431
|
|
|
|
|
|
|
# anything else |
432
|
|
|
|
|
|
|
elsif ( $var =~ /^[\$\@\%]/ ) { |
433
|
0
|
|
|
|
|
0
|
( my $var2 = $var ) =~ s/^([\$\@\%])//; |
434
|
|
|
|
|
|
|
#print "DEBUG sub $caller: WARNING: Debug::Statements::d() does not support special variables such as $var\n"; |
435
|
|
|
|
|
|
|
#print "DEBUG sub $caller: Use double-quotes as a workaround: d(\"$var2 = $var\")\n"; |
436
|
0
|
|
|
|
|
0
|
return handlelocalvar( $var, $opt ); |
437
|
|
|
|
|
|
|
} else { |
438
|
0
|
0
|
|
|
|
0
|
if ($id) { print "internaldebug dumpvar: \$var is bad!\n" } |
|
0
|
|
|
|
|
0
|
|
439
|
0
|
|
|
|
|
0
|
return; |
440
|
|
|
|
|
|
|
} |
441
|
|
|
|
|
|
|
} |
442
|
|
|
|
|
|
|
|
443
|
|
|
|
|
|
|
# Sanity check |
444
|
176
|
100
|
|
|
|
344
|
if ( !defined $reference ) { |
445
|
7
|
|
|
|
|
173
|
print "DEBUG sub $caller: $var is not a defined local variable!\n"; |
446
|
7
|
|
|
|
|
49
|
print "DEBUG sub $caller: Check if you misspelled your variable name when you called d() or used the wrong sigil (\$/\@/\%)\n"; |
447
|
|
|
|
|
|
|
#print "DEBUG sub $caller: ! defined \$h->{$var}\n"; |
448
|
7
|
|
|
|
|
14
|
return; |
449
|
|
|
|
|
|
|
} |
450
|
169
|
50
|
|
|
|
254
|
if ($id) { print "internaldebug dumpvar: \$reference = '$reference'\n" } |
|
0
|
|
|
|
|
0
|
|
451
|
|
|
|
|
|
|
|
452
|
|
|
|
|
|
|
# Get value |
453
|
169
|
|
|
|
|
220
|
my $ref = ref($reference); |
454
|
169
|
50
|
|
|
|
237
|
if ($id) { print "internaldebug dumpvar: \$ref = '$ref'\n" } |
|
0
|
|
|
|
|
0
|
|
455
|
169
|
|
|
|
|
255
|
my $dump = cleanDump( $reference, $opt ); |
456
|
169
|
100
|
|
|
|
297
|
if ( $opt->{compress} ) { |
457
|
52
|
100
|
66
|
|
|
178
|
if ( $ref !~ /^SCALAR/ or $newsigil ne '$' ) { |
458
|
32
|
|
|
|
|
236
|
$dump =~ s/\s+/ /g; |
459
|
|
|
|
|
|
|
} |
460
|
|
|
|
|
|
|
} |
461
|
169
|
50
|
|
|
|
292
|
if ($id) { print "internaldebug dumpvar: \$dump = '$dump'\n" } |
|
0
|
|
|
|
|
0
|
|
462
|
169
|
|
|
|
|
278
|
return $dump; |
463
|
|
|
|
|
|
|
} |
464
|
|
|
|
|
|
|
|
465
|
|
|
|
|
|
|
# Local variables and package variables are both considered local, and are in the scope of d() |
466
|
|
|
|
|
|
|
sub handlelocalvar { |
467
|
9
|
|
|
9
|
0
|
11
|
my ( $var, $opt ) = @_; |
468
|
9
|
50
|
|
|
|
16
|
if ($id) { print "internaldebug handlelocalvar: \$var = '$var'\n" } |
|
0
|
|
|
|
|
0
|
|
469
|
9
|
50
|
|
|
|
21
|
if ( $var =~ /^([\$\@\%])/ ) { |
470
|
9
|
|
|
|
|
15
|
my $sigil = $1; |
471
|
9
|
|
|
|
|
26
|
( my $var2 = $var ) =~ s/^([\$\@\%])//; |
472
|
|
|
|
|
|
|
#print "\$var = $var\n"; |
473
|
1
|
|
|
1
|
|
6
|
no strict 'refs'; ## no critic |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
1363
|
|
474
|
9
|
100
|
|
|
|
24
|
if ( $sigil eq '$' ) { |
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
475
|
|
|
|
|
|
|
#print "Dumper cleanvar>" . Dumper( %$var2 ) . "<\n"; |
476
|
5
|
|
|
|
|
20
|
return cleanDump( \$$var2, $opt ); |
477
|
|
|
|
|
|
|
} elsif ( $sigil eq '@' ) { |
478
|
|
|
|
|
|
|
#print "Dumper cleanvar>" . Dumper( %$var2 ) . "<\n"; |
479
|
2
|
|
|
|
|
8
|
return cleanDump( \@$var2, $opt ); |
480
|
|
|
|
|
|
|
} elsif ( $sigil eq '%' ) { |
481
|
|
|
|
|
|
|
#print "Dumper cleanvar>" . Dumper( %$var2 ) . "<\n"; |
482
|
2
|
|
|
|
|
7
|
return cleanDump( \%$var2, $opt ); |
483
|
|
|
|
|
|
|
} else { |
484
|
0
|
0
|
|
|
|
0
|
croak "Program bug: \$sigil = $sigil" if $id; |
485
|
|
|
|
|
|
|
} |
486
|
|
|
|
|
|
|
} else { |
487
|
0
|
0
|
|
|
|
0
|
croak "Program bug: \$var = $var" if $id; |
488
|
|
|
|
|
|
|
} |
489
|
0
|
|
|
|
|
0
|
return; |
490
|
|
|
|
|
|
|
} |
491
|
|
|
|
|
|
|
|
492
|
|
|
|
|
|
|
sub cleanDump { |
493
|
178
|
|
|
178
|
0
|
199
|
my ( $reference, $opt ) = @_; |
494
|
178
|
|
|
|
|
162
|
my $ref = ref($reference); |
495
|
178
|
50
|
|
|
|
252
|
if ($id) { print "internaldebug cleanDump \$ref = $ref\n" } |
|
0
|
|
|
|
|
0
|
|
496
|
178
|
|
|
|
|
166
|
$Data::Dumper::Sortkeys = 1; |
497
|
|
|
|
|
|
|
# $Data::Dumper::Terse = 0; # causes a hang |
498
|
|
|
|
|
|
|
|
499
|
178
|
100
|
|
|
|
264
|
if ( $opt->{compress} ) { |
500
|
53
|
|
|
|
|
51
|
$Data::Dumper::Indent = 1; # 0=minimal 1=spaces 2=newlines(default) 3=addlSpaces |
501
|
|
|
|
|
|
|
} else { |
502
|
125
|
|
|
|
|
123
|
$Data::Dumper::Indent = 2; # 0=minimal 1=spaces 2=newlines(default) 3=addlSpaces |
503
|
|
|
|
|
|
|
} |
504
|
|
|
|
|
|
|
|
505
|
178
|
|
|
|
|
167
|
my $dump; |
506
|
178
|
100
|
100
|
|
|
357
|
if ( $opt->{Sort} and $ref eq "ARRAY" ) { |
507
|
2
|
|
|
|
|
9
|
$dump = Dumper( [ sort { $a cmp $b } @$reference ] ); # to sort array |
|
10
|
|
|
|
|
16
|
|
508
|
|
|
|
|
|
|
} else { |
509
|
176
|
|
|
|
|
486
|
$dump = Dumper($reference); |
510
|
|
|
|
|
|
|
} |
511
|
178
|
50
|
|
|
|
8825
|
if ($id) { print "internaldebug cleanDump: \$dump = '$dump'\n" } |
|
0
|
|
|
|
|
0
|
|
512
|
178
|
|
|
|
|
448
|
$dump =~ s/^\\//; |
513
|
178
|
|
|
|
|
233
|
chomp $dump; |
514
|
|
|
|
|
|
|
|
515
|
178
|
100
|
|
|
|
355
|
if ( $opt->{Elements} ) { |
516
|
4
|
|
|
|
|
4
|
my $numElements; |
517
|
4
|
100
|
|
|
|
10
|
if ( $ref eq "ARRAY" ) { |
|
|
50
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
518
|
2
|
|
|
|
|
2
|
$numElements = scalar @$reference; |
519
|
2
|
|
|
|
|
12
|
$dump = "($numElements) " . $dump; |
520
|
|
|
|
|
|
|
} elsif ( $ref eq "HASH" ) { |
521
|
2
|
|
|
|
|
3
|
$numElements = scalar keys %$reference; |
522
|
2
|
|
|
|
|
5
|
$dump = "($numElements) " . $dump; |
523
|
|
|
|
|
|
|
} elsif ( $ref eq "SCALAR" ) { |
524
|
|
|
|
|
|
|
# do nothing |
525
|
|
|
|
|
|
|
} else { |
526
|
|
|
|
|
|
|
# do nothing |
527
|
|
|
|
|
|
|
} |
528
|
|
|
|
|
|
|
} |
529
|
|
|
|
|
|
|
|
530
|
178
|
100
|
|
|
|
293
|
if ( $opt->{tRuncate} ) { |
531
|
1
|
|
|
|
|
3
|
my $severalLines = '[^\n]*\n' x $truncateLines; |
532
|
1
|
50
|
|
|
|
47
|
if ( $dump =~ s/\A($severalLines).*$/$1/s ) { # s allows . to match \n |
533
|
1
|
|
|
|
|
3
|
$dump .= " ...\n"; # ]\n"; |
534
|
|
|
|
|
|
|
} |
535
|
|
|
|
|
|
|
} |
536
|
|
|
|
|
|
|
|
537
|
178
|
|
|
|
|
318
|
return $dump; |
538
|
|
|
|
|
|
|
} |
539
|
|
|
|
|
|
|
|
540
|
|
|
|
|
|
|
sub printdebugsub { |
541
|
188
|
|
|
188
|
0
|
329
|
my ( $caller, $level, $var, $dump, $prefix, $suffix, $opt ) = @_; |
542
|
188
|
50
|
|
|
|
304
|
if ($id) { print "sub printdebugsub()\n" } |
|
0
|
|
|
|
|
0
|
|
543
|
|
|
|
|
|
|
|
544
|
|
|
|
|
|
|
# Variations: |
545
|
|
|
|
|
|
|
# "DEBUG: " $printdebug GLOBAL -> splits off $colon |
546
|
|
|
|
|
|
|
# debug levels 1 2 3 $printlevel |
547
|
|
|
|
|
|
|
# sub name |
548
|
|
|
|
|
|
|
# |
549
|
|
|
|
|
|
|
# Examples of desired output: |
550
|
|
|
|
|
|
|
# |
551
|
|
|
|
|
|
|
|
552
|
|
|
|
|
|
|
# Insert level if >=2 |
553
|
188
|
|
|
|
|
168
|
my $printlevel = ""; |
554
|
188
|
100
|
|
|
|
333
|
$printlevel = $level if $level >= 2; |
555
|
188
|
50
|
|
|
|
295
|
if ($id) { print "internaldebug printdebugsub: \$printlevel = '$printlevel'\n" } |
|
0
|
|
|
|
|
0
|
|
556
|
|
|
|
|
|
|
|
557
|
|
|
|
|
|
|
# Handle option $Debug::Statements::printdebug |
558
|
188
|
|
|
|
|
164
|
my $printdebugsub = $printdebug; # default is 'DEBUG: ' |
559
|
188
|
|
|
|
|
146
|
my $colon = ":"; |
560
|
188
|
100
|
|
|
|
292
|
if ($printdebug) { |
561
|
186
|
|
|
|
|
751
|
$printdebugsub =~ s/\s*$//; |
562
|
186
|
50
|
|
|
|
583
|
if ( $printdebugsub =~ s/([:-=>])$// ) { |
563
|
186
|
|
|
|
|
299
|
$colon = $1; |
564
|
|
|
|
|
|
|
} |
565
|
186
|
|
|
|
|
214
|
$printdebugsub .= $printlevel; |
566
|
186
|
50
|
|
|
|
296
|
if ($id) { print "internaldebug printdebugsub: \$printdebugsub = '$printdebugsub'\n" } |
|
0
|
|
|
|
|
0
|
|
567
|
|
|
|
|
|
|
} |
568
|
188
|
50
|
|
|
|
255
|
if ($id) { print "internaldebug printdebugsub: \$colon = '$colon'\n" } |
|
0
|
|
|
|
|
0
|
|
569
|
|
|
|
|
|
|
|
570
|
|
|
|
|
|
|
# Handle option 's' = printSub |
571
|
188
|
100
|
|
|
|
322
|
if ( $opt->{'printSub'} ) { |
572
|
183
|
|
|
|
|
187
|
my $printcaller = $caller; |
573
|
183
|
50
|
|
|
|
300
|
if ( $printcaller ne "" ) { |
574
|
183
|
|
|
|
|
385
|
$printcaller =~ s/^main:://; |
575
|
183
|
|
|
|
|
217
|
$printcaller =~ s/^Debug::Statements:://; |
576
|
183
|
|
|
|
|
276
|
$printcaller = "sub $printcaller"; |
577
|
|
|
|
|
|
|
} |
578
|
183
|
50
|
|
|
|
289
|
if ($id) { print "internaldebug printdebugsub: \$printcaller = '$printcaller'\n" } |
|
0
|
|
|
|
|
0
|
|
579
|
183
|
100
|
66
|
|
|
645
|
$printdebugsub .= " " if $printdebug and $printcaller ne ""; |
580
|
183
|
|
|
|
|
173
|
$printdebugsub .= $printcaller; |
581
|
183
|
50
|
|
|
|
282
|
if ($id) { print "internaldebug printdebugsub: \$printdebugsub = '$printdebugsub'\n" } |
|
0
|
|
|
|
|
0
|
|
582
|
|
|
|
|
|
|
} |
583
|
|
|
|
|
|
|
|
584
|
|
|
|
|
|
|
# Handle option 'c' = Chomp |
585
|
188
|
100
|
|
|
|
290
|
$dump =~ s/\n'$/'/ if $opt->{'Chomp'}; |
586
|
|
|
|
|
|
|
|
587
|
|
|
|
|
|
|
# Handle option 't' = 'Timestamp' |
588
|
188
|
|
|
|
|
183
|
my $timestamp = ""; |
589
|
188
|
100
|
|
|
|
494
|
$timestamp = " at " . localtime() . " " . gettimeofday() if $opt->{'Timestamp'}; |
590
|
|
|
|
|
|
|
|
591
|
|
|
|
|
|
|
# Handle option 'n' = 'LineNumber' |
592
|
188
|
|
|
|
|
211
|
my $linenumber = ""; |
593
|
188
|
100
|
|
|
|
316
|
if ( $opt->{'LineNumber'} ) { |
594
|
2
|
|
50
|
|
|
9
|
my $n = $. || 'undef'; |
595
|
2
|
|
|
|
|
4
|
$linenumber = "At line $n: "; |
596
|
|
|
|
|
|
|
} |
597
|
|
|
|
|
|
|
|
598
|
|
|
|
|
|
|
# Append colon |
599
|
188
|
100
|
100
|
|
|
427
|
$printdebugsub .= "$colon " if $printdebug or $opt->{'printSub'}; |
600
|
188
|
50
|
|
|
|
283
|
if ($id) { print "internaldebug printdebugsub: \$printdebugsub = '$printdebugsub'\n" } |
|
0
|
|
|
|
|
0
|
|
601
|
|
|
|
|
|
|
|
602
|
188
|
100
|
|
|
|
231
|
if ($var) { |
603
|
180
|
|
|
|
|
5054
|
print "$prefix$printdebugsub$linenumber$var = $dump$timestamp$suffix\n"; |
604
|
|
|
|
|
|
|
} else { |
605
|
|
|
|
|
|
|
# no vars found, just print prefix and suffix |
606
|
8
|
|
|
|
|
373
|
print "$printdebugsub$prefix$timestamp$suffix\n"; |
607
|
|
|
|
|
|
|
} |
608
|
|
|
|
|
|
|
|
609
|
188
|
100
|
|
|
|
628
|
croak if $opt->{die}; |
610
|
|
|
|
|
|
|
|
611
|
187
|
|
|
|
|
727
|
return; |
612
|
|
|
|
|
|
|
} |
613
|
|
|
|
|
|
|
|
614
|
|
|
|
|
|
|
# ls($filename) |
615
|
|
|
|
|
|
|
# ls($filename, $level) |
616
|
|
|
|
|
|
|
# ls("$filename1 filename2", $level) |
617
|
|
|
|
|
|
|
sub ls { |
618
|
3
|
|
|
3
|
1
|
3952
|
my ( $filenames, $level ) = @_; |
619
|
3
|
50
|
|
|
|
22
|
return if $disable; |
620
|
3
|
50
|
|
|
|
9
|
$level = 1 if !$level; |
621
|
3
|
50
|
|
|
|
7
|
if ($id) { print "internaldebug ls: \$level = '$level'\n" } |
|
0
|
|
|
|
|
0
|
|
622
|
3
|
|
|
|
|
100
|
my $h = PadWalker::peek_my(1); |
623
|
3
|
50
|
|
|
|
8
|
return if not checkLevel( $h, $level ); |
624
|
3
|
50
|
|
|
|
15
|
my $windows = ($^O =~ /Win/) ? 1 : 0; |
625
|
3
|
|
|
|
|
4
|
my $command; |
626
|
3
|
|
|
|
|
12
|
for my $file ( split /\s+/, $filenames ) { |
627
|
3
|
50
|
|
|
|
5
|
if ( $windows ) { |
628
|
0
|
|
|
|
|
0
|
$command = "dir $file"; |
629
|
|
|
|
|
|
|
} else { |
630
|
3
|
|
|
|
|
6
|
$command = "ls -l $file"; |
631
|
|
|
|
|
|
|
} |
632
|
3
|
50
|
|
|
|
8
|
if ($id) { print "internaldebug ls: \$command = '$command'\n" } |
|
0
|
|
|
|
|
0
|
|
633
|
3
|
|
|
|
|
3
|
my $lsl; |
634
|
3
|
100
|
66
|
|
|
67
|
if ( -d $file or -f $file ) { |
|
|
50
|
|
|
|
|
|
635
|
1
|
|
|
|
|
4089
|
$lsl = `$command`; |
636
|
1
|
|
|
|
|
16
|
chomp $lsl; |
637
|
|
|
|
|
|
|
} elsif ( -f $file ) { |
638
|
0
|
|
|
|
|
0
|
$lsl = `$command`; |
639
|
0
|
|
|
|
|
0
|
chomp $lsl; |
640
|
|
|
|
|
|
|
} else { |
641
|
2
|
100
|
|
|
|
12
|
if ( $file =~ /^\$/ ) { |
642
|
1
|
|
|
|
|
41
|
print "DEBUG: WARNING: Debug::Statements::ls() did not understand file name $file. You probably need to remove the 'single quotes' around your variable\n"; |
643
|
1
|
|
|
|
|
15
|
return; |
644
|
|
|
|
|
|
|
} |
645
|
1
|
|
|
|
|
2
|
$lsl = "$file does not exist!"; |
646
|
|
|
|
|
|
|
} |
647
|
2
|
50
|
|
|
|
8
|
if ($id) { print "internaldebug ls: \$lsl = '$lsl'\n" } |
|
0
|
|
|
|
|
0
|
|
648
|
2
|
|
50
|
|
|
19
|
my $caller = ( caller(1) )[3] || ""; |
649
|
2
|
|
|
|
|
13
|
printdebugsub( $caller, $level, "ls -l", $lsl, "", "" ); |
650
|
|
|
|
|
|
|
} |
651
|
2
|
|
|
|
|
50
|
return; |
652
|
|
|
|
|
|
|
} |
653
|
|
|
|
|
|
|
|
654
|
|
|
|
|
|
|
sub dumperTests { |
655
|
0
|
|
|
0
|
0
|
0
|
my $h = shift; |
656
|
|
|
|
|
|
|
# Used during development of this module |
657
|
0
|
|
|
|
|
0
|
print "internaldebug: ----\n"; |
658
|
0
|
|
|
|
|
0
|
print Dumper($h); # good |
659
|
0
|
|
|
|
|
0
|
print Dumper( $h->{'@listvar'} ); # good |
660
|
0
|
|
|
|
|
0
|
print Dumper( $h->{'$listvar[0]'} ); # bad |
661
|
0
|
|
|
|
|
0
|
print Dumper( $h->{'@listvar'}[0] ); # good |
662
|
0
|
|
|
|
|
0
|
print Dumper( $h->{'@listvar'}[3] ); # good |
663
|
|
|
|
|
|
|
#print Dumper($h->{'$listvar'}[1:3]); # hash slice syntax error |
664
|
|
|
|
|
|
|
#print Dumper($h->{'@listvar'}[1:3]); # hash slice syntax error |
665
|
0
|
|
|
|
|
0
|
print Dumper( $h->{'%hashvar'} ); # bad |
666
|
0
|
|
|
|
|
0
|
print Dumper( $h->{'$hashvar{one}'} ); # bad |
667
|
0
|
|
|
|
|
0
|
print Dumper( $h->{'%hashvar'}{one} ); # bad |
668
|
0
|
|
|
|
|
0
|
print Dumper( $h->{'@nestedlist'} ); |
669
|
0
|
|
|
|
|
0
|
print Dumper( $h->{'$nestedlist[1][1]'} ); # bad |
670
|
0
|
|
|
|
|
0
|
print Dumper( $h->{'@nestedlist'}[1][1] ); # good |
671
|
0
|
|
|
|
|
0
|
print Dumper( $h->{'%nestedhash'} ); # good |
672
|
0
|
|
|
|
|
0
|
print Dumper( $h->{'%nestedhash'}{flintstones}{pal} ); # good |
673
|
0
|
|
|
|
|
0
|
print Dumper( $h->{'%nestedhash'}{flintstones} ); # good |
674
|
0
|
|
|
|
|
0
|
print "internaldebug: ----\n"; |
675
|
0
|
|
|
|
|
0
|
return; |
676
|
|
|
|
|
|
|
} |
677
|
|
|
|
|
|
|
|
678
|
|
|
|
|
|
|
# Convert '\n' to "\n", convert '\t' to "\t" |
679
|
|
|
|
|
|
|
sub expandEscapes { |
680
|
378
|
|
|
378
|
0
|
429
|
local $_ = shift; |
681
|
378
|
50
|
|
|
|
502
|
if ($id) { print "internaldebug: sub expandEscapes()\n" } |
|
0
|
|
|
|
|
0
|
|
682
|
378
|
|
|
|
|
353
|
s{(\\n|\\t)}{qq["$1"]}geexs; |
|
11
|
|
|
|
|
610
|
|
683
|
378
|
|
|
|
|
520
|
return $_; |
684
|
|
|
|
|
|
|
} |
685
|
|
|
|
|
|
|
|
686
|
|
|
|
|
|
|
sub evlwrapper { |
687
|
31
|
|
|
31
|
0
|
44
|
my ( $h, $expression, $description ) = @_; |
688
|
31
|
50
|
|
|
|
51
|
if ($id) { print "internaldebug: evaling ($evalcounter) $description\n" } |
|
0
|
|
|
|
|
0
|
|
689
|
31
|
|
|
|
|
29
|
$evalcounter++; |
690
|
31
|
|
|
|
|
1944
|
return eval($expression); ## no critic |
691
|
|
|
|
|
|
|
} |
692
|
|
|
|
|
|
|
|
693
|
|
|
|
|
|
|
1; |
694
|
|
|
|
|
|
|
|
695
|
|
|
|
|
|
|
__END__ |
696
|
|
|
|
|
|
|
|
697
|
|
|
|
|
|
|
=head1 NAME |
698
|
|
|
|
|
|
|
|
699
|
|
|
|
|
|
|
Debug::Statements - provides an easy way to insert and enable/disable debug statements. |
700
|
|
|
|
|
|
|
|
701
|
|
|
|
|
|
|
=head1 SYNOPSIS |
702
|
|
|
|
|
|
|
|
703
|
|
|
|
|
|
|
The C<d()> function prints the name of the variable AND its value. |
704
|
|
|
|
|
|
|
|
705
|
|
|
|
|
|
|
This implementation been optimized to minimize your keystrokes. |
706
|
|
|
|
|
|
|
|
707
|
|
|
|
|
|
|
=head2 Example code |
708
|
|
|
|
|
|
|
|
709
|
|
|
|
|
|
|
my $myvar = 'some value'; |
710
|
|
|
|
|
|
|
my @list = ('zero', 1, 'two', "3"); |
711
|
|
|
|
|
|
|
my %hash = ('one' => 2, 'three' => 4); |
712
|
|
|
|
|
|
|
|
713
|
|
|
|
|
|
|
use Debug::Statements; |
714
|
|
|
|
|
|
|
my $d = 1; |
715
|
|
|
|
|
|
|
d "Hello world"; |
716
|
|
|
|
|
|
|
d '$myvar'; |
717
|
|
|
|
|
|
|
d '@list %hash'; |
718
|
|
|
|
|
|
|
|
719
|
|
|
|
|
|
|
=head2 Output |
720
|
|
|
|
|
|
|
|
721
|
|
|
|
|
|
|
DEBUG sub mysub: Hello world |
722
|
|
|
|
|
|
|
DEBUG sub mysub: $myvar = 'some value' |
723
|
|
|
|
|
|
|
DEBUG sub mysub: @list = [ |
724
|
|
|
|
|
|
|
'zero', |
725
|
|
|
|
|
|
|
1, |
726
|
|
|
|
|
|
|
'two', |
727
|
|
|
|
|
|
|
'3' |
728
|
|
|
|
|
|
|
] |
729
|
|
|
|
|
|
|
DEBUG sub mysub: %hash = { |
730
|
|
|
|
|
|
|
'one' => 2, |
731
|
|
|
|
|
|
|
'three' => 4 |
732
|
|
|
|
|
|
|
} |
733
|
|
|
|
|
|
|
|
734
|
|
|
|
|
|
|
|
735
|
|
|
|
|
|
|
=head1 BACKGROUND |
736
|
|
|
|
|
|
|
|
737
|
|
|
|
|
|
|
=head2 Advantages of debug statements |
738
|
|
|
|
|
|
|
|
739
|
|
|
|
|
|
|
"The most effective debugging tool is still careful thought, coupled with judiciously placed print statements" |
740
|
|
|
|
|
|
|
- Brian Kernighan, Unix for Beginners (1979) |
741
|
|
|
|
|
|
|
|
742
|
|
|
|
|
|
|
=over |
743
|
|
|
|
|
|
|
|
744
|
|
|
|
|
|
|
=item * |
745
|
|
|
|
|
|
|
Familiarity - everyone has used them. |
746
|
|
|
|
|
|
|
|
747
|
|
|
|
|
|
|
=item * |
748
|
|
|
|
|
|
|
When strategically placed, they show the values of key variables as well as the flow of control. |
749
|
|
|
|
|
|
|
|
750
|
|
|
|
|
|
|
=item * |
751
|
|
|
|
|
|
|
May be left in the code to facilitate debugging, when the code next needs to be enhanced. |
752
|
|
|
|
|
|
|
|
753
|
|
|
|
|
|
|
=item * |
754
|
|
|
|
|
|
|
May be turned on to help remotely debug problems. |
755
|
|
|
|
|
|
|
|
756
|
|
|
|
|
|
|
=item * |
757
|
|
|
|
|
|
|
Printing the names of executing subroutines can be particularly useful |
758
|
|
|
|
|
|
|
when debugging large unfamiliar programs produced by multiple developers over the span of years. |
759
|
|
|
|
|
|
|
|
760
|
|
|
|
|
|
|
=item * |
761
|
|
|
|
|
|
|
Can be used in conjuction with a debugger, which can be used to |
762
|
|
|
|
|
|
|
change variables on-the-fly, step into libraries, or skip/repeat sections of code |
763
|
|
|
|
|
|
|
|
764
|
|
|
|
|
|
|
=item * |
765
|
|
|
|
|
|
|
If the results are saved to a file, file comparisons can be useful |
766
|
|
|
|
|
|
|
during regression testing. |
767
|
|
|
|
|
|
|
|
768
|
|
|
|
|
|
|
=back |
769
|
|
|
|
|
|
|
|
770
|
|
|
|
|
|
|
=head2 Traditional debug statement example |
771
|
|
|
|
|
|
|
|
772
|
|
|
|
|
|
|
my $d = 1; |
773
|
|
|
|
|
|
|
my $myvar = 'some value'; |
774
|
|
|
|
|
|
|
if ($d) { print "DEBUG sub xyz: \$myvar is $myvar\n" } |
775
|
|
|
|
|
|
|
use Dumpvalue; |
776
|
|
|
|
|
|
|
if ($d) { print "\nDEBUG: Dumping \@list:\n"; Dumpvalue->new->dumpValue(\@list) } |
777
|
|
|
|
|
|
|
if ($d) { print "\nDEBUG: Dumping \%hash:\n"; Dumpvalue->new->dumpValue(\%hash) } |
778
|
|
|
|
|
|
|
|
779
|
|
|
|
|
|
|
=head2 Disadvantages of traditional "print" debug statements |
780
|
|
|
|
|
|
|
|
781
|
|
|
|
|
|
|
=over |
782
|
|
|
|
|
|
|
|
783
|
|
|
|
|
|
|
=item * |
784
|
|
|
|
|
|
|
Tedious, require many keystrokes to type |
785
|
|
|
|
|
|
|
|
786
|
|
|
|
|
|
|
=item * |
787
|
|
|
|
|
|
|
Reduces readability of the source code. |
788
|
|
|
|
|
|
|
|
789
|
|
|
|
|
|
|
=item * |
790
|
|
|
|
|
|
|
Print statements clutter the standard output |
791
|
|
|
|
|
|
|
|
792
|
|
|
|
|
|
|
=item * |
793
|
|
|
|
|
|
|
Need to be removed or commented out later |
794
|
|
|
|
|
|
|
|
795
|
|
|
|
|
|
|
=item * |
796
|
|
|
|
|
|
|
If some statements are mistakenly left in, the output can cause problems or confusion |
797
|
|
|
|
|
|
|
|
798
|
|
|
|
|
|
|
=item * |
799
|
|
|
|
|
|
|
The next time the code needs to be enhanced, |
800
|
|
|
|
|
|
|
any removed print statements need to be re-inserted or uncommented |
801
|
|
|
|
|
|
|
|
802
|
|
|
|
|
|
|
=back |
803
|
|
|
|
|
|
|
|
804
|
|
|
|
|
|
|
=head1 Debug::Statements Example |
805
|
|
|
|
|
|
|
|
806
|
|
|
|
|
|
|
C<Debug::Statements::d()> provides an easy way to insert and enable/disable debug statements. |
807
|
|
|
|
|
|
|
|
808
|
|
|
|
|
|
|
my $myvar = 'some value'; |
809
|
|
|
|
|
|
|
use Debug::Statements; |
810
|
|
|
|
|
|
|
my $d = 1; |
811
|
|
|
|
|
|
|
d '$myvar'; |
812
|
|
|
|
|
|
|
|
813
|
|
|
|
|
|
|
=head2 Output |
814
|
|
|
|
|
|
|
|
815
|
|
|
|
|
|
|
DEBUG sub mysub: $myvar = 'some value' |
816
|
|
|
|
|
|
|
|
817
|
|
|
|
|
|
|
This is all you need to know to get started. |
818
|
|
|
|
|
|
|
|
819
|
|
|
|
|
|
|
=head1 FEATURES |
820
|
|
|
|
|
|
|
|
821
|
|
|
|
|
|
|
=head2 Arrays, hashes and refs |
822
|
|
|
|
|
|
|
|
823
|
|
|
|
|
|
|
d '@list'; |
824
|
|
|
|
|
|
|
d '$list[2]'; |
825
|
|
|
|
|
|
|
d '$list[$i]'; |
826
|
|
|
|
|
|
|
d '%hash'; |
827
|
|
|
|
|
|
|
d '$nestedhash{key}'; |
828
|
|
|
|
|
|
|
d '$nestedhash{$key1}{$key2}'; |
829
|
|
|
|
|
|
|
d '$listref'; |
830
|
|
|
|
|
|
|
d '$arrayref'; |
831
|
|
|
|
|
|
|
d '$arrayref->[2]'; |
832
|
|
|
|
|
|
|
d '$hashref->{key}'; |
833
|
|
|
|
|
|
|
d '$hashref->{$key}'; |
834
|
|
|
|
|
|
|
|
835
|
|
|
|
|
|
|
=head2 Plain text can be entered as a comment |
836
|
|
|
|
|
|
|
|
837
|
|
|
|
|
|
|
d 'Processing...'; |
838
|
|
|
|
|
|
|
d "This comment prints the value of a variable: $myvar"; |
839
|
|
|
|
|
|
|
|
840
|
|
|
|
|
|
|
=head2 Multiple debug levels |
841
|
|
|
|
|
|
|
|
842
|
|
|
|
|
|
|
use Debug::Statements qw(d d2 d0 D); |
843
|
|
|
|
|
|
|
|
844
|
|
|
|
|
|
|
my $d = 1; |
845
|
|
|
|
|
|
|
d '$myvar'; # prints |
846
|
|
|
|
|
|
|
d2 '$myvar'; # does not print since $d < 2 |
847
|
|
|
|
|
|
|
|
848
|
|
|
|
|
|
|
$d = 2; |
849
|
|
|
|
|
|
|
d '$myvar'; # prints |
850
|
|
|
|
|
|
|
d2 '$myvar'; # prints |
851
|
|
|
|
|
|
|
|
852
|
|
|
|
|
|
|
D '$myvar'; # always prints, even if $d is 0 or undef |
853
|
|
|
|
|
|
|
# this is useful for short term debugging |
854
|
|
|
|
|
|
|
# of existing code |
855
|
|
|
|
|
|
|
|
856
|
|
|
|
|
|
|
d0 '$myvar'; # same as D |
857
|
|
|
|
|
|
|
|
858
|
|
|
|
|
|
|
=head2 Supports newlines or other characters before/after the variable |
859
|
|
|
|
|
|
|
|
860
|
|
|
|
|
|
|
d '\n $myvar'; |
861
|
|
|
|
|
|
|
d '\n$myvar\n\n'; |
862
|
|
|
|
|
|
|
d '\n-------\n@list\n--------\n'; |
863
|
|
|
|
|
|
|
|
864
|
|
|
|
|
|
|
=head2 Multiple variables can be printed easily |
865
|
|
|
|
|
|
|
|
866
|
|
|
|
|
|
|
d '$myvar $myvar2 $myvar3'; |
867
|
|
|
|
|
|
|
or |
868
|
|
|
|
|
|
|
d '$myvar,$myvar2,$myvar3'; |
869
|
|
|
|
|
|
|
or |
870
|
|
|
|
|
|
|
d '$myvar, $myvar2, $myvar3'; |
871
|
|
|
|
|
|
|
or |
872
|
|
|
|
|
|
|
d '($myvar, $myvar2, $myvar3)'; |
873
|
|
|
|
|
|
|
|
874
|
|
|
|
|
|
|
Each of these examples prints one line each for $myvar, $myvar2, and $myvar3 |
875
|
|
|
|
|
|
|
|
876
|
|
|
|
|
|
|
=head2 Alternate syntax with parentheses |
877
|
|
|
|
|
|
|
|
878
|
|
|
|
|
|
|
d('$myvar'); |
879
|
|
|
|
|
|
|
|
880
|
|
|
|
|
|
|
=head1 OPTIONS |
881
|
|
|
|
|
|
|
|
882
|
|
|
|
|
|
|
Options may be specifed with an 2nd argment to C<d()> |
883
|
|
|
|
|
|
|
|
884
|
|
|
|
|
|
|
=over |
885
|
|
|
|
|
|
|
|
886
|
|
|
|
|
|
|
B<b> |
887
|
|
|
|
|
|
|
print suBroutine name (on by default) |
888
|
|
|
|
|
|
|
|
889
|
|
|
|
|
|
|
B<c> |
890
|
|
|
|
|
|
|
Chomp newline before printing, useful when printing captured $line from a parsed input file |
891
|
|
|
|
|
|
|
|
892
|
|
|
|
|
|
|
B<e> |
893
|
|
|
|
|
|
|
print # of Elements contained in top level of the array or hash |
894
|
|
|
|
|
|
|
|
895
|
|
|
|
|
|
|
B<n> |
896
|
|
|
|
|
|
|
print line Number $. of the input file |
897
|
|
|
|
|
|
|
|
898
|
|
|
|
|
|
|
B<q> |
899
|
|
|
|
|
|
|
treat the string as text, do not try to evaluate it. |
900
|
|
|
|
|
|
|
This is useful if you are parsing another Perl script, and the text contains sigil characters C<$@%> |
901
|
|
|
|
|
|
|
|
902
|
|
|
|
|
|
|
B<r> |
903
|
|
|
|
|
|
|
tRuncate output (defaults to 10 lines) |
904
|
|
|
|
|
|
|
|
905
|
|
|
|
|
|
|
B<s> |
906
|
|
|
|
|
|
|
Sort contents of arrays (hashes are always sorted) |
907
|
|
|
|
|
|
|
|
908
|
|
|
|
|
|
|
B<t> |
909
|
|
|
|
|
|
|
print Timestamp using C<localtime()> and C<Time::HiRes::gettimeofday()> |
910
|
|
|
|
|
|
|
|
911
|
|
|
|
|
|
|
B<x> |
912
|
|
|
|
|
|
|
die when code reaches this line |
913
|
|
|
|
|
|
|
|
914
|
|
|
|
|
|
|
B<z> |
915
|
|
|
|
|
|
|
compress array and hash dumps to save screen space |
916
|
|
|
|
|
|
|
|
917
|
|
|
|
|
|
|
=back |
918
|
|
|
|
|
|
|
|
919
|
|
|
|
|
|
|
=head2 Examples |
920
|
|
|
|
|
|
|
|
921
|
|
|
|
|
|
|
To print $line chomped and with line number and timestamp |
922
|
|
|
|
|
|
|
|
923
|
|
|
|
|
|
|
d('$line', 'cnt'); |
924
|
|
|
|
|
|
|
|
925
|
|
|
|
|
|
|
To print %hash in a compressed format |
926
|
|
|
|
|
|
|
|
927
|
|
|
|
|
|
|
d('%hash', 'z'); |
928
|
|
|
|
|
|
|
|
929
|
|
|
|
|
|
|
=head2 Negating options |
930
|
|
|
|
|
|
|
|
931
|
|
|
|
|
|
|
To negate an option, capitialize it (use 'B' instead of 'b') |
932
|
|
|
|
|
|
|
|
933
|
|
|
|
|
|
|
=head2 Persistent options |
934
|
|
|
|
|
|
|
|
935
|
|
|
|
|
|
|
Options are only valid for the current debug statement |
936
|
|
|
|
|
|
|
|
937
|
|
|
|
|
|
|
To make the current options global (peristent), append a star * |
938
|
|
|
|
|
|
|
|
939
|
|
|
|
|
|
|
For example, to set timestamp globally |
940
|
|
|
|
|
|
|
|
941
|
|
|
|
|
|
|
d('$var', 't*'); |
942
|
|
|
|
|
|
|
|
943
|
|
|
|
|
|
|
For example, to unset timestamp globally |
944
|
|
|
|
|
|
|
|
945
|
|
|
|
|
|
|
'$var', 'T*'); |
946
|
|
|
|
|
|
|
|
947
|
|
|
|
|
|
|
=head1 REQUIREMENTS |
948
|
|
|
|
|
|
|
|
949
|
|
|
|
|
|
|
B<L<PadWalker> must be installed> |
950
|
|
|
|
|
|
|
|
951
|
|
|
|
|
|
|
In addition, the test suites require Test::Fatal, Test::More, and Test::Output |
952
|
|
|
|
|
|
|
|
953
|
|
|
|
|
|
|
=head2 $d variable |
954
|
|
|
|
|
|
|
|
955
|
|
|
|
|
|
|
B<Your code must have a variable '$d' defined to enable the debug statements> |
956
|
|
|
|
|
|
|
|
957
|
|
|
|
|
|
|
Exception: C<D()> does not require the $d variable to exist. |
958
|
|
|
|
|
|
|
It always prints. See "Multiple debug levels" above. |
959
|
|
|
|
|
|
|
|
960
|
|
|
|
|
|
|
$d was chosen because it is easy to type and intuitive |
961
|
|
|
|
|
|
|
|
962
|
|
|
|
|
|
|
If your code already uses '$d' for another purpose, |
963
|
|
|
|
|
|
|
this can be changed with C<Debug::Statements::setFlag()> |
964
|
|
|
|
|
|
|
|
965
|
|
|
|
|
|
|
Your code must not already contain a local subroutine called 'd()', |
966
|
|
|
|
|
|
|
since this function is imported |
967
|
|
|
|
|
|
|
|
968
|
|
|
|
|
|
|
Consider enabling $d through the command line of your script |
969
|
|
|
|
|
|
|
|
970
|
|
|
|
|
|
|
use Getopt::Long; |
971
|
|
|
|
|
|
|
my %opt; |
972
|
|
|
|
|
|
|
my $d = 0; |
973
|
|
|
|
|
|
|
GetOptions( \%opt, 'd' => sub{$d=1}, 'dd' => sub{$d=2}, ... ); |
974
|
|
|
|
|
|
|
|
975
|
|
|
|
|
|
|
This provides an easy way for others to set your code into debug mode. |
976
|
|
|
|
|
|
|
They can then capture stdout and email it to you. |
977
|
|
|
|
|
|
|
|
978
|
|
|
|
|
|
|
=head2 Quoting |
979
|
|
|
|
|
|
|
|
980
|
|
|
|
|
|
|
Calls to d() should use 'single quotes' instead of "double quotes" |
981
|
|
|
|
|
|
|
|
982
|
|
|
|
|
|
|
Exception: To produce custom output, call d() with double-quotes. |
983
|
|
|
|
|
|
|
As is always the case with double-quotes in Perl, |
984
|
|
|
|
|
|
|
variables will be interpolated into values before entering the d() subroutine. |
985
|
|
|
|
|
|
|
|
986
|
|
|
|
|
|
|
=head3 Example #1 |
987
|
|
|
|
|
|
|
|
988
|
|
|
|
|
|
|
d "Found pattern: $mynum in file $filename"; |
989
|
|
|
|
|
|
|
|
990
|
|
|
|
|
|
|
=head3 Output #1 |
991
|
|
|
|
|
|
|
|
992
|
|
|
|
|
|
|
DEBUG sub mysub: Found pattern asdf in file foo.txt |
993
|
|
|
|
|
|
|
|
994
|
|
|
|
|
|
|
=head3 Example #2 |
995
|
|
|
|
|
|
|
|
996
|
|
|
|
|
|
|
d "Found $key and replaced with $subtable_ref->{$key} on: $line" |
997
|
|
|
|
|
|
|
|
998
|
|
|
|
|
|
|
=head3 Output #2 |
999
|
|
|
|
|
|
|
|
1000
|
|
|
|
|
|
|
DEBUG sub mysub: Found foo and replaced with bar on: foobar |
1001
|
|
|
|
|
|
|
|
1002
|
|
|
|
|
|
|
Remember that when using escaped \$ \@ \% within "double quotes", |
1003
|
|
|
|
|
|
|
this is equivalent to using $ @ % within 'single quotes' |
1004
|
|
|
|
|
|
|
|
1005
|
|
|
|
|
|
|
This means that d() will try to print the names and values of those variables. |
1006
|
|
|
|
|
|
|
|
1007
|
|
|
|
|
|
|
=head2 Functions |
1008
|
|
|
|
|
|
|
|
1009
|
|
|
|
|
|
|
The module includes functions which affect global operation |
1010
|
|
|
|
|
|
|
|
1011
|
|
|
|
|
|
|
Debug::Statements::enable(); # enable operation (default) |
1012
|
|
|
|
|
|
|
Debug::Statements::disable(); # disable operation, even if $d >= 1 |
1013
|
|
|
|
|
|
|
Debug::Statements::setFlag('$yourvar'); # default is '$d' |
1014
|
|
|
|
|
|
|
Debug::Statements::setPrintDebug(""); # default is "DEBUG: " |
1015
|
|
|
|
|
|
|
Debug::Statements::setTruncate(10); # default is 10 lines |
1016
|
|
|
|
|
|
|
|
1017
|
|
|
|
|
|
|
=head1 LIMITATIONS |
1018
|
|
|
|
|
|
|
|
1019
|
|
|
|
|
|
|
Not supported |
1020
|
|
|
|
|
|
|
|
1021
|
|
|
|
|
|
|
=over |
1022
|
|
|
|
|
|
|
|
1023
|
|
|
|
|
|
|
=item * |
1024
|
|
|
|
|
|
|
Array slices such as C<$listvar[1:3]> |
1025
|
|
|
|
|
|
|
|
1026
|
|
|
|
|
|
|
=item * |
1027
|
|
|
|
|
|
|
Some special variables such as C<$1 $_ @_> |
1028
|
|
|
|
|
|
|
...but any of these can be printed by using "double quotes", |
1029
|
|
|
|
|
|
|
since this will cause Perl to evaluate the expression before calling d(). For example d "@_" |
1030
|
|
|
|
|
|
|
|
1031
|
|
|
|
|
|
|
=item * |
1032
|
|
|
|
|
|
|
The evaluation is of variables does not support the full range of Perl syntax. |
1033
|
|
|
|
|
|
|
Most cases work, for example: C<d '$hash{$key}'> |
1034
|
|
|
|
|
|
|
However hashes used as hash keys will not work, for example: C<d '$hash{$hash2{$key}}'> |
1035
|
|
|
|
|
|
|
As a workaround, use "double quotes": C<d "\$hash{$hash2{$key}}"> instead. |
1036
|
|
|
|
|
|
|
The rule is similar for arrays |
1037
|
|
|
|
|
|
|
|
1038
|
|
|
|
|
|
|
=back |
1039
|
|
|
|
|
|
|
|
1040
|
|
|
|
|
|
|
=head1 Additional features |
1041
|
|
|
|
|
|
|
|
1042
|
|
|
|
|
|
|
=head2 ls() |
1043
|
|
|
|
|
|
|
|
1044
|
|
|
|
|
|
|
ls() is also provided for convenience, but not exported by default |
1045
|
|
|
|
|
|
|
|
1046
|
|
|
|
|
|
|
use Debug::Statements qw(d d0 d1 d2 d3 D ls); |
1047
|
|
|
|
|
|
|
ls($myfilename); |
1048
|
|
|
|
|
|
|
|
1049
|
|
|
|
|
|
|
When $d >= 1, prints an ls -l listing of $myfilename. |
1050
|
|
|
|
|
|
|
|
1051
|
|
|
|
|
|
|
Note that ' ' is not used inside ls() |
1052
|
|
|
|
|
|
|
|
1053
|
|
|
|
|
|
|
=head1 Perl versions |
1054
|
|
|
|
|
|
|
|
1055
|
|
|
|
|
|
|
This module has been tested on |
1056
|
|
|
|
|
|
|
|
1057
|
|
|
|
|
|
|
=over |
1058
|
|
|
|
|
|
|
|
1059
|
|
|
|
|
|
|
=item * |
1060
|
|
|
|
|
|
|
Linux 5.8.6, 5.8.8, 5.12, 5.14, and 5.20 |
1061
|
|
|
|
|
|
|
|
1062
|
|
|
|
|
|
|
It will probably work as far back as 5.8.0 |
1063
|
|
|
|
|
|
|
|
1064
|
|
|
|
|
|
|
=item * |
1065
|
|
|
|
|
|
|
Windows 5.20 |
1066
|
|
|
|
|
|
|
|
1067
|
|
|
|
|
|
|
=back |
1068
|
|
|
|
|
|
|
|
1069
|
|
|
|
|
|
|
=head1 GORY DETAILS |
1070
|
|
|
|
|
|
|
|
1071
|
|
|
|
|
|
|
=head2 How it works |
1072
|
|
|
|
|
|
|
|
1073
|
|
|
|
|
|
|
C<PadWalker::peek_my()> gets the value of $d and the contents of your variables |
1074
|
|
|
|
|
|
|
(from outside its scope!) The variable values are stored in an internal hash reference |
1075
|
|
|
|
|
|
|
|
1076
|
|
|
|
|
|
|
It does NOT change the values of your variables. |
1077
|
|
|
|
|
|
|
|
1078
|
|
|
|
|
|
|
C<caller()[3]> gets the name of subroutine which encloses your code |
1079
|
|
|
|
|
|
|
|
1080
|
|
|
|
|
|
|
C<Data::Dumper> pretty-prints the contents of your variable |
1081
|
|
|
|
|
|
|
|
1082
|
|
|
|
|
|
|
=head2 Performance |
1083
|
|
|
|
|
|
|
|
1084
|
|
|
|
|
|
|
For performance-critical applications, |
1085
|
|
|
|
|
|
|
frequent calls to C<PadWalker::peek_my()> and C<caller()> may be too intensive |
1086
|
|
|
|
|
|
|
|
1087
|
|
|
|
|
|
|
=head3 Solutions |
1088
|
|
|
|
|
|
|
|
1089
|
|
|
|
|
|
|
=over |
1090
|
|
|
|
|
|
|
|
1091
|
|
|
|
|
|
|
=item * |
1092
|
|
|
|
|
|
|
Globally disable all functionality by calling C<Debug::Statements::disable();> |
1093
|
|
|
|
|
|
|
The PadWalker and caller functions will not be called. Debug statements will not be printed. |
1094
|
|
|
|
|
|
|
|
1095
|
|
|
|
|
|
|
=item * |
1096
|
|
|
|
|
|
|
OR comment out some of your calls to C<d()> within performance-critical loops |
1097
|
|
|
|
|
|
|
|
1098
|
|
|
|
|
|
|
=item * |
1099
|
|
|
|
|
|
|
OR completely disable this code is to define you own empty d() subroutines. |
1100
|
|
|
|
|
|
|
|
1101
|
|
|
|
|
|
|
#use Debug::Statements qw(d d2); |
1102
|
|
|
|
|
|
|
d{}; d2{}; |
1103
|
|
|
|
|
|
|
|
1104
|
|
|
|
|
|
|
=back |
1105
|
|
|
|
|
|
|
|
1106
|
|
|
|
|
|
|
=head1 AUTHOR |
1107
|
|
|
|
|
|
|
|
1108
|
|
|
|
|
|
|
Chris Koknat 2014 chris.koknat@gmail.com |
1109
|
|
|
|
|
|
|
|
1110
|
|
|
|
|
|
|
=head1 COPYRIGHT AND LICENSE |
1111
|
|
|
|
|
|
|
|
1112
|
|
|
|
|
|
|
This software is copyright (c) 2013-14 by Chris Koknat. |
1113
|
|
|
|
|
|
|
|
1114
|
|
|
|
|
|
|
This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. |
1115
|
|
|
|
|
|
|
|
1116
|
|
|
|
|
|
|
=cut |
1117
|
|
|
|
|
|
|
|