File Coverage

blib/lib/Fred/Fish/DBUG/ON.pm
Criterion Covered Total %
statement 858 1036 82.8
branch 416 626 66.4
condition 142 260 54.6
subroutine 85 91 93.4
pod 24 32 75.0
total 1525 2045 74.5


line stmt bran cond sub pod time code
1             ###
2             ### Copyright (c) 2007 - 2025 Curtis Leach. All rights reserved.
3             ###
4             ### Based on the Fred Fish DBUG macros in C/C++.
5             ### This Algorithm is in the public domain!
6             ###
7             ### Module: Fred::Fish::DBUG::ON
8              
9             =head1 NAME
10              
11             Fred::Fish::DBUG::ON - Fred Fish Live library for Perl
12              
13             =head1 SYNOPSIS
14              
15             use Fred::Fish::DBUG qw / ON /;
16             or
17             require Fred::Fish::DBUG;
18             Fred::Fish::DBUG->import (qw / ON /);
19              
20             Depreciated way.
21             use Fred::Fish::DBUG::ON;
22             or
23             require Fred::Fish::DBUG::ON;
24              
25             =head1 DESCRIPTION
26              
27             F is a pure Perl implementation of the C/C++ Fred Fish
28             macro libraries. While in C/C++ this library is implemented mostly via macros,
29             in Perl this library is implemented using true function calls. It has also
30             been slightly modified to address Perlish features over C/C++ ones. This can
31             make using some features a bit strange compared to C/C++. But the basic
32             concepts are the same.
33              
34             Using this module directly has been depreciated. You should be using
35             L instead. The list of functions listed below are a subset
36             of what's available there. It also provides a lot of other usefull information
37             not repeated here.
38              
39             =head1 FUNCTIONS
40              
41             =over 4
42              
43             =cut
44              
45             package Fred::Fish::DBUG::ON;
46              
47 43     43   450911 use strict;
  43         81  
  43         1670  
48 43     43   222 use warnings;
  43         74  
  43         2475  
49              
50 43     43   229 use vars qw( @ISA @EXPORT @EXPORT_OK $VERSION );
  43         75  
  43         3479  
51 43     43   382 use Exporter;
  43         157  
  43         2497  
52              
53 43     43   21198 use Perl::OSType ':all';
  43         24099  
  43         6975  
54 43     43   19936 use FileHandle;
  43         497694  
  43         273  
55 43     43   16455 use File::Basename;
  43         90  
  43         4251  
56 43     43   306 use Cwd 'abs_path';
  43         96  
  43         2942  
57 43     43   280 use Config qw( %Config );
  43         80  
  43         1997  
58 43     43   17731 use Sub::Identify 'sub_fullname';
  43         45008  
  43         7981  
59              
60             $VERSION = "2.10";
61             @ISA = qw( Exporter );
62              
63             # ------------------------------------------------------------------------------
64             # The special var @EXPORT contains the list of functions and constants exposed
65             # to the users of this module. The breakdown is as follows:
66             # 1) The 1st section is a list of exposed functions that a user may call.
67             # They mostly follow the Fred Fish standards!
68             # 2) The remaining sections are exposed constants that can be passed as values
69             # to exposed functions. They can also be used to test some return values.
70             # See the POD for more details!
71             #
72             # Function names that are in lower case will never be exposed! They are not for
73             # the general public and risk breaking your code between releases if used!
74             # Those that begin with underscores (_) are for internal use only to centralize
75             # common tasks.
76             # The others were written to help the t/*.t programs validate that this module
77             # worked as advertised. Exposing them would just polute Perl's name space.
78             # ------------------------------------------------------------------------------
79              
80              
81             @EXPORT = qw( DBUG_PUSH DBUG_POP
82             DBUG_ENTER_FUNC DBUG_ENTER_BLOCK DBUG_PRINT
83             DBUG_RETURN DBUG_ARRAY_RETURN
84             DBUG_VOID_RETURN DBUG_RETURN_SPECIAL
85             DBUG_LEAVE DBUG_CATCH DBUG_PAUSE
86             DBUG_MASK DBUG_MASK_NEXT_FUNC_CALL
87             DBUG_FILTER DBUG_SET_FILTER_COLOR
88             DBUG_CUSTOM_FILTER DBUG_CUSTOM_FILTER_OFF
89             DBUG_ACTIVE DBUG_EXECUTE
90             DBUG_FILE_NAME DBUG_FILE_HANDLE DBUG_ASSERT
91             DBUG_MODULE_LIST
92              
93             DBUG_SPECIAL_ARRAYREF DBUG_SPECIAL_COUNT
94             DBUG_SPECIAL_LAST
95              
96             DBUG_FILTER_LEVEL_FUNC DBUG_FILTER_LEVEL_ARGS
97             DBUG_FILTER_LEVEL_ERROR DBUG_FILTER_LEVEL_STD
98             DBUG_FILTER_LEVEL_WARN
99             DBUG_FILTER_LEVEL_DEBUG DBUG_FILTER_LEVEL_INFO
100             DBUG_FILTER_LEVEL_OTHER DBUG_FILTER_LEVEL_INTERNAL
101             );
102              
103             @EXPORT_OK = qw( );
104              
105             # NOTE: OFF.pm inherits all exposed functions and constants exported here.
106             # So if you add a new function, consider if it needs to be a stub in
107             # OFF.pm. Otherwise it's automatically available in OFF.pm. Done this
108             # way to keep this module and OFF.pm compatible.
109              
110             # Constants for use by DBUG_RETURN_SPECIAL () ...
111 43     43   373 use constant DBUG_SPECIAL_ARRAYREF => "_-"x40 . "_"; # A long random string ...
  43         95  
  43         5809  
112 43     43   262 use constant DBUG_SPECIAL_COUNT => "-_"x40 . "-"; # A long random string ...
  43         108  
  43         2974  
113 43     43   252 use constant DBUG_SPECIAL_LAST => "-="x40 . "="; # A long random string ...
  43         84  
  43         3075  
114              
115             # An array for convering the DBUG_FILTER_LEVEL_... constants into stings ...
116             my @dbug_levels;
117             my @dbug_custom_levels;
118              
119             # For filtering what get's written to fish ... (never use level 0)
120 43     43   309 use constant DBUG_FILTER_LEVEL_FUNC => 1; # Most restrictive.
  43         121  
  43         2509  
121 43     43   330 use constant DBUG_FILTER_LEVEL_ARGS => 2;
  43         161  
  43         2204  
122 43     43   366 use constant DBUG_FILTER_LEVEL_ERROR => 3;
  43         86  
  43         2376  
123 43     43   224 use constant DBUG_FILTER_LEVEL_STD => 4;
  43         88  
  43         2141  
124 43     43   202 use constant DBUG_FILTER_LEVEL_WARN => 5;
  43         91  
  43         3343  
125 43     43   243 use constant DBUG_FILTER_LEVEL_DEBUG => 6;
  43         85  
  43         2100  
126 43     43   210 use constant DBUG_FILTER_LEVEL_INFO => 7;
  43         90  
  43         2031  
127 43     43   211 use constant DBUG_FILTER_LEVEL_OTHER => 8; # Least restrictive.
  43         103  
  43         1952  
128              
129             # Used for debugging this module.
130 43     43   276 use constant DBUG_FILTER_LEVEL_INTERNAL => 99;
  43         97  
  43         2367  
131              
132             # So can easily add new levels and not have to worry about changing other code!
133 43     43   267 use constant DBUG_FILTER_LEVEL_MIN => DBUG_FILTER_LEVEL_FUNC;
  43         147  
  43         2196  
134 43     43   245 use constant DBUG_FILTER_LEVEL_MAX => DBUG_FILTER_LEVEL_OTHER;
  43         97  
  43         2122  
135              
136             # Names the unamed main function for the trace ...
137 43     43   454 use constant MAIN_FUNC_NAME => "main-prog";
  43         334  
  43         2167  
138              
139             # Value to use when masking sensitive data in fish ...
140 43     43   224 use constant MASKING_VALUE => "<******>";
  43         77  
  43         2142  
141              
142             # Value to use when making undefined values printable in fish ...
143 43     43   494 use constant UNDEF_VALUE => "";
  43         98  
  43         23706  
144              
145             # This hash variable holds all the global variables used by this module.
146             my %dbug_global_vars; # The current fish frame ...
147              
148             my $threads_possible; # Boolean flag telling if threads are supported.
149             my $fork_possible; # Boolean flag telling if forks are supported.
150             my $color_supported; # Boolean flag telling if Term::ANSIColor is avaailable.
151             my @color_list;
152             my $color_clear;
153             my $time_hires_flag; # Boolean flag telling if Time::HiRes is supported!
154              
155             # Holds the version of Perl & OS ...
156             my $dbug_log_msg;
157              
158             # So we can one day support multiple fish frames
159             sub _init_frame
160             {
161 80     80   183 my $frame_ref = shift; # A hash reference ...
162 80         190 my $old_stack = shift; # An array of hash reference ...
163              
164 80         238 $frame_ref->{can_close} = 0; # OK to close the file handle.
165 80         215 $frame_ref->{fh} = undef; # Fish's file handle.
166 80         240 $frame_ref->{file} = ""; # The full absolute path to fish file.
167 80         267 $frame_ref->{who_called} = 0; # Print func/file/line of caller.
168 80         156 $frame_ref->{no_end} = 0; # Turn off fish tracing for END blocks!
169 80         215 $frame_ref->{on} = 0; # Is Fish currently turned on or off.
170 80         183 $frame_ref->{pause} = 0; # Is Fish is currently paused?
171 80         208 $frame_ref->{multi} = 0; # Will we write the PID-TID or PID/xx pair to Fish?
172 80         164 $frame_ref->{limit} = 0; # Will we limit which thread to write to Fish?
173 80         161 $frame_ref->{screen} = 0; # Fish is writing to your screen.
174 80         227 $frame_ref->{strip} = 0; # Will fish strip the module part of func namee?
175 80         191 $frame_ref->{delay} = 0.0; # Will we delay after each write to fish?
176 80         182 $frame_ref->{elapsed} = 0; # Will we track elapsed time in your code?
177 80         163 $frame_ref->{keep} = 0; # Will we toss the logs on success? (keep on failure)
178 80         142 $frame_ref->{no_addresses} = 0; # Will we supress unique addresses for references?
179 80         183 $frame_ref->{dbug_leave_called} = 0; # Tells if DBUG_LEAVE() was called or not.
180 80         149 $frame_ref->{allow_utf8} = 0; # Will we support UTF8 chars to fish?
181              
182             # Used when forking a sub-process (not separate threads!)
183 80         590 $frame_ref->{PID} = $$; # The process PID.
184              
185             # Tell's how many return values by DBUG_RETURN() were to be masked.
186             # Only non-zero if DBUG_MASK() was called!
187             # You will always get the same results even if the return values
188             # weren't printed to fish.
189             # For DBUG_VOID_RETURN() it will always be zero!
190 80         169 $frame_ref->{mask_return_count} = 0;
191              
192             # The filtering tags ...
193 80         213 $frame_ref->{filter} = DBUG_FILTER_LEVEL_MAX;
194 80         215 $dbug_global_vars{pkg_lvl} = DBUG_FILTER_LEVEL_INTERNAL;
195 80         252 $frame_ref->{filter_style} = 1; # Standard filtering enabled ...
196              
197             # What to call the unnamed main function block in your code ...
198 80         260 $frame_ref->{main} = MAIN_FUNC_NAME;
199              
200             # Tells what functions are currently on the stack ...
201 80 100       304 if ( $old_stack ) {
202 37         147 $frame_ref->{functions} = $old_stack;
203             } else {
204 43         833 my @funcs; # Will be an array of hashes ...
205 43         167 $frame_ref->{functions} = \@funcs;
206             }
207              
208             # Flag tells if the exit status was printed in DBUG_LEAVE().
209 80         2322 $frame_ref->{printed_exit_status} = 0;
210              
211 80         208 return;
212             }
213              
214             # --------------------------------
215             # This BEGIN block handles the initialization of the DBUG frame logic.
216             # It can only call DBUG functions appearing before this function is defined!
217             # All BEGIN blocks are automatically executed when this module is 1st soruced
218             # in via 'use' or 'require'!
219             # --------------------------------
220             BEGIN
221             {
222 43     43   248 _init_frame ( \%dbug_global_vars, undef );
223              
224             # The array to convert the constant values into something human readable!
225 43         97 $dbug_levels[DBUG_FILTER_LEVEL_FUNC] = "DBUG_FILTER_LEVEL_FUNC";
226 43         128 $dbug_levels[DBUG_FILTER_LEVEL_ARGS] = "DBUG_FILTER_LEVEL_ARGS";
227 43         175 $dbug_levels[DBUG_FILTER_LEVEL_ERROR] = "DBUG_FILTER_LEVEL_ERROR";
228 43         2361 $dbug_levels[DBUG_FILTER_LEVEL_STD] = "DBUG_FILTER_LEVEL_STD";
229 43         133 $dbug_levels[DBUG_FILTER_LEVEL_WARN] = "DBUG_FILTER_LEVEL_WARN";
230 43         85 $dbug_levels[DBUG_FILTER_LEVEL_DEBUG] = "DBUG_FILTER_LEVEL_DEBUG";
231 43         124 $dbug_levels[DBUG_FILTER_LEVEL_INFO] = "DBUG_FILTER_LEVEL_INFO";
232 43         133 $dbug_levels[DBUG_FILTER_LEVEL_OTHER] = "DBUG_FILTER_LEVEL_OTHER";
233              
234             # The odd ball undocumented filter level.
235 43         166 $dbug_levels[DBUG_FILTER_LEVEL_INTERNAL] = "DBUG_FILTER_LEVEL_INTERNAL";
236              
237             # The custom levels are all off by default!
238             # $dbug_custom_levels[...] = 0;
239              
240 43         8527 return;
241             }
242              
243             # --------------------------------
244             # This BEGIN block detects if Perl supports threads.
245             # So that we can detect which thread we're in for logging purposes!
246             # Tests came from Test2::Util ...
247             # --------------------------------
248             BEGIN
249             {
250 43     43   157 $threads_possible = 0; # Threads are not supporteed ...
251              
252 43 50 33     8475 if ( $] >= 5.008001 && $Config{useithreads} ) {
253             # Threads are broken on Perl 5.10.0 built with gcc 4.8+
254 0         0 my $broken = 0;
255 0 0 0     0 if ($] == 5.010000 && $Config{ccname} eq 'gcc' && $Config{gccversion}) {
      0        
256 0         0 my @parts = split /\./, $Config{gccversion};
257 0 0 0     0 $broken = 1 if ($parts[0] > 4 || ($parts[0] == 4 && $parts[1] >= 8));
      0        
258             }
259              
260 0 0       0 unless ( $broken ) {
261 0         0 eval {
262 0         0 require threads;
263 0         0 threads->import ();
264 0         0 $threads_possible = 1; # Threads are supporteed after all ...
265             };
266             }
267             } # Ends if Perl > v5.8.1 && compiled with threads.
268             }
269              
270              
271             # --------------------------------
272             # This BEGIN block detects if Perl supports forking.
273             # So that we can detect which child process we're in for logging purposes!
274             # Tests came from Test2::Util ...
275             # --------------------------------
276             BEGIN
277             {
278 43     43   175 $fork_possible = 1; # Assuming fork is supporteed ...
279              
280 43 50       28646 unless ( $Config{d_fork} ) {
281 0 0 0     0 $fork_possible = 0 unless ($^O eq 'MSWin32' || $^O eq 'NetWare');
282 0 0       0 $fork_possible = 0 if ( $threads_possible == 0 );
283 0 0       0 $fork_possible = 0 unless ($Config{ccflags} =~ m/-DPERL_IMPLICIT_SYS/);
284             }
285             }
286              
287             # --------------------------------
288             # Tells if the optional Term::ANSIColor module is installed!
289             # Done this way so that color is an optional feature.
290             # --------------------------------
291             BEGIN
292             {
293 43     43   175 $color_supported = 0; # Assume color isn't supported!
294              
295 43         132 eval {
296 43 50       253 if ( $^O eq "MSWin32" ) {
297             # Windows needs this module for Term::ANSIColor to work.
298 0         0 require Win32::Console::ANSI;
299 0         0 Win32::Console::ANSI->import ();
300             }
301              
302 43         36058 require Term::ANSIColor;
303 43         510187 Term::ANSIColor->import ();
304              
305 43         3698 $color_supported = 1;
306             };
307             }
308              
309             # --------------------------------
310             # Tells if the HiRes timer is available ...
311             # Overrides the core time() & sleep() functions if available.
312             # --------------------------------
313             BEGIN
314             {
315 43     43   144 $time_hires_flag = 0; # Assume the HiRes timer isn't supported!
316              
317 43         88 eval {
318 43         345 require Time::HiRes;
319 43         327 Time::HiRes->import ( qw(time sleep) );
320 43         14318 $time_hires_flag = 1;
321             };
322             }
323              
324             # --------------------------------
325             # Builds the string for CPAN support ...
326             # --------------------------------
327             BEGIN
328             {
329 43     43   749 my $pv = sprintf ("%s [%vd]", $], $^V); # The version of perl!
330 43         368 my $flvr = os_type ();
331              
332 43         743 $dbug_log_msg = "Perl: $pv, OS: $^O, Flavor: $flvr\n";
333 43 50       262 $dbug_log_msg .= "Threads: " . ($threads_possible ? "Supported" : "Unsupported") . "\n";
334 43 50       197 $dbug_log_msg .= "Forking: " . ($fork_possible ? "Supported" : "Unsupported") . "\n";
335 43 50       128 $dbug_log_msg .= "Color: " . ($color_supported ? "Supported" : "Unsupported") . "\n";
336 43 50       159 $dbug_log_msg .= "HiRes: " . ($time_hires_flag ? "Supported" : "Unsupported") . "\n";
337 43         205 $dbug_log_msg .= "Program: $0\n";
338              
339             # Assume not running via a "make test" variant ...
340 43         95 my $make_test_flag = 0;
341              
342 43 50       200 if ( $ENV{PERL_DL_NONLAZY} ) {
    0          
    0          
343 43         89 $make_test_flag = 1; # Detects "make test" on Unix like systems ...
344              
345             } elsif ( $ENV{PERL_USE_UNSAFE_INC} ) {
346 0         0 $make_test_flag = 1; # Detects "gmake test" on Windows (Strawberry Perl) ...
347              
348             } elsif ( $ENV{HARNESS_ACTIVE} ) {
349 0         0 $make_test_flag = 1; # Detects "prove -vl t/*.t" ...
350             }
351              
352 43 50       152 if ( $make_test_flag ) {
353 43         175223 $dbug_log_msg .= "Run during a \"make test\" run.\n";
354             }
355             }
356              
357              
358             # --------------------------------
359             # END is automatically called when this module goes out of scope!
360             # --------------------------------
361             END
362             {
363             # Only happens if you call exit() directly, die due to an
364             # untrapped signal, or just return from your main program.
365             # If this happens the code never gets the chance to clean
366             # up properly. So doing it now!
367 43 100   43   421 unless ( $dbug_global_vars{dbug_leave_called} ) {
368 2         7 _dbug_leave_cleanup ();
369             }
370              
371             # Clear the function stack of all remaining entries ...
372 43         223 while ( pop (@{$dbug_global_vars{functions}}) ) { }
  43         269  
373              
374 43         266 DBUG_ENTER_FUNC (@_);
375              
376 43         253 _dbug_print_pkg_tag ( DBUG_FILTER_LEVEL_INFO,
377             "So Long, and Thanks for All the Fish!" );
378              
379 43 100       278 unless ( $dbug_global_vars{printed_exit_status} ) {
380 6         43 _dbug_print_pkg_tag ( DBUG_FILTER_LEVEL_INFO,
381             "Exit Status (%d)", $? );
382             }
383              
384 43         246 DBUG_VOID_RETURN ();
385              
386             # ------------------------------------------------
387             # Implements: keep => 1 or keep => \&test().
388             # ------------------------------------------------
389 43         90 my $toss_the_file;
390 43 0 33     260 if ( $dbug_global_vars{keep} && $dbug_global_vars{file} ) {
391 0         0 my $keep = ($? != 0);
392 0 0       0 if ( ref ($dbug_global_vars{keep}) eq "CODE" ) {
393 0         0 $keep = $dbug_global_vars{keep}->($?);
394             }
395 0 0       0 $toss_the_file = $dbug_global_vars{file} unless ( $keep );
396             }
397              
398 43         130 $dbug_global_vars{on} = 0; # Turn fish off.
399              
400 43 100       229 if ( $dbug_global_vars{can_close} ) {
401 36         128 my $dbug_fh = $dbug_global_vars{fh};
402 36         848 close ( $dbug_fh );
403             }
404              
405             # Finishes: keep => ?.
406 43 50       2224 unlink ( $toss_the_file ) if ( $toss_the_file );
407             }
408              
409              
410             # --------------------------------
411             # Tells if you are in the required thread/process ...
412             # Returns:
413             # 1 - You are in the correct thread
414             # 0 - You are in the wrong thread.
415             # --------------------------------
416             sub _limit_thread_check
417             {
418 18211 50   18211   70147 return (1) unless ( $dbug_global_vars{limit} );
419              
420             # Which thread/process are we in ...
421 0         0 my $parent = 0;
422 0 0       0 if ( $dbug_global_vars{PID} == $$ ) {
423 0 0       0 my $tid = ( $threads_possible ) ? threads->tid () : 0;
424 0 0       0 $parent = 1 if ( $tid == 0 );
425             }
426              
427 0 0 0     0 return (1) if ( $parent == 1 && $dbug_global_vars{limit} == 1 );
428 0 0 0     0 return (1) if ( $parent == 0 && $dbug_global_vars{limit} == -1 );
429              
430 0         0 return (0); # In the wrong thread/process ...
431             }
432              
433             # --------------------------------
434             # This function handles all printing to the fish logs.
435             # Done this way so we don't have to call "or die" all over the place or check
436             # if fish is active all the time or not. This slows the module down slightly
437             # when fish is turned off, but makes the coding significantly simpler.
438             # If formatted printing is desired, just use "sprintf" & then call this method!
439             # Returns:
440             # 0 - Nothing written to fish
441             # 1 - Something was written to fish
442             # Calls die if the write fails!
443             # --------------------------------
444             sub _printing
445             {
446             # Fish must be active to print anything ...
447 9155 100   9155   17047 return (0) unless ( DBUG_ACTIVE () );
448              
449 8777         31882 my $dbug_fh = $dbug_global_vars{fh};
450              
451 8777 100       17213 if ( defined $dbug_fh ) {
452 8752 50       310943 print $dbug_fh @_ or
453             die ("Can't write the mesage to the fish file! $!\n");
454             } else {
455             # Open, write, close the fish file ... doesn't return on error!
456 25         57 _dbug_auto_open_printing (@_);
457             }
458              
459 8777         28636 return (1);
460             }
461              
462              
463             # For inserting color directives into preformatted multi-line messages ...
464             sub _printing_with_color
465             {
466 111     111   218 my $lvl = shift;
467              
468 111         364 my @colors = _get_filter_color ( $lvl );
469 111 50       440 if ( $colors[0] eq "" ) {
470 111         416 return ( _printing ( @_ ) ); # No color asked for.
471             }
472              
473             # Join the rest of the arguments into a single message to parse!
474 0         0 my $msg = join ("", @_);
475              
476 0         0 my $term = "-_"x100 . "-";
477 0         0 my @lines = split ( /\n/, $msg . $term );
478              
479 0         0 my ($build, $sep) = ("", "");
480 0         0 my $final = $lines[-1];
481              
482 0         0 foreach my $ln ( @lines ) {
483 0 0 0     0 if ( (! defined $ln) || $ln eq $term || $ln =~ m/^\s*$/ ) {
    0 0        
484 0         0 $build .= $sep; # Blank lines have no color!
485             } elsif ( $ln eq $final ) {
486 0         0 $ln =~ s/${term}$//;
487 0         0 $build .= $sep . $colors[0] . $ln . $colors[1];
488             } else {
489 0         0 $build .= $sep . $colors[0] . $ln . $colors[1];
490             }
491              
492 0         0 $sep = "\n";
493             }
494              
495 0         0 return ( _printing ( $build ) );
496             }
497              
498             # --------------------------------
499             # To handle printing for the auto-open option ... (very slow!)
500             # Only called via _printing()! Never by anyone else!
501             # --------------------------------
502             sub _dbug_auto_open_printing
503             {
504 25     25   58 my $f = $dbug_global_vars{file};
505 25 50       57 unless ($f) {
506 0         0 die ("No fish file name available for auto-reopen to use!\n");
507             }
508 25 50       1417 open (REOPEN_FISH_FILE, ">>", $f) or
509             die ("Can't reopen the FISH file: " . basename ($f) . " $!\n");
510 25 50       100 if ( $dbug_global_vars{allow_utf8} ) {
511 0         0 binmode (REOPEN_FISH_FILE, "encoding(UTF-8)");
512             }
513              
514 25 50       310 print REOPEN_FISH_FILE @_ or
515             die ("Can't write the mesage to the reopened fish file! $!\n");
516 25         1119 close (REOPEN_FISH_FILE);
517 25         100 return (1);
518             }
519              
520             # --------------------------------
521             # These 2 private functions handle indenting each line written to fish!
522             # It builds & returns the string to use to allow the caller to
523             # combine calls to _printing(), just in case using the auto-reopen logic,
524             # which is slow, slow, slow, ...
525             # Or if multiple threads are writing to fish to make the calls atomic!
526             # --------------------------------
527             sub _indent_multi
528             {
529 15012   100 15012   45873 my $remove = shift || 0;
530              
531             # A no-op if option multi wasn't used ...
532 15012 100       41006 return ( "" ) unless ( $dbug_global_vars{multi} );
533              
534 935         5550 my ($tid, $fid, $ind_str) = (-1, -1, "");
535              
536             # Gives preference to logging threads over forks ...
537              
538             # Logging Threads ...
539 935 50       3292 $tid = threads->tid () if ( $threads_possible );
540              
541             # Logging Forks ...
542 935 50       2084 if ( $fork_possible ) {
543 935 100       6131 if ( $dbug_global_vars{PID} == $$ ) {
544 611 50       1637 $fid = 0 if ( $tid == -1 );
545             } else {
546 324         1409 my $id = ( abs ($$) % 100 );
547 324 50       990 $fid = ($id == 0) ? 100 : $id;
548 324 50       980 $tid = -1 if ( $tid == 0 );
549             }
550             }
551              
552             # Build the line's prefix ...
553 935 50 33     3526 if ( $tid != -1 && $fid != -1 ) {
    50          
    50          
554             # Both threads and forks ...
555 0         0 $ind_str .= sprintf ( "%d/%02d-%d", $$, $fid, $tid );
556             } elsif ( $tid != -1 ) {
557             # Threads only ...
558 0         0 $ind_str .= sprintf ( "%d-%d", $$, $tid );
559             } elsif ( $fid != -1 ) {
560             # Forks only ...
561 935         5130 $ind_str .= sprintf ( "%d/%02d", $$, $fid );
562             } else {
563             # Neither threads nor forks are supported ...
564 0         0 $ind_str = $$;
565             }
566              
567             # Easier to not add it than remove it ...
568 935 100       2465 $ind_str .= ":: " if ( $remove == 0 );
569              
570 935         3046 return ( $ind_str );
571             }
572              
573              
574             # Determines how deep to indent each row ...
575             sub _indent
576             {
577 9006   50 9006   22446 my $label = shift || "";
578              
579 9006         20163 my $ind_str = _indent_multi ();
580              
581             # Building the indenting string ... "| | | | | ..."
582 9006         14818 my $cnt = @{$dbug_global_vars{functions}};
  9006         18061  
583 9006         25854 $ind_str .= "| "x$cnt . $label;
584              
585 9006         23584 return ($ind_str);
586             }
587              
588              
589             # ==============================================================
590             # A helper function ...
591             # Returns the number of evals on the stack + an array refernce containing
592             # the line number each eval appears on.
593             sub _eval_depth
594             {
595 10805   50 10805   24902 my $base = shift || 0; # The caller() index to the code that called DBUG_...
596              
597 10805         17960 my @eval_lines;
598              
599 10805         16656 my $eval_lvl = 0;
600 10805         64339 my ($c2, $ln2) = (caller ($base + $eval_lvl))[3,2];
601 10805         30709 while ( defined $c2 ) {
602 52375 100       97753 if ( $c2 eq "(eval)" ) {
603 5607         10175 ++$eval_lvl; # Just count how deep in eval's we are!
604 5607         11455 push (@eval_lines, $ln2);
605             } else {
606 46768         67454 ++$base; # Wasn't an eval!
607             }
608 52375         208032 ($c2, $ln2) = (caller ($base + $eval_lvl))[3,2];
609             }
610              
611 10805 50       36258 return ( wantarray ? ( $eval_lvl, \@eval_lines) : $eval_lvl );
612             }
613              
614              
615             # ==============================================================
616             # A helper function for elapsed time ...
617             sub _dbug_elapsed_time
618             {
619 786     786   2245 my $start_clock = shift;
620              
621 786 100       4748 return ("") unless ( $dbug_global_vars{elapsed} );
622 14 50       34 return ("") unless ( defined $start_clock );
623              
624 14         54 my $elapsed_time = time () - $start_clock;
625              
626 14         40 my $msg;
627 14 50       31 if ( $time_hires_flag ) {
628 14         146 $msg = sprintf (" -- Elapsed time: %0.6f second(s)", $elapsed_time);
629             } else {
630 0         0 $msg = sprintf (" -- Elapsed time: %d second(s)", $elapsed_time);
631             }
632              
633 14         46 return ( $msg );
634             }
635              
636             # ==============================================================
637             # A helper function ...
638             # This will never return a Fred::Fish::DBUG::ON funtion as the caller!
639             # It will return who called the DBUG function instead!
640             # So sometimes the caller looks a bit indirect!
641             # Returns: " -- caller at file line 1234"
642             # or: "caller at file line 1234"
643             sub _dbug_called_by
644             {
645             # Uncomment next 2 lines to demonstrate potential problem with t/*.t progs...
646             # _dbug_auto_fix_eval_exception ();
647             # _printing ("XXXX: Inside of _dbug_called_by(", join (", ", @_), ")\n");
648              
649             # Only happens if called by any of the t/*.t program hacks as an object!
650 447 100 66 447   2059 shift if ( defined $_[0] && $_[0] eq __PACKAGE__ );
651              
652             # The real arguments ...
653 447   100     1240 my $no_prefix_flg = shift || 0;
654 447   100     1388 my $dbug_enter_flg = shift || 0; # Called by DBUG_ENTER_FUNC() ?
655 447   100     1333 my $anon_flag = shift || 0; # Ignored unless $dbug_enter_flg is true.
656              
657              
658 447         724 my $eval_caller = '(eval)';
659 447         708 my $pkg = __PACKAGE__ . '::';
660 447         2707 $pkg =~ s/::ON::$/::/;
661              
662             # Start with who called me ...
663 447         1103 my ($ind_by, $ind_call) = (1, 0);
664              
665 447   66     2870 my $by = (caller($ind_by))[3] || $dbug_global_vars{main};
666              
667             # Find caller of the 1st Fred::Fish::DBUG::ON entry point ...
668 447   100     3937 while ( $by =~ m/^${pkg}/ || $by eq $eval_caller ) {
669 952 100       3474 $ind_call = $ind_by if ( $by =~ m/^${pkg}/ );
670 952   66     6881 $by = (caller(++$ind_by))[3] || $dbug_global_vars{main};
671             }
672              
673             # Get the line number of where the calling function was called.
674             # Only happens when called by DBUG_ENTER_FUNC() & it asked for it.
675             # Will never return as the caller another DBUG function!
676 447 100 66     1308 if ( $dbug_enter_flg && $by ne $dbug_global_vars{main} ) {
677 55         88 $by = $pkg; # So I'll skip over the current function!
678              
679 55   100     249 while ( $by =~ m/^${pkg}/ || $by eq $eval_caller ) {
680 96 100       311 $ind_call = $ind_by if ( $by =~ m/^${pkg}/ );
681             # ++$ind_call if ( $by ne $eval_caller );
682 96   66     586 $by = (caller(++$ind_by))[3] || $dbug_global_vars{main};
683             }
684              
685             # HACK: If called in a try/catch/finally block ...
686             # Then was called with wrong arguments to this function!
687             # So ask caller to try again with $dbug_enter_flg set to 0!
688 55 100       103 if ( $anon_flag ) {
689 2 50       6 return ("") if ( $by eq "Try::Tiny::try" );
690 2 50       4 return ("") if ( $by eq "Try::Tiny::ScopeGuard::DESTROY" );
691 2 50       4 return ("") if ( $by eq "Error::subs::try" );
692             }
693             }
694              
695             # Get file & line number ...
696 447         1641 my @c = (caller($ind_call))[1,2];
697              
698 447 100       1279 my $prefix = ($no_prefix_flg) ? "" : " -- ";
699 447         756 my $line;
700 447 50       1054 if ( $#c == -1 ) {
701 0         0 $line = sprintf ("%s%s at ? line ?", $prefix, $by); # Can we fix?
702             } else {
703 447         1858 $line = sprintf ("%s%s at %s line %d", $prefix, $by, @c);
704             }
705              
706             # (${ind_by} > ${ind_call}) is always true! Never equal!
707             # $line .= " IDX: ${ind_by}, ${ind_call}";
708              
709 447         1734 return ( $line );
710             }
711              
712             # ==============================================================
713             # Allows for a quick and dirty way to cheat this module without
714             # giving you access to the underlying module configuration
715             # variable %dbug_global_vars.
716             # It tells which key(s) to temporarily override before calling
717             # the requested function without having to worry about the
718             # scope of the change.
719             # Since not exposed, you don't have access to it by default and
720             # can remain undocumentded in the POD.
721             # For use by my helper modules and t/*.t programs only!
722             # Also use internally by the Signal handling & TIE routines!
723             # --------------------------------------------------------------
724             # Usage: $res = Fred::Fish::DBUG::ON::_dbug_hack ( %opts, $func, @args);
725             sub _dbug_hack
726             {
727 894     894   1787 my $key = shift;
728 894         1694 my $val = shift;
729 894         1716 my $func = shift; # May be start of another key/val pair instead!
730             # my @args = @_;
731              
732             # Usage error ... no hash key provided.
733 894 50       2371 rturn (undef) unless ( $key );
734              
735             # If undef, don't change the value ...
736 894 100       2337 $val = $dbug_global_vars{$key} unless ( defined $val );
737              
738             # ERROR: Can only replace with the same data type ...
739 894 50       3031 return (undef) if ( ref ($val) ne ref ($dbug_global_vars{$key}) );
740              
741 894         2348 local $dbug_global_vars{$key} = $val;
742              
743 894 100 66     4006 if ( $func && ref ($func) eq "CODE" ) {
744 655         2118 return ( $func->( @_ ) );
745             }
746              
747             # Recursively add the next key/value pair ...
748 239         719 return ( _dbug_hack ($func, @_) );
749             }
750              
751             # --------------------------------------------------------------
752             # Get the requested entry in the global hash ...
753             # --------------------------------------------------------------
754             sub _get_global_var
755             {
756 481     481   897 my $key = shift;
757 481         2610 return ( $dbug_global_vars{$key} );
758             }
759              
760             # --------------------------------------------------------------
761             # Permanently set the requested entry in the global hash ...
762             # --------------------------------------------------------------
763             sub _set_global_var
764             {
765 292     292   558 my $key = shift;
766 292         479 my $val = shift;
767 292         612 $dbug_global_vars{$key} = $val;
768 292         709 return;
769             }
770              
771             # ------------------------------------------------------------------------------
772             # DBUG Code
773             #
774             # I have tried to keep the functions in a meaningfull order, to make it
775             # easier to learn how to use this module.
776             #
777             # ------------------------------------------------------------------------------
778              
779             =item DBUG_PUSH ( [$file [, %opts]] )
780              
781             Calling this function turns logging on so that all future DBUG B calls are
782             written to the requested file. Failure to call this function results in nothing
783             being written to the B logs. Currently there is no way to turn B
784             back off again except by aborting the program. But there are ways to turn
785             some of the logging off.
786              
787             You are expected to provide a filename to write the fish logs to. If
788             that file already exists, this function will recreate the B file and
789             write as its first log message that this happened. By default, the B
790             log's file permissions allow anyone to read the log file no matter the current
791             I settings.
792              
793             But if you fail to provide a filename, B will instead be written to
794             I. You may also use an open file handle or I reference instead
795             of a filename and B would be written there instead.
796              
797             The options hash may be passed by either reference or value. Either way works.
798             Most options are ignored unless you also gave it a filename to open.
799             Most option's value is a flag telling if it's turned on (1) or off (0), and
800             most options default to off unless otherwise specified. The valid options are:
801              
802             =over 4
803              
804             B - Open an old B log in append mode instead of creating a new
805             one.
806              
807             B - Turn autoflush on/off. By default it's turned on!
808              
809             B - Turn auto-open on/off. Causes each call to a B function to
810             auto-reopen the B log, write out its message, and then close the B
811             file again.
812              
813             B - If set, treat as if I was never called! (IE: Fish is off.)
814             It overrides all other options.
815              
816             B - See I for more details.
817              
818             B - Suppress the B logging for the Perl B blocks.
819              
820             B - Adds I to the end of the enter function
821             block. So you can locate the code making the call. Also added to the end of
822             I messages.
823              
824             B - Turns on/off writing process ownership info to the start of each line
825             of the B log. For multi-thread programs this is B-B.
826             Ex: 252345-0 is the main process && 252345-4 is the 4th thread spawned by the
827             process. But if it's a forked process it would be B/B<2-digits>.
828             Ex: 252345/00 is the main process. And 536435/35 is one of its forked child
829             processes. There are no sequential ids for forked processes, nor is the 2-digit
830             code guaranteed to be unique.
831              
832             B - If your program is multi-threaded or muli-process, use this option to
833             limit what gets written to B. B<1> - Limit B to the parent process.
834             B<0> - Write everything (default). B<-1> - Limit B to the child processes.
835              
836             B - Override the default B file permissions. Default is B<0644>.
837             It ignores the current I settings!
838              
839             B - Normally the 1st call to I is after the call to
840             I, but set to B if you've already called it. But you will lose
841             printing the function arguments if you do it this way.
842              
843             B - Strip off the module name for I and the various
844             return methods. So I becomes I in B.
845              
846             B - Number of seconds to sleep after calling I in your code.
847             The delay only happens if the write to B actually happens.
848             If I is installed you can sleep for fractions of a second. But if
849             it isn't installed your time will be truncated. IE: 0.5 becomes 0.
850              
851             B - Prints the elapsed time inside the function once any DBUG return
852             function is called. If I is installed it tracks to fractions of a
853             second. Otherwise it's whole seconds only.
854              
855             B - (1/0/code ref) - (1) Keep your B log only if your program exits
856             with a non-zero exit status. (0) Always keep your B log (default).
857             Otherwise it calls your function with the exit status as it's single argument.
858             It's expected to return B<1> to keep the B log or B<0> to toss it. This
859             code ref is only called if there is a B log to potentially remove.
860              
861             B - (1/0) - (0) Default, print variable reference addresses like
862             S which change between runs. (1) Suppress addresses so shows
863             up like S so it's easier to compare fish files between runs. Only
864             works for arguments and return values.
865              
866             B - Writes to B in UTF-8 mode. Use if you get warnings
867             about writing S<'Wide character in print'> to B.
868              
869             =back
870              
871             =cut
872              
873             # ==============================================================
874             sub DBUG_PUSH
875             {
876 38     38 1 2599 my $file = shift;
877 38 50       324 my $opts = (ref ($_[0]) eq "HASH") ? $_[0] : {@_};
878              
879 38 50       220 if ( $dbug_global_vars{on} ) {
880 0         0 warn "You may not call DBUG_PUSH() more than once!\n";
881 0         0 return;
882             }
883              
884             # Check if eval needs rebalancing ...
885 38         198 _dbug_auto_fix_eval_exception ();
886              
887 38 100       142 if ( $opts->{off} ) {
888             # warn "You disabled fish, no fish logs are kept!\n";
889 1         2 return;
890             }
891              
892             # DBUG_SET_FILTER_COLOR ( DBUG_FILTER_LEVEL_INTERNAL, "green" );
893              
894             # Set all flags to a default value ...
895 37         80 my @lst = @{$dbug_global_vars{functions}};
  37         111  
896 37         216 _init_frame ( \%dbug_global_vars, \@lst );
897              
898 37 100       275 $dbug_global_vars{no_end} = 1 if ( $opts->{kill_end_trace} );
899 37 100       176 $dbug_global_vars{who_called} = 1 if ( $opts->{who_called} );
900 37 100       239 $dbug_global_vars{multi} = 1 if ( $opts->{multi} );
901 37 50       207 $dbug_global_vars{strip} = 1 if ( $opts->{strip} );
902 37 100       152 $dbug_global_vars{elapsed} = 1 if ( $opts->{elapsed} );
903 37 50       174 $dbug_global_vars{no_addresses} = 1 if ( $opts->{no_addresses} );
904 37 100       223 $dbug_global_vars{allow_utf8} = 1 if ( $opts->{allow_utf8} );
905              
906 37 50       178 if ( $opts->{keep} ) {
907 0 0       0 if ( ref ($opts->{keep}) eq "CODE" ) {
908 0         0 $dbug_global_vars{keep} = $opts->{keep};
909             } else {
910 0         0 $dbug_global_vars{keep} = 1;
911             }
912             }
913              
914 37 50       183 if ( $opts->{limit} ) {
915 0 0       0 $dbug_global_vars{limit} = ( $opts->{limit} > 0 ) ? 1 : -1;
916             }
917              
918 37 100 66     420 if ( $opts->{delay} && $opts->{delay} =~ m/(^\d+$)|(\d+\.\d+$)/ ) {
    50          
919 1         4 $dbug_global_vars{delay} = $opts->{delay};
920 1 50       4 unless ( $time_hires_flag ) {
921 0 0       0 if ( $dbug_global_vars{delay} =~ s/[.]\d+$// ) {
922             warn ( "Time::HiRes isn't installed. Truncating delay to ",
923 0         0 $dbug_global_vars{delay}, ".\n" );
924             }
925             }
926             } elsif ( $opts->{delay} ) {
927 0         0 warn ( "Option 'delay' isn't numeric, so the delay request is ignored!\n" );
928             }
929              
930 37         259 DBUG_FILTER ($opts->{filter});
931              
932 37 50       158 $file = \*STDERR unless ( defined $file );
933              
934 37 50       156 if ( ref ($file) eq "GLOB" ) {
935 0 0 0     0 if ( $file == \*STDERR || $file == \*STDOUT ) {
936 0         0 $dbug_global_vars{screen} = 1;
937             }
938              
939             # Enable writing to the open file handle by fish ...
940 0         0 $dbug_global_vars{on} = 1;
941              
942             # Provided an open file handle to write to ...
943 0         0 $dbug_global_vars{fh} = $file;
944 0         0 return;
945             }
946              
947 37 50       151 if ( ref ($file) ne "" ) {
948 0         0 die ("Unknown reference for a filename: " . ref($file) . "\n");
949             }
950              
951             # Trim leading/trailing spaces from the file name.
952 37         178 $file =~ s/^\s+//;
953 37         128 $file =~ s/\s+$//;
954 37 50       124 die ("The filename can't be all spaces!\n") if ( $file eq "" );
955              
956             # Now let's acutally open up the file ... if we were given a name ...
957              
958             # Don't need to remember this option ...
959 37         79 my $flush = 1;
960 37 50 33     192 if ( exists $opts->{autoflush} && ! $opts->{autoflush} ) {
961 0         0 $flush = 0;
962             }
963              
964             # Get the old fish log file's age ...
965 37         162 my ($age, $overwritten, $type, $mode) = (0, 0, "day(s)", ">");
966 37 50       2690 if ( -f $file ) {
967 0         0 $age = -M _;
968 0 0       0 if ( $age < 1 ) {
969 0         0 $age *= 24; $type = "hour(s)";
  0         0  
970 0 0       0 if ( $age < 1 ) {
971 0         0 $age *= 60; $type = "minute(s)";
  0         0  
972 0 0       0 if ( $age < 1 ) {
973 0         0 $age *= 60; $type = "second(s)";
  0         0  
974             }
975             }
976             }
977              
978 0 0       0 if ( $opts->{append} ) {
979 0         0 $mode = ">>";
980             } else {
981 0         0 $overwritten = 1;
982 0         0 unlink ( $file );
983             }
984             }
985              
986 37 50       7305 open ( FISH_FILE, $mode, $file ) or
987             die ("Can't open the fish file for writing: $file ($!)\n");
988 37 50       1132 FISH_FILE->autoflush (1) if ( $flush );
989 37 100       2608 if ( $dbug_global_vars{allow_utf8} ) {
990 1     1   24 binmode (FISH_FILE, "encoding(UTF-8)");
  1         636  
  1         13  
  1         33  
991             }
992 37         15785 $dbug_global_vars{fh} = \*FISH_FILE;
993              
994             # If we're going to auto-open/close the file, we need to always have
995             # a full absolute path name to the file instead of a relatve file name!
996             # Just in case the program changes directories on us!
997             # On Windows, this file must always exists for this to work!
998 37         1777 $dbug_global_vars{file} = abs_path ($file);
999              
1000             # Allow writing to the fish log ...
1001             # Must set only after the fish log has been opened!
1002 37         120 $dbug_global_vars{on} = 1;
1003              
1004 37 50       331 if ( $overwritten ) {
    50          
1005 0         0 my $fmt = " *** Overwrote a previous fish file of the same name. ***\n"
1006             . " *** Previous file was last written to %0.3f %s ago. ***\n\n";
1007 0         0 _printing_with_color ( DBUG_FILTER_LEVEL_INTERNAL,
1008             sprintf ( $fmt, $age, $type ) );
1009              
1010             } elsif ( $mode eq ">>" ) {
1011 0 0       0 my $id = $dbug_global_vars{multi} ? _indent_multi (1) : $$;
1012              
1013 0         0 my $msg = "\n" . "="x70 .
1014             "\n*** Appending to a pre-existing fish log. PID ($id)\n";
1015 0         0 $msg .= sprintf ("*** The log was last written to %0.3f %s ago.\n", $age, $type);
1016 0         0 $msg .= "="x70 . "\n\n";
1017 0         0 _printing_with_color ( DBUG_FILTER_LEVEL_INTERNAL, $msg );
1018             }
1019              
1020             # Print out the CPAN support info to FISH ...
1021 37         348 _printing_with_color ( DBUG_FILTER_LEVEL_INTERNAL,
1022             sprintf ("%s %s\n", __PACKAGE__, $VERSION) );
1023 37         143 _printing_with_color ( DBUG_FILTER_LEVEL_INTERNAL, $dbug_log_msg );
1024 37         154 _printing "\n";
1025              
1026             # ------------------------------------------------------------------
1027             # Tells what options were selected for generating the fish file ...
1028             # ------------------------------------------------------------------
1029 37         90 my $opts_prefix = "DBUG_PUSH Options: ";
1030 37         181 my ($opts_str, $sep) = ("", "");
1031 37         227 foreach my $k ( sort keys %{$opts} ) {
  37         261  
1032 62         131 my $str;
1033 62 50 33     307 if ( $k eq "chmod" && defined $opts->{chmod} ) {
1034 0         0 $str = sprintf ("%s => 0%o", $k, $opts->{$k});
1035             } else {
1036 62         236 $str = sprintf ("%s => %s", $k, $opts->{$k});
1037             }
1038 62         179 $opts_str .= ${sep} . ${str};
1039 62         186 $sep = ", ";
1040             }
1041 37 100       192 if ( $opts_str eq "" ) {
1042 4         12 $opts_str = ${opts_prefix} . "\n\n";
1043             } else {
1044 33         99 $opts_str = ${opts_prefix} . ${opts_str} . "\n\n";
1045             }
1046 37         256 _printing_with_color ( DBUG_FILTER_LEVEL_INTERNAL, _indent ($opts_str) );
1047             # ------------------------------------------------------------------
1048              
1049 37 50       185 if ( defined $opts->{chmod} ) {
1050 0         0 chmod (oct ($opts->{chmod}), $file);
1051             } else {
1052 37         1661 chmod (0644, $file); # So it's always -rw-r--r--.
1053             }
1054              
1055 37 100       228 if ( $opts->{autoopen} ) {
1056 1         12 close (FISH_FILE);
1057 1         4 $dbug_global_vars{fh} = undef;
1058             } else {
1059 36         119 $dbug_global_vars{can_close} = 1;
1060             }
1061              
1062             # Check if we have to print the previous function declaration ...
1063             # We've lost the arguments if this option was used!
1064             # We've also lost the start time if asked for!
1065 37 50 33     280 if ( $opts->{before} && $#lst != -1 ) {
1066 0         0 my $block = pop ( @{$dbug_global_vars{functions}} );
  0         0  
1067 0         0 my $func = $block->{NAME};
1068 0         0 my $line = $block->{LINE};
1069 0         0 _printing ( $block->{COLOR1}, _indent (">${func}${line}"), $block->{COLOR2}, "\n");
1070 0         0 push ( @{$dbug_global_vars{functions}}, $block );
  0         0  
1071             }
1072              
1073 37         276 return;
1074             }
1075              
1076              
1077             =item DBUG_POP ( )
1078              
1079             Not yet implemented.
1080              
1081             =cut
1082              
1083             # ==============================================================
1084             sub DBUG_POP
1085             {
1086 0     0 1 0 warn "DBUG_POP() is currently a NO-OP!\n";
1087             }
1088              
1089              
1090             =item DBUG_ENTER_FUNC ( [@arguments] )
1091              
1092             Its expected to be called whenever you enter a function. You pass all the
1093             arguments from the calling function to this one (B<@_>). It automatically
1094             knows the calling function without having to be told what it is.
1095              
1096             To keep things in the B logs balanced, it expects you to call one of the
1097             I variant methods when exiting your function!
1098              
1099             This function also works when called inside named blocks such as B blocks
1100             or even try/catch blocks.
1101              
1102             It returns the name of the calling function. In rare cases this name can be
1103             useful.
1104              
1105             See I should you need to mask any arguments!
1106              
1107             =cut
1108              
1109             # ==============================================================
1110             sub DBUG_ENTER_FUNC
1111             {
1112             # Who called this function ...
1113 1027   66 1027 1 7940711 my $func = (caller (1))[3] || $dbug_global_vars{main};
1114              
1115             # Check if eval needs rebalancing ...
1116 1027         5780 _dbug_auto_fix_eval_exception ();
1117              
1118             # Count how deep in eval blocks we are so DBUG_CATCH can work!
1119 1027         2416 my ($eval_cnt, $eval_lns) = _eval_depth (1);
1120 1027         2027 my $eval_flg = 0;
1121 1027 100       2575 if ( $func eq "(eval)" ) {
1122 35         133 $func .=" [${eval_cnt}, " . $eval_lns->[0] . "]";
1123 35         87 $eval_flg = 1;
1124             }
1125              
1126             # This special function traps calls to undefined functions.
1127             # So we want to know what the user was really calling by
1128             # referencing the special variable named after the function!
1129 1027 100       3893 if ( $func =~ m/::AUTOLOAD$/ ) {
1130 43     43   447 no strict; # So can indirectly access the variable as a ref.
  43         105  
  43         405945  
1131 8         9 my $aka = ${$func};
  8         23  
1132 8 50 33     26 $aka = $1 if ( $dbug_global_vars{strip} && $aka =~ m/::([^:]+)$/ );
1133 8         17 $func .= " ";
1134             }
1135              
1136             # Do we need to know who called ${func} at this time ???
1137 1027         2414 my $line="";
1138 1027 100 100     3407 if ( $dbug_global_vars{who_called} && $func ne $dbug_global_vars{main} ) {
1139             # Special functions where there are no valid callers ...
1140 71 100 66     837 if ( $eval_flg || $func =~ m/::END$/ || $func =~ m/::BEGIN$/ ||
    100 100        
      100        
      100        
      100        
      100        
      100        
      100        
1141             $func =~ m/::UNITCHECK$/ || $func =~ m/::CHECK$/ || $func =~ m/::INIT$/ ||
1142             $func =~ m/::DESTROY$/ ) {
1143 15         35 $line = _dbug_called_by (0, 0, 0);
1144              
1145             # When Try::Tiny renames the __ANON__ function to ... "YourModule::xxx {...}"
1146             # It doesn't always do this ...
1147             } elsif ( $func =~ m/::try [{][.]{3}[}]\s*$/ ||
1148             $func =~ m/::catch [{][.]{3}[}]\s*$/ ||
1149             $func =~ m/::finally [{][.]{3}[}]\s*$/ ) {
1150 3         6 $line = _dbug_called_by (0, 0, 0);
1151              
1152             # Want who called the logged function, not who called DBUG_ENTER_FUNC ...
1153             } else {
1154 53         98 my $may_be_a_try_catch_finally_event = ( $func =~ m/::__ANON__$/ );
1155 53         102 $line = _dbug_called_by (0, 1, $may_be_a_try_catch_finally_event);
1156 53 50       115 $line = _dbug_called_by (0, 0, 0) unless ( $line );
1157             }
1158             }
1159              
1160             # Put a blank line before all END blocks ...
1161 1027 100       4035 my $skip = ( $func =~ m/::END$/ ) ? "\n" : "";
1162              
1163             # Strip off any module info from the calling function's name?
1164 1027 50 33     3192 $func = $1 if ( $dbug_global_vars{strip} && $func =~ m/::([^:]+)$/ );
1165              
1166 1027         3343 my @colors = _get_filter_color (DBUG_FILTER_LEVEL_FUNC);
1167 1027 100       2617 if ( DBUG_EXECUTE ( DBUG_FILTER_LEVEL_FUNC ) ) {
1168 948         3909 _printing ( $skip, $colors[0], _indent (">${func}${line}"), $colors[1], "\n");
1169             }
1170              
1171             my %block = ( NAME => $func,
1172             PAUSED => $dbug_global_vars{pause},
1173 1027         12340 EVAL => $eval_cnt,
1174             EVAL_LN => $eval_lns->[0],
1175             LINE => $line,
1176             FUNC => 1,
1177             COLOR1 => $colors[0],
1178             COLOR2 => $colors[1] );
1179 1027 100       3066 $block{TIME} = time () if ( $dbug_global_vars{elapsed} );
1180 1027 100       2628 $block{MULTI} = _indent_multi (1) if ( $dbug_global_vars{multi} );
1181              
1182 1027         1971 push ( @{$dbug_global_vars{functions}}, \%block );
  1027         2836  
1183              
1184 1027         3741 _dbug_args ( @_ );
1185              
1186 1027         4812 return ( $func );
1187             }
1188              
1189              
1190             # Helper method to DBUG_ENTER_FUNC & DBUG_ENTER_BLOCK!
1191             # Called almost as frequently as DBUG_PRINT ...
1192             sub _dbug_args
1193             {
1194 2017     2017   5028 my @args = @_;
1195              
1196 2017         4509 $dbug_global_vars{mask_last_argument_count} = 0;
1197              
1198             # If nothing to write to fish ...
1199 2017 100       5767 if ( $#args == -1 ) {
    100          
1200 1369         2604 delete $dbug_global_vars{mask_func_call};
1201 1369         2873 return;
1202             } elsif ( DBUG_EXECUTE ("args") == 0 ) {
1203 104 50       303 if ( exists $dbug_global_vars{mask_func_call} ) {
1204 0         0 $dbug_global_vars{mask_last_argument_count} = -1;
1205 0         0 delete $dbug_global_vars{mask_func_call};
1206             }
1207 104         224 return;
1208             }
1209              
1210             # Optionally mask your function arguments ...
1211 544 100       3106 if ( exists $dbug_global_vars{mask_func_call} ) {
1212 7         18 my $mask = $dbug_global_vars{mask_func_call};
1213 7 100       27 if ( $mask->{ALL} ) {
1214 1         5 foreach (0..$#args) {
1215 4         8 $args[$_] = MASKING_VALUE;
1216 4         8 ++$dbug_global_vars{mask_last_argument_count};
1217             }
1218             }
1219 7 100       26 if ( $mask->{ARRAY} ) {
1220 4         11 foreach ( @{$mask->{ARRAY}} ) {
  4         17  
1221 9 100       31 if ( $_ <= $#args ) {
1222 5         33 $args[$_] = MASKING_VALUE;
1223 5         16 ++$dbug_global_vars{mask_last_argument_count};
1224             }
1225             }
1226             }
1227 7 100       30 if ( $mask->{HASH} ) {
1228 2         6 my $mask_flag = 0;
1229 2         10 foreach (0..$#args) {
1230 18 100       37 if ( $mask_flag ) {
1231 3         126 $args[$_] = MASKING_VALUE;
1232 3         10 $mask_flag = 0;
1233 3         9 ++$dbug_global_vars{mask_last_argument_count};
1234             } else {
1235 15         33 my $k = lc ($args[$_]); # All keys are in lower case.
1236 15 100       42 $mask_flag = 1 if ( exists $mask->{HASH}->{$k} );
1237             }
1238             }
1239             }
1240 7         34 delete $dbug_global_vars{mask_func_call};
1241             }
1242              
1243             # Convert any code refs into it's function name ...
1244 544         2335 foreach (0..$#args) {
1245 1272 100       4229 if ( ref ( $args[$_] ) eq "CODE" ) {
1246 84         994 my $f = sub_fullname ( $args[$_] );
1247 84 50 33     1419 $f = $1 if ( $dbug_global_vars{strip} && $f =~ m/::([^:]+)$/ );
1248 84         297 $args[$_] = '\&' . $f;
1249             }
1250             }
1251              
1252 544 50       1595 if ( $dbug_global_vars{no_addresses} ) {
1253 0         0 my $i = 0;
1254 0         0 foreach (0..$#args) {
1255 0 0       0 if ( ref ( $args[$_] ) ne "" ) {
1256 0         0 $args[$_] = sprintf ("%s(%03d)", ref ( $args[$_] ), ++$i);
1257             }
1258             }
1259             }
1260              
1261             # Now format the arugment list you need to print out ...
1262 544         1740 my ($sep, $msg) = ("", "");
1263 544         1366 foreach (0..$#args) {
1264 1272 50       3212 my $val = (defined $args[$_]) ? $args[$_] : UNDEF_VALUE;
1265              
1266 1272         3988 $msg .= $sep . "[${val}]";
1267 1272         2629 $sep = ", ";
1268             }
1269              
1270 544         1882 _dbug_print_no_delay_or_caller ("args", $msg);
1271              
1272 544         1572 return;
1273             }
1274              
1275              
1276             =item DBUG_ENTER_BLOCK ( $name[, @arguments] )
1277              
1278             Similar to I except that it deals with I blocks of
1279             code. Or if you wish to call a particular function a different name in the
1280             B logs.
1281              
1282             It usually expects you to call I when the block goes out of
1283             scope to keep the B logs balanced. But nothing prevents you from using
1284             one of the other return variants instead.
1285              
1286             It returns the name of the code block you used. In rare cases this name can
1287             be useful.
1288              
1289             =cut
1290              
1291             # ==============================================================
1292             sub DBUG_ENTER_BLOCK
1293             {
1294 990     990 1 176162 my $block_name = shift;
1295              
1296 990 50       2547 $block_name = "[undef]" unless ( defined $block_name );
1297              
1298             # Strip off any module info from the passed block name?
1299 990 50 33     2996 $block_name = $1 if ( $dbug_global_vars{strip} && $block_name =~ m/::([^:]+)$/ );
1300              
1301             # Determine if the caller info is needed at this point.
1302 990         1852 my $line="";
1303 990 100       2362 if ( $dbug_global_vars{who_called} ) {
1304 7         12 $line = _dbug_called_by (0);
1305             }
1306              
1307             # Check if eval needs rebalancing ...
1308 990         2832 _dbug_auto_fix_eval_exception ();
1309              
1310 990         2703 my @colors = _get_filter_color (DBUG_FILTER_LEVEL_FUNC);
1311 990 100       2293 if ( DBUG_EXECUTE ( DBUG_FILTER_LEVEL_FUNC ) ) {
1312 317         1293 _printing ( $colors[0], _indent (">>${block_name}${line}"), $colors[1], "\n");
1313             }
1314              
1315 990         2664 my ($eval_dp, $eval_lns) = _eval_depth (1);
1316             my %block = ( NAME => $block_name,
1317             PAUSED => $dbug_global_vars{pause},
1318 990         10029 EVAL => $eval_dp,
1319             EVAL_LN => $eval_lns->[0],
1320             LINE => $line,
1321             FUNC => 0,
1322             COLOR1 => $colors[0],
1323             COLOR2 => $colors[1] );
1324 990 50       2827 $block{TIME} = time () if ( $dbug_global_vars{elapsed} );
1325 990 50       2602 $block{MULTI} = _indent_multi (1) if ( $dbug_global_vars{multi} );
1326              
1327 990         1841 push ( @{$dbug_global_vars{functions}}, \%block );
  990         2926  
1328              
1329 990         3294 _dbug_args ( @_ );
1330              
1331 990         4461 return ( $block_name );
1332             }
1333              
1334              
1335             =item DBUG_PRINT ( $tag, $fmt [, $val1 [, $val2 [, ...]]] )
1336              
1337             This function writes the requested message to the active B log.
1338              
1339             The B<$tag> argument is a text identifier that will be used to 'tag' the line
1340             being printed out and enforce any requested filtering and/or coloring.
1341              
1342             The remaining arguments are the same as what's passed to L if given a
1343             B<$fmt> and one or more values. But if no values are given then it's treated
1344             as a regular call to L.
1345              
1346             If the formatted message should be terminated by multiple B<\n>, then it will
1347             be truncated to a single B<\n>. All trailing whitespace on each line will be
1348             removed as well.
1349              
1350             It returns the formatted message written to fish and it will always end in
1351             B<\n>. This message doesn't include the I<$tag> or the optional caller info
1352             if the I option was used by B.
1353              
1354             This message is returned even if fish is currently turned off!
1355              
1356             B: If this request resulted in a write to B, and you asked for a
1357             B in I, this function will sleep the requested number of
1358             seconds before returning control to you. If no write, then no delay!
1359              
1360             =cut
1361              
1362             # ==============================================================
1363             # Determine the current filter level from the tag's value ...
1364             sub _filter_lvl
1365             {
1366 15604   50 15604   36887 my $tag = shift || ""; # The keyword/tag passed to DBUG_PRINT!
1367             # or _filter_on() or DBUG_EXECUTE() ...
1368              
1369             # Not recomended: But someone always tries it ...
1370             # If you used one of the DBUG_FILTER_LEVEL_... constants instead
1371             # of a string in your DBUG_PRINT($tag,...) call.
1372             # So if valid just return it as the level selected!
1373             # Also greatly helped with Custom Filtering to allow this.
1374 15604 100 66     93269 if ( $tag =~ m/^\d+$/ && defined $dbug_levels[$tag] ) {
1375 2964 50       10890 return ( wantarray ? ($tag, $tag) : $tag );
1376             }
1377              
1378 12640         25715 my $utag = uc ( $tag ); # The tag in upper case!
1379              
1380             # Assume this level until proven otherwise ...
1381 12640         18957 my $fltr_lvl = DBUG_FILTER_LEVEL_OTHER; # Filtering ...
1382 12640         18507 my $clr_lvl = $fltr_lvl; # Coloring ...
1383              
1384 12640         19671 my $pkg = __PACKAGE__;
1385              
1386 12640 100 100     134134 if ( $tag eq "args" ) {
    100 100        
    100 100        
    100          
    100          
    100          
    50          
    100          
    100          
1387 1636         3252 $fltr_lvl = $clr_lvl = DBUG_FILTER_LEVEL_ARGS;
1388             } elsif ( $utag eq "ERROR" ) {
1389 704         1149 $fltr_lvl = $clr_lvl = DBUG_FILTER_LEVEL_ERROR;
1390             } elsif ( $utag eq "STDOUT" || $utag eq "STDERR") {
1391 20         39 $fltr_lvl = $clr_lvl = DBUG_FILTER_LEVEL_STD;
1392             } elsif ( $utag eq "WARN" || $utag eq "WARNING" ) {
1393 144         295 $fltr_lvl = $clr_lvl = DBUG_FILTER_LEVEL_WARN;
1394             } elsif ( $utag eq "DEBUG" || $utag eq "DBUG" ) {
1395 136         245 $fltr_lvl = $clr_lvl = DBUG_FILTER_LEVEL_DEBUG;
1396             } elsif ( $utag eq "INFO" ) {
1397 206         683 $fltr_lvl = $clr_lvl = DBUG_FILTER_LEVEL_INFO;
1398              
1399             # The 3 different ways to specify internal levels ...
1400             } elsif ( $utag eq "INTERNAL" ) {
1401 0         0 $fltr_lvl = $clr_lvl = DBUG_FILTER_LEVEL_INTERNAL;
1402             } elsif ( $tag eq __PACKAGE__ ) {
1403 698   50     2019 $fltr_lvl = $dbug_global_vars{pkg_lvl} || DBUG_FILTER_LEVEL_INTERNAL;
1404 698         1216 $clr_lvl = DBUG_FILTER_LEVEL_INTERNAL;
1405             } elsif ( $tag =~ m/^${pkg}::/ ) {
1406 202   50     585 $fltr_lvl = $dbug_global_vars{pkg_lvl} || DBUG_FILTER_LEVEL_INTERNAL;
1407 202         321 $clr_lvl = DBUG_FILTER_LEVEL_INTERNAL;
1408             }
1409              
1410 12640 100       38661 return ( wantarray ? ($fltr_lvl, $clr_lvl) : $fltr_lvl );
1411             }
1412              
1413             # ==============================================================
1414             # Does the filter rule say it's OK to print things?
1415             # Based on the keyword/tag value ($_[0]) ...
1416             # Or the DBUG_FILTER_LEVEL_... constants ...
1417             sub _filter_on
1418             {
1419 9846     9846   23275 my $lvl = _filter_lvl ( $_[0] );
1420              
1421 9846 50       23228 if ( $dbug_global_vars{filter_style} >= 0 ) {
1422 9846         36321 return ( $lvl <= $dbug_global_vars{filter} ); # Standard filtering ...
1423             } else {
1424 0         0 return ( $dbug_custom_levels[$lvl] ); # Custom filtering ...
1425             }
1426             }
1427              
1428             # ==============================================================
1429             # So can always call DBUG_PRINT internally without any delays or caller info ...
1430             sub _dbug_print_no_delay_or_caller
1431             {
1432 2107     2107   6329 local $dbug_global_vars{delay} = 0; # Don't delay on this call ...
1433 2107         4355 local $dbug_global_vars{who_called} = 0; # Don't add caller info ...
1434 2107         5131 return DBUG_PRINT (@_);
1435             }
1436              
1437             # ==============================================================
1438             # So can print with tag PACKAGE with custom internal levels ...
1439             sub _dbug_print_pkg_tag
1440             {
1441 508     508   988 my $level = shift; # if undef, don't change the level!
1442              
1443 508 50       1786 $level = $dbug_global_vars{pkg_lvl} unless ( $level );
1444              
1445 508         1706 local $dbug_global_vars{pkg_lvl} = $level;
1446              
1447 508         985 my $pkg = __PACKAGE__;
1448 508 100 66     3284 if ( $_[0] && $_[0] =~ m/^::[^:]/ ) {
1449 105         322 $pkg .= shift;
1450             }
1451              
1452 508         1403 return ( _dbug_print_no_delay_or_caller ( $pkg, @_ ) );
1453             }
1454              
1455             # ==============================================================
1456             # Make as efficient as possible since this is the most frequently called method!
1457             # And usually the return value is tossed!
1458             # ------------------------------------------------------------------
1459             sub DBUG_PRINT
1460             {
1461 6759     6759 1 30990591 my ($keyword, $fmt, @values) = @_;
1462              
1463             # Check if untrapped eval needs rebalancing ...
1464 6759         19231 _dbug_auto_fix_eval_exception ();
1465              
1466             # If undef, the caller wasn't interested in any return value!
1467 6759         11470 my $want_return = wantarray; # Or could have used: (caller(0))[5] instead;
1468              
1469 6759         15318 my $fish_on = DBUG_EXECUTE ( $keyword );
1470              
1471             # -------------------------------------------------------------------
1472             # A no-op if fish isn't turned on & you don't want the return value!
1473             # Very, very common!
1474             # -------------------------------------------------------------------
1475 6759 100       15073 unless ( defined $want_return ) {
1476 6739 100       14813 unless ( $fish_on ) {
1477 997         3523 return (undef); # Not interested in the return value ...
1478             }
1479             }
1480              
1481             # ---------------------------------------------------------
1482             # Build the message that we want to print out.
1483             # ---------------------------------------------------------
1484             # Also converts any CODE references encountered.
1485             # ---------------------------------------------------------
1486 5762         8740 my $msg;
1487 5762 50       15662 if ( ! defined $fmt ) {
    100          
1488 0         0 $msg = "";
1489             } elsif ( $#values == -1 ) {
1490 3243         5376 $msg = $fmt;
1491 3243 50       7325 if ( ref ($fmt) eq "CODE" ) {
1492 0         0 my $f = sub_fullname ($fmt);
1493 0 0 0     0 $f = $1 if ( $dbug_global_vars{strip} && $f =~ m/::([^:]+)$/ );
1494 0         0 $msg = '\&' . $f;
1495             }
1496             } else {
1497             # Get rid of undef warnings & CODE references for sprintf() ...
1498 2519         5669 foreach (@values) {
1499 8444 50       17367 $_ = "" unless ( defined $_ );
1500 8444 100       19410 if ( ref ($_) eq "CODE" ) {
1501 4         21 my $f = sub_fullname ($_);
1502 4 50 33     46 $f = $1 if ( $dbug_global_vars{strip} && $f =~ m/::([^:]+)$/ );
1503 4         14 $_ = '\&' . $f;
1504             }
1505             }
1506 2519         11509 $msg = sprintf ( $fmt, @values );
1507             }
1508              
1509             # ---------------------------------------------------------
1510             # Split the resulting message into multiple lines ...
1511             # ---------------------------------------------------------
1512 5762         22674 my @lines = split ( /[^\S\n]*\n/, $msg ); # Split on "\n" & trim!
1513 5762 100       14166 push (@lines, "") if ( $#lines == -1 ); # Must have at least one line!
1514              
1515 5762 100       11186 if ( defined $want_return ) {
1516 20         72 $msg = join ( "\n", @lines ) . "\n"; # Put back together trimmed!
1517             } else {
1518 5742         10357 $msg = undef; # The message wasn't wanted!
1519             }
1520              
1521             # ---------------------------------------------------------
1522             # Only do this complex work if fish is turned on ...
1523             # ---------------------------------------------------------
1524 5762 100       11614 if ( $fish_on ) {
1525 5758         18762 my $sep = _indent ("${keyword}: ");
1526 5758         12668 my $len = length ($sep) - 2; # Doesn't count the trailing ": ".
1527              
1528 5758         9946 my $help_str = _indent_multi ();
1529 5758         10451 $len = $len - length ($help_str);
1530              
1531 5758         11759 my ($level, $color_lvl) = _filter_lvl ($keyword);
1532              
1533             # Check if the caller info needs to be retuned as part of $msg ...
1534 5758 100       15454 if ( $dbug_global_vars{who_called} ) {
1535 101         197 my $ln = _dbug_called_by (1);
1536             # unshift (@lines, $ln); # Put before the message.
1537 101         200 push (@lines, $ln); # Put after the message.
1538             }
1539              
1540 5758 100       13103 if ( $dbug_global_vars{delay} ) {
1541 22 50       100 if ( $time_hires_flag ) {
1542 22         215 push (@lines, sprintf ("Sleeping %0.6f second(s)", $dbug_global_vars{delay}));
1543             } else {
1544 0         0 push (@lines, sprintf ("Sleeping %d second(s)", $dbug_global_vars{delay}));
1545             }
1546             }
1547              
1548 5758         12569 my @colors = _get_filter_color ( $color_lvl );
1549              
1550             # Indent each line of the message ... (note: \s includes \n!)
1551 5758         17599 my ($output, $spaces) = ("", ${help_str} . " "x${len} . ": ");
1552 5758         12104 foreach my $row (@lines) {
1553 6230         12502 $output .= $colors[0] . ${sep} . $row . $colors[1] . "\n";
1554 6230         12603 $sep = $spaces;
1555             }
1556 5758         12566 my $flg = _printing ($output);
1557              
1558 5758 100 66     32511 if ( $flg && $dbug_global_vars{delay} ) {
1559 22         33034078 sleep ( $dbug_global_vars{delay} );
1560             }
1561             }
1562              
1563 5762         27142 return ( $msg ); # Returns what was printed out to the fish file.
1564             }
1565              
1566              
1567             =item DBUG_RETURN ( ... )
1568              
1569             It takes the parameter(s) passed as arguments and uses them as the return
1570             values to the calling function similar to how perl's return command works.
1571             Except that it also writes what is being returned to B. Since this is a
1572             function, care should be taken if called from the middle of your function's
1573             code. In that case use the syntax:
1574             S<"return DBUG_RETURN( value1 [, value2 [, ...]] );">.
1575              
1576             It uses Perl's B feature to determine what to print to B and
1577             return to the calling function. IE scalar mode (only the 1st value) or list
1578             mode (all the values in the list). Which is not quite what many perl developers
1579             might expect.
1580              
1581             EX: return (wantarray ? (value1, value2, ...) : value1);
1582              
1583             If I was called, it will mask the appropriate return value(s)
1584             as: B******E>>.
1585              
1586             =cut
1587              
1588             # ==============================================================
1589             # Tells which return values are to be masked ...
1590             # The index to the values to mask are returned as keys to a hash.
1591             sub _dbug_mask_expect
1592             {
1593 388     388   735 my $func = shift; # The return func block hash ref.
1594 388         685 my $max = shift; # The count of return values. (-1 is no args)
1595 388         619 my $args = shift; # A reference to the list of args to DBUG_RETURN.
1596              
1597             # Did we decide to mask specific values by offset ??
1598 388 100       1247 my %mask = %{$func->{AMASK}} if ( exists $func->{AMASK} );
  27         135  
1599 388         897 my $all = $mask{-1}; # Did we say mask everything returned???
1600              
1601             # Did we decide to mask specific hash values ??
1602             # If so, get the offset to that hash key's value!
1603 388 100       990 unless ( $all ) {
1604 386 100 66     1297 if ( exists $func->{HMASK} && $max > 0 ) {
1605 1 50       9 my $idx = (($max % 2) == 0) ? 1 : 0;
1606 1         5 while ( $idx <= $max ) {
1607 4         7 my $key = $args->[$idx]; # The key to check for
1608 4         6 my $iv = $idx + 1; # It's value
1609 4         7 $idx += 2; # Skip to the next key
1610              
1611 4 50       8 next unless ( defined $key );
1612 4 100       29 next unless ( exists $func->{HMASK}->{$key} );
1613 2         8 $mask{$iv} = 1; # Mark this key's value as maskable!
1614             }
1615             }
1616             }
1617              
1618             # Now count how many of the return values would be masked ...
1619 388         702 my $cnt = 0;
1620 388         1130 foreach (0..$max) {
1621 952 100 100     4597 ++$cnt if ( $all || $mask{$_} );
1622             }
1623              
1624             # The keys to this hash are it's offsets!
1625 388         1442 return ($cnt, %mask);
1626             }
1627              
1628             # ==============================================================
1629             sub DBUG_RETURN
1630             {
1631 413     413 1 49968 my @args = @_;
1632              
1633             # Check if untrapped eval needs rebalancing ...
1634 413         1345 _dbug_auto_fix_eval_exception ();
1635              
1636             # Pop off the function being returned ...
1637 413         911 my $block = pop ( @{$dbug_global_vars{functions}} );
  413         1012  
1638              
1639             # Will this turn pause off ???
1640 413 100       1232 unless ( $block->{PAUSED} ) {
1641 408         981 $dbug_global_vars{pause} = 0; # Yes!
1642             }
1643              
1644             # How many of the return values are to be masked in fish ...
1645 413         791 $dbug_global_vars{mask_return_count} = 0; # Actual count
1646 413         679 my %mask;
1647              
1648             # ------------------------------------------------------------------------
1649             # If undef, the caller wasn't interested in looking at any return values!
1650             # Assume that its planing on doing a normal "return" later on and you just
1651             # wanted to see what the expected return values are in fish.
1652             # But DBUG_RETURN() will still return undef to the caller in this case!
1653             # ------------------------------------------------------------------------
1654             # See t/15-return_simple.t for examples of this type of return.
1655             # It's too difficult to explain otherwise.
1656             # ------------------------------------------------------------------------
1657 413         785 my $fish_return = wantarray; # Or could have used: (caller(0))[5] instead.
1658              
1659 413 100       1208 unless ( defined $fish_return ) {
1660 85         164 my $func;
1661 85         14184 my $called_by_special = __PACKAGE__ . "::DBUG_RETURN_SPECIAL";
1662 85         161 my $called_by_special2 = __PACKAGE__ . "::DBUG_ARRAY_RETURN";
1663 85         352 ($func, $fish_return) = (caller(1))[3,5];
1664 85 100 66     661 $fish_return = (caller(2))[5] if ( defined $func && ($func eq $called_by_special || $func eq $called_by_special2) );
      33        
1665             }
1666              
1667             # Take a shortcut if fish is currently disabled ...
1668 413 100       1326 unless ( DBUG_EXECUTE ( DBUG_FILTER_LEVEL_FUNC ) ) {
1669 21 50 33     128 my $unknown = ( exists $block->{AMASK} || exists $block->{HMASK} ) ? -1 : 0;
1670 21 100       70 if ( ! defined $fish_return ) {
    50          
    100          
1671 16         87 return ( undef ); # Return value is being ignored!
1672             } elsif ( DBUG_EXECUTE ( DBUG_FILTER_LEVEL_ARGS ) ) {
1673             ; # Can't quit now, we have return values to print out!
1674             } elsif ( $fish_return ) {
1675 4         9 $dbug_global_vars{mask_return_count} = $unknown;
1676 4         31 return ( @args ); # Array context ...
1677             } else {
1678 1         3 $dbug_global_vars{mask_return_count} = $unknown;
1679 1         14 return ( $args[0] ); # Scalar context ...
1680             }
1681             }
1682              
1683             # From here on down we know we know we'll write something to fish ...
1684              
1685             # How many of the arguments do we expect to mask when we print them out ...
1686 392         786 my $max = $#args;
1687 392 100       983 if ($max != -1) {
1688 388 100       931 $max = ($fish_return ? $#args : 0);
1689 388         1633 ($dbug_global_vars{mask_return_count}, %mask) =
1690             _dbug_mask_expect ($block, $max, \@args);
1691             }
1692              
1693 392         1028 my @colors = _get_filter_color (DBUG_FILTER_LEVEL_ARGS);
1694              
1695 392         1065 my $func = $block->{NAME};
1696 392 100       1310 my $lbl = ( $block->{FUNC} ) ? "<" : "<<";
1697 392         1014 my $ret = $block->{COLOR1};
1698 392         1584 $ret .= _indent ("${lbl}${func} - return (");
1699 392         1393 $ret .= $block->{COLOR2} . $colors[0];
1700              
1701 392 100 66     955 unless ( _filter_on ( DBUG_FILTER_LEVEL_ARGS ) ) {
1702 4         27 $ret .= "?"; # Don't print the return value(s) to fish ...
1703              
1704             # Do we have any return values to print to fish ???
1705             } elsif ( $max != -1 && defined $fish_return ) {
1706             my $all = $mask{-1}; # Did we request to mask all return values ???
1707              
1708             # Now let's build the return value list to print to fish ...
1709             my $sep = "";
1710             my $cnt = 0; # Count return values masked.
1711             my $i = 500; # Count reference addresses dereferenced.
1712              
1713             foreach (0..$max) {
1714             my $val;
1715              
1716             if ( $all || $mask{$_} ) {
1717             $val = MASKING_VALUE; # Let's mask it ...
1718             ++$cnt; # Count it!
1719             } elsif ( ! defined $args[$_] ) {
1720             $val = UNDEF_VALUE;
1721             } elsif ( ref ($args[$_]) eq "CODE" ) {
1722             my $f = sub_fullname ( $args[$_] );
1723             $f = $1 if ( $dbug_global_vars{strip} && $f =~ m/::([^:]+)$/ );
1724             $val = '\&' . $f;
1725             } elsif ( $dbug_global_vars{no_addresses} && ref ($args[$_]) ne "" ) {
1726             $val = sprintf ("%s(%03d)", ref ($args[$_]), ++$i);
1727             } else {
1728             $val = $args[$_];
1729             }
1730              
1731             $ret .= $sep . "[" . $val . "]";
1732             $sep = ", ";
1733             }
1734              
1735             # Should never happen ...
1736             if ( $cnt != $dbug_global_vars{mask_return_count} ) {
1737             _dbug_print_pkg_tag ( DBUG_FILTER_LEVEL_INFO,
1738             "Expected %d masked return values and found %d.",
1739             $dbug_global_vars{mask_return_count}, $cnt );
1740             $dbug_global_vars{mask_return_count} = $cnt;
1741             }
1742             }
1743              
1744             # Finishing up all paths ...
1745 392         941 $ret .= $colors[1] . $block->{COLOR1} . ")";
1746 392 100       1143 $ret .= _dbug_elapsed_time ($block->{TIME}) if ( $dbug_global_vars{elapsed} );
1747 392         843 $ret .= $block->{COLOR2} . "\n";
1748              
1749 392         1344 _printing ($ret);
1750              
1751 392 100       1206 if ( $fish_return ) {
    100          
1752 204         2561 return ( @args ); # Array context ...
1753             } elsif ( defined $fish_return ) {
1754 137         2064 return ( $args[0] ); # Scalar context ...
1755             } else {
1756 51         452 return ( undef ); # Return value is being ignored!
1757             }
1758             }
1759              
1760              
1761             =item DBUG_ARRAY_RETURN ( @args )
1762              
1763             A variant of S<"DBUG_RETURN()"> that behaves the same as perl does natively when
1764             returning a list to a scalar. IE it returns the # of elements in the @args
1765             array.
1766              
1767             It always assumes @args is a list, even when provided a single scalar value.
1768              
1769             =cut
1770              
1771             # ==============================================================
1772             sub DBUG_ARRAY_RETURN
1773             {
1774 20     20 1 235 my @args = @_;
1775              
1776 20 100       47 unless ( defined wantarray ) {
1777 8         104 return DBUG_VOID_RETURN ();
1778             }
1779              
1780 12 100       27 if ( wantarray ) {
1781 8         21 return DBUG_RETURN ( @args );
1782             }
1783              
1784 4         8 my $cnt = @args; # The number of elements in the array.
1785 4         12 return DBUG_RETURN ( $cnt )
1786             }
1787              
1788              
1789             =item DBUG_VOID_RETURN ( )
1790              
1791             Terminates the current block of B code. It doesn't return any value back
1792             to the calling function.
1793              
1794             =cut
1795              
1796             # ==============================================================
1797             sub DBUG_VOID_RETURN
1798             {
1799             # Check if untrapped eval needs rebalancing ...
1800 723     723 1 3685529 _dbug_auto_fix_eval_exception ();
1801              
1802             # Pop off the function being returned ...
1803 723         1140 my $block = pop ( @{$dbug_global_vars{functions}} );
  723         2551  
1804              
1805 723 100       2301 unless ( $block->{PAUSED} ) {
1806 649         1343 $dbug_global_vars{pause} = 0;
1807              
1808 649 100       1511 if ( DBUG_EXECUTE ( DBUG_FILTER_LEVEL_FUNC ) ) {
1809 628         1766 my $func = $block->{NAME};
1810 628 100       1650 my $lbl = ( $block->{FUNC} ) ? "<" : "<<";
1811             _printing ( $block->{COLOR1}, _indent ("${lbl}${func} ()"),
1812             _dbug_elapsed_time ($block->{TIME}),
1813 628         2520 $block->{COLOR2}, "\n" );
1814             }
1815             }
1816              
1817             # No return values can ever be masked here!
1818 723         2774 $dbug_global_vars{mask_return_count} = 0;
1819              
1820 723         124980 return (undef); # Undef just in case someone looks!
1821             }
1822              
1823              
1824             =item DBUG_RETURN_SPECIAL ( $scalar, @array )
1825              
1826             This I variant allows you to differentiate between what to return
1827             when your function is called in a scalar context vs an array context vs void
1828             context.
1829              
1830             If called in an array context, the return value is equivalent to
1831             S.>
1832              
1833             If called in a scalar context, the return value is equivalent to
1834             S.> With a few special case exceptions.
1835              
1836             =over
1837              
1838             Special case # 1: If I<$scalar> is set to the predefined constant value
1839             B, it returns the equivalent to
1840             S.> Feel free to modify the contents of the referenced
1841             array, it can't hurt anything. It's a copy.
1842              
1843             Special case # 2: If I<$scalar> is set to the predefined constant value
1844             B, it returns the equivalent to
1845             S,> the number of elements in the array.
1846              
1847             Special case # 3: If I<$scalar> is set to the predefined constant value
1848             B, it returns the equivalent to
1849             S,> the last element in the array.
1850              
1851             Special case # 4: If I<$scalar> is a CODE ref, it returns the equivalent to
1852             S(@array)))>.>
1853              
1854             =back
1855              
1856             If called in a void context, the return value is equivalent to
1857             S.> But in some cases it will print additional
1858             information to B. But it will B call the CODE reference
1859             when called in void context.
1860              
1861             =cut
1862              
1863              
1864             # ==============================================================
1865             # Must always call DBUG_RETURN() or DBUG_VOID_RETURN ()
1866             # to handle all the bookkeeping!
1867             # --------------------------------------------------------------
1868             sub DBUG_RETURN_SPECIAL
1869             {
1870 79     79 1 556 my $scalar = shift; # Just take the scalar of the stack ...
1871              
1872             # Caller is asking for an array of values ...
1873 79 100       183 if ( wantarray ) {
1874 33         91 return DBUG_RETURN ( @_ );
1875             }
1876              
1877             # Check if we have to monkey with the return value masking ...
1878 46         69 my $last_masked = 0;
1879 46         75 my %new_mask;
1880 46 100 100     215 if ( $scalar eq DBUG_SPECIAL_LAST && exists $dbug_global_vars{functions}->[-1]->{AMASK} ) {
1881 4         12 my $msk = $dbug_global_vars{functions}->[-1]->{AMASK};
1882 4 100       18 if ( $msk->{$#_ + 0} ) {
    50          
1883 2         5 $new_mask{0} = 1;
1884 2         5 $last_masked = 1;
1885             } elsif ( $msk->{0} ) {
1886 2         5 $last_masked = 1;
1887             }
1888             }
1889              
1890             # ------------------------------------------------------------------------
1891             # If undef, the caller wasn't interested in looking at any return values!
1892             # Assume that its planing on doing a normal "return" later on and you just
1893             # wanted to see what the expected return values are in fish.
1894             # But DBUG_RETURN_SPECIAL() will still return undef to the caller no
1895             # matter what's written to fish in this case!
1896             # ------------------------------------------------------------------------
1897             # See "t/16-return_special_scalar_join.t" for examples of this type of
1898             # return. It's just too difficult to explain otherwise.
1899             # ------------------------------------------------------------------------
1900             # return_test_1 () - Shows the expected way to use this function.
1901             # return_test_2 () - Shows the problem way on why this code is complex.
1902             # I don't recommend you use DBUG_RETURN_SPECIAL() this 2nd way.
1903             # deep_test_1 () - Shows how your intuition may be wrong!
1904             # ------------------------------------------------------------------------
1905 46 100       112 unless ( defined wantarray ) {
1906 31         152 my $parent_wantarray = (caller(1))[5];
1907              
1908             # If called like return_test_1 () ... (expected way)
1909 31 100       137 return DBUG_VOID_RETURN () unless ( defined $parent_wantarray );
1910              
1911             # If called like return_test_2 () ... (problem way)
1912 12 100       54 return DBUG_RETURN ( @_ ) if ( $parent_wantarray );
1913              
1914             # Not doing the CODE ref conversion on purpose! Since not saving any
1915             # return value we want to avoid any potenial side affects due to
1916             # calling the CODE ref function.
1917 4 50       15 if ( defined $scalar ) {
1918 4 100       25 if ( $scalar eq DBUG_SPECIAL_ARRAYREF ) {
    100          
    100          
1919 1         4 $scalar = \@_;
1920             } elsif ( $scalar eq DBUG_SPECIAL_COUNT ) {
1921 1         3 $scalar = scalar (@_);
1922             } elsif ( $scalar eq DBUG_SPECIAL_LAST ) {
1923 1         3 $scalar = $_[-1];
1924             }
1925             }
1926              
1927 4 50       14 if ( $last_masked ) {
1928 0         0 local $dbug_global_vars{functions}->[-1]->{AMASK};
1929 0         0 $dbug_global_vars{functions}->[-1]->{AMASK} = \%new_mask;
1930 0         0 return DBUG_RETURN ( $scalar );
1931             } else {
1932 4         14 return DBUG_RETURN ( $scalar );
1933             }
1934             }
1935              
1936             # ------------------------------------------------------------------------
1937             # If you get here, you want a scalar value returned ...
1938             # Was it one of the special case values???
1939             # ------------------------------------------------------------------------
1940 15 50       50 if ( defined $scalar ) {
1941 15 100 66     96 if ( ref ($scalar) eq "CODE" ) {
    100 33        
    100          
    100          
    50          
1942 5         13 my $res = $scalar->( @_ );
1943 5         15 return DBUG_RETURN ( $res );
1944             } elsif ( $scalar eq DBUG_SPECIAL_ARRAYREF ) {
1945 3         15 my @args = @_;
1946 3         126 return DBUG_RETURN ( \@args );
1947             } elsif ( $scalar eq DBUG_SPECIAL_COUNT ) {
1948 3         11 return DBUG_RETURN ( scalar (@_) );
1949             } elsif ( $scalar eq DBUG_SPECIAL_LAST && ! $last_masked ) {
1950 2         9 return DBUG_RETURN ( $_[-1] );
1951             } elsif ( $scalar eq DBUG_SPECIAL_LAST && $last_masked ) {
1952 2         8 local $dbug_global_vars{functions}->[-1]->{AMASK};
1953 2         6 $dbug_global_vars{functions}->[-1]->{AMASK} = \%new_mask;
1954 2         7 return DBUG_RETURN ( $_[-1] );
1955             }
1956             }
1957              
1958             # Not a special case ... returning the literal value!
1959 0         0 DBUG_RETURN ( $scalar );
1960             }
1961              
1962              
1963             =item DBUG_LEAVE ( [$status] )
1964              
1965             This function terminates your program with a call to I. It expects a
1966             numeric argument to use as the program's I<$status> code, but will default to
1967             zero if it's missing. It is considered the final return of your program.
1968              
1969             Only module B and B blocks can be logged after this function is
1970             called as Perl cleans up after itself, unless you turned this feature off with
1971             option B when B was first enabled.
1972              
1973             =cut
1974              
1975             # ==============================================================
1976             sub DBUG_LEAVE
1977             {
1978 39   50 39 1 28939 my $status = shift || 0;
1979              
1980             # Check if untrapped eval needs rebalancing ...
1981 39         496 _dbug_auto_fix_eval_exception ();
1982              
1983             # Pop off the function being returned ...
1984 39         154 my $block = pop ( @{$dbug_global_vars{functions}} );
  39         221  
1985              
1986 39 100       566 if ( DBUG_EXECUTE ( DBUG_FILTER_LEVEL_FUNC ) ) {
1987 37         152 my $func;
1988             my @colors;
1989 37         371 my $lbl = "<";
1990 37         206 my $elaps = "";
1991 37 50       499 unless ( defined $block ) {
1992 0         0 $func = " *** Unbalanced Returns *** Potential bug in your code!";
1993 0         0 $colors[0] = $colors[1] = "";
1994             } else {
1995 37         198 $func = $block->{NAME};
1996 37         279 $colors[0] = $block->{COLOR1};
1997 37         104 $colors[1] = $block->{COLOR2};
1998 37 100       285 $lbl = "<<" unless ( $block->{FUNC} );
1999 37 100       336 $elaps = _dbug_elapsed_time ( $block->{TIME} ) if ( $dbug_global_vars{elapsed} );
2000             }
2001              
2002 37         356 $dbug_global_vars{printed_exit_status} = _printing (
2003             $colors[0], _indent ("${lbl}${func}"), $elaps, $colors[1], "\n",
2004             _indent_multi (), "exit ($status)\n\n" );
2005             }
2006              
2007 39         235 _dbug_leave_cleanup ();
2008              
2009 39         7942 exit ($status); # Exit the program! (This isn't trappable by eval!)
2010             }
2011              
2012              
2013             # Broken out so I can call from END block and
2014             # Fred::Fish::DBUG::OFF as well.
2015             # So that we can trace all the END/DESTROY blocks cleanly ...
2016             sub _dbug_leave_cleanup
2017             {
2018 43     43   178 $dbug_global_vars{pause} = 0;
2019              
2020 43         387 my @empty;
2021 43         133 @{$dbug_global_vars{functions}} = @empty;
  43         829  
2022              
2023             # Are we tracing the END/DESTROY blocks after all?
2024 43 100       415 $dbug_global_vars{on} = 0 if ( $dbug_global_vars{no_end} );
2025              
2026             # So any requested caller info/line numbers are never printed out ...
2027 43         149 $dbug_global_vars{who_called} = 0;
2028              
2029             # Tells the END code DBUG_LEAVE was aleady called.
2030 43         212 $dbug_global_vars{dbug_leave_called} = 1;
2031              
2032 43         151 return;
2033             }
2034              
2035              
2036             =item DBUG_CATCH ( )
2037              
2038             This function rebalances the B function trace after trapping B from
2039             an B or B code block.
2040              
2041             If using B, place this function call inside the S> section
2042             after each B block of code.
2043              
2044             If using B/B, place this function inside the B block instead.
2045              
2046             But if you don't call this function, the B logs will still try to auto
2047             rebalance itself. But you loose why this happens and it I mischaracterize
2048             why it did so in the B logs. It implies you trapped an B or B
2049             event.
2050              
2051             So calling this function is in most cases optional. One of the few times it
2052             could be considered required is if you used the B option to
2053             I. In that case failure to immediately call it could affect your
2054             timings when the rebalancing gets deferred until the next DBUG call.
2055              
2056             =cut
2057              
2058             # ==============================================================
2059             sub DBUG_CATCH
2060             {
2061             # No matter what, when called don't disable rebalancing the stack!
2062 151     151 1 3062 local $dbug_global_vars{skip_eval_fix} = 0;
2063              
2064 151         499 _dbug_auto_fix_eval_exception (1);
2065              
2066 151         611 return;
2067             }
2068              
2069             # --------------------------------------------------------------
2070             # Auto-handles dynamic DBUG_CATCH logic ... It's a real mess!
2071             # This was the reason keys EVAL_LN & MULTI were added to the function block ...
2072             # Called whenever anything writes to the fish logs ...
2073             # --------------------------------------------------------------
2074             # Works since "eval" is in Perl's stack trace and I can easily detect from the
2075             # fish stack if we're still in the same eval block of code.
2076             # It works for "try" since it eventually puts an "eval" onto the stack itself.
2077             # --------------------------------------------------------------
2078             # Doesn't work for perl -we '...' scripts since everything is a 1 liner!
2079             # --------------------------------------------------------------
2080             # Too bad we can't auto-balance other usage issues with this module.
2081              
2082             sub _dbug_auto_fix_eval_exception
2083             {
2084 10140   100 10140   37617 my $from_dbug_catch_flag = shift || 0;
2085              
2086 10140 100       26043 return if ( $dbug_global_vars{skip_eval_fix} );
2087              
2088 8788         22296 my ($eval_cnt, $eval_lns) = _eval_depth (2);
2089              
2090 8788         14475 my @list = @{$dbug_global_vars{functions}};
  8788         23889  
2091              
2092 8788 100       20207 my $pop_msg = $from_dbug_catch_flag
2093             ? " *** Caught eval/try trap and popped the fish stack! ***"
2094             : " *** Auto-balancing the fish stack again after leaving an eval/try block! ***";
2095              
2096 8788         18810 foreach my $b ( reverse @list ) {
2097 8618 100       24480 last if ( $b->{EVAL} < $eval_cnt );
2098 8331 100 100     41176 last if ( $eval_cnt == 0 && $b->{EVAL} == 0 );
2099              
2100             # Don't pop items owned by another thread/PID ...
2101 1613 50 66     4801 last if ( exists $b->{MULTI} && $b->{MULTI} ne _indent_multi (1) );
2102              
2103             # Checking if in the same eval block. May have to add a filename
2104             # comparision to this logic in the future.
2105             # IE two evals with the same depth & line numbers from different files.
2106 1613 100       4132 if ( $b->{EVAL} == $eval_cnt ) {
2107 1400 100       4287 last if ( $b->{EVAL_LN} == $eval_lns->[0] );
2108 3         7 --$eval_cnt;
2109 3         4 shift ( @{$eval_lns} );
  3         7  
2110             }
2111              
2112             # Now lets pop off the bypassed return calls ...
2113 216         378 pop ( @{$dbug_global_vars{functions}} );
  216         499  
2114              
2115 216 100       658 unless ( $b->{PAUSED} ) {
2116 152         356 $dbug_global_vars{pause} = 0;
2117              
2118 152 50       472 if ( DBUG_EXECUTE ( DBUG_FILTER_LEVEL_FUNC ) ) {
2119 152         348 my $func = $b->{NAME};
2120 152 100       421 my $lbl = ( $b->{FUNC} ) ? "<" : "<<";
2121 152         628 my $elaps = _dbug_elapsed_time ($b->{TIME});
2122 152         682 _printing $b->{COLOR1}, _indent ("${lbl}${func}"), $pop_msg, $elaps, $b->{COLOR2}, "\n";
2123             }
2124             }
2125             }
2126              
2127 8788         22448 return;
2128             }
2129              
2130              
2131             =item DBUG_PAUSE ( )
2132              
2133             Temporarily turns B off until the pause request goes out of scope. This
2134             allows you to conditionally disable B for particularly verbose blocks of
2135             code or any other reason you choose.
2136              
2137             The scope of the pause is defined as the previous call to a I
2138             function variant and it's coresponding call to a I variant.
2139              
2140             While the pause is active, calling it again does nothing.
2141              
2142             =cut
2143              
2144             # ==============================================================
2145             sub DBUG_PAUSE
2146             {
2147 45 100   45 1 303 return if ( $dbug_global_vars{pause} );
2148              
2149 43         137 _dbug_print_pkg_tag ( DBUG_FILTER_LEVEL_INFO,
2150             "PAUSE: Fish has been paused! In %s",
2151             _dbug_called_by (1) );
2152              
2153 43         100 $dbug_global_vars{pause} = 1;
2154              
2155 43         158 return;
2156             }
2157              
2158              
2159             =item DBUG_MASK ( @offsets )
2160              
2161             Sometimes the return value(s) returned by I and/or it's variants
2162             contain sensitive data that you wouldn't want to see recorded in a B file.
2163             Such as user names and passwords. So we need a way to mask these values without
2164             the programmer having to jump through too many hoops to do so.
2165              
2166             So this function tells the I call that goes with the most recent
2167             I variant which of its return values to mask. So if you have
2168             multiple exit points to the current function, this one call handles the masking
2169             for them all.
2170              
2171             The I<@offsets> array consists of 1 or more integers representing the offset to
2172             expected return values. Or the special case of B<-1> to say mask all return
2173             values.
2174              
2175             So I would cause I to mask the 1st and 3rd elements
2176             being returned.
2177              
2178             If you pass a non-numeric value, it will assume that the return value is a hash
2179             and that you are providing a hash key who's value needs to be masked.
2180              
2181             So if you say I, it might return
2182             B*****E], [ONE], [1]>>. And since there is no key "THREE"
2183             in your hash, nothing was masked for it. And as you can see, we only mask the
2184             value, not the key itself! The key is case sensitive, so "two" wouldn't have
2185             matched anything. Also remember that the order of the keys returned is random,
2186             so pure numeric offsets wouldn't give you the desired results.
2187              
2188             We could have combined both examples with I.
2189              
2190             =cut
2191              
2192             # ==============================================================
2193             sub DBUG_MASK
2194             {
2195 42     42 1 327 my @lst = sort (@_); # So the list of offsets are in predictable order.
2196              
2197 42 100       201 return if ( $#lst == -1 );
2198              
2199              
2200             # Silently drop any invalid masking offset.
2201 34         124 my (%amask, %hmask);
2202 34         105 my ($acnt, $hcnt) = (0, 0);
2203 34         78 foreach my $idx (@lst) {
2204 61 50       159 next unless ( defined $idx );
2205 61 50       273 next if ( $idx =~ m/^\s*$/ );
2206              
2207             # if non-numeric ... assume it's a hash key to match.
2208 61 100       320 unless ( $idx =~ m/^-?\d+$/ ) {
2209 3         9 $hmask{$idx} = 1;
2210 3         4 ++$hcnt;
2211 3         6 next;
2212             }
2213              
2214 58         98 ++$acnt;
2215 58 100       167 if ( $idx <= -1 ) {
2216 2         8 $amask{-1} = 1;
2217 2         4 $hcnt = 0;
2218 2         6 last;
2219             }
2220              
2221 56         190 $amask{$idx + 0} = 1; # The +0 removes leading 0's.
2222             }
2223              
2224             # Updates the most recent ENTER block ...
2225 34 100       84 if ( $acnt > 0 ) {
2226 33         158 $dbug_global_vars{functions}->[-1]->{AMASK} = \%amask;
2227             } else {
2228 1         3 delete $dbug_global_vars{functions}->[-1]->{AMASK};
2229             }
2230 34 100       83 if ( $hcnt > 0 ) {
2231 1         4 $dbug_global_vars{functions}->[-1]->{HMASK} = \%hmask;
2232             } else {
2233 33         95 delete $dbug_global_vars{functions}->[-1]->{HMASK};
2234             }
2235              
2236 34         140 return;
2237             }
2238              
2239              
2240             =item DBUG_MASK_NEXT_FUNC_CALL ( @offsets )
2241              
2242             Sometimes some arguments passed to I contain sensitive data
2243             that you wouldn't want to see recorded in a B file. Such as user names
2244             and passwords. So we need a way to mask these values without the programmer
2245             having to jump through too many hoops to do so.
2246              
2247             So this function tells the next I or I call
2248             which arguments are sensitive. If you call it multiple times before the next
2249             time the enter function is called it will only remember the last time called!
2250              
2251             The I<@offsets> array consists of 1 or more integers representing the offset to
2252             expected arguments. Or the special case of B<-1> to say mask all arguments
2253             passed. Any other negative value will be ignored.
2254              
2255             But should any offset be non-numeric, it assumes one of the arguments was a
2256             hash I with that string as it's key. And so it will mask the
2257             next value after it if the key exists. Needed since the order of hash keys is
2258             random. Also in this case the hash key is case insensitive. So "abc" and "ABC"
2259             represent the same hash key.
2260              
2261             So I would cause I
2262             to mask the 1st and 3rd elements passed to it as well as the next argument
2263             after the "password" key.
2264              
2265             Any invalid offset value will be silently ignored.
2266              
2267             =cut
2268              
2269             # ==============================================================
2270             sub DBUG_MASK_NEXT_FUNC_CALL
2271             {
2272 11     11 1 92 my @args = @_;
2273              
2274 11         29 delete $dbug_global_vars{mask_func_call};
2275              
2276 11 50       34 return if ( $#args == -1 );
2277              
2278 11         25 my (@offsets, %mask);
2279 11         32 my ($acnt, $hcnt, $all) = (0, 0, 0);
2280              
2281 11         64 foreach my $idx (@args) {
2282 16 50       47 next unless ( defined $idx );
2283 16 50       84 next if ( $idx =~ m/^\s*$/ );
2284              
2285 16 100       90 if ( $idx =~ m/^-\d+$/ ) {
    100          
2286 4 50       14 if ( $idx == -1 ) {
2287 4         9 $acnt = $hcnt = 0;
2288 4         8 $all = 1;
2289 4         12 last;
2290             }
2291              
2292             } elsif ( $idx =~ m/^\d+$/ ) {
2293 9         26 push (@offsets, $idx);
2294 9         19 ++$acnt;
2295              
2296             } else {
2297 3         17 $mask{lc($idx)} = 1; # Make case insensitive.
2298 3         12 ++$hcnt;
2299             }
2300             }
2301              
2302             # Register that the next call to DBUG_ENTER_FUNC() should mask it's values!
2303 11 50       51 if ( ($acnt + $hcnt + $all) > 0 ) {
2304 11         22 my %mask_it;
2305              
2306 11         33 $mask_it{ALL} = $all;
2307 11 100       50 $mask_it{HASH} = \%mask if ( $hcnt > 0 );
2308              
2309 11 100       30 if ( $acnt > 0 ) {
2310 4         32 @offsets = sort (@offsets);
2311 4         16 $mask_it{ARRAY} = \@offsets;
2312             }
2313              
2314 11         32 $dbug_global_vars{mask_func_call} = \%mask_it;
2315             }
2316              
2317 11         71 return;
2318             }
2319              
2320              
2321             =item DBUG_FILTER ( [$level] )
2322              
2323             This function allows you to filter out unwanted messages being written to
2324             B. This is controlled by the value of I<$level> being passed to
2325             this method. If you never call this method, by default you'll get
2326             everything.
2327              
2328             If you call it with no I<$level> provided, the current level will remain
2329             unchanged!
2330              
2331             It returns up to two values: (old_level, new_level)
2332              
2333             The old_level may be -1 if it was previously using custom filtering.
2334              
2335             The valid levels are defined by the following exposed constants:
2336              
2337             =over 4
2338              
2339             B - Just the function entry and exit points.
2340              
2341             B - Add on the function arguments & return values.
2342              
2343             B - Add on DBUG_PRINT calls with ERROR as their tag.
2344              
2345             B - Add on trapped writes to STDOUT & STDERR.
2346              
2347             B - Add on DBUG_PRINT calls with WARN or WARNING as
2348             their tag.
2349              
2350             B - Add on DBUG_PRINT calls with DEBUG or DBUG as
2351             their tag.
2352              
2353             B - Add on DBUG_PRINT calls with INFO as their tag.
2354              
2355             B - Include everything! (default)
2356              
2357             B - Include Fred::Fish::DBUG diagnostics.
2358              
2359             =back
2360              
2361             =cut
2362              
2363             # ==============================================================
2364             sub DBUG_FILTER
2365             {
2366 84     84 1 377 my $level = shift;
2367              
2368 84         150 my $old_lvl;
2369 84 50       276 if ( $dbug_global_vars{filter_style} == 1 ) {
2370 84   50     329 $old_lvl = $dbug_global_vars{filter} || DBUG_FILTER_LEVEL_MAX;
2371             } else {
2372 0         0 $old_lvl = -1; # Currently using custom filtering ...
2373             }
2374 84         242 my $new_lvl = $old_lvl;
2375              
2376             # Only update the level if it's valid ...
2377 84 100 66     567 if ( $level && $level =~ m/^\d+$/ ) {
2378 39 100 66     267 if (DBUG_FILTER_LEVEL_MIN <= $level && $level <= DBUG_FILTER_LEVEL_MAX) {
    50          
2379 32         90 $new_lvl = $dbug_global_vars{filter} = $level;
2380             } elsif ( $level == DBUG_FILTER_LEVEL_INTERNAL ) {
2381 7         27 $new_lvl = $dbug_global_vars{filter} = $level;
2382             }
2383              
2384 39 100       195 if ( $old_lvl != $new_lvl ) {
2385 38 50 33     262 my $old = ($old_lvl == -1) ? "Custom Level" : ($dbug_levels[$old_lvl] || $old_lvl);
2386 38   33     208 my $new = $dbug_levels[$new_lvl] || $new_lvl;
2387 38 100       153 my $direction = ($old_lvl > $new_lvl) ? "down to" : "up to";
2388              
2389             # Standard Style ...
2390 38         100 $dbug_global_vars{filter_style} = 1;
2391              
2392             # Determine index to whom to say was our caller.
2393 38   100     227 my $c = (caller(1))[3] || "";
2394              
2395 38         148 _dbug_print_pkg_tag ( DBUG_FILTER_LEVEL_MIN,
2396             "The fish filtering level was changed from\n%s %s %s\n%s",
2397             $old, $direction, $new, _dbug_called_by (1) );
2398             }
2399             }
2400              
2401 84 50       402 return ( wantarray ? ( $old_lvl, $new_lvl ) : $old_lvl );
2402             }
2403              
2404              
2405             =item DBUG_CUSTOM_FILTER ( @levels )
2406              
2407             This function allows you to customize which filter level(s) should appear in
2408             your B logs. You can pick and choose from any of the levels defined by
2409             I. If you provide an invalid level, it will be silently ignored.
2410             Any level not listed will no longer appear in B.
2411              
2412             =cut
2413              
2414             # ==============================================================
2415             sub DBUG_CUSTOM_FILTER
2416             {
2417             # Convert this list of arguments into a hash of valid levels ...
2418 0     0 1 0 my %levels;
2419 0         0 foreach my $lvl (@_) {
2420 0 0 0     0 next unless ( defined $lvl && $lvl =~ m/^\d+$/ );
2421              
2422 0 0 0     0 if (DBUG_FILTER_LEVEL_MIN <= $lvl || $lvl <= DBUG_FILTER_LEVEL_MAX) {
    0          
2423 0         0 $levels{$lvl + 0} = 1;
2424             } elsif ( $lvl == DBUG_FILTER_LEVEL_INTERNAL ) {
2425 0         0 $levels{DBUG_FILTER_LEVEL_INTERNAL} = 1;
2426             }
2427             }
2428              
2429 0         0 my ( $msg, $sep, $plvl ) = ( "", "", DBUG_FILTER_LEVEL_MIN );
2430              
2431             # Now lets turn on/off the individual filter levels ...
2432 0         0 foreach (DBUG_FILTER_LEVEL_MIN..DBUG_FILTER_LEVEL_MAX, DBUG_FILTER_LEVEL_INTERNAL) {
2433 0 0       0 $dbug_custom_levels[$_] = ( $levels{$_} ) ? 1 : 0;
2434 0 0       0 if ( $dbug_custom_levels[$_] ) {
2435 0         0 $msg .= ${sep} . $dbug_levels[$_];
2436 0 0       0 $plvl = $_ if ( $sep eq "" );
2437 0         0 $sep = ", ";
2438             }
2439             }
2440              
2441             # Custom Style ...
2442 0         0 $dbug_global_vars{filter_style} = -1;
2443              
2444             # What if called by the inverse function?
2445 0   0     0 my $c = (caller(1))[3] || "";
2446 0 0       0 return if ( $c eq __PACKAGE__ . "::DBUG_CUSTOM_FILTER_OFF" );
2447              
2448 0         0 _dbug_print_pkg_tag ( $plvl, "The filtering level was changed to custom level(s): %s", $msg );
2449              
2450 0         0 return;
2451             }
2452              
2453              
2454             =item DBUG_CUSTOM_FILTER_OFF ( @levels )
2455              
2456             This function is the reverse of I. Instead of specifying
2457             the filter levels you wish to see, you specify the list of levels you don't
2458             want to see. Sometimes it's just easier to list what you don't want to see
2459             in B.
2460              
2461             =cut
2462              
2463             # ==============================================================
2464             sub DBUG_CUSTOM_FILTER_OFF
2465             {
2466 0     0 1 0 DBUG_CUSTOM_FILTER ( @_ ); # Set to custom filter levels ...
2467              
2468 0         0 my ( $msg, $sep, $plvl ) = ( "", "", DBUG_FILTER_LEVEL_MIN );
2469              
2470             # Now lets invert the on/off settings of the individual filter levels ...
2471 0         0 foreach (DBUG_FILTER_LEVEL_MIN..DBUG_FILTER_LEVEL_MAX, DBUG_FILTER_LEVEL_INTERNAL) {
2472 0 0       0 $dbug_custom_levels[$_] = ( $dbug_custom_levels[$_] ) ? 0 : 1;
2473              
2474 0 0       0 if ( $dbug_custom_levels[$_] ) {
2475 0         0 $msg .= ${sep} . $dbug_levels[$_];
2476 0 0       0 $plvl = $_ if ( $sep eq "" );
2477 0         0 $sep = ", ";
2478             }
2479             }
2480              
2481 0         0 _dbug_print_pkg_tag ( $plvl, "The filtering level was changed to custom level(s): %s", $msg );
2482              
2483 0         0 return;
2484             }
2485              
2486              
2487             =item DBUG_SET_FILTER_COLOR ( $level [, @color_attr] )
2488              
2489             This method allows you to control what I to use when printing to the
2490             B logs for each filter I. Each I may use different
2491             I or repeat the same I between I.
2492              
2493             See I above to see what the valid levels are.
2494              
2495             See L for what I strings are available. But I
2496             or the empty string means to use no I information. (default) You may
2497             use strings like ("red on_yellow") or ("red", "on_yellow") or even use the color
2498             constants (RED, ON_YELLOW).
2499              
2500             If L is not installed, this method does nothing. If you set
2501             I<$ENV{ANSI_COLORS_DISABLED}> to a non-zero value it will disable your I
2502             choice as well.
2503              
2504             Returns B<1> if the color request was accepted, else B<0>.
2505              
2506             =cut
2507              
2508             # ==============================================================
2509             sub DBUG_SET_FILTER_COLOR
2510             {
2511 21     21 1 494070 my $level = shift; # Always non-zero ...
2512 21         89 my @color_attr = @_; # List of color attributs.
2513              
2514             # If color not supported ...
2515 21 50       70 return (0) if ( $color_supported == 0 );
2516              
2517 21         48 my $valid_level = 0;
2518 21 50 33     203 if ( $level && $level =~ m/^\d+$/ ) {
2519 21 100 66     139 if ( (DBUG_FILTER_LEVEL_MIN <= $level && $level <= DBUG_FILTER_LEVEL_MAX) ||
      100        
2520             ($level == DBUG_FILTER_LEVEL_INTERNAL) ) {
2521 19         35 $valid_level = 1;
2522             }
2523             }
2524              
2525             # Merge all the color attributes into a single escape sequence string ...
2526 21         45 my $color_str = "";
2527 21 100       63 if ( $valid_level ) {
2528 19         192 local $ENV{ANSI_COLORS_DISABLED} = 0; # Enable colors!
2529 19         92 local $SIG{__DIE__} = ""; # Disable any die customization ...
2530              
2531 19         44 foreach my $cm ( @color_attr ) {
2532 47 50       117 next unless (defined $cm);
2533 47 50       185 next if ( $cm =~m/^\s*$/ );
2534 47         107 eval {
2535             # Throws an exception if not a valid color string such as "red",
2536             # "red on_yellow", or "bold red on_yellow".
2537 47         171 my $str = color ($cm); # Convert to an escape sequence ...
2538 26         773 $color_str .= $str;
2539             # print STDERR "Valid Color String '$cm'\n";
2540             };
2541 47 100       4249 if ( $@ ) {
2542 21         43 eval {
2543             # Throws exception if color value wasn't from a color macro!
2544             # Ex: use Term::ANSIColor qw(:constants); $color = RED;
2545             # Not all color macro values are escape sequences ...
2546 21         70 my @str = Term::ANSIColor::uncolor ($cm);
2547 21         1025 foreach my $s ( @str ) {
2548 21         62 $color_str .= color ($s); # Makes sure always an escape sequence ...
2549             }
2550             # print STDERR "Valid Color Macro(s): '", join (", ", @str), "'\n";
2551             };
2552 21 50       757 if ( $@ ) {
2553 0         0 warn ("Invalid color string '$cm'.\nColor request reset to no colors for level $dbug_levels[$level]!\n");
2554 0         0 $color_str = "";
2555 0         0 last;
2556             }
2557             }
2558             }
2559             }
2560              
2561             # Save the results ...
2562 21 100       175 if ( $valid_level ) {
2563 19 50       57 if ( $color_str ) {
2564 19         122 local $ENV{ANSI_COLORS_DISABLED} = 0; # Enable colors!
2565 19         56 $color_list[$level] = $color_str; # Get the escape sequence for this color.
2566 19         84 $color_clear = color ("clear"); # Back to defaults.
2567             } else {
2568 0         0 delete ( $color_list[$level] );
2569             }
2570             }
2571              
2572 21         691 return ( $valid_level );
2573             }
2574              
2575              
2576             # ==============================================================
2577             # Get the colors to use for the current filter level.
2578             sub _get_filter_color
2579             {
2580 8376     8376   14082 my $level = shift;
2581              
2582 8376 50       18564 return ("", "") if ( $color_supported == 0 );
2583 8376 100       23394 return ("", "") if ( $ENV{ANSI_COLORS_DISABLED} );
2584 8220 100       28841 return ("", "") unless ( defined $color_list[$level] );
2585              
2586 183         650 return ( $color_list[$level], $color_clear );
2587             }
2588              
2589              
2590             =item DBUG_ACTIVE ( )
2591              
2592             This function tells you if B is currently turned on or not.
2593              
2594             It will return B<0> if I was never called, called with
2595             S 1>>, or if I is currently in effect. It ignores
2596             any filter request.
2597              
2598             It will return B<1> if B is currently writing to a file.
2599              
2600             It will return B<-1> if B is currently writing to your screen via
2601             B or B.
2602              
2603             =cut
2604              
2605             # ==============================================================
2606             sub DBUG_ACTIVE
2607             {
2608 20321     20321 1 31777 my $active = 0; # Assume not currently active ...
2609              
2610 20321 100 100     93510 if ( $dbug_global_vars{on} && (! $dbug_global_vars{pause}) &&
      66        
2611             _limit_thread_check () ) {
2612 18211 50       37906 $active = ($dbug_global_vars{screen}) ? -1 : 1;
2613             }
2614              
2615 20321         42579 return ( $active );
2616             }
2617              
2618              
2619             =item DBUG_EXECUTE ( $tag )
2620              
2621             This boolean function helps determine if a call to I using this
2622             I<$tag> would actually result in the print request being written to B
2623             or not.
2624              
2625             It returns B<1> if the I would write it to B and B<0> if for
2626             any reason it wouldn't write to B. It returns B<-1> if B is
2627             currently writing to your screena via B or B.
2628              
2629             Reasons for returning B<0> would be: Fish was turned off, pause was turned on,
2630             or you set your B filtering level too low.
2631              
2632             This way you can write conditional code based on what's being written to fish!
2633              
2634             =cut
2635              
2636             # ==============================================================
2637             sub DBUG_EXECUTE
2638             {
2639 11074     11074 1 20184 my $tag = shift;
2640              
2641             # Is fish active ?
2642 11074         23126 my $active = DBUG_ACTIVE (); # -1, 0, 1
2643              
2644             # Return if inactive ...
2645 11074 100       26436 return (0) unless ( $active );
2646              
2647             # Are we filtering the results out of fish ???
2648 9356 100       20691 return (0) unless ( _filter_on ( $tag ) );
2649              
2650 8888         20480 return ($active); # This tag would be written to fish!
2651             }
2652              
2653              
2654             =item DBUG_FILE_NAME ( )
2655              
2656             Returns the full absolute file name to the B log created by I.
2657             If I was passed an open file handle, then the file name is unknown
2658             and the empty string is returned!
2659              
2660             =cut
2661              
2662             # ==============================================================
2663             sub DBUG_FILE_NAME
2664             {
2665 46     46 1 430 return ( $dbug_global_vars{file} );
2666             }
2667              
2668              
2669             =item DBUG_FILE_HANDLE ( )
2670              
2671             Returns the file handle to the open I file created by I. If
2672             I wasn't called, or called using I, then it returns
2673             I instead.
2674              
2675             =cut;
2676              
2677             # ==============================================================
2678             sub DBUG_FILE_HANDLE
2679             {
2680 0     0 1 0 return ( $dbug_global_vars{fh} ); # The open file handle written to ...
2681             }
2682              
2683              
2684             =item DBUG_ASSERT ( $expression [, $always_on [, $msg]] )
2685              
2686             This function works similar to the C/C++ I function except that it
2687             can't tell you what the boolean expression was.
2688              
2689             This I is usually turned off when B isn't currently active.
2690             But you may enable it even when B is turned off by setting the
2691             I<$always_on> flag to true.
2692              
2693             If the I<$expression> is true, no action is taken and nothing is written
2694             to B.
2695              
2696             But if the I<$expression> is false, it will log the event to B and then
2697             exit your program with a status code of B<14>. Meaning this exit can't be
2698             trapped by I or I/I blocks.
2699              
2700             If you provide the optional I<$msg>, it will print out that message as well
2701             after the assert statement.
2702              
2703             These messages will be written to both B and B.
2704              
2705             =cut
2706              
2707             # ==============================================================
2708             sub DBUG_ASSERT
2709             {
2710 0     0 1 0 my $bool_expr = shift;
2711 0 0       0 return if ( $bool_expr ); # The assertion is true ... (noop)
2712              
2713 0         0 my $always_on = shift;
2714 0         0 my $msg = shift;
2715              
2716 0         0 my $asserted = 0; # Assume it can't be triggered ...
2717              
2718             # Checks if the assert was triggered.
2719 0 0       0 if ( $always_on ) {
    0          
2720 0         0 $asserted = 1; # Always assert ...
2721             } elsif ( DBUG_ACTIVE () ) {
2722 0         0 $asserted = 1; # Only when Fish is turned on ...
2723             }
2724              
2725 0 0       0 if ( $asserted ) {
2726 0         0 my $str = _dbug_called_by (1); # Where the assertion was made.
2727 0         0 $str = "Assertion Violation: " . $str;
2728              
2729 0         0 my $level = DBUG_FILTER_LEVEL_ERROR;
2730              
2731 0 0 0     0 unless ( $dbug_global_vars{screen} && _filter_on ( $level ) ) {
2732 0         0 print STDERR "\n", $str, "\n";
2733 0 0       0 print STDERR $msg, "\n" if ( $msg );
2734 0         0 print STDERR "\n";
2735             }
2736              
2737 0         0 _dbug_print_pkg_tag ( $level, "ASSERT: %s", $str );
2738 0 0       0 _dbug_print_pkg_tag ( $level, "ASSERT: %s", $msg ) if ( $msg );
2739 0         0 DBUG_LEAVE (14);
2740             }
2741              
2742 0         0 return;
2743             }
2744              
2745              
2746             =item DBUG_MODULE_LIST ( )
2747              
2748             This optional method writes to B all modules used by your program. It
2749             provides the module version as well as where the module was installed. Very
2750             useful when you are trying to see what's different between different installs
2751             of perl or when you need to open a CPAN ticket.
2752              
2753             =cut
2754              
2755             sub DBUG_MODULE_LIST
2756             {
2757 7     7 1 27 my ($max1, $max2) = (0, 0); # (label len, version len)
2758 7         16 my %vers;
2759             my %mod;
2760              
2761             # Get the formatting data & version info.
2762 7         995 foreach ( sort keys %INC ) {
2763 1029         1668 my $len = length ($_);
2764 1029 100       2047 $max1 = $len if ( $len > $max1 );
2765              
2766             # Get the module name ...
2767 1029         1681 my $module = $_;
2768 1029         4142 $module =~ s#[\\/]#::#g;
2769 1029         3140 $module =~ s/[.]pm$//i;
2770              
2771             # Determine the module's version ...
2772 1029         1780 my $ver = "(Unknown)";
2773 1029         1626 eval {
2774 1029         2857 local $SIG{__DIE__} = undef; # Just in case already trapped.
2775 1029         12478 my $tmp = ${module}->VERSION ();
2776 1029 100       4102 $ver = $tmp if ( $tmp );
2777             };
2778              
2779             # Save the version info ...
2780 1029         1473 $len = length ($ver);
2781 1029 100       1934 $max2 = $len if ( $len > $max2 );
2782 1029         2539 $vers{$_} = $ver;
2783              
2784             # Save the module info ...
2785 1029         1969 $mod{$_} = $module;
2786 1029         1528 $len = length ($module);
2787 1029 50       2502 $max1 = $len if ( $len > $max1 );
2788             }
2789              
2790 7         157 _dbug_print_no_delay_or_caller ( "INFO", "The Module List ..." );
2791              
2792             # Now print out the results ...
2793 7         746 foreach ( sort keys %INC ) {
2794             _dbug_print_no_delay_or_caller ( "MODULE", "%*s ==> %*s ==> %s",
2795 1029         4132 $max1, $mod{$_}, $max2, $vers{$_}, $INC{$_} );
2796             }
2797              
2798 7         795 return;
2799             }
2800              
2801              
2802             # Converts the reqeuested code ref or function string into a code ref/name pair.
2803             # Used by both the Signal & TIE extensions for low level work!
2804             sub _get_func_info
2805             {
2806 92     92   209 my $callback = shift; # A String or a CODE ref ...
2807 92         186 my $msg = shift; # A label to use when printing warnings.
2808              
2809 92         189 my ( $code, $func ); # The return values ...
2810              
2811 92 50       302 if ( $callback ) {
2812 92         234 my $pkg_name = __PACKAGE__ . "::";
2813 92         585 $pkg_name =~ s/:ON::$/:/;
2814 92         219 my $use_warn = 1;
2815              
2816 92 100       539 if ( ref ($callback) eq "CODE" ) {
    50          
    100          
2817             # Can't detect if there was typo in the given func name of the CODE ref
2818 71         163 $code = $callback; # Already a code referencd.
2819 71         350 $func = sub_fullname ($callback); # Get it's name ... or _ANNON_
2820              
2821 71 50       1885 if ( $func =~ m/^${pkg_name}/ ) {
2822 0         0 warn ("You may not ${msg} a member of the FISH package!\n",
2823             ' ==> ' . $func . "\n");
2824 0         0 $code = $func = undef;
2825 0         0 $use_warn = 0;
2826             }
2827              
2828             # May not self-reference something in this module ...
2829             } elsif ( $callback =~ m/^${pkg_name}/ ) {
2830 0         0 warn ("You may not ${msg} a member of the FISH package!\n",
2831             ' ==> ' . $callback . "\n");
2832 0         0 $use_warn = 0;
2833              
2834             # Provided a fully qualified function name as a string ...
2835             } elsif ( $callback =~ m/^(.+)::([^:]+)$/ ) {
2836 2         12 my ($pkg, $name) = ($1, $2);
2837 2 50       21 if ( $pkg->can ($name) ) {
2838 2         9 $code = $pkg->can ($name); # Convert name into code ref.
2839 2         7 $func = $callback;
2840             }
2841              
2842             # Provided a partially qualified function name as a string ...
2843             # Done by figuring out who called the original DBUG method!
2844             } else {
2845 19         49 my $call_ind = 1;
2846 19   50     176 my $called_by = (caller ($call_ind))[3] || "";
2847 19   66     244 while ( $called_by =~ m/^${pkg_name}/ || $called_by eq "(eval)" ) {
2848 57   100     464 $called_by = (caller (++$call_ind))[3] || "";
2849             }
2850              
2851             # Get the package name of the caller ...
2852 19 100 66     120 if ( $called_by && $called_by =~ m/^(.+)::([^:]+)$/ ) {
2853 5         32 my ($pkg, $name) = ($1, $2);
2854 5 50       67 if ( $pkg->can ($callback) ) {
2855 5         50 $code = $pkg->can ($callback); # Convert name into code ref.
2856 5         15 $func = $callback;
2857             }
2858             }
2859              
2860             # If not from the caller's package ...
2861 19 100       62 unless ( $func ) {
2862 14         179 my $tmp = "main"->can ($callback);
2863 14 50       60 if ( $tmp ) {
2864 14         26 $code = $tmp;
2865 14         40 $func = "main::" . $callback;
2866             }
2867             }
2868             }
2869              
2870 92 50 33     663 if ( $use_warn && ! $func ) {
2871 0         0 warn ("No such ${msg} function! ($callback)\n");
2872             }
2873             }
2874              
2875 92 100       613 return ( wantarray ? ( $code, $func ) : $code );
2876             }
2877              
2878             # ==============================================================================
2879             # Start of Helper methods designed to help test out this module's functionality.
2880             # ==============================================================================
2881              
2882             # ==============================================================
2883             # Not exposed on purpose, so they don't polute the naming space!
2884             # Or have people trying to use them!
2885             # ==============================================================
2886             # Undocumented helper functions exclusively for use by the "t/*.t" programs via
2887             # the t/off/helper1234.pm helper module.
2888             # Not intended for use by anyone else.
2889             # So subject to change without notice!
2890             # They are used to help these test programs validate that this module is working
2891             # as expected without having to manually examine the fish logs for everything!!
2892             # But despite everything, some manual checks will always be needed!
2893             # ==============================================================
2894             # Most of these functions in Fred::Fish::DBUG:OFF are broken and do not
2895             # work there unless you lie and use the $hint arguments! So it's another
2896             # reason not to use them in yor own code base!
2897             # In fact many of these functions in this module are broken as well if fish was
2898             # turned off or paused when the measured event happened.
2899             # ==============================================================
2900             # NOTE: Be carefull how they are called in the t/*.t programs. If called
2901             # the wrong way the HINT parameter won't be handled properly when
2902             # you swap over to the OFF.pm module! The $hint arguments are
2903             # ignored here!
2904             # ==============================================================
2905             # The current FISH function on the fish stack ...
2906             sub dbug_func_name
2907             {
2908 68     68 0 144 my $hint = shift; # Only used in OFF.pm ...
2909 68         332 return ( $dbug_global_vars{functions}->[-1]->{NAME} );
2910             }
2911              
2912             # Number of fish functions on the stack
2913             # This one is used internally as well.
2914             sub dbug_level
2915             {
2916 384     384 0 787 my $hint = shift; # Only used in OFF.pm ...
2917 384         683 my $cnt = @{$dbug_global_vars{functions}};
  384         1063  
2918 384         1679 return ( $cnt );
2919             }
2920              
2921             # This value is set via the calls to DBUG_RETURN() / DBUG_VOID_RETURN() /
2922             # DBUG_RETURN_SPECIAL().
2923             # It can only be non-zero if DBUG_MASK() was called 1st and only for
2924             # DBUG_RETURN(). If fish is turned off it will be -1. Otherwise
2925             # it will be a count of the masked values in fish!
2926             # In all other situations it will return zero!
2927              
2928             sub dbug_mask_return_counts
2929             {
2930 9     9 0 14 my $hint = shift; # Only used in OFF.pm ...
2931 9         22 my $cnt = $dbug_global_vars{mask_return_count};
2932 9 50 33     33 $cnt = $hint if ( $cnt == -1 && defined $hint ); # If unknown ...
2933 9         33 return ( $cnt );
2934             }
2935              
2936             # This value is set via the last call to DBUG_ENTER_FUNC() / DBUG_ENTER_BLOCK()
2937             # when it prints it's masked arguments to fish. If the write to fish doesn't
2938             # happen the count will be -1!
2939             # To decide what needs to be masked, you must call DBUG_MASK_NEXT_FUNC_CALL() 1st!
2940             # Otherwise it will always be zero!
2941              
2942             sub dbug_mask_argument_counts
2943             {
2944 17     17 0 31 my $hint = shift; # Only used in OFF.pm ...
2945 17         61 my $cnt = $dbug_global_vars{mask_last_argument_count};
2946 17 50 33     78 $cnt = $hint if ( $cnt == -1 && defined $hint ); # If unknown ...
2947 17         67 return ( $cnt );
2948             }
2949              
2950             # These 4 actually work in Fred::Fish::DBUG::OFF as well!
2951             sub dbug_threads_supported
2952             {
2953 1     1 0 8 return ( $threads_possible );
2954             }
2955              
2956             sub dbug_fork_supported
2957             {
2958 15     15 0 64 return ( $fork_possible );
2959             }
2960              
2961             sub dbug_time_hires_supported
2962             {
2963 2     2 0 12 return ( $time_hires_flag );
2964             }
2965              
2966             sub dbug_get_frame_value
2967             {
2968 0     0 0 0 my $key = shift;
2969              
2970 0         0 my $value;
2971              
2972 0 0 0     0 if ( $dbug_global_vars{on} && exists $dbug_global_vars{$key} ) {
2973 0         0 $value = $dbug_global_vars{$key};
2974             }
2975              
2976 0         0 return ( $value );
2977             }
2978              
2979             =back
2980              
2981             =head1 CREDITS
2982              
2983             To Fred Fish for developing the basic algorithm and putting it into the
2984             public domain! Any bugs in its implementation are purely my fault.
2985              
2986             =head1 SEE ALSO
2987              
2988             L The controling module which you should be using instead
2989             of this one.
2990              
2991             L The stub version of the ON module.
2992              
2993             L - Allows you to trap and log STDOUT/STDERR to B.
2994              
2995             L - Allows you to trap and log signals to B.
2996              
2997             L - Allows you to implement action
2998             DBUG_SIG_ACTION_LOG for B. Really dangerous to use. Will break most
2999             code bases.
3000              
3001             L - A L wrapper to redirect test results to
3002             B.
3003              
3004             L - Sample code demonstrating using DBUG module.
3005              
3006             =head1 COPYRIGHT
3007              
3008             Copyright (c) 2007 - 2025 Curtis Leach. All rights reserved.
3009              
3010             This program is free software. You can redistribute it and/or modify it
3011             under the same terms as Perl itself.
3012              
3013             =cut
3014              
3015             # ============================================================
3016             #required if module is included w/ require command;
3017             1;
3018