1 #####################################################################
3 # The Perl::Tidy::Logger class writes the .LOG and .ERR files
5 #####################################################################
7 package Perl::Tidy::Logger;
10 our $VERSION = '20181120';
14 my ( $class, $rOpts, $log_file, $warning_file, $fh_stderr, $saw_extrude ) =
17 my $fh_warnings = $rOpts->{'standard-error-output'} ? $fh_stderr : undef;
19 # remove any old error output file if we might write a new one
20 unless ( $fh_warnings || ref($warning_file) ) {
21 if ( -e $warning_file ) {
24 "couldn't unlink warning file $warning_file: $!\n");
29 defined( $rOpts->{'logfile-gap'} )
30 ? $rOpts->{'logfile-gap'}
32 if ( $logfile_gap == 0 ) { $logfile_gap = 1 }
35 _log_file => $log_file,
36 _logfile_gap => $logfile_gap,
38 _fh_warnings => $fh_warnings,
39 _last_input_line_written => 0,
42 _block_log_output => 0,
43 _line_of_tokens => undef,
44 _output_line_number => undef,
45 _wrote_line_information_string => 0,
46 _wrote_column_headings => 0,
47 _warning_file => $warning_file,
49 _complaint_count => 0,
50 _saw_code_bug => -1, # -1=no 0=maybe 1=for sure
51 _saw_brace_error => 0,
52 _saw_extrude => $saw_extrude,
57 sub get_warning_count {
59 return $self->{_warning_count};
64 return $self->{_use_prefix};
67 sub block_log_output {
69 $self->{_block_log_output} = 1;
73 sub unblock_log_output {
75 $self->{_block_log_output} = 0;
79 sub interrupt_logfile {
81 $self->{_use_prefix} = 0;
83 $self->write_logfile_entry( '#' x 24 . " WARNING " . '#' x 25 . "\n" );
89 $self->write_logfile_entry( '#' x 60 . "\n" );
90 $self->{_use_prefix} = 1;
94 sub we_are_at_the_last_line {
96 unless ( $self->{_wrote_line_information_string} ) {
97 $self->write_logfile_entry("Last line\n\n");
99 $self->{_at_end_of_file} = 1;
103 # record some stuff in case we go down in flames
105 my ( $self, $line_of_tokens, $output_line_number ) = @_;
106 my $input_line = $line_of_tokens->{_line_text};
107 my $input_line_number = $line_of_tokens->{_line_number};
109 # save line information in case we have to write a logfile message
110 $self->{_line_of_tokens} = $line_of_tokens;
111 $self->{_output_line_number} = $output_line_number;
112 $self->{_wrote_line_information_string} = 0;
114 my $last_input_line_written = $self->{_last_input_line_written};
115 my $rOpts = $self->{_rOpts};
118 ( $input_line_number - $last_input_line_written ) >=
119 $self->{_logfile_gap}
121 || ( $input_line =~ /^\s*(sub|package)\s+(\w+)/ )
124 my $structural_indentation_level = $line_of_tokens->{_level_0};
125 $structural_indentation_level = 0
126 if ( $structural_indentation_level < 0 );
127 $self->{_last_input_line_written} = $input_line_number;
128 ( my $out_str = $input_line ) =~ s/^\s*//;
131 $out_str = ( '.' x $structural_indentation_level ) . $out_str;
133 if ( length($out_str) > 35 ) {
134 $out_str = substr( $out_str, 0, 35 ) . " ....";
136 $self->logfile_output( "", "$out_str\n" );
141 sub write_logfile_entry {
143 my ( $self, @msg ) = @_;
145 # add leading >>> to avoid confusing error messages and code
146 $self->logfile_output( ">>>", "@msg" );
150 sub write_column_headings {
153 $self->{_wrote_column_headings} = 1;
154 my $routput_array = $self->{_output_array};
155 push @{$routput_array}, <<EOM;
156 The nesting depths in the table below are at the start of the lines.
157 The indicated output line numbers are not always exact.
158 ci = levels of continuation indentation; bk = 1 if in BLOCK, 0 if not.
160 in:out indent c b nesting code + messages; (messages begin with >>>)
161 lines levels i k (code begins with one '.' per indent level)
162 ------ ----- - - -------- -------------------------------------------
167 sub make_line_information_string {
169 # make columns of information when a logfile message needs to go out
171 my $line_of_tokens = $self->{_line_of_tokens};
172 my $input_line_number = $line_of_tokens->{_line_number};
173 my $line_information_string = "";
174 if ($input_line_number) {
176 my $output_line_number = $self->{_output_line_number};
177 my $brace_depth = $line_of_tokens->{_curly_brace_depth};
178 my $paren_depth = $line_of_tokens->{_paren_depth};
179 my $square_bracket_depth = $line_of_tokens->{_square_bracket_depth};
180 my $guessed_indentation_level =
181 $line_of_tokens->{_guessed_indentation_level};
182 ##my $rtoken_array = $line_of_tokens->{_rtoken_array};
184 my $structural_indentation_level = $line_of_tokens->{_level_0};
186 $self->write_column_headings() unless $self->{_wrote_column_headings};
188 # keep logfile columns aligned for scripts up to 999 lines;
189 # for longer scripts it doesn't really matter
190 my $extra_space = "";
192 ( $input_line_number < 10 ) ? " "
193 : ( $input_line_number < 100 ) ? " "
196 ( $output_line_number < 10 ) ? " "
197 : ( $output_line_number < 100 ) ? " "
200 # there are 2 possible nesting strings:
201 # the original which looks like this: (0 [1 {2
202 # the new one, which looks like this: {{[
203 # the new one is easier to read, and shows the order, but
204 # could be arbitrarily long, so we use it unless it is too long
206 "($paren_depth [$square_bracket_depth {$brace_depth";
207 my $nesting_string_new = $line_of_tokens->{_nesting_tokens_0};
208 my $ci_level = $line_of_tokens->{_ci_level_0};
209 if ( $ci_level > 9 ) { $ci_level = '*' }
210 my $bk = ( $line_of_tokens->{_nesting_blocks_0} =~ /1$/ ) ? '1' : '0';
212 if ( length($nesting_string_new) <= 8 ) {
214 $nesting_string_new . " " x ( 8 - length($nesting_string_new) );
216 $line_information_string =
217 "L$input_line_number:$output_line_number$extra_space i$guessed_indentation_level:$structural_indentation_level $ci_level $bk $nesting_string";
219 return $line_information_string;
223 my ( $self, $prompt, $msg ) = @_;
224 return if ( $self->{_block_log_output} );
226 my $routput_array = $self->{_output_array};
227 if ( $self->{_at_end_of_file} || !$self->{_use_prefix} ) {
228 push @{$routput_array}, "$msg";
231 my $line_information_string = $self->make_line_information_string();
232 $self->{_wrote_line_information_string} = 1;
234 if ($line_information_string) {
235 push @{$routput_array}, "$line_information_string $prompt$msg";
238 push @{$routput_array}, "$msg";
244 sub get_saw_brace_error {
246 return $self->{_saw_brace_error};
249 sub increment_brace_error {
251 $self->{_saw_brace_error}++;
256 my ( $self, $msg ) = @_;
258 #use constant BRACE_WARNING_LIMIT => 10;
259 my $BRACE_WARNING_LIMIT = 10;
260 my $saw_brace_error = $self->{_saw_brace_error};
262 if ( $saw_brace_error < $BRACE_WARNING_LIMIT ) {
263 $self->warning($msg);
266 $self->{_saw_brace_error} = $saw_brace_error;
268 if ( $saw_brace_error == $BRACE_WARNING_LIMIT ) {
269 $self->warning("No further warnings of this type will be given\n");
276 # handle non-critical warning messages based on input flag
277 my ( $self, $msg ) = @_;
278 my $rOpts = $self->{_rOpts};
280 # these appear in .ERR output only if -w flag is used
281 if ( $rOpts->{'warning-output'} ) {
282 $self->warning($msg);
285 # otherwise, they go to the .LOG file
287 $self->{_complaint_count}++;
288 $self->write_logfile_entry($msg);
295 # report errors to .ERR file (or stdout)
296 my ( $self, $msg ) = @_;
298 #use constant WARNING_LIMIT => 50;
299 my $WARNING_LIMIT = 50;
301 my $rOpts = $self->{_rOpts};
302 unless ( $rOpts->{'quiet'} ) {
304 my $warning_count = $self->{_warning_count};
305 my $fh_warnings = $self->{_fh_warnings};
306 if ( !$fh_warnings ) {
307 my $warning_file = $self->{_warning_file};
308 ( $fh_warnings, my $filename ) =
309 Perl::Tidy::streamhandle( $warning_file, 'w' );
310 $fh_warnings or Perl::Tidy::Die("couldn't open $filename $!\n");
311 Perl::Tidy::Warn("## Please see file $filename\n")
312 unless ref($warning_file);
313 $self->{_fh_warnings} = $fh_warnings;
314 $fh_warnings->print("Perltidy version is $Perl::Tidy::VERSION\n");
317 if ( $warning_count < $WARNING_LIMIT ) {
318 if ( $self->get_use_prefix() > 0 ) {
319 my $input_line_number =
320 Perl::Tidy::Tokenizer::get_input_line_number();
321 if ( !defined($input_line_number) ) { $input_line_number = -1 }
322 $fh_warnings->print("$input_line_number:\t$msg");
323 $self->write_logfile_entry("WARNING: $msg");
326 $fh_warnings->print($msg);
327 $self->write_logfile_entry($msg);
331 $self->{_warning_count} = $warning_count;
333 if ( $warning_count == $WARNING_LIMIT ) {
334 $fh_warnings->print("No further warnings will be given\n");
340 # programming bug codes:
342 # 0 = maybe, not sure.
344 sub report_possible_bug {
346 my $saw_code_bug = $self->{_saw_code_bug};
347 $self->{_saw_code_bug} = ( $saw_code_bug < 0 ) ? 0 : $saw_code_bug;
351 sub report_definite_bug {
353 $self->{_saw_code_bug} = 1;
357 sub ask_user_for_bug_report {
359 my ( $self, $infile_syntax_ok, $formatter ) = @_;
360 my $saw_code_bug = $self->{_saw_code_bug};
361 if ( ( $saw_code_bug == 0 ) && ( $infile_syntax_ok == 1 ) ) {
362 $self->warning(<<EOM);
364 You may have encountered a code bug in perltidy. If you think so, and
365 the problem is not listed in the BUGS file at
366 http://perltidy.sourceforge.net, please report it so that it can be
367 corrected. Include the smallest possible script which has the problem,
368 along with the .LOG file. See the manual pages for contact information.
373 elsif ( $saw_code_bug == 1 ) {
374 if ( $self->{_saw_extrude} ) {
375 $self->warning(<<EOM);
377 You may have encountered a bug in perltidy. However, since you are using the
378 -extrude option, the problem may be with perl or one of its modules, which have
379 occasional problems with this type of file. If you believe that the
380 problem is with perltidy, and the problem is not listed in the BUGS file at
381 http://perltidy.sourceforge.net, please report it so that it can be corrected.
382 Include the smallest possible script which has the problem, along with the .LOG
383 file. See the manual pages for contact information.
388 $self->warning(<<EOM);
390 Oops, you seem to have encountered a bug in perltidy. Please check the
391 BUGS file at http://perltidy.sourceforge.net. If the problem is not
392 listed there, please report it so that it can be corrected. Include the
393 smallest possible script which produces this message, along with the
394 .LOG file if appropriate. See the manual pages for contact information.
395 Your efforts are appreciated.
398 my $added_semicolon_count = 0;
400 $added_semicolon_count =
401 $formatter->get_added_semicolon_count();
403 if ( $added_semicolon_count > 0 ) {
404 $self->warning(<<EOM);
406 The log file shows that perltidy added $added_semicolon_count semicolons.
407 Please rerun with -nasc to see if that is the cause of the syntax error. Even
408 if that is the problem, please report it so that it can be fixed.
419 # called after all formatting to summarize errors
420 my ( $self, $infile_syntax_ok, $formatter ) = @_;
422 my $rOpts = $self->{_rOpts};
423 my $warning_count = $self->{_warning_count};
424 my $saw_code_bug = $self->{_saw_code_bug};
427 ( $saw_code_bug == 0 && $infile_syntax_ok == 1 )
428 || $saw_code_bug == 1
429 || $rOpts->{'logfile'};
430 my $log_file = $self->{_log_file};
431 if ($warning_count) {
433 $self->block_log_output(); # avoid echoing this to the logfile
435 "The logfile $log_file may contain useful information\n");
436 $self->unblock_log_output();
439 if ( $self->{_complaint_count} > 0 ) {
441 "To see $self->{_complaint_count} non-critical warnings rerun with -w\n"
445 if ( $self->{_saw_brace_error}
446 && ( $self->{_logfile_gap} > 1 || !$save_logfile ) )
448 $self->warning("To save a full .LOG file rerun with -g\n");
451 $self->ask_user_for_bug_report( $infile_syntax_ok, $formatter );
454 my $log_file = $self->{_log_file};
455 my ( $fh, $filename ) = Perl::Tidy::streamhandle( $log_file, 'w' );
457 my $routput_array = $self->{_output_array};
458 foreach ( @{$routput_array} ) { $fh->print($_) }
459 if ( $log_file ne '-' && !ref $log_file ) {
460 eval { $fh->close() };