File Coverage

blib/lib/Perl/Tidy/Logger.pm
Criterion Covered Total %
statement 148 250 59.2
branch 36 98 36.7
condition 8 24 33.3
subroutine 22 35 62.8
pod 0 23 0.0
total 214 430 49.7


line stmt bran cond sub pod time code
1             package Perl::Tidy::Logger;
2              
3             #####################################################################
4             #
5             # The Perl::Tidy::Logger class writes any .LOG and .ERR files
6             # and supplies some basic run information for error handling.
7             #
8             #####################################################################
9              
10 44     44   257 use strict;
  44         68  
  44         1250  
11 44     44   142 use warnings;
  44         77  
  44         2170  
12             our $VERSION = '20260705';
13 44     44   198 use Carp;
  44         62  
  44         2381  
14 44     44   178 use English qw( -no_match_vars );
  44         88  
  44         279  
15              
16 44     44   14099 use constant EMPTY_STRING => q{};
  44         76  
  44         2386  
17 44     44   178 use constant SPACE => q{ };
  44         67  
  44         8530  
18              
19             sub AUTOLOAD {
20              
21             # Catch any undefined sub calls so that we are sure to get
22             # some diagnostic information. This sub should never be called
23             # except for a programming error.
24 0     0   0 our $AUTOLOAD;
25 0 0       0 return if ( $AUTOLOAD =~ /\bDESTROY$/ );
26 0         0 my ( $pkg, $fname, $lno ) = caller();
27 0         0 my $my_package = __PACKAGE__;
28 0         0 print {*STDERR} <<EOM;
  0         0  
29             ======================================================================
30             Error detected in package '$my_package', version $VERSION
31             Received unexpected AUTOLOAD call for sub '$AUTOLOAD'
32             Called from package: '$pkg'
33             Called from File '$fname' at line '$lno'
34             This error is probably due to a recent programming change
35             ======================================================================
36             EOM
37 0         0 exit 1;
38             } ## end sub AUTOLOAD
39              
40       0     sub DESTROY {
41              
42             # required to avoid call to AUTOLOAD in some versions of perl
43             }
44              
45 44     44   238 use constant DEFAULT_LOGFILE_GAP => 50;
  44         86  
  44         24609  
46              
47             sub new {
48              
49 657     657 0 2969 my ( $class, @arglist ) = @_;
50 657 50       2240 if ( @arglist % 2 ) { croak "Odd number of items in arg hash list\n" }
  0         0  
51              
52 657         5013 my %defaults = (
53             rOpts => undef,
54             log_file => undef,
55             warning_file => undef,
56             fh_stderr => undef,
57             display_name => undef,
58             is_encoded_data => undef,
59             );
60              
61 657         4175 my %args = ( %defaults, @arglist );
62              
63 657         1707 my $rOpts = $args{rOpts};
64 657         1422 my $log_file = $args{log_file};
65 657         1163 my $warning_file = $args{warning_file};
66 657         921 my $fh_stderr = $args{fh_stderr};
67 657         1022 my $display_name = $args{display_name};
68 657         1033 my $is_encoded_data = $args{is_encoded_data};
69              
70 657 100       1760 my $fh_warnings = $rOpts->{'standard-error-output'} ? $fh_stderr : undef;
71              
72             # remove any old error output file if we might write a new one
73 657 100 100     2886 if ( !$fh_warnings && !ref($warning_file) ) {
74 16 50       540 if ( -e $warning_file ) {
75 0 0       0 unlink($warning_file)
76             or Perl::Tidy::Die(
77             "couldn't unlink warning file $warning_file: $OS_ERROR\n");
78             }
79             }
80              
81             my $logfile_gap =
82             defined( $rOpts->{'logfile-gap'} )
83 657 100       1712 ? $rOpts->{'logfile-gap'}
84             : DEFAULT_LOGFILE_GAP;
85 657 100       1666 if ( $logfile_gap == 0 ) { $logfile_gap = 1 }
  1         1  
86              
87 657 50       1934 my $filename_stamp = $display_name ? $display_name . ':' : "??";
88 657 50       1521 my $input_stream_name = $display_name ? $display_name : "??";
89             return bless {
90             _log_file => $log_file,
91             _logfile_gap => $logfile_gap,
92             _rOpts => $rOpts,
93             _fh_warnings => $fh_warnings,
94             _last_input_line_written => 0,
95             _last_input_line_number => undef,
96             _at_end_of_file => 0,
97             _use_prefix => 1,
98             _block_log_output => 0,
99             _line_of_tokens => undef,
100             _output_line_number => undef,
101             _wrote_line_information_string => 0,
102             _wrote_column_headings => 0,
103             _warning_file => $warning_file,
104             _warning_count => 0,
105             _complaint_count => 0,
106             _is_encoded_data => $is_encoded_data,
107             _saw_code_bug => -1, # -1=no 0=maybe 1=for sure
108             _saw_brace_error => 0,
109             _output_array => [],
110             _input_stream_name => $input_stream_name,
111             _filename_stamp => $filename_stamp,
112 657         15400 _save_logfile => $rOpts->{'logfile'},
113             }, $class;
114             } ## end sub new
115              
116             sub get_input_stream_name {
117 0     0 0 0 my $self = shift;
118 0         0 return $self->{_input_stream_name};
119             }
120              
121             sub set_last_input_line_number {
122 657     657 0 1405 my ( $self, $lno ) = @_;
123 657         1423 $self->{_last_input_line_number} = $lno;
124 657         1191 return;
125             }
126              
127             sub get_warning_count {
128 0     0 0 0 my $self = shift;
129 0         0 return $self->{_warning_count};
130             }
131              
132             sub get_use_prefix {
133 0     0 0 0 my $self = shift;
134 0         0 return $self->{_use_prefix};
135             }
136              
137             sub block_log_output {
138 0     0 0 0 my $self = shift;
139 0         0 $self->{_block_log_output} = 1;
140 0         0 return;
141             }
142              
143             sub unblock_log_output {
144 0     0 0 0 my $self = shift;
145 0         0 $self->{_block_log_output} = 0;
146 0         0 return;
147             }
148              
149             sub interrupt_logfile {
150 0     0 0 0 my $self = shift;
151 0         0 $self->{_use_prefix} = 0;
152 0         0 $self->warning("\n");
153 0         0 $self->write_logfile_entry( '#' x 24 . " WARNING " . '#' x 25 . "\n" );
154 0         0 return;
155             } ## end sub interrupt_logfile
156              
157             sub resume_logfile {
158 0     0 0 0 my $self = shift;
159 0         0 $self->write_logfile_entry( '#' x 60 . "\n" );
160 0         0 $self->{_use_prefix} = 1;
161 0         0 return;
162             } ## end sub resume_logfile
163              
164             sub we_are_at_the_last_line {
165 656     656 0 907 my $self = shift;
166 656 50       1962 if ( !$self->{_wrote_line_information_string} ) {
167 0         0 $self->write_logfile_entry("Last line\n\n");
168             }
169 656         1242 $self->{_at_end_of_file} = 1;
170 656         1107 return;
171             } ## end sub we_are_at_the_last_line
172              
173             # record some stuff in case we go down in flames
174 44     44   269 use constant MAX_PRINTED_CHARS => 35;
  44         60  
  44         38625  
175              
176             sub black_box {
177 3     3 0 6 my ( $self, $line_of_tokens, $output_line_number ) = @_;
178              
179             # This routine saves information comparing the indentation of input
180             # and output lines when a detailed logfile is requested.
181             # This was very useful during the initial development of perltidy.
182              
183 3         4 my $input_line = $line_of_tokens->{_line_text};
184 3         5 my $input_line_number = $line_of_tokens->{_line_number};
185              
186 3         6 $self->{_line_of_tokens} = $line_of_tokens;
187 3         5 $self->{_output_line_number} = $output_line_number;
188 3         3 $self->{_wrote_line_information_string} = 0;
189              
190 3         5 my $last_input_line_written = $self->{_last_input_line_written};
191 3 50 33     9 if (
192             (
193             ( $input_line_number - $last_input_line_written ) >=
194             $self->{_logfile_gap}
195             )
196             || ( $input_line =~ /^\s*(sub|package)\s+(\w+)/ )
197             )
198             {
199 3         4 my $structural_indentation_level = $line_of_tokens->{_level_0};
200 3 50       7 $structural_indentation_level = 0
201             if ( $structural_indentation_level < 0 );
202 3         3 $self->{_last_input_line_written} = $input_line_number;
203 3         11 ( my $out_str = $input_line ) =~ s/^\s+//;
204 3         5 chomp $out_str;
205              
206 3         7 $out_str = ( '.' x $structural_indentation_level ) . $out_str;
207              
208 3 50       6 if ( length($out_str) > MAX_PRINTED_CHARS ) {
209 0         0 $out_str = substr( $out_str, 0, MAX_PRINTED_CHARS ) . " ....";
210             }
211 3         10 $self->logfile_output( EMPTY_STRING, "$out_str\n" );
212             }
213 3         6 return;
214             } ## end sub black_box
215              
216             sub write_logfile_entry {
217              
218 8553     8553 0 13438 my ( $self, @msg ) = @_;
219              
220             # add leading >>> to avoid confusing error messages and code
221 8553         24532 $self->logfile_output( ">>>", "@msg" );
222 8553         13398 return;
223             } ## end sub write_logfile_entry
224              
225             sub write_column_headings {
226 1     1 0 1 my $self = shift;
227              
228 1         2 $self->{_wrote_column_headings} = 1;
229 1         1 my $routput_array = $self->{_output_array};
230 1         1 push @{$routput_array}, <<EOM;
  1         2  
231              
232             Starting formatting pass...
233             The nesting depths in the table below are at the start of the lines.
234             The indicated output line numbers are not always exact.
235             ci = levels of continuation indentation; bk = 1 if in BLOCK, 0 if not.
236              
237             in:out indent c b nesting code + messages; (messages begin with >>>)
238             lines levels i k (code begins with one '.' per indent level)
239             ------ ----- - - -------- -------------------------------------------
240             EOM
241 1         2 return;
242             } ## end sub write_column_headings
243              
244             sub make_line_information_string {
245              
246             # make columns of information when a logfile message needs to go out
247 5091     5091 0 5800 my $self = shift;
248 5091         6288 my $line_of_tokens = $self->{_line_of_tokens};
249 5091         6276 my $input_line_number = $line_of_tokens->{_line_number};
250 5091         6687 my $line_information_string = EMPTY_STRING;
251 5091 100       7539 if ($input_line_number) {
252              
253 3         3 my $output_line_number = $self->{_output_line_number};
254 3         4 my $brace_depth = $line_of_tokens->{_curly_brace_depth};
255 3         3 my $paren_depth = $line_of_tokens->{_paren_depth};
256 3         4 my $square_bracket_depth = $line_of_tokens->{_square_bracket_depth};
257             my $guessed_indentation_level =
258 3         4 $line_of_tokens->{_guessed_indentation_level};
259              
260 3         3 my $structural_indentation_level = $line_of_tokens->{_level_0};
261              
262             $self->write_column_headings()
263 3 100       7 unless ( $self->{_wrote_column_headings} );
264              
265             # keep logfile columns aligned for scripts up to 999 lines;
266             # for longer scripts it doesn't really matter
267 3         4 my $extra_space = EMPTY_STRING;
268 3 0       4 $extra_space .=
    50          
269             ( $input_line_number < 10 ) ? SPACE x 2
270             : ( $input_line_number < 100 ) ? SPACE
271             : EMPTY_STRING;
272 3 0       5 $extra_space .=
    50          
273             ( $output_line_number < 10 ) ? SPACE x 2
274             : ( $output_line_number < 100 ) ? SPACE
275             : EMPTY_STRING;
276              
277             # there are 2 possible nesting strings:
278             # the original which looks like this: (0 [1 {2
279             # the new one, which looks like this: {{[
280             # the new one is easier to read, and shows the order, but
281             # could be arbitrarily long, so we use it unless it is too long
282 3         6 my $nesting_string =
283             "($paren_depth [$square_bracket_depth {$brace_depth";
284 3         3 my $nesting_string_new = $line_of_tokens->{_nesting_tokens_0};
285 3         3 my $ci_level = $line_of_tokens->{_ci_level_0};
286 3 50       6 if ( $ci_level > 9 ) { $ci_level = '*' }
  0         0  
287 3 50       11 my $bk = ( $line_of_tokens->{_nesting_blocks_0} =~ /1$/ ) ? '1' : '0';
288              
289 3 50       4 if ( length($nesting_string_new) <= 8 ) {
290 3         8 $nesting_string =
291             $nesting_string_new . SPACE x ( 8 - length($nesting_string_new) );
292             }
293             $line_information_string =
294 3         7 "L$input_line_number:$output_line_number$extra_space i$guessed_indentation_level:$structural_indentation_level $ci_level $bk $nesting_string";
295             }
296 5091         8853 return $line_information_string;
297             } ## end sub make_line_information_string
298              
299             sub logfile_output {
300              
301 8556     8556 0 12693 my ( $self, $prompt, $msg ) = @_;
302              
303             # Write a message to the log file
304              
305 8556 50       15031 return if ( $self->{_block_log_output} );
306              
307 8556         10352 my $routput_array = $self->{_output_array};
308 8556 100 66     20595 if ( $self->{_at_end_of_file} || !$self->{_use_prefix} ) {
309 3465         3586 push @{$routput_array}, "$msg";
  3465         6785  
310             }
311             else {
312 5091         8623 my $line_information_string = $self->make_line_information_string();
313 5091         7171 $self->{_wrote_line_information_string} = 1;
314              
315 5091 100       6956 if ($line_information_string) {
316 3         4 push @{$routput_array}, "$line_information_string $prompt$msg";
  3         8  
317             }
318             else {
319 5088         5475 push @{$routput_array}, "$msg";
  5088         10849  
320             }
321             }
322 8556         11305 return;
323             } ## end sub logfile_output
324              
325             sub get_saw_brace_error {
326 656     656 0 967 my $self = shift;
327 656         2206 return $self->{_saw_brace_error};
328             }
329              
330             sub increment_brace_error {
331 0     0 0 0 my $self = shift;
332 0         0 $self->{_saw_brace_error}++;
333 0         0 return;
334             }
335              
336             sub brace_warning {
337 0     0 0 0 my ( $self, $msg, $msg_line_number ) = @_;
338              
339 44     44   334 use constant BRACE_WARNING_LIMIT => 10;
  44         97  
  44         9594  
340 0         0 my $saw_brace_error = $self->{_saw_brace_error};
341              
342 0 0       0 if ( $saw_brace_error < BRACE_WARNING_LIMIT ) {
343 0         0 $self->warning( $msg, $msg_line_number );
344             }
345 0         0 $saw_brace_error++;
346 0         0 $self->{_saw_brace_error} = $saw_brace_error;
347              
348 0 0       0 if ( $saw_brace_error == BRACE_WARNING_LIMIT ) {
349 0         0 $self->warning("No further warnings of this type will be given\n");
350             }
351 0         0 return;
352             } ## end sub brace_warning
353              
354             sub complain {
355              
356             # handle non-critical warning messages based on input flag
357 42     42 0 88 my ( $self, $msg, $msg_line_number ) = @_;
358 42         73 my $rOpts = $self->{_rOpts};
359              
360             # these appear in .ERR output only if -w flag is used
361 42 50       123 if ( $rOpts->{'warning-output'} ) {
362 0         0 $self->warning( $msg, $msg_line_number );
363             }
364              
365             # otherwise, they go to the .LOG file
366             else {
367 42         67 $self->{_complaint_count}++;
368 42 50       87 if ($msg_line_number) {
369              
370             # NOTE: consider using same prefix as warning()
371 42         117 $msg = $msg_line_number . ':' . $msg;
372             }
373 42         110 $self->write_logfile_entry($msg);
374             }
375 42         101 return;
376             } ## end sub complain
377              
378             sub warning {
379              
380 0     0 0 0 my ( $self, $msg, ($msg_line_number) ) = @_;
381              
382             # Report errors to .ERR file (or stdout)
383             # Given:
384             # $msg = a string with the warning message
385             # $msg_line_number = optional line number prefix
386              
387 44     44   242 use constant WARNING_LIMIT => 50;
  44         93  
  44         32252  
388              
389             # Always bump the warn count, even if no message goes out
390 0         0 Perl::Tidy::Warn_count_bump();
391              
392 0         0 my $rOpts = $self->{_rOpts};
393 0 0       0 if ( !$rOpts->{'quiet'} ) {
394              
395 0         0 my $warning_count = $self->{_warning_count};
396 0         0 my $fh_warnings = $self->{_fh_warnings};
397 0         0 my $is_encoded_data = $self->{_is_encoded_data};
398 0 0       0 if ( !$fh_warnings ) {
399 0         0 my $warning_file = $self->{_warning_file};
400 0         0 $fh_warnings =
401             Perl::Tidy::streamhandle( $warning_file, 'w', $is_encoded_data );
402 0 0       0 if ( !$fh_warnings ) {
403 0         0 Perl::Tidy::Die("couldn't open warning file '$warning_file'\n");
404             }
405 0         0 Perl::Tidy::nag_flush($fh_warnings);
406 0 0       0 Perl::Tidy::Warn_msg("## Please see file $warning_file\n")
407             unless ( ref($warning_file) );
408 0         0 $self->{_fh_warnings} = $fh_warnings;
409 0         0 $fh_warnings->print("Perltidy version is $Perl::Tidy::VERSION\n");
410             }
411              
412 0         0 my $filename_stamp = $self->{_filename_stamp};
413              
414 0 0       0 if ( $warning_count < WARNING_LIMIT ) {
415              
416 0 0       0 if ( !$warning_count ) {
417              
418             # On first error always write a line with the filename. Note
419             # that the filename will be 'perltidy' if input is from stdin
420             # or from a data structure.
421 0 0       0 if ($filename_stamp) {
422 0         0 $fh_warnings->print(
423             "\n$filename_stamp Begin Error Output Stream\n");
424             }
425              
426             # Turn off filename stamping unless error output is directed
427             # to the standard error output (with -se flag)
428 0 0       0 if ( !$rOpts->{'standard-error-output'} ) {
429 0         0 $filename_stamp = EMPTY_STRING;
430 0         0 $self->{_filename_stamp} = $filename_stamp;
431             }
432             }
433              
434 0 0 0     0 if ( $self->get_use_prefix() > 0 && defined($msg_line_number) ) {
435 0         0 $self->write_logfile_entry("WARNING: $msg");
436              
437             # add prefix 'filename:line_no: ' to message lines
438 0         0 my $pre_string = $filename_stamp . $msg_line_number . ': ';
439 0         0 chomp $msg;
440 0         0 $msg =~ s/\n/\n$pre_string/g;
441 0         0 $msg = $pre_string . $msg . "\n";
442              
443 0         0 $fh_warnings->print($msg);
444              
445             }
446             else {
447 0         0 $self->write_logfile_entry($msg);
448              
449             # add prefix 'filename: ' to message lines
450 0 0       0 if ($filename_stamp) {
451 0         0 my $pre_string = $filename_stamp . SPACE;
452 0         0 chomp $msg;
453 0         0 $msg =~ s/\n/\n$pre_string/g;
454 0         0 $msg = $pre_string . $msg . "\n";
455             }
456              
457 0         0 $fh_warnings->print($msg);
458             }
459             }
460 0         0 $warning_count++;
461 0         0 $self->{_warning_count} = $warning_count;
462              
463 0 0       0 if ( $warning_count == WARNING_LIMIT ) {
464 0         0 $fh_warnings->print(
465             $filename_stamp . "No further warnings will be given\n" );
466             }
467             }
468 0         0 return;
469             } ## end sub warning
470              
471             sub report_definite_bug {
472 0     0 0 0 my $self = shift;
473 0         0 $self->{_saw_code_bug} = 1;
474 0         0 return;
475             }
476              
477             sub get_save_logfile {
478 1969     1969 0 2587 my $self = shift;
479 1969         5784 return $self->{_save_logfile};
480             }
481              
482             sub finish {
483              
484             # called after all formatting to summarize errors
485 657     657 0 1269 my ($self) = @_;
486              
487 657         1391 my $warning_count = $self->{_warning_count};
488 657         1387 my $save_logfile = $self->{_save_logfile};
489 657         1272 my $log_file = $self->{_log_file};
490 657         1204 my $msg_line_number = $self->{_last_input_line_number};
491              
492 657 50       1768 if ($warning_count) {
493 0 0       0 if ($save_logfile) {
494 0         0 $self->block_log_output(); # avoid echoing this to the logfile
495 0         0 $self->warning(
496             "The logfile $log_file may contain useful information\n",
497             $msg_line_number );
498 0         0 $self->unblock_log_output();
499             }
500              
501 0 0       0 if ( $self->{_complaint_count} > 0 ) {
502 0         0 $self->warning(
503             "To see $self->{_complaint_count} non-critical warnings rerun with -w\n",
504             $msg_line_number
505             );
506             }
507              
508 0 0 0     0 if ( $self->{_saw_brace_error}
      0        
509             && ( $self->{_logfile_gap} > 1 || !$save_logfile ) )
510             {
511 0         0 $self->warning( "To save a full .LOG file rerun with -g\n",
512             $msg_line_number );
513             }
514             }
515              
516 657 100       1479 if ($save_logfile) {
517 1         2 my $is_encoded_data = $self->{_is_encoded_data};
518 1         3 my $fh = Perl::Tidy::streamhandle( $log_file, 'w', $is_encoded_data );
519 1 50       2 if ( !$fh ) {
520 0         0 Perl::Tidy::Warn("unable to open log file '$log_file'\n");
521             }
522             else {
523 1         2 my $routput_array = $self->{_output_array};
524 1         1 foreach my $line ( @{$routput_array} ) { $fh->print($line) }
  1         2  
  18         24  
525 1 0 33     13 if ( $fh->can('close')
      33        
526             && !ref($log_file)
527             && $log_file ne '-' )
528             {
529 0 0       0 $fh->close()
530             or Perl::Tidy::Warn(
531             "Error closing LOG file '$log_file': $OS_ERROR\n");
532             }
533             }
534             }
535 657         3099 return;
536             } ## end sub finish
537             1;