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