File Coverage

lib/Debug/Statements.pm
Criterion Covered Total %
statement 343 465 73.7
branch 189 308 61.3
condition 32 49 65.3
subroutine 30 31 96.7
pod 3 21 14.2
total 597 874 68.3


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