]> git.donarmstrong.com Git - perltidy.git/blob - lib/Perl/Tidy.pm
New upstream release 20250105
[perltidy.git] / lib / Perl / Tidy.pm
1 #
2 ###########################################################
3 #
4 #    perltidy - a perl script indenter and formatter
5 #
6 #    Copyright (c) 2000-2025 by Steve Hancock
7 #    Distributed under the GPL license agreement; see file COPYING
8 #
9 #    This program is free software; you can redistribute it and/or modify
10 #    it under the terms of the GNU General Public License as published by
11 #    the Free Software Foundation; either version 2 of the License, or
12 #    (at your option) any later version.
13 #
14 #    This program is distributed in the hope that it will be useful,
15 #    but WITHOUT ANY WARRANTY; without even the implied warranty of
16 #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 #    GNU General Public License for more details.
18 #
19 #    You should have received a copy of the GNU General Public License along
20 #    with this program; if not, write to the Free Software Foundation, Inc.,
21 #    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22 #
23 #    For brief instructions, try 'perltidy -h'.
24 #    For more complete documentation, try 'man perltidy'
25 #    or visit the GitHub site https://perltidy.github.io/perltidy/
26 #
27 #    This script is an example of the default style.  It was formatted with:
28 #
29 #      perltidy Tidy.pm
30 #
31 #    Code Contributions: See ChangeLog.html for a complete history.
32 #      Michael Cartmell supplied code for adaptation to VMS and helped with
33 #        v-strings.
34 #      Hugh S. Myers supplied sub streamhandle and the supporting code to
35 #        create a Perl::Tidy module which can operate on strings, arrays, etc.
36 #      Yves Orton supplied coding to help detect Windows versions.
37 #      Axel Rose supplied a patch for MacPerl.
38 #      Sebastien Aperghis-Tramoni supplied a patch for the defined or operator.
39 #      Dan Tyrell contributed a patch for binary I/O.
40 #      Ueli Hugenschmidt contributed a patch for -fpsc
41 #      Sam Kington supplied a patch to identify the initial indentation of
42 #      entabbed code.
43 #      jonathan swartz supplied patches for:
44 #      * .../ pattern, which looks upwards from directory
45 #      * --notidy, to be used in directories where we want to avoid
46 #        accidentally tidying
47 #      * prefilter and postfilter
48 #      * iterations option
49 #
50 #      Many others have supplied key ideas, suggestions, and bug reports;
51 #        see the CHANGES file.
52 #
53 ############################################################
54
55 package Perl::Tidy;
56
57 # perlver reports minimum version needed is 5.8.1
58 # 5.004 needed for IO::File
59 # 5.008 needed for wide characters
60 # 5.008001 needed for utf8::is_utf8
61 # 5.008001 needed for Scalar::Util::refaddr
62 use 5.008001;
63 use warnings;
64 use strict;
65 use Exporter;
66 use Carp;
67 use English     qw( -no_match_vars );
68 use Digest::MD5 qw(md5_hex);
69 use Perl::Tidy::Debugger;
70 use Perl::Tidy::Diagnostics;
71 use Perl::Tidy::FileWriter;
72 use Perl::Tidy::Formatter;
73 use Perl::Tidy::HtmlWriter;
74 use Perl::Tidy::IOScalar;
75 use Perl::Tidy::IOScalarArray;
76 use Perl::Tidy::IndentationItem;
77 use Perl::Tidy::Logger;
78 use Perl::Tidy::Tokenizer;
79 use Perl::Tidy::VerticalAligner;
80 local $OUTPUT_AUTOFLUSH = 1;
81
82 # DEVEL_MODE can be turned on for extra checking during development
83 use constant DEVEL_MODE   => 0;
84 use constant DIAGNOSTICS  => 0;
85 use constant EMPTY_STRING => q{};
86 use constant SPACE        => q{ };
87 use constant CONST_1024   => 1024;    # bytes per kb; 2**10
88
89 use vars qw{
90   $VERSION
91   @ISA
92   @EXPORT
93 };
94
95 @ISA    = qw( Exporter );
96 @EXPORT = qw( &perltidy );
97
98 use Cwd;
99 use Encode ();
100 use Encode::Guess;
101 use IO::File;
102 use File::Basename;
103 use File::Copy;
104 use File::Spec ();
105
106 # perl stat function index names, based on
107 #    https://perldoc.perl.org/functions/stat
108 use constant {
109
110     _mode_  => 2,    # file mode  (type and permissions)
111     _uid_   => 4,    # numeric user ID of file's owner
112     _gid_   => 5,    # numeric group ID of file's owner
113     _atime_ => 8,    # last access time in seconds since the epoch
114     _mtime_ => 9,    # last modify time in seconds since the epoch
115
116 ##  _dev_     => 0,     # device number of filesystem
117 ##  _ino_     => 1,     # inode number
118 ##  _nlink_   => 3,     # number of (hard) links to the file
119 ##  _rdev_    => 6,     # the device identifier (special files only)
120 ##  _size_    => 7,     # total size of file, in bytes
121 ##  _ctime_   => 10,    # inode change time in seconds since the epoch (*)
122 ##  _blksize_ => 11,    # preferred I/O size in bytes for interacting with
123 ##                      # the file (may vary from file to file)
124 ##  _blocks_  => 12,    # actual number of system-specific blocks allocated
125 ##                      # on disk (often, but not always, 512 bytes each)
126 };
127
128 BEGIN {
129
130     # Release version is the approximate YYYYMMDD of the release.
131     # Development version is (Last Release).(Development Number)
132
133     # To make the number continually increasing, the Development Number is a 2
134     # digit number starting at 01 after a release. It is continually bumped
135     # along at significant points during development. If it ever reaches 99
136     # then the Release version must be bumped, and it is probably past time for
137     # a release anyway.
138
139     $VERSION = '20250105';
140 } ## end BEGIN
141
142 sub DESTROY {
143     my $self = shift;
144
145     # required to avoid call to AUTOLOAD in some versions of perl
146     return;
147 } ## end sub DESTROY
148
149 sub AUTOLOAD {
150
151     # Catch any undefined sub calls so that we are sure to get
152     # some diagnostic information.  This sub should never be called
153     # except for a programming error.
154     our $AUTOLOAD;
155     return if ( $AUTOLOAD =~ /\bDESTROY$/ );
156     my ( $pkg, $fname, $lno ) = caller();
157     print {*STDERR} <<EOM;
158 ======================================================================
159 Unexpected call to Autoload looking for sub $AUTOLOAD
160 Called from package: '$pkg'
161 Called from File '$fname'  at line '$lno'
162 This error is probably due to a recent programming change
163 ======================================================================
164 EOM
165     exit 1;
166 } ## end sub AUTOLOAD
167
168 sub streamhandle {
169
170     my ( $filename, $mode, ($is_encoded_data) ) = @_;
171
172     # Given:
173     #   $filename
174     #   $mode = 'r' or 'w' (only 'w' is used now, see note below)
175     #   $is_encoded_data (optional flag)
176
177     # Create an object which:
178     #   has a 'getline' method if mode='r', and
179     #   has a 'print' method if mode='w'.
180     # The objects also need a 'close' method.
181     #
182     # How the object is made:
183     #
184     # if $filename is:     Make object using:
185     # ----------------     -----------------
186     # '-'                  (STDIN if mode = 'r', STDOUT if mode='w')
187     # string               IO::File
188     # ARRAY  ref           Perl::Tidy::IOScalarArray (formerly IO::ScalarArray)
189     # STRING ref           Perl::Tidy::IOScalar      (formerly IO::Scalar)
190     # object               object
191     #                      (check for 'print' method for 'w' mode)
192     #                      (check for 'getline' method for 'r' mode)
193
194     # An optional flag '$is_encoded_data' may be given, as follows:
195     # - true: encoded data is being transferred,
196     #    set encoding to be utf8 for files and for stdin.
197     # - false: unencoded binary data is being transferred,
198     #    set binary mode for files and for stdin.
199
200     # NOTE: mode 'r' works but is no longer used.
201     # Use sub stream_slurp instead for mode 'r', for efficiency.
202     $mode = lc($mode);
203     if ( $mode ne 'w' ) {
204         if ( DEVEL_MODE || $mode ne 'r' ) {
205             Fault("streamhandle called in unexpected mode '$mode'\n");
206         }
207     }
208
209     my $ref = ref($filename);
210     my $New;
211     my $fh;
212
213     #-------------------
214     # handle a reference
215     #-------------------
216     if ($ref) {
217         if ( $ref eq 'ARRAY' ) {
218             $New = sub { Perl::Tidy::IOScalarArray->new( $filename, $mode ) };
219         }
220         elsif ( $ref eq 'SCALAR' ) {
221             $New = sub { Perl::Tidy::IOScalar->new( $filename, $mode ) };
222         }
223         else {
224
225             # Accept an object with a getline method for reading. Note:
226             # IO::File is built-in and does not respond to the defined
227             # operator.  If this causes trouble, the check can be
228             # skipped and we can just let it crash if there is no
229             # getline.
230             if ( $mode eq 'r' ) {
231
232                 # RT#97159; part 1 of 2: updated to use 'can'
233                 if ( $ref->can('getline') ) {
234                     $New = sub { $filename };
235                 }
236                 else {
237                     $New = sub { undef };
238                     confess <<EOM;
239 ------------------------------------------------------------------------
240 No 'getline' method is defined for object of class '$ref'
241 Please check your call to Perl::Tidy::perltidy.  Trace follows.
242 ------------------------------------------------------------------------
243 EOM
244                 }
245             }
246
247             # Accept an object with a print method for writing.
248             # See note above about IO::File
249             if ( $mode eq 'w' ) {
250
251                 # RT#97159; part 2 of 2: updated to use 'can'
252                 if ( $ref->can('print') ) {
253                     $New = sub { $filename };
254                 }
255                 else {
256                     $New = sub { undef };
257                     confess <<EOM;
258 ------------------------------------------------------------------------
259 No 'print' method is defined for object of class '$ref'
260 Please check your call to Perl::Tidy::perltidy. Trace follows.
261 ------------------------------------------------------------------------
262 EOM
263                 }
264             }
265         }
266     }
267
268     #----------------
269     # handle a string
270     #----------------
271     else {
272         if ( $filename eq '-' ) {
273             $New = sub { $mode eq 'w' ? *STDOUT : *STDIN }
274         }
275         else {
276             $New = sub { IO::File->new( $filename, $mode ) };
277         }
278     }
279
280     #--------------
281     # Open the file
282     #--------------
283     $fh = $New->( $filename, $mode );
284
285     if ( !$fh ) {
286         Warn("Couldn't open file:'$filename' in mode:$mode : $OS_ERROR\n");
287     }
288
289     #------------
290     # Set binmode
291     #------------
292     else {
293         if ( ref($fh) eq 'IO::File' ) {
294             ## binmode object call not available in older perl versions
295             ## $fh->binmode(":raw:encoding(UTF-8)");
296             if ($is_encoded_data) { binmode $fh, ":raw:encoding(UTF-8)"; }
297             else                  { binmode $fh }
298         }
299         elsif ( $filename eq '-' ) {
300             if ($is_encoded_data) { binmode STDOUT, ":raw:encoding(UTF-8)"; }
301             else                  { binmode STDOUT }
302         }
303         else {
304
305             # shouldn't get here
306             if (DEVEL_MODE) {
307                 my $ref_fh = ref($fh);
308                 Fault(<<EOM);
309 unexpected streamhandle state for file='$filename' mode='$mode' ref(fh)=$ref_fh
310 EOM
311             }
312         }
313     }
314
315     return $fh;
316 } ## end sub streamhandle
317
318 sub stream_slurp {
319
320     my ( $filename, ($timeout_in_seconds) ) = @_;
321
322     # Given:
323     #   $filename
324     #   $timeout_in_seconds (optional timeout, in seconds)
325
326     # Read the text in $filename and
327     # return:
328     #    undef if read error, or
329     #    $rinput_string = ref to string of text
330
331     # if $filename is:     Read
332     # ----------------     -----------------
333     # ARRAY  ref           array ref
334     # SCALAR ref           string ref
335     # object ref           object with 'getline' method (exit if no 'getline')
336     # '-'                  STDIN
337     # string               file named $filename
338
339     # Note that any decoding from utf8 must be done by the caller
340
341     my $ref = ref($filename);
342     my $rinput_string;
343
344     # handle a reference
345     if ($ref) {
346         if ( $ref eq 'ARRAY' ) {
347             my $buf = join EMPTY_STRING, @{$filename};
348             $rinput_string = \$buf;
349         }
350         elsif ( $ref eq 'SCALAR' ) {
351             $rinput_string = $filename;
352         }
353         else {
354             if ( $ref->can('getline') ) {
355                 my $buf = EMPTY_STRING;
356                 while ( defined( my $line = $filename->getline() ) ) {
357                     $buf .= $line;
358                 }
359                 $rinput_string = \$buf;
360             }
361             else {
362                 confess <<EOM;
363 ------------------------------------------------------------------------
364 No 'getline' method is defined for object of class '$ref'
365 Please check your call to Perl::Tidy::perltidy.  Trace follows.
366 ------------------------------------------------------------------------
367 EOM
368             }
369         }
370     }
371
372     # handle a string
373     else {
374         if ( $filename eq '-' ) {
375             local $INPUT_RECORD_SEPARATOR = undef;
376             my $buf;
377             if ( $timeout_in_seconds && $timeout_in_seconds > 0 ) {
378                 eval {
379                     local $SIG{ALRM} = sub { die "alarm\n" };
380                     alarm($timeout_in_seconds);
381                     $buf = <>;
382                     alarm(0);
383                     1;
384                 }
385                   or Die(
386 "Timeout reading stdin using -tos=$timeout_in_seconds seconds. Use -tos=0 to skip timeout check.\n"
387                   );
388             }
389             else {
390                 $buf = <>;
391             }
392             $rinput_string = \$buf;
393         }
394         else {
395             if ( open( my $fh, '<', $filename ) ) {
396                 local $INPUT_RECORD_SEPARATOR = undef;
397                 my $buf = <$fh>;
398                 $fh->close() or Warn("Cannot close $filename\n");
399                 $rinput_string = \$buf;
400             }
401             else {
402                 Warn("Cannot open $filename: $OS_ERROR\n");
403                 return;
404             }
405         }
406     }
407
408     return $rinput_string;
409 } ## end sub stream_slurp
410
411 # Here is a map of the flow of data from the input source to the output
412 # line sink:
413 #
414 #             -->Tokenizer-->Formatter-->VerticalAligner-->FileWriter-->
415 #       input                         groups                 output
416 #       lines   tokens      lines       of          lines    lines
417 #                                      lines
418 #
419 # The names correspond to the package names responsible for the unit processes.
420 #
421 # The overall process is controlled by the "main" package.
422 #
423 # Tokenizer analyzes a line and breaks it into tokens, peeking ahead
424 # if necessary.  A token is any section of the input line which should be
425 # manipulated as a single entity during formatting.  For example, a single
426 # ',' character is a token, and so is an entire side comment.  It handles
427 # the complexities of Perl syntax, such as distinguishing between '<<' as
428 # a shift operator and as a here-document, or distinguishing between '/'
429 # as a divide symbol and as a pattern delimiter.
430 #
431 # Formatter inserts and deletes whitespace between tokens, and breaks
432 # sequences of tokens at appropriate points as output lines.  It bases its
433 # decisions on the default rules as modified by any command-line options.
434 #
435 # VerticalAligner collects groups of lines together and tries to line up
436 # certain tokens, such as '=>', '#', and '=' by adding whitespace.
437 #
438 # FileWriter simply writes lines to the output stream.
439 #
440 # The Logger package, not shown, records significant events and warning
441 # messages.  It writes a .LOG file, which may be saved with a
442 # '-log' or a '-g' flag.
443
444 { #<<<  (this side comment avoids excessive indentation in a closure)
445
446 my $Warn_count;
447 my $fh_stderr;
448 my $loaded_unicode_gcstring;
449 my $rstatus;
450
451 # Bump Warn_count only: it is essential to bump the count on all warnings, even
452 # if no message goes out, so that the correct exit status is set.
453 sub Warn_count_bump { $Warn_count++; return }
454
455 # Output Warn message only
456 sub Warn_msg { my $msg = shift; $fh_stderr->print($msg); return }
457
458 # Output Warn message and bump Warn count
459 sub Warn { my $msg = shift; $fh_stderr->print($msg); $Warn_count++; return }
460
461 sub is_char_mode {
462
463     my ($string) = @_;
464
465     # Returns:
466     #   true  if $string is in Perl's internal character mode
467     #         (also called the 'upgraded form', or UTF8=1)
468     #   false if $string is in Perl's internal byte mode
469
470     # This function isolates the call to Perl's internal function
471     # utf8::is_utf8() which is true for strings represented in an 'upgraded
472     # form'. It is available AFTER Perl version 5.8.
473     # See https://perldoc.perl.org/Encode.
474     # See also comments in Carp.pm and other modules using this function
475
476     return 1 if ( utf8::is_utf8($string) );
477     return;
478 } ## end sub is_char_mode
479
480 my $md5_hex = sub {
481     my ($buf) = @_;
482
483     # Evaluate the MD5 sum for a string:
484     # Given:
485     #   $buf = a string
486     # Return:
487     #   $digest = its MD5 sum
488
489     # Patch for [rt.cpan.org #88020]
490     # Use utf8::encode since md5_hex() only operates on bytes.
491     # my $digest = md5_hex( utf8::encode($sink_buffer) );
492
493     # Note added 20180114: the above patch did not work correctly.  I'm not
494     # sure why.  But switching to the method recommended in the Perl 5
495     # documentation for Encode worked.  According to this we can either use
496     #    $octets = encode_utf8($string)  or equivalently
497     #    $octets = encode("utf8",$string)
498     # and then calculate the checksum.  So:
499     my $octets = Encode::encode( "utf8", $buf );
500     my $digest = md5_hex($octets);
501     return $digest;
502 }; ## end $md5_hex = sub
503
504 sub get_iteration_count {
505     return $rstatus->{iteration_count};
506 }
507
508 BEGIN {
509
510     # Array index names for $self.
511     # Do not combine with other BEGIN blocks (c101).
512     my $i = 0;
513     use constant {
514         _actual_output_extension_  => $i++,
515         _debugfile_stream_         => $i++,
516         _decoded_input_as_         => $i++,
517         _destination_stream_       => $i++,
518         _diagnostics_object_       => $i++,
519         _display_name_             => $i++,
520         _file_extension_separator_ => $i++,
521         _fileroot_                 => $i++,
522         _is_encoded_data_          => $i++,
523         _length_function_          => $i++,
524         _line_separator_default_   => $i++,
525         _line_separator_           => $i++,
526         _line_tidy_begin_          => $i++,
527         _line_tidy_end_            => $i++,
528         _logger_object_            => $i++,
529         _output_file_              => $i++,
530         _postfilter_               => $i++,
531         _prefilter_                => $i++,
532         _rOpts_                    => $i++,
533         _saw_pbp_                  => $i++,
534         _teefile_stream_           => $i++,
535         _user_formatter_           => $i++,
536         _input_copied_verbatim_    => $i++,
537         _input_output_difference_  => $i++,
538         _dump_to_stdout_           => $i++,
539     };
540 } ## end BEGIN
541
542 sub perltidy {
543
544     my %input_hash = @_;
545
546     # This is the main perltidy routine
547
548     my %defaults = (
549         argv                  => undef,
550         destination           => undef,
551         formatter             => undef,
552         logfile               => undef,
553         errorfile             => undef,
554         teefile               => undef,
555         debugfile             => undef,
556         perltidyrc            => undef,
557         source                => undef,
558         stderr                => undef,
559         dump_options          => undef,
560         dump_options_type     => undef,
561         dump_getopt_flags     => undef,
562         dump_options_category => undef,
563         dump_options_range    => undef,
564         dump_abbreviations    => undef,
565         prefilter             => undef,
566         postfilter            => undef,
567     );
568
569     # Status information which can be returned for diagnostic purposes.
570     # NOTE: This is intended only for testing and subject to change.
571
572     # List of "key => value" hash entries:
573
574     # Some relevant user input parameters for convenience:
575     # opt_format         => value of --format: 'tidy', 'html', or 'user'
576     # opt_encoding       => value of -enc flag: 'utf8', 'none', or 'guess'
577     # opt_encode_output  => value of -eos flag: 'eos' or 'neos'
578     # opt_max_iterations => value of --iterations=n
579
580     # file_count         => number of files processed in this call
581
582     # If multiple files are processed, then the following values will be for
583     # the last file only:
584
585     # input_name         => name of the input stream
586     # output_name        => name of the output stream
587
588     # The following two variables refer to Perl's two internal string modes,
589     # and have the values 0 for 'byte' mode and 1 for 'char' mode:
590     # char_mode_source   => true if source is in 'char' mode. Will be false
591     #      unless we received a source string ref with utf8::is_utf8() set.
592     # char_mode_used     => true if text processed by perltidy in 'char' mode.
593     #      Normally true for text identified as utf8, otherwise false.
594
595     # This tells if Unicode::GCString was used
596     # gcs_used           => true if -gcs and Unicode::GCString found & used
597
598     # These variables tell what utf8 decoding/encoding was done:
599     # input_decoded_as   => non-blank if perltidy decoded the source text
600     # output_encoded_as  => non-blank if perltidy encoded before return
601
602     # These variables are related to iterations and convergence testing:
603     # iteration_count    => number of iterations done
604     #                       ( can be from 1 to opt_max_iterations )
605     # converged          => true if stopped on convergence
606     #                       ( can only happen if opt_max_iterations > 1 )
607     # blinking           => true if stopped on blinking states
608     #                       ( i.e., unstable formatting, should not happen )
609
610     $rstatus = {
611
612         file_count         => 0,
613         opt_format         => EMPTY_STRING,
614         opt_encoding       => EMPTY_STRING,
615         opt_encode_output  => EMPTY_STRING,
616         opt_max_iterations => EMPTY_STRING,
617
618         input_name        => EMPTY_STRING,
619         output_name       => EMPTY_STRING,
620         char_mode_source  => 0,
621         char_mode_used    => 0,
622         input_decoded_as  => EMPTY_STRING,
623         output_encoded_as => EMPTY_STRING,
624         gcs_used          => 0,
625         iteration_count   => 0,
626         converged         => 0,
627         blinking          => 0,
628     };
629
630     # Fix for issue git #57
631     $Warn_count = 0;
632
633     # don't overwrite callers ARGV
634     # Localization of @ARGV could be avoided by calling GetOptionsFromArray
635     # instead of GetOptions, but that is not available before perl 5.10
636     local @ARGV   = @ARGV;
637     local *STDERR = *STDERR;
638
639     if ( my @bad_keys = grep { !exists $defaults{$_} } keys %input_hash ) {
640         local $LIST_SEPARATOR = ')(';
641         my @good_keys = sort keys %defaults;
642         @bad_keys = sort @bad_keys;
643         confess <<EOM;
644 ------------------------------------------------------------------------
645 Unknown perltidy parameter : (@bad_keys)
646 perltidy only understands : (@good_keys)
647 ------------------------------------------------------------------------
648
649 EOM
650     }
651
652     my $get_hash_ref = sub {
653         my ($key) = @_;
654         my $hash_ref = $input_hash{$key};
655         if ( defined($hash_ref) ) {
656             if ( ref($hash_ref) ne 'HASH' ) {
657                 my $what = ref($hash_ref);
658                 my $but_is =
659                   $what ? "but is ref to $what" : "but is not a reference";
660                 croak <<EOM;
661 ------------------------------------------------------------------------
662 error in call to perltidy:
663 -$key must be reference to HASH $but_is
664 ------------------------------------------------------------------------
665 EOM
666             }
667         }
668         return $hash_ref;
669     }; ## end $get_hash_ref = sub
670
671     %input_hash = ( %defaults, %input_hash );
672     my $argv               = $input_hash{'argv'};
673     my $destination_stream = $input_hash{'destination'};
674     my $perltidyrc_stream  = $input_hash{'perltidyrc'};
675     my $source_stream      = $input_hash{'source'};
676     my $stderr_stream      = $input_hash{'stderr'};
677     my $user_formatter     = $input_hash{'formatter'};
678     my $prefilter          = $input_hash{'prefilter'};
679     my $postfilter         = $input_hash{'postfilter'};
680
681     if ($stderr_stream) {
682         $fh_stderr = Perl::Tidy::streamhandle( $stderr_stream, 'w' );
683         if ( !$fh_stderr ) {
684             croak <<EOM;
685 ------------------------------------------------------------------------
686 Unable to redirect STDERR to $stderr_stream
687 Please check value of -stderr in call to perltidy
688 ------------------------------------------------------------------------
689 EOM
690         }
691     }
692     else {
693         $fh_stderr = *STDERR;
694     }
695
696     my $self = [];
697     bless $self, __PACKAGE__;
698
699     sub Exit {
700         my $flag = shift;
701         if   ($flag) { goto ERROR_EXIT }
702         else         { goto NORMAL_EXIT }
703         croak "unexpected return to sub Exit";
704     } ## end sub Exit
705
706     sub Die {
707         my $msg = shift;
708         Warn($msg);
709         Exit(1);
710         croak "unexpected return from sub Exit";
711     } ## end sub Die
712
713     sub Fault {
714         my ($msg) = @_;
715
716         # This routine is called for errors that really should not occur
717         # except if there has been a bug introduced by a recent program change.
718         # Please add comments at calls to Fault to explain why the call
719         # should not occur, and where to look to fix it.
720         my ( $package0_uu, $filename0_uu, $line0, $subroutine0_uu ) = caller(0);
721         my ( $package1_uu, $filename1,    $line1, $subroutine1 )    = caller(1);
722         my ( $package2_uu, $filename2_uu, $line2_uu, $subroutine2 ) = caller(2);
723         my $pkg = __PACKAGE__;
724
725         my $input_stream_name = $rstatus->{'input_name'};
726         $input_stream_name = '(unknown)' unless ($input_stream_name);
727         Die(<<EOM);
728 ==============================================================================
729 While operating on input stream with name: '$input_stream_name'
730 A fault was detected at line $line0 of sub '$subroutine1'
731 in file '$filename1'
732 which was called from line $line1 of sub '$subroutine2'
733 Message: '$msg'
734 This is probably an error introduced by a recent programming change.
735 $pkg reports VERSION='$VERSION'.
736 ==============================================================================
737 EOM
738
739         croak "unexpected return from sub Die";
740     } ## end sub Fault
741
742     # extract various dump parameters
743     my $dump_options_type     = $input_hash{'dump_options_type'};
744     my $dump_options          = $get_hash_ref->('dump_options');
745     my $dump_getopt_flags     = $get_hash_ref->('dump_getopt_flags');
746     my $dump_options_category = $get_hash_ref->('dump_options_category');
747     my $dump_abbreviations    = $get_hash_ref->('dump_abbreviations');
748     my $dump_options_range    = $get_hash_ref->('dump_options_range');
749
750     # validate dump_options_type
751     if ( defined($dump_options) ) {
752         if ( !defined($dump_options_type) ) {
753             $dump_options_type = 'perltidyrc';
754         }
755         if (   $dump_options_type ne 'perltidyrc'
756             && $dump_options_type ne 'full' )
757         {
758             croak <<EOM;
759 ------------------------------------------------------------------------
760 Please check value of -dump_options_type in call to perltidy;
761 saw: '$dump_options_type'
762 expecting: 'perltidyrc' or 'full'
763 ------------------------------------------------------------------------
764 EOM
765
766         }
767     }
768     else {
769         $dump_options_type = EMPTY_STRING;
770     }
771
772     if ($user_formatter) {
773
774         # if the user defines a formatter, there is no output stream,
775         # but we need a null stream to keep coding simple
776         $destination_stream = \my $tmp;
777     }
778
779     # see if ARGV is overridden
780     if ( defined($argv) ) {
781
782         my $rargv = ref($argv);
783         if ( $rargv eq 'SCALAR' ) { $argv = ${$argv}; $rargv = undef }
784
785         # ref to ARRAY
786         if ($rargv) {
787             if ( $rargv eq 'ARRAY' ) {
788                 @ARGV = @{$argv};
789             }
790             else {
791                 croak <<EOM;
792 ------------------------------------------------------------------------
793 Please check value of -argv in call to perltidy;
794 it must be a string or ref to ARRAY but is: $rargv
795 ------------------------------------------------------------------------
796 EOM
797             }
798         }
799
800         # string
801         else {
802             my ( $rargv_str, $msg ) = parse_args($argv);
803             if ($msg) {
804                 Die(<<EOM);
805 Error parsing this string passed to to perltidy with 'argv':
806 $msg
807 EOM
808             }
809             @ARGV = @{$rargv_str};
810         }
811     }
812
813     # These string refs will hold any warnings and error messages to be written
814     # to the logfile object when it eventually gets created.
815     my $rpending_complaint;
816     ${$rpending_complaint} = EMPTY_STRING;
817
818     my $rpending_logfile_message;
819     ${$rpending_logfile_message} = EMPTY_STRING;
820
821     my ( $is_Windows, $Windows_type ) = look_for_Windows($rpending_complaint);
822
823     # VMS file names are restricted to a 40.40 format, so we append _tdy
824     # instead of .tdy, etc. (but see also sub check_vms_filename)
825     my $dot;
826     my $dot_pattern;
827     if ( $OSNAME eq 'VMS' ) {
828         $dot         = '_';
829         $dot_pattern = '_';
830     }
831     else {
832         $dot         = '.';
833         $dot_pattern = '\.';    # must escape for use in regex
834     }
835     $self->[_file_extension_separator_] = $dot;
836
837     # save a copy of the last two input args for error checking later
838     my @ARGV_saved;
839     if ( @ARGV > 1 ) {
840         @ARGV_saved = ( $ARGV[-2], $ARGV[-1] );
841     }
842
843     # see if -wvt was entered on the command line before @ARGV is changed
844     my $wvt_in_args = grep { /-(wvt|warn-variable-types)=/ } @ARGV;
845
846     #-------------------------
847     # get command line options
848     #-------------------------
849     my ( $rOpts, $config_file, $rraw_options, $roption_string,
850         $rexpansion, $roption_category, $roption_range, $rinteger_option_range )
851       = process_command_line(
852         $perltidyrc_stream,  $is_Windows, $Windows_type,
853         $rpending_complaint, $dump_options_type,
854       );
855
856     # Only filenames should remain in @ARGV
857     my @Arg_files = @ARGV;
858
859     $self->[_rOpts_] = $rOpts;
860
861     my $saw_pbp =
862       grep { $_ eq '-pbp' || $_ eq '-perl-best-practices' } @{$rraw_options};
863     $self->[_saw_pbp_] = $saw_pbp;
864
865     #------------------------------------
866     # Handle requests to dump information
867     #------------------------------------
868
869     # return or exit immediately after all dumps
870     my $quit_now = 0;
871
872     # Getopt parameters and their flags
873     if ( defined($dump_getopt_flags) ) {
874         $quit_now = 1;
875         foreach my $op ( @{$roption_string} ) {
876             my $opt  = $op;
877             my $flag = EMPTY_STRING;
878
879             # Examples:
880             #  some-option=s
881             #  some-option=i
882             #  some-option:i
883             #  some-option!
884             if ( $opt =~ /(.*)(!|=.*|:.*)$/ ) {
885                 $opt  = $1;
886                 $flag = $2;
887             }
888             $dump_getopt_flags->{$opt} = $flag;
889         }
890     }
891
892     if ( defined($dump_options_category) ) {
893         $quit_now = 1;
894         %{$dump_options_category} = %{$roption_category};
895     }
896
897     if ( defined($dump_options_range) ) {
898         $quit_now = 1;
899         %{$dump_options_range} = %{$roption_range};
900     }
901
902     if ( defined($dump_abbreviations) ) {
903         $quit_now = 1;
904         %{$dump_abbreviations} = %{$rexpansion};
905     }
906
907     if ( defined($dump_options) ) {
908         $quit_now = 1;
909         %{$dump_options} = %{$rOpts};
910     }
911
912     Exit(0) if ($quit_now);
913
914     # make printable string of options for this run as possible diagnostic
915     my $readable_options = readable_options( $rOpts, $roption_string );
916
917     # dump from command line
918     if ( $rOpts->{'dump-options'} ) {
919         print {*STDOUT} $readable_options;
920         Exit(0);
921     }
922
923     # some dump options require one filename in the arg list.  This is a safety
924     # precaution in case a user accidentally adds such an option to the command
925     # line parameters and is expecting formatted output to stdout.  Another
926     # precaution, added elsewhere, is to ignore these in a .perltidyrc
927     my $num_files = @Arg_files;
928     foreach my $opt_name (
929         qw(
930         dump-block-summary
931         dump-unusual-variables
932         dump-mixed-call-parens
933         dump-mismatched-args
934         dump-mismatched-returns
935         dump-unique-keys
936         )
937       )
938     {
939         if ( $rOpts->{$opt_name} ) {
940             $self->[_dump_to_stdout_] = 1;
941             if ( $num_files != 1 ) {
942                 Die(<<EOM);
943 --$opt_name expects 1 filename in the arg list but saw $num_files filenames
944 EOM
945             }
946         }
947     }
948
949     #----------------------------------------
950     # check parameters and their interactions
951     #----------------------------------------
952     $self->check_options( $num_files, $rinteger_option_range );
953
954     if ($user_formatter) {
955         $rOpts->{'format'} = 'user';
956     }
957
958     # there must be one entry here for every possible format
959     my %default_file_extension = (
960         tidy => 'tdy',
961         html => 'html',
962         user => EMPTY_STRING,
963     );
964
965     $rstatus->{'opt_format'}         = $rOpts->{'format'};
966     $rstatus->{'opt_max_iterations'} = $rOpts->{'iterations'};
967     $rstatus->{'opt_encode_output'} =
968       $rOpts->{'encode-output-strings'} ? 'eos' : 'neos';
969
970     # be sure we have a valid output format
971     if ( !exists $default_file_extension{ $rOpts->{'format'} } ) {
972         my $formats = join SPACE,
973           sort map { "'" . $_ . "'" } keys %default_file_extension;
974         my $fmt = $rOpts->{'format'};
975         Die("-format='$fmt' but must be one of: $formats\n");
976     }
977
978     my $output_extension =
979       $self->make_file_extension( $rOpts->{'output-file-extension'},
980         $default_file_extension{ $rOpts->{'format'} } );
981
982     # get parameters associated with the -b option
983     my ( $in_place_modify, $backup_extension, $delete_backup ) =
984       $self->check_in_place_modify( $source_stream, $destination_stream );
985
986     my $line_range_clipped = $rOpts->{'line-range-tidy'}
987       && ( $self->[_line_tidy_begin_] > 1
988         || defined( $self->[_line_tidy_end_] ) );
989
990     Perl::Tidy::Formatter::check_options( $rOpts, $wvt_in_args, $num_files,
991         $line_range_clipped );
992     Perl::Tidy::Tokenizer::check_options($rOpts);
993     Perl::Tidy::VerticalAligner::check_options($rOpts);
994     if ( $rOpts->{'format'} eq 'html' ) {
995         Perl::Tidy::HtmlWriter->check_options($rOpts);
996     }
997
998     # Try to catch an unusual missing string parameter error, like this:
999     #    perltidy -wvt perltidy.pl
1000     # The problem is that -wvt wants a string, so it grabs 'perltidy.pl'.
1001     # Then there is no output filename, so input is assumed to be stdin.
1002     # This make perltidy unexpectedly wait for input. To the user, it
1003     # appears that perltidy has gone into an infinite loop. Issue c312.
1004     # To avoid getting this far, it is best for parameters which take a
1005     # string to check the strings in one of the 'check_options' subs, and
1006     # exit if there is an obvious error. This has been done for -wvt,
1007     # but are undoubtedly other parameters where this problem might occur.
1008     if ( !$num_files && @ARGV_saved > 1 ) {
1009         my $opt_test  = $ARGV_saved[-2];
1010         my $file_test = $ARGV_saved[-1];
1011         if (   $opt_test =~ s/^[-]+//
1012             && $file_test !~ /^[-]/
1013             && $file_test !~ /^\d+$/
1014             && -e $file_test )
1015         {
1016
1017             # These options can take filenames, so we will ignore them here
1018             my %is_option_with_file_parameter;
1019             my @qf = qw( outfile profile );
1020             @is_option_with_file_parameter{@qf} = (1) x scalar(@qf);
1021
1022             # Expand an abbreviation into a long name
1023             my $long_name;
1024             my $exp = $rexpansion->{$opt_test};
1025             if    ( !$exp )        { $long_name = $opt_test }
1026             elsif ( @{$exp} == 1 ) { $long_name = $exp->[0] }
1027             else                   { }
1028
1029             # If this arg grabbed the file, then it must take a string arg
1030             if (   $long_name
1031                 && defined( $rOpts->{$long_name} )
1032                 && $rOpts->{$long_name} eq $file_test
1033                 && !$is_option_with_file_parameter{$long_name} )
1034             {
1035                 Die(<<EOM);
1036 Stopping on possible missing string parameter for '-$opt_test':
1037 This parameter takes a string and has been set equal to file '$file_test',
1038 and formatted output will go to standard output. If this is actually correct,
1039 you can skip this message by entering this as '-$opt_test=$file_test'.
1040 EOM
1041             }
1042         }
1043     }
1044
1045     # make the pattern of file extensions that we shouldn't touch
1046     my $forbidden_file_extensions = "(($dot_pattern)(LOG|DEBUG|ERR|TEE)";
1047     if ($output_extension) {
1048         my $ext = quotemeta($output_extension);
1049         $forbidden_file_extensions .= "|$ext";
1050     }
1051     if ( $in_place_modify && $backup_extension ) {
1052         my $ext = quotemeta($backup_extension);
1053         $forbidden_file_extensions .= "|$ext";
1054     }
1055     $forbidden_file_extensions .= ')$';
1056
1057     # Create a diagnostics object if requested;
1058     # This is only useful for code development
1059     my $diagnostics_object = undef;
1060     if (DIAGNOSTICS) {
1061         $diagnostics_object = Perl::Tidy::Diagnostics->new();
1062     }
1063
1064     # no filenames should be given if input is from an array
1065     if ($source_stream) {
1066         if ( @Arg_files > 0 ) {
1067             Die(
1068 "You may not specify any filenames when a source array is given\n"
1069             );
1070         }
1071
1072         # we'll stuff the source array into Arg_files
1073         unshift( @Arg_files, $source_stream );
1074
1075         # No special treatment for source stream which is a filename.
1076         # This will enable checks for binary files and other bad stuff.
1077         $source_stream = undef unless ref($source_stream);
1078     }
1079
1080     # use stdin by default if no source array and no args
1081     elsif ( !@Arg_files ) {
1082         unshift( @Arg_files, '-' );
1083     }
1084
1085     # check file existence and expand any globs
1086     else {
1087         my @updated_files;
1088         foreach my $input_file (@Arg_files) {
1089             if ( -e $input_file ) {
1090                 push @updated_files, $input_file;
1091             }
1092             else {
1093
1094                 # file doesn't exist - check for a file glob
1095                 if ( $input_file =~ /([\?\*\[\{])/ ) {
1096
1097                     # Windows shell may not remove quotes, so do it
1098                     my $ifile = $input_file;
1099                     if ( $ifile =~ /^\'(.+)\'$/ ) { $ifile = $1 }
1100                     if ( $ifile =~ /^\"(.+)\"$/ ) { $ifile = $1 }
1101                     my $pattern = fileglob_to_re($ifile);
1102                     my $dh;
1103                     if ( opendir( $dh, './' ) ) {
1104                         my @files =
1105                           grep { /$pattern/ && !-d } readdir($dh);
1106                         closedir($dh);
1107                         next unless (@files);
1108                         push @updated_files, @files;
1109                         next;
1110                     }
1111                 }
1112                 Warn("skipping file: '$input_file': no matches found\n");
1113                 next;
1114             }
1115         } ## end loop over input filenames
1116
1117         @Arg_files = @updated_files;
1118         if ( !@Arg_files ) {
1119             Die("no matching input files found\n");
1120         }
1121     }
1122
1123     # Flag for loading module Unicode::GCString for evaluating text width:
1124     #   undef = ok to use but not yet loaded
1125     #       0 = do not use; failed to load or not wanted
1126     #       1 = successfully loaded and ok to use
1127     # The module is not actually loaded unless/until it is needed
1128     if ( !$rOpts->{'use-unicode-gcstring'} ) {
1129         $loaded_unicode_gcstring = 0;
1130     }
1131
1132     # Remove duplicate filenames.  Otherwise, for example if the user entered
1133     #     perltidy -b myfile.pl myfile.pl
1134     # the backup version of the original would be lost.
1135     if ( @Arg_files > 1 ) {
1136         my %seen = ();
1137         @Arg_files = grep { !$seen{$_}++ } @Arg_files;
1138     }
1139
1140     # If requested, process in order of increasing file size
1141     # This can significantly reduce perl's virtual memory usage during testing.
1142     if ( @Arg_files > 1 && $rOpts->{'file-size-order'} ) {
1143         @Arg_files =
1144           map  { $_->[0] }
1145           sort { $a->[1] <=> $b->[1] }
1146           map  { [ $_, -e $_ ? -s $_ : 0 ] } @Arg_files;
1147     }
1148
1149     my $logfile_header = make_logfile_header( $rOpts, $config_file,
1150         $rraw_options, $Windows_type, $readable_options );
1151
1152     # Store some values needed by lower level routines
1153     $self->[_diagnostics_object_] = $diagnostics_object;
1154     $self->[_postfilter_]         = $postfilter;
1155     $self->[_prefilter_]          = $prefilter;
1156     $self->[_user_formatter_]     = $user_formatter;
1157
1158     #--------------------------
1159     # loop to process all files
1160     #--------------------------
1161     $self->process_all_files(
1162         {
1163             rinput_hash => \%input_hash,
1164             rfiles      => \@Arg_files,
1165
1166             # filename stuff...
1167             source_stream             => $source_stream,
1168             output_extension          => $output_extension,
1169             forbidden_file_extensions => $forbidden_file_extensions,
1170             in_place_modify           => $in_place_modify,
1171             backup_extension          => $backup_extension,
1172             delete_backup             => $delete_backup,
1173
1174             # logfile stuff...
1175             logfile_header           => $logfile_header,
1176             rpending_complaint       => $rpending_complaint,
1177             rpending_logfile_message => $rpending_logfile_message,
1178         }
1179     );
1180
1181     #-----
1182     # Exit
1183     #-----
1184
1185     # Fix for RT #130297: return a true value if anything was written to the
1186     # standard error output, even non-fatal warning messages, otherwise return
1187     # false.
1188
1189     # These exit codes are returned:
1190     #  0 = perltidy ran to completion with no errors
1191     #  1 = perltidy could not run to completion due to errors
1192     #  2 = perltidy ran to completion with error messages
1193
1194     # Note that if perltidy is run with multiple files, any single file with
1195     # errors or warnings will write a line like
1196     #        '## Please see file testing.t.ERR'
1197     # to standard output for each file with errors, so the flag will be true,
1198     # even if only some of the multiple files may have had errors.
1199
1200   NORMAL_EXIT:
1201     my $ret = $Warn_count ? 2 : 0;
1202     return wantarray ? ( $ret, $rstatus ) : $ret;
1203
1204   ERROR_EXIT:
1205     return wantarray ? ( 1, $rstatus ) : 1;
1206
1207 } ## end sub perltidy
1208
1209 sub make_file_extension {
1210
1211     # Make a file extension, adding any leading '.' if necessary.
1212     # (the '.' may actually be an '_' under VMS).
1213     my ( $self, $extension, ($default) ) = @_;
1214
1215     # Given:
1216     #  $extension = the first choice (usually a user entry)
1217     #  $default   = an optional backup extension
1218     # Return:
1219     #  $extension = the actual file extension
1220
1221     $extension = EMPTY_STRING unless defined($extension);
1222     $extension =~ s/^\s+//;
1223     $extension =~ s/\s+$//;
1224
1225     # Use default extension if nothing remains of the first choice
1226     if ( length($extension) == 0 ) {
1227         $extension = $default;
1228         $extension = EMPTY_STRING unless defined($extension);
1229         $extension =~ s/^\s+//;
1230         $extension =~ s/\s+$//;
1231     }
1232
1233     # Only extensions with these leading characters get a '.'
1234     # This rule gives the user some freedom.
1235     if ( $extension =~ /^[a-zA-Z0-9]/ ) {
1236         my $dot = $self->[_file_extension_separator_];
1237         $extension = $dot . $extension;
1238     }
1239     return $extension;
1240 } ## end sub make_file_extension
1241
1242 sub check_in_place_modify {
1243
1244     my ( $self, $source_stream, $destination_stream ) = @_;
1245
1246     # See if --backup-and-modify-in-place (-b) is set, and if so,
1247     # return its associated parameters
1248     my $rOpts = $self->[_rOpts_];
1249
1250     # check for -b option;
1251     # silently ignore unless beautify mode
1252     my $in_place_modify = $rOpts->{'backup-and-modify-in-place'}
1253       && $rOpts->{'format'} eq 'tidy';
1254
1255     my ( $backup_extension, $delete_backup );
1256
1257     # Turn off -b with warnings in case of conflicts with other options.
1258     # NOTE: Do this silently, without warnings, if there is a source or
1259     # destination stream, or standard output is used.  This is because the -b
1260     # flag may have been in a .perltidyrc file and warnings break
1261     # Test::NoWarnings.  See email discussion with Merijn Brand 26 Feb 2014.
1262     if ($in_place_modify) {
1263         if (   $rOpts->{'standard-output'}
1264             || $destination_stream
1265             || ref($source_stream)
1266             || $rOpts->{'outfile'}
1267             || defined( $rOpts->{'output-path'} ) )
1268         {
1269             $in_place_modify = 0;
1270         }
1271     }
1272
1273     if ($in_place_modify) {
1274
1275         # If the backup extension contains a / character then the backup should
1276         # be deleted when the -b option is used.   On older versions of
1277         # perltidy this will generate an error message due to an illegal
1278         # file name.
1279         #
1280         # A backup file will still be generated but will be deleted
1281         # at the end.  If -bext='/' then this extension will be
1282         # the default 'bak'.  Otherwise it will be whatever characters
1283         # remains after all '/' characters are removed.  For example:
1284         # -bext         extension     slashes
1285         #  '/'          bak           1
1286         #  '/delete'    delete        1
1287         #  'delete/'    delete        1
1288         #  '/dev/null'  devnull       2    (Currently not allowed)
1289         my $bext = $rOpts->{'backup-file-extension'};
1290         $delete_backup = ( $rOpts->{'backup-file-extension'} =~ s/\///g );
1291
1292         # At present only one forward slash is allowed.  In the future multiple
1293         # slashes may be allowed to allow for other options
1294         if ( $delete_backup > 1 ) {
1295             Die("-bext=$bext contains more than one '/'\n");
1296         }
1297
1298         $backup_extension =
1299           $self->make_file_extension( $rOpts->{'backup-file-extension'},
1300             'bak' );
1301     }
1302
1303     my $backup_method = $rOpts->{'backup-method'};
1304     if (   defined($backup_method)
1305         && $backup_method ne 'copy'
1306         && $backup_method ne 'move' )
1307     {
1308         Die(
1309 "Unexpected --backup-method='$backup_method'; must be one of: 'move', 'copy'\n"
1310         );
1311     }
1312
1313     return ( $in_place_modify, $backup_extension, $delete_backup );
1314 } ## end sub check_in_place_modify
1315
1316 sub backup_method_copy {
1317
1318     my ( $self, $input_file, $routput_string, $backup_extension,
1319         $delete_backup )
1320       = @_;
1321
1322     # Handle the -b (--backup-and-modify-in-place) option with -bm='copy':
1323     # - First copy $input file to $backup_name.
1324     # - Then open input file and rewrite with contents of $routput_string
1325     # - Then delete the backup if requested
1326
1327     # NOTES:
1328     # - Die immediately on any error.
1329     # - $routput_string is a SCALAR ref
1330
1331     my $backup_file = $input_file . $backup_extension;
1332
1333     if ( !-f $input_file ) {
1334
1335         # no real file to backup ..
1336         # This shouldn't happen because of numerous preliminary checks
1337         Die(
1338             "problem with -b backing up input file '$input_file': not a file\n"
1339         );
1340     }
1341
1342     if ( -f $backup_file ) {
1343         unlink($backup_file)
1344           or Die(
1345 "unable to remove previous '$backup_file' for -b option; check permissions: $OS_ERROR\n"
1346           );
1347     }
1348
1349     # Copy input file to backup
1350     File::Copy::copy( $input_file, $backup_file )
1351       or Die("File::Copy failed trying to backup source: $OS_ERROR");
1352
1353     # set permissions of the backup file to match the input file
1354     my @input_file_stat = stat($input_file);
1355     my $in_place_modify = 1;
1356     $self->set_output_file_permissions( $backup_file, \@input_file_stat,
1357         $in_place_modify );
1358
1359     # set the modification time of the copy to the original value (rt#145999)
1360     my ( $read_time, $write_time ) = @input_file_stat[ _atime_, _mtime_ ];
1361     if ( defined($write_time) ) {
1362         utime( $read_time, $write_time, $backup_file )
1363           || Warn("error setting times for backup file '$backup_file'\n");
1364     }
1365
1366     # Open the original input file for writing ... opening with ">" will
1367     # truncate the existing data.
1368     open( my $fout, ">", $input_file )
1369       or Die(
1370 "problem re-opening $input_file for write for -b option; check file and directory permissions: $OS_ERROR\n"
1371       );
1372
1373     if ( $self->[_is_encoded_data_] ) { binmode $fout, ":raw:encoding(UTF-8)" }
1374     else                              { binmode $fout }
1375
1376     # Now copy the formatted output to it..
1377     # output must be SCALAR ref..
1378     if ( ref($routput_string) eq 'SCALAR' ) {
1379         $fout->print( ${$routput_string} )
1380           or Die("cannot print to '$input_file' with -b option: $OS_ERROR\n");
1381     }
1382
1383     # Error if anything else ...
1384     else {
1385         my $ref = ref($routput_string);
1386         Die(<<EOM);
1387 Programming error: unable to print to '$input_file' with -b option:
1388 unexpected ref type '$ref'; expecting 'ARRAY' or 'SCALAR'
1389 EOM
1390     }
1391
1392     $fout->close()
1393       or Die("cannot close '$input_file' with -b option: $OS_ERROR\n");
1394
1395     # Set permissions of the output file to match the input file. This is
1396     # necessary even if the inode remains unchanged because suid/sgid bits may
1397     # have been reset.
1398     $self->set_output_file_permissions( $input_file, \@input_file_stat,
1399         $in_place_modify );
1400
1401     # Keep original modification time if no change (rt#145999)
1402     if ( !$self->[_input_output_difference_] && defined($write_time) ) {
1403         utime( $read_time, $write_time, $input_file )
1404           || Warn("error setting times for '$input_file'\n");
1405     }
1406
1407     #---------------------------------------------------------
1408     # remove the original file for in-place modify as follows:
1409     #   $delete_backup=0 never
1410     #   $delete_backup=1 only if no errors
1411     #   $delete_backup>1 always  : NOT ALLOWED, too risky
1412     #---------------------------------------------------------
1413     if ( $delete_backup && -f $backup_file ) {
1414
1415         # Currently, $delete_backup may only be 1. But if a future update
1416         # allows a value > 1, then reduce it to 1 if there were warnings.
1417         if (   $delete_backup > 1
1418             && $self->[_logger_object_]->get_warning_count() )
1419         {
1420             $delete_backup = 1;
1421         }
1422
1423         # As an added safety precaution, do not delete the source file
1424         # if its size has dropped from positive to zero, since this
1425         # could indicate a disaster of some kind, including a hardware
1426         # failure.  Actually, this could happen if you had a file of
1427         # all comments (or pod) and deleted everything with -dac (-dap)
1428         # for some reason.
1429         if ( !-s $input_file && -s $backup_file && $delete_backup == 1 ) {
1430             Warn(
1431 "output file '$input_file' missing or zero length; original '$backup_file' not deleted\n"
1432             );
1433         }
1434         else {
1435             unlink($backup_file)
1436               or Die(
1437 "unable to remove backup file '$backup_file' for -b option; check permissions: $OS_ERROR\n"
1438               );
1439         }
1440     }
1441
1442     # Verify that inode is unchanged during development
1443     if (DEVEL_MODE) {
1444         my @output_file_stat = stat($input_file);
1445         my $inode_input      = $input_file_stat[1];
1446         my $inode_output     = $output_file_stat[1];
1447         if ( $inode_input != $inode_output ) {
1448             Fault(<<EOM);
1449 inode changed with -bm=copy for file '$input_file': inode_input=$inode_input inode_output=$inode_output
1450 EOM
1451         }
1452     }
1453
1454     return;
1455 } ## end sub backup_method_copy
1456
1457 sub backup_method_move {
1458
1459     my ( $self, $input_file, $routput_string, $backup_extension,
1460         $delete_backup )
1461       = @_;
1462
1463     # Handle the -b (--backup-and-modify-in-place) option with -bm='move':
1464     # - First move $input file to $backup_name.
1465     # - Then copy $routput_string to $input_file.
1466     # - Then delete the backup if requested
1467
1468     # NOTES:
1469     # - Die immediately on any error.
1470     # - $routput_string is a SCALAR ref
1471     # - $input_file permissions will be set by sub set_output_file_permissions
1472
1473     my $backup_name = $input_file . $backup_extension;
1474
1475     if ( !-f $input_file ) {
1476
1477         # oh, oh, no real file to backup ..
1478         # shouldn't happen because of numerous preliminary checks
1479         Die(
1480             "problem with -b backing up input file '$input_file': not a file\n"
1481         );
1482     }
1483     if ( -f $backup_name ) {
1484         unlink($backup_name)
1485           or Die(
1486 "unable to remove previous '$backup_name' for -b option; check permissions: $OS_ERROR\n"
1487           );
1488     }
1489
1490     my @input_file_stat = stat($input_file);
1491
1492     # backup the input file
1493     # we use copy for symlinks, move for regular files
1494     if ( -l $input_file ) {
1495         File::Copy::copy( $input_file, $backup_name )
1496           or Die("File::Copy failed trying to backup source: $OS_ERROR");
1497     }
1498     else {
1499         rename( $input_file, $backup_name )
1500           or Die(
1501 "problem renaming $input_file to $backup_name for -b option: $OS_ERROR\n"
1502           );
1503     }
1504
1505     # Open a file with the original input file name for writing ...
1506     open( my $fout, ">", $input_file )
1507       or Die(
1508 "problem re-opening $input_file for write for -b option; check file and directory permissions: $OS_ERROR\n"
1509       );
1510
1511     if ( $self->[_is_encoded_data_] ) { binmode $fout, ":raw:encoding(UTF-8)" }
1512     else                              { binmode $fout }
1513
1514     # Now copy the formatted output to it..
1515     # output must be SCALAR ref..
1516     if ( ref($routput_string) eq 'SCALAR' ) {
1517         $fout->print( ${$routput_string} )
1518           or Die("cannot print to '$input_file' with -b option: $OS_ERROR\n");
1519     }
1520
1521     # Error if anything else ...
1522     else {
1523         my $ref = ref($routput_string);
1524         Die(<<EOM);
1525 Programming error: unable to print to '$input_file' with -b option:
1526 unexpected ref type '$ref'; expecting 'ARRAY' or 'SCALAR'
1527 EOM
1528     }
1529
1530     $fout->close()
1531       or Die("cannot close '$input_file' with -b option: $OS_ERROR\n");
1532
1533     # set permissions of the output file to match the input file
1534     my $in_place_modify = 1;
1535     $self->set_output_file_permissions( $input_file, \@input_file_stat,
1536         $in_place_modify );
1537
1538     # Keep original modification time if no change (rt#145999)
1539     my ( $read_time, $write_time ) = @input_file_stat[ _atime_, _mtime_ ];
1540     if ( !$self->[_input_output_difference_] && defined($write_time) ) {
1541         utime( $read_time, $write_time, $input_file )
1542           || Warn("error setting times for '$input_file'\n");
1543     }
1544
1545     #---------------------------------------------------------
1546     # remove the original file for in-place modify as follows:
1547     #   $delete_backup=0 never
1548     #   $delete_backup=1 only if no errors
1549     #   $delete_backup>1 always  : NOT ALLOWED, too risky
1550     #---------------------------------------------------------
1551     if ( $delete_backup && -f $backup_name ) {
1552
1553         # Currently, $delete_backup may only be 1. But if a future update
1554         # allows a value > 1, then reduce it to 1 if there were warnings.
1555         if (   $delete_backup > 1
1556             && $self->[_logger_object_]->get_warning_count() )
1557         {
1558             $delete_backup = 1;
1559         }
1560
1561         # As an added safety precaution, do not delete the source file
1562         # if its size has dropped from positive to zero, since this
1563         # could indicate a disaster of some kind, including a hardware
1564         # failure.  Actually, this could happen if you had a file of
1565         # all comments (or pod) and deleted everything with -dac (-dap)
1566         # for some reason.
1567         if ( !-s $input_file && -s $backup_name && $delete_backup == 1 ) {
1568             Warn(
1569 "output file '$input_file' missing or zero length; original '$backup_name' not deleted\n"
1570             );
1571         }
1572         else {
1573             unlink($backup_name)
1574               or Die(
1575 "unable to remove previous '$backup_name' for -b option; check permissions: $OS_ERROR\n"
1576               );
1577         }
1578     }
1579
1580     return;
1581
1582 } ## end sub backup_method_move
1583
1584 # masks for file permissions
1585 use constant OCT_777  => oct(777);     # All users (O+G+W) + r/w/x bits
1586 use constant OCT_7777 => oct(7777);    # Same + suid/sgid/sbit
1587 use constant OCT_600  => oct(600);     # Owner RW permission
1588
1589 sub set_output_file_permissions {
1590
1591     my ( $self, $output_file, $rinput_file_stat, $in_place_modify ) = @_;
1592
1593     # Set the permissions for the output file
1594
1595     # Given:
1596     #  $output_file      = the file whose permissions we will set
1597     #  $rinput_file_stat = the result of stat($input_file)
1598     #  $in_place_modify  = true if --backup-and-modify-in-place is set
1599
1600     my ( $mode_i, $uid_i, $gid_i ) =
1601       @{$rinput_file_stat}[ _mode_, _uid_, _gid_ ];
1602     my ( $uid_o, $gid_o ) = ( stat($output_file) )[ _uid_, _gid_ ];
1603     my $input_file_permissions  = $mode_i & OCT_7777;
1604     my $output_file_permissions = $input_file_permissions;
1605
1606     #rt128477: avoid inconsistent owner/group and suid/sgid
1607     if ( $uid_i != $uid_o || $gid_i != $gid_o ) {
1608
1609         # try to change owner and group to match input file if
1610         # in -b mode.  Note: chown returns number of files
1611         # successfully changed.
1612         if ( $in_place_modify
1613             && chown( $uid_i, $gid_i, $output_file ) )
1614         {
1615             # owner/group successfully changed
1616         }
1617         else {
1618
1619             # owner or group differ: do not copy suid and sgid
1620             $output_file_permissions = $mode_i & OCT_777;
1621             if ( $input_file_permissions != $output_file_permissions ) {
1622                 Warn(
1623 "Unable to copy setuid and/or setgid bits for output file '$output_file'\n"
1624                 );
1625             }
1626         }
1627     }
1628
1629     # Mark the output file for rw unless we are in -b mode.
1630     # Explanation: perltidy does not unlink existing output
1631     # files before writing to them, for safety.  If a
1632     # designated output file exists and is not writable,
1633     # perltidy will halt.  This can prevent a data loss if a
1634     # user accidentally enters "perltidy infile -o
1635     # important_ro_file", or "perltidy infile -st
1636     # >important_ro_file". But it also means that perltidy can
1637     # get locked out of rerunning unless it marks its own
1638     # output files writable. The alternative, of always
1639     # unlinking the designated output file, is less safe and
1640     # not always possible, except in -b mode, where there is an
1641     # assumption that a previous backup can be unlinked even if
1642     # not writable.
1643     if ( !$in_place_modify ) {
1644         $output_file_permissions |= OCT_600;
1645     }
1646
1647     if ( !chmod( $output_file_permissions, $output_file ) ) {
1648
1649         # couldn't change file permissions
1650         my $operm = sprintf "%04o", $output_file_permissions;
1651         Warn(
1652 "Unable to set permissions for output file '$output_file' to $operm\n"
1653         );
1654     }
1655     return;
1656 } ## end sub set_output_file_permissions
1657
1658 sub get_decoded_string_buffer {
1659
1660     my ( $self, $input_file, $display_name ) = @_;
1661
1662     # Decode the input buffer from utf8 if necessary or requested
1663
1664     # Given:
1665     #   $input_file   = the input file or stream
1666     #   $display_name = its name to use in error messages
1667
1668     # Set $self->[_line_separator_], and
1669
1670     # Return:
1671     #   $rinput_string = ref to input string, decoded from utf8 if necessary
1672     #   $is_encoded_data  = true if $buf is decoded from utf8
1673     #   $decoded_input_as = true if perltidy decoded input buf
1674     #   $encoding_log_message = messages for log file,
1675     #   $length_function  = function to use for measuring string width
1676
1677     # Return nothing on any error; this is a signal to skip this file
1678
1679     my $rOpts = $self->[_rOpts_];
1680
1681     my $rinput_string =
1682       stream_slurp( $input_file, $rOpts->{'timeout-in-seconds'} );
1683     return unless ( defined($rinput_string) );
1684
1685     # Note that we could have a zero size input string here if it
1686     # arrived from standard input or from a string ref. For example
1687     # 'perltidy <null.pl'.  If we issue a warning and stop, as we would
1688     # for a zero length file ('perltidy null.pl'), then we could cause
1689     # a call to the perltidy module to misbehave as a filter. So we will
1690     # process this as any other file in this case without any warning (c286).
1691     if ( !length( ${$rinput_string} ) ) {
1692
1693         # zero length, but keep going
1694     }
1695
1696     # Check size of strings arriving from the standard input. These
1697     # could not be checked until now.
1698     if ( $input_file eq '-' ) {
1699         my $size_in_mb =
1700           length( ${$rinput_string} ) / ( CONST_1024 * CONST_1024 );
1701         my $maximum_file_size_mb = $rOpts->{'maximum-file-size-mb'};
1702         if ( $size_in_mb > $maximum_file_size_mb ) {
1703             $size_in_mb = sprintf( "%0.1f", $size_in_mb );
1704             Warn(
1705 "skipping file: <stdin>: size $size_in_mb MB exceeds limit $maximum_file_size_mb; use -maxfs=i to change\n"
1706             );
1707             return;
1708         }
1709     }
1710
1711     $rinput_string = $self->set_line_separator($rinput_string);
1712
1713     my $encoding_in              = EMPTY_STRING;
1714     my $rOpts_character_encoding = $rOpts->{'character-encoding'};
1715     my $encoding_log_message;
1716     my $decoded_input_as = EMPTY_STRING;
1717     $rstatus->{'char_mode_source'} = 0;
1718
1719     # Case 1: If Perl is already in a character-oriented mode for this
1720     # string rather than a byte-oriented mode.  Normally, this happens if
1721     # the caller has decoded a utf8 string before calling perltidy.  But it
1722     # could also happen if the user has done some unusual manipulations of
1723     # the source.  In any case, we will not attempt to decode it because
1724     # that could result in an output string in a different mode.
1725     if ( is_char_mode( ${$rinput_string} ) ) {
1726         $encoding_in = "utf8";
1727         $rstatus->{'char_mode_source'} = 1;
1728     }
1729
1730     # Case 2. No input stream encoding requested.  This is appropriate
1731     # for single-byte encodings like ascii, latin-1, etc
1732     elsif ( !$rOpts_character_encoding
1733         || $rOpts_character_encoding eq 'none' )
1734     {
1735
1736         # nothing to do
1737     }
1738
1739     # Case 3. guess input stream encoding if requested
1740     elsif ( lc($rOpts_character_encoding) eq 'guess' ) {
1741
1742         # The guessing strategy is simple: use Encode::Guess to guess
1743         # an encoding.  If and only if the guess is utf8, try decoding and
1744         # use it if successful.  Otherwise, we proceed assuming the
1745         # characters are encoded as single bytes (same as if 'none' had
1746         # been specified as the encoding).
1747
1748         # In testing I have found that including additional guess 'suspect'
1749         # encodings sometimes works but can sometimes lead to disaster by
1750         # using an incorrect decoding.
1751
1752         my $decoder;
1753         if ( ${$rinput_string} =~ /[^[:ascii:]]/ ) {
1754             $decoder = guess_encoding( ${$rinput_string}, 'utf8' );
1755         }
1756         if ( $decoder && ref($decoder) ) {
1757             $encoding_in = $decoder->name;
1758             if ( $encoding_in ne 'UTF-8' && $encoding_in ne 'utf8' ) {
1759                 $encoding_in = EMPTY_STRING;
1760                 $encoding_log_message .= <<EOM;
1761 Guessed encoding '$encoding_in' is not utf8; no encoding will be used
1762 EOM
1763             }
1764             else {
1765
1766                 my $buf;
1767                 if ( !eval { $buf = $decoder->decode( ${$rinput_string} ); 1 } )
1768                 {
1769
1770                     $encoding_log_message .= <<EOM;
1771 Guessed encoding '$encoding_in' but decoding was unsuccessful; no encoding is used
1772 EOM
1773
1774                     # Note that a guess failed, but keep going
1775                     # This warning can eventually be removed
1776                     Warn(
1777 "file: $display_name: bad guess to decode source as $encoding_in\n"
1778                     );
1779                     $encoding_in = EMPTY_STRING;
1780                 }
1781                 else {
1782                     $encoding_log_message .= <<EOM;
1783 Guessed encoding '$encoding_in' successfully decoded
1784 EOM
1785                     $decoded_input_as = $encoding_in;
1786                     $rinput_string    = \$buf;
1787                 }
1788             }
1789         }
1790         else {
1791             $encoding_log_message .= <<EOM;
1792 Does not look like utf8 encoded text so processing as raw bytes
1793 EOM
1794         }
1795     }
1796
1797     # Case 4. Decode with a specific encoding
1798     else {
1799         $encoding_in = $rOpts_character_encoding;
1800         my $buf;
1801         if (
1802             !eval {
1803                 $buf = Encode::decode( $encoding_in, ${$rinput_string},
1804                     Encode::FB_CROAK | Encode::LEAVE_SRC );
1805                 1;
1806             }
1807           )
1808         {
1809
1810             # Quit if we cannot decode by the requested encoding;
1811             # Something is not right.
1812             Warn(
1813 "skipping file: $display_name: Unable to decode source as $encoding_in\n"
1814             );
1815
1816             # return nothing on error
1817             return;
1818         }
1819         else {
1820             $encoding_log_message .= <<EOM;
1821 Specified encoding '$encoding_in' successfully decoded
1822 EOM
1823             $decoded_input_as = $encoding_in;
1824             $rinput_string    = \$buf;
1825         }
1826     }
1827
1828     # Set the encoding to be used for all further i/o: If we have
1829     # decoded the data with any format, then we must continue to
1830     # read and write it as encoded data, and we will normalize these
1831     # operations with utf8.  If we have not decoded the data, then
1832     # we must not treat it as encoded data.
1833     my $is_encoded_data = $encoding_in ? 'utf8' : EMPTY_STRING;
1834     $self->[_is_encoded_data_] = $is_encoded_data;
1835
1836     # Delete any Byte Order Mark (BOM), which can cause trouble
1837     if ($is_encoded_data) {
1838         ${$rinput_string} =~ s/^\x{FEFF}//;
1839     }
1840
1841     $rstatus->{'input_name'}       = $display_name;
1842     $rstatus->{'opt_encoding'}     = $rOpts_character_encoding;
1843     $rstatus->{'char_mode_used'}   = $encoding_in ? 1 : 0;
1844     $rstatus->{'input_decoded_as'} = $decoded_input_as;
1845
1846     # Define the function to determine the display width of character
1847     # strings
1848     my $length_function;
1849     if ($is_encoded_data) {
1850
1851         # Try to load Unicode::GCString for defining text display width, if
1852         # requested, when the first encoded file is encountered
1853         if ( !defined($loaded_unicode_gcstring) ) {
1854             if ( eval { require Unicode::GCString; 1 } ) {
1855                 $loaded_unicode_gcstring = 1;
1856             }
1857             else {
1858                 $loaded_unicode_gcstring = 0;
1859                 if ( $rOpts->{'use-unicode-gcstring'} ) {
1860                     Warn(<<EOM);
1861 ----------------------
1862 Unable to load Unicode::GCString: $EVAL_ERROR
1863 Processing continues but some vertical alignment may be poor
1864 To prevent this warning message, you can either:
1865 - install module Unicode::GCString, or
1866 - remove '--use-unicode-gcstring' or '-gcs' from your perltidyrc or command line
1867 ----------------------
1868 EOM
1869                 }
1870             }
1871         }
1872         if ($loaded_unicode_gcstring) {
1873             $length_function = sub {
1874                 return Unicode::GCString->new( $_[0] )->columns;
1875             };
1876             $encoding_log_message .= <<EOM;
1877 Using 'Unicode::GCString' to measure horizontal character widths
1878 EOM
1879             $rstatus->{'gcs_used'} = 1;
1880         }
1881     }
1882     return (
1883         $rinput_string,
1884         $is_encoded_data,
1885         $decoded_input_as,
1886         $encoding_log_message,
1887         $length_function,
1888
1889     );
1890 } ## end sub get_decoded_string_buffer
1891
1892 { #<<<
1893
1894 my $LF;
1895 my $CR;
1896 my $CRLF;
1897
1898 BEGIN {
1899     $LF   = chr(10);
1900     $CR   = chr(13);
1901     $CRLF = $CR . $LF;
1902 }
1903
1904 sub get_line_separator_default {
1905
1906     my ($rOpts) = @_;
1907
1908     # Get the line separator that will apply unless overridden by a
1909     # --preserve-line-endings flag for a specific file
1910
1911     my $line_separator_default = "\n";
1912
1913     my $ole = $rOpts->{'output-line-ending'};
1914     if ($ole) {
1915         my %endings = (
1916             dos  => $CRLF,
1917             win  => $CRLF,
1918             mac  => $CR,
1919             unix => $LF,
1920         );
1921
1922         $line_separator_default = $endings{ lc $ole };
1923
1924         if ( !$line_separator_default ) {
1925             my $str = join SPACE, keys %endings;
1926             Die(<<EOM);
1927 Unrecognized line ending '$ole'; expecting one of: $str
1928 EOM
1929         }
1930
1931         # Check for conflict with -ple
1932         if ( $rOpts->{'preserve-line-endings'} ) {
1933             Warn("Ignoring -ple; conflicts with -ole\n");
1934             $rOpts->{'preserve-line-endings'} = undef;
1935         }
1936     }
1937
1938     return $line_separator_default;
1939
1940 } ## end sub get_line_separator_default
1941
1942 sub set_line_separator {
1943
1944     my ( $self, $rinput_string ) = @_;
1945
1946     # Set the (output) line separator as requested or necessary
1947
1948     my $rOpts = $self->[_rOpts_];
1949
1950     # Start with the default (output) line separator
1951     my $line_separator = $self->[_line_separator_default_];
1952
1953     # First try to find the line separator of the input stream
1954     my $input_line_separator;
1955
1956     # Limit the search to a reasonable number of characters, in case we
1957     # have a weird file
1958     my $str = substr( ${$rinput_string}, 0, CONST_1024 );
1959     if ($str) {
1960
1961         if ( $str =~ m/(($CR|$LF)+)/ ) {
1962
1963             my $test = $1;
1964
1965             # dos
1966             if ( $test =~ /^($CRLF)+\z/ ) {
1967                 $input_line_separator = $CRLF;
1968             }
1969
1970             # mac
1971             elsif ( $test =~ /^($CR)+\z/ ) {
1972                 $input_line_separator = $CR;
1973             }
1974
1975             # unix
1976             elsif ( $test =~ /^($LF)+\z/ ) {
1977                 $input_line_separator = $LF;
1978             }
1979
1980             # unknown
1981             else { }
1982         }
1983
1984         # no ending seen
1985         else { }
1986     }
1987
1988     if ( defined($input_line_separator) ) {
1989
1990         # Remember the input line separator if needed
1991         if ( $rOpts->{'preserve-line-endings'} ) {
1992             $line_separator = $input_line_separator;
1993         }
1994
1995         # Convert line endings to "\n" for processing if necessary.
1996         if ( $input_line_separator ne "\n" ) {
1997             my @lines = split /^/, ${$rinput_string};
1998
1999             # try to convert CR to \n
2000             if ( $input_line_separator eq $CR ) {
2001
2002                 # if this file is currently a single line ..
2003                 if ( @lines == 1 ) {
2004
2005                     # and becomes multiple lines with the change ..
2006                     @lines = map { $_ . "\n" } split /$CR/, ${$rinput_string};
2007                     if ( @lines > 1 ) {
2008
2009                         # then make the change
2010                         my $buf = join EMPTY_STRING, @lines;
2011                         $rinput_string = \$buf;
2012                     }
2013                 }
2014             }
2015
2016             # convert CR-LF to LF
2017             elsif ( ( $input_line_separator eq $CRLF ) && ( "\n" eq $LF ) ) {
2018                 foreach my $line (@lines) { $line =~ s/$CRLF$/\n/ }
2019                 my $buf = join EMPTY_STRING, @lines;
2020                 $rinput_string = \$buf;
2021             }
2022
2023             # unknown line ending scheme - leave it alone and let the tokenizer
2024             # deal with it
2025             else {
2026             }
2027         }
2028     }
2029
2030     $self->[_line_separator_] = $line_separator;
2031     return $rinput_string;
2032 } ## end sub set_line_separator
2033 }
2034
2035 sub process_all_files {
2036
2037     my ( $self, $rcall_hash ) = @_;
2038
2039     # This routine is the main loop to process all files.
2040     # Total formatting is done with these layers of subroutines:
2041     #   perltidy                - main routine; checks run parameters
2042     #  *process_all_files       - main loop to process all files; *THIS LAYER
2043     #   process_filter_layer    - do any pre and post processing;
2044     #   process_iteration_layer - handle any iterations on formatting
2045     #   process_single_case     - solves one formatting problem
2046
2047     my $rinput_hash               = $rcall_hash->{rinput_hash};
2048     my $rfiles                    = $rcall_hash->{rfiles};
2049     my $source_stream             = $rcall_hash->{source_stream};
2050     my $output_extension          = $rcall_hash->{output_extension};
2051     my $forbidden_file_extensions = $rcall_hash->{forbidden_file_extensions};
2052     my $in_place_modify           = $rcall_hash->{in_place_modify};
2053     my $backup_extension          = $rcall_hash->{backup_extension};
2054     my $delete_backup             = $rcall_hash->{delete_backup};
2055     my $logfile_header            = $rcall_hash->{logfile_header};
2056     my $rpending_complaint        = $rcall_hash->{rpending_complaint};
2057     my $rpending_logfile_message  = $rcall_hash->{rpending_logfile_message};
2058
2059     my $rOpts              = $self->[_rOpts_];
2060     my $dot                = $self->[_file_extension_separator_];
2061     my $diagnostics_object = $self->[_diagnostics_object_];
2062
2063     my $destination_stream = $rinput_hash->{'destination'};
2064     my $errorfile_stream   = $rinput_hash->{'errorfile'};
2065     my $logfile_stream     = $rinput_hash->{'logfile'};
2066     my $teefile_stream     = $rinput_hash->{'teefile'};
2067     my $debugfile_stream   = $rinput_hash->{'debugfile'};
2068
2069     my $number_of_files = @{$rfiles};
2070     foreach my $input_file ( @{$rfiles} ) {
2071         my $fileroot;
2072         my @input_file_stat;
2073         my $display_name;
2074
2075         #--------------------------
2076         # prepare this input stream
2077         #--------------------------
2078         if ($source_stream) {
2079             $fileroot     = "perltidy";
2080             $display_name = "<source_stream>";
2081
2082             # If the source is from an array or string, then .LOG output
2083             # is only possible if a logfile stream is specified.  This prevents
2084             # unexpected perltidy.LOG files.  If the stream is not defined
2085             # then we will capture it in a string ref but it will not be
2086             # accessible. Previously by Perl::Tidy::DevNull (fix c255);
2087             if ( !defined($logfile_stream) ) {
2088                 $logfile_stream = \my $tmp;
2089
2090                 # Likewise for .TEE and .DEBUG output
2091             }
2092             if ( !defined($teefile_stream) ) {
2093                 $teefile_stream = \my $tmp;
2094             }
2095             if ( !defined($debugfile_stream) ) {
2096                 $debugfile_stream = \my $tmp;
2097             }
2098         }
2099         elsif ( $input_file eq '-' ) {    # '-' indicates input from STDIN
2100             $fileroot     = "perltidy";   # root name to use for .ERR, .LOG, etc
2101             $display_name = "<stdin>";
2102             $in_place_modify = 0;
2103         }
2104         else {
2105             $fileroot     = $input_file;
2106             $display_name = $input_file;
2107             if ( !-e $input_file ) {
2108                 Warn("skipping file: '$input_file': no matches found\n");
2109                 next;
2110             }
2111
2112             if ( !-f $input_file ) {
2113                 Warn("skipping file: $input_file: not a regular file\n");
2114                 next;
2115             }
2116
2117             # As a safety precaution, skip zero length files.
2118             # If for example a source file got clobbered somehow,
2119             # the old .tdy or .bak files might still exist so we
2120             # shouldn't overwrite them with zero length files.
2121             if ( !-s $input_file ) {
2122                 Warn("skipping file: $input_file: Zero size\n");
2123                 next;
2124             }
2125
2126             # And avoid formatting extremely large files. Since perltidy reads
2127             # files into memory, trying to process an extremely large file
2128             # could cause system problems.
2129             my $size_in_mb = ( -s $input_file ) / ( CONST_1024 * CONST_1024 );
2130             my $maximum_file_size_mb = $rOpts->{'maximum-file-size-mb'};
2131             if ( $size_in_mb > $maximum_file_size_mb ) {
2132                 $size_in_mb = sprintf( "%0.1f", $size_in_mb );
2133                 Warn(
2134 "skipping file: $input_file: size $size_in_mb MB exceeds limit $maximum_file_size_mb; use -maxfs=i to change\n"
2135                 );
2136                 next;
2137             }
2138
2139             if ( !-T $input_file && !$rOpts->{'force-read-binary'} ) {
2140                 Warn("skipping file: $input_file: Non-text (override with -f)\n"
2141                 );
2142                 next;
2143             }
2144
2145             # Input file must be writable for -b -bm='copy'.  We must catch
2146             # this early to prevent encountering trouble after unlinking the
2147             # previous backup.
2148             if ( $in_place_modify && !-w $input_file ) {
2149                 my $backup_method = $rOpts->{'backup-method'};
2150                 if ( defined($backup_method) && $backup_method eq 'copy' ) {
2151                     Warn(
2152 "skipping file '$input_file' for -b option: file reported as non-writable\n"
2153                     );
2154                     next;
2155                 }
2156             }
2157
2158             # we should have a valid filename now
2159             $fileroot        = $input_file;
2160             @input_file_stat = stat($input_file);
2161
2162             if ( $OSNAME eq 'VMS' ) {
2163                 ( $fileroot, $dot ) = check_vms_filename($fileroot);
2164                 $self->[_file_extension_separator_] = $dot;
2165             }
2166
2167             # add option to change path here
2168             if ( defined( $rOpts->{'output-path'} ) ) {
2169
2170                 my ( $base, $old_path_uu ) = fileparse($fileroot);
2171                 my $new_path = $rOpts->{'output-path'};
2172                 if ( !-d $new_path ) {
2173                     mkdir($new_path)    # Default MODE is 0777
2174                       or
2175                       Die("unable to create directory $new_path: $OS_ERROR\n");
2176                 }
2177                 my $path = $new_path;
2178                 $fileroot = File::Spec->catfile( $path, $base );
2179                 if ( !$fileroot ) {
2180                     Die(<<EOM);
2181 ------------------------------------------------------------------------
2182 Problem combining $new_path and $base to make a filename; check -opath
2183 ------------------------------------------------------------------------
2184 EOM
2185                 }
2186             }
2187         }
2188
2189         # Skip files with same extension as the output files because
2190         # this can lead to a messy situation with files like
2191         # script.tdy.tdy.tdy ... or worse problems ...  when you
2192         # rerun perltidy over and over with wildcard input.
2193         if (
2194             !$source_stream
2195             && (   $input_file =~ /$forbidden_file_extensions/
2196                 || $input_file eq 'DIAGNOSTICS' )
2197           )
2198         {
2199             Warn("skipping file: $input_file: wrong extension\n");
2200             next;
2201         }
2202
2203         # copy source to a string buffer, decoding from utf8 if necessary
2204         my (
2205             $rinput_string,
2206             $is_encoded_data,
2207             $decoded_input_as,
2208             $encoding_log_message,
2209             $length_function,
2210
2211         ) = $self->get_decoded_string_buffer( $input_file, $display_name );
2212
2213         # Skip this file on any error
2214         next if ( !defined($rinput_string) );
2215
2216         # Register this file name with the Diagnostics package, if any.
2217         $diagnostics_object->set_input_file($input_file)
2218           if $diagnostics_object;
2219
2220         # The (possibly decoded) input is now in string ref $rinput_string.
2221         # Now prepare the output stream and error logger.
2222
2223         #--------------------------
2224         # prepare the output stream
2225         #--------------------------
2226         my $output_file;
2227         my $output_name = EMPTY_STRING;
2228         my $actual_output_extension;
2229
2230         if ( $rOpts->{'outfile'} ) {
2231
2232             if ( $number_of_files <= 1 ) {
2233
2234                 if ( $rOpts->{'standard-output'} ) {
2235                     my $saw_pbp = $self->[_saw_pbp_];
2236                     my $msg     = "You may not use -o and -st together";
2237                     $msg .= " (-pbp contains -st; see manual)" if ($saw_pbp);
2238                     Die("$msg\n");
2239                 }
2240
2241                 if ($destination_stream) {
2242                     Die(
2243 "You may not specify a destination array and -o together\n"
2244                     );
2245                 }
2246
2247                 if ( defined( $rOpts->{'output-path'} ) ) {
2248                     Die("You may not specify -o and -opath together\n");
2249                 }
2250
2251                 if ( defined( $rOpts->{'output-file-extension'} ) ) {
2252                     Die("You may not specify -o and -oext together\n");
2253                 }
2254
2255                 $output_file = $rOpts->{outfile};
2256                 $output_name = $output_file;
2257
2258                 # make sure user gives a file name after -o
2259                 if ( $output_file =~ /^-/ ) {
2260                     Die("You must specify a valid filename after -o\n");
2261                 }
2262
2263                 # do not overwrite input file with -o
2264                 if ( @input_file_stat && ( $output_file eq $input_file ) ) {
2265                     Die("Use 'perltidy -b $input_file' to modify in-place\n");
2266                 }
2267             }
2268             else {
2269                 Die("You may not use -o with more than one input file\n");
2270             }
2271         }
2272         elsif ( $rOpts->{'standard-output'} ) {
2273             if ($destination_stream) {
2274                 my $saw_pbp = $self->[_saw_pbp_];
2275                 my $msg =
2276                   "You may not specify a destination array and -st together\n";
2277                 $msg .= " (-pbp contains -st; see manual)" if ($saw_pbp);
2278                 Die("$msg\n");
2279             }
2280             $output_file = '-';
2281             $output_name = "<stdout>";
2282
2283             if ( $number_of_files <= 1 ) {
2284             }
2285             else {
2286                 Die("You may not use -st with more than one input file\n");
2287             }
2288         }
2289         elsif ($destination_stream) {
2290
2291             $output_file = $destination_stream;
2292             $output_name = "<destination_stream>";
2293         }
2294         elsif ($source_stream) {    # source but no destination goes to stdout
2295             $output_file = '-';
2296             $output_name = "<stdout>";
2297         }
2298         elsif ( $input_file eq '-' ) {
2299             $output_file = '-';
2300             $output_name = "<stdout>";
2301         }
2302         else {
2303             if ($in_place_modify) {
2304                 $output_name = $display_name;
2305             }
2306             else {
2307                 $actual_output_extension = $output_extension;
2308                 $output_file             = $fileroot . $output_extension;
2309                 $output_name             = $output_file;
2310             }
2311         }
2312
2313         # prepare standard output in case of a dump to stdout
2314         if ( $is_encoded_data && $self->[_dump_to_stdout_] ) {
2315             binmode *STDOUT, ':encoding(UTF-8)';
2316         }
2317
2318         $rstatus->{'file_count'} += 1;
2319         $rstatus->{'output_name'}     = $output_name;
2320         $rstatus->{'iteration_count'} = 0;
2321         $rstatus->{'converged'}       = 0;
2322
2323         #------------------------------------------
2324         # initialize the error logger for this file
2325         #------------------------------------------
2326         my $warning_file = $fileroot . $dot . "ERR";
2327         if ($errorfile_stream) { $warning_file = $errorfile_stream }
2328         my $log_file = $fileroot . $dot . "LOG";
2329         if ($logfile_stream) { $log_file = $logfile_stream }
2330
2331         # The logger object handles warning messages, logfile messages,
2332         # and can supply basic run information to lower level routines.
2333         my $logger_object = Perl::Tidy::Logger->new(
2334             rOpts           => $rOpts,
2335             log_file        => $log_file,
2336             warning_file    => $warning_file,
2337             fh_stderr       => $fh_stderr,
2338             display_name    => $display_name,
2339             is_encoded_data => $is_encoded_data,
2340         );
2341         $logger_object->write_logfile_entry($logfile_header);
2342         $logger_object->write_logfile_entry($encoding_log_message)
2343           if $encoding_log_message;
2344
2345         # Now we can add any pending messages to the log
2346         if ( ${$rpending_logfile_message} ) {
2347             $logger_object->write_logfile_entry( ${$rpending_logfile_message} );
2348         }
2349         if ( ${$rpending_complaint} ) {
2350             $logger_object->complain( ${$rpending_complaint} );
2351         }
2352
2353         # additional parameters needed by lower level routines
2354         $self->[_actual_output_extension_] = $actual_output_extension;
2355         $self->[_debugfile_stream_]        = $debugfile_stream;
2356         $self->[_decoded_input_as_]        = $decoded_input_as;
2357         $self->[_destination_stream_]      = $destination_stream;
2358         $self->[_display_name_]            = $display_name;
2359         $self->[_fileroot_]                = $fileroot;
2360         $self->[_is_encoded_data_]         = $is_encoded_data;
2361         $self->[_length_function_]         = $length_function;
2362         $self->[_logger_object_]           = $logger_object;
2363         $self->[_output_file_]             = $output_file;
2364         $self->[_teefile_stream_]          = $teefile_stream;
2365         $self->[_input_copied_verbatim_]   = 0;
2366         $self->[_input_output_difference_] = 1;    ## updated later if -b used
2367
2368         #--------------------
2369         # process this buffer
2370         #--------------------
2371         my $routput_string = $self->process_filter_layer($rinput_string);
2372
2373         #------------------------------------------------
2374         # send the tidied output to its final destination
2375         #------------------------------------------------
2376         if ( $rOpts->{'format'} eq 'tidy' && defined($routput_string) ) {
2377
2378             $self->write_tidy_output(
2379                 {
2380                     routput_string   => $routput_string,
2381                     rinput_file_stat => \@input_file_stat,
2382                     in_place_modify  => $in_place_modify,
2383                     input_file       => $input_file,
2384                     backup_extension => $backup_extension,
2385                     delete_backup    => $delete_backup,
2386                 }
2387             );
2388         }
2389
2390         $logger_object->finish()
2391           if $logger_object;
2392     } ## end loop over files
2393
2394     return;
2395 } ## end sub process_all_files
2396
2397 sub write_tidy_output {
2398
2399     my ( $self, $rcall_hash ) = @_;
2400
2401     # Write tidied output in '$routput_string' to its final destination
2402
2403     my $routput_string   = $rcall_hash->{routput_string};
2404     my $rinput_file_stat = $rcall_hash->{rinput_file_stat};
2405     my $in_place_modify  = $rcall_hash->{in_place_modify};
2406     my $input_file       = $rcall_hash->{input_file};
2407     my $backup_extension = $rcall_hash->{backup_extension};
2408     my $delete_backup    = $rcall_hash->{delete_backup};
2409
2410     my $rOpts           = $self->[_rOpts_];
2411     my $is_encoded_data = $self->[_is_encoded_data_];
2412     my $output_file     = $self->[_output_file_];
2413
2414     # There are three main output paths:
2415
2416     #-------------------------------------------------------------------------
2417     # PATH 1: $output_file is not defined: --backup and modify in-place option
2418     #-------------------------------------------------------------------------
2419     if ($in_place_modify) {
2420
2421         # For -b option, leave the file unchanged if a severe error caused
2422         # formatting to be skipped. Otherwise we will overwrite any backup.
2423         if ( !$self->[_input_copied_verbatim_] ) {
2424
2425             my $backup_method = $rOpts->{'backup-method'};
2426
2427             #-------------------------------------------------------------
2428             # PATH 1a: -bm='copy': uses newer version in which original is
2429             # copied to the backup and rewritten; see git #103.
2430             #-------------------------------------------------------------
2431             if ( defined($backup_method) && $backup_method eq 'copy' ) {
2432                 $self->backup_method_copy(
2433                     $input_file,       $routput_string,
2434                     $backup_extension, $delete_backup
2435                 );
2436             }
2437
2438             #-------------------------------------------------------------
2439             # PATH 1b: -bm='move': uses older version, where original is
2440             # moved to the backup and formatted output goes to a new file.
2441             #-------------------------------------------------------------
2442             else {
2443                 $self->backup_method_move(
2444                     $input_file,       $routput_string,
2445                     $backup_extension, $delete_backup
2446                 );
2447             }
2448         }
2449     }
2450
2451     #--------------------------------------------------------------------------
2452     # PATH 2: $output_file is a reference (=destination_stream): send output to
2453     # a destination stream ref received from an external perl program. We use
2454     # a sub to do this because the encoding rules are a bit tricky.
2455     #--------------------------------------------------------------------------
2456     elsif ( ref($output_file) ) {
2457         $self->copy_buffer_to_external_ref( $routput_string, $output_file );
2458     }
2459
2460     #--------------------------------------------------------------------------
2461     # PATH 3: $output_file is named file or '-'; send output to the file system
2462     #--------------------------------------------------------------------------
2463     else {
2464
2465         #--------------------------
2466         # PATH 3a: output to STDOUT
2467         #--------------------------
2468         if ( $output_file eq '-' ) {
2469             my $fh = *STDOUT;
2470             if ($is_encoded_data) { binmode $fh, ":raw:encoding(UTF-8)" }
2471             else                  { binmode $fh }
2472             $fh->print( ${$routput_string} );
2473         }
2474
2475         #--------------------------------
2476         # PATH 3b: output to a named file
2477         #--------------------------------
2478         else {
2479             if ( open( my $fh, '>', $output_file ) ) {
2480                 if ($is_encoded_data) { binmode $fh, ":raw:encoding(UTF-8)" }
2481                 else                  { binmode $fh }
2482                 $fh->print( ${$routput_string} );
2483                 $fh->close() or Die("Cannot close '$output_file': $OS_ERROR\n");
2484             }
2485             else {
2486                 Die("Cannot open $output_file to write: $OS_ERROR\n");
2487             }
2488
2489             # set output file ownership and permissions if appropriate
2490             if ( $output_file && -f $output_file && !-l $output_file ) {
2491                 if ( @{$rinput_file_stat} ) {
2492                     $self->set_output_file_permissions( $output_file,
2493                         \@{$rinput_file_stat}, $in_place_modify );
2494                 }
2495             }
2496         }
2497
2498         # Save diagnostic info
2499         if ($is_encoded_data) {
2500             $rstatus->{'output_encoded_as'} = 'UTF-8';
2501         }
2502     }
2503
2504     return;
2505
2506 } ## end sub write_tidy_output
2507
2508 sub process_filter_layer {
2509
2510     my ( $self, $rinput_string ) = @_;
2511
2512     # This is the filter layer of processing.
2513     # Do all requested formatting on the string ref '$rinput_string', including
2514     # any pre- and post-processing with filters.
2515     # Returns:
2516     #   $routput_string = ref to tidied output if in 'tidy' mode
2517     #   (nothing) if not in 'tidy' mode [these modes handle output separately]
2518
2519     # Total formatting is done with these layers of subroutines:
2520     #   perltidy                - main routine; checks run parameters
2521     #   process_all_files       - main loop to process all files;
2522     #  *process_filter_layer    - do any pre and post processing; *THIS LAYER
2523     #   process_iteration_layer - handle any iterations on formatting
2524     #   process_single_case     - solves one formatting problem
2525
2526     # Data Flow in this layer:
2527     #  $rinput_string
2528     #   -> optional prefilter operations
2529     #     -> [ formatting by sub process_iteration_layer ]
2530     #       -> return if not in 'tidy' mode
2531     #         -> optional postfilter operations
2532     #           -> $routput_string
2533
2534     # What is done based on format type:
2535     #  utf8 decoding is done for all format types
2536     #  prefiltering is applied to all format types
2537     #   - because it may be needed to get through the tokenizer
2538     #  postfiltering is only done for format='tidy'
2539     #   - not appropriate for html text, which has already been output
2540     #  encoding of decoded output is only done for format='tidy'
2541     #   - because html does its own encoding; user formatter does what it wants
2542
2543     # Be sure the string we received is defined
2544     if ( !defined($rinput_string) ) {
2545         Fault("bad call: the source string ref \$rinput_string is undefined\n");
2546     }
2547     if ( ref($rinput_string) ne 'SCALAR' ) {
2548         Fault("bad call: the source string ref is not SCALAR\n");
2549     }
2550
2551     my $rOpts         = $self->[_rOpts_];
2552     my $logger_object = $self->[_logger_object_];
2553
2554     # vars for --line-range-tidy filter, if needed
2555     my @input_lines_pre;
2556     my @input_lines_post;
2557
2558     # vars for checking assertions, if needed
2559     my $digest_input;
2560     my $saved_input_buf;
2561
2562     # var for checking --noadd-terminal-newline
2563     my $chomp_terminal_newline;
2564
2565     # Setup post-filter vars; these apply to 'tidy' mode only
2566     if ( $rOpts->{'format'} eq 'tidy' ) {
2567
2568         #---------------------------------------------------------------------
2569         # for --line-range-tidy, clip '$rinput_string' to a limited line range
2570         #---------------------------------------------------------------------
2571         my $line_tidy_begin = $self->[_line_tidy_begin_];
2572         if ($line_tidy_begin) {
2573
2574             my @input_lines = split /^/, ${$rinput_string};
2575
2576             my $num = @input_lines;
2577             if ( $line_tidy_begin > $num ) {
2578                 Die(<<EOM);
2579 #--line-range-tidy=n1:n2 has n1=$line_tidy_begin which exceeds max line number of $num
2580 EOM
2581             }
2582             else {
2583                 my $line_tidy_end = $self->[_line_tidy_end_];
2584                 if ( !defined($line_tidy_end) || $line_tidy_end > $num ) {
2585                     $line_tidy_end = $num;
2586                 }
2587                 my $input_string = join EMPTY_STRING,
2588                   @input_lines[ $line_tidy_begin - 1 .. $line_tidy_end - 1 ];
2589                 $rinput_string = \$input_string;
2590
2591                 @input_lines_pre  = @input_lines[ 0 .. $line_tidy_begin - 2 ];
2592                 @input_lines_post = @input_lines[ $line_tidy_end .. $num - 1 ];
2593             }
2594         }
2595
2596         #------------------------------------------
2597         # evaluate MD5 sum of input file, if needed
2598         #------------------------------------------
2599         if (   $rOpts->{'assert-tidy'}
2600             || $rOpts->{'assert-untidy'}
2601             || $rOpts->{'backup-and-modify-in-place'} )
2602         {
2603             $digest_input    = $md5_hex->( ${$rinput_string} );
2604             $saved_input_buf = ${$rinput_string};
2605         }
2606
2607         # When -noadd-terminal-newline is set, and the input does not
2608         # have a newline, then we remove the final newline of the output
2609         $chomp_terminal_newline = !$rOpts->{'add-terminal-newline'}
2610           && substr( ${$rinput_string}, -1, 1 ) !~ /\n/;
2611
2612     }
2613
2614     #-----------------------------------------------------------------------
2615     # Apply any prefilter. The prefilter is a code reference that will be
2616     # applied to the source before tokenizing.  Note that we are doing this
2617     # for all format types ('tidy', 'html', 'user') because it may be needed
2618     # to avoid tokenization errors.
2619     #-----------------------------------------------------------------------
2620     my $prefilter = $self->[_prefilter_];
2621     if ($prefilter) {
2622         my $input_string = $prefilter->( ${$rinput_string} );
2623         $rinput_string = \$input_string;
2624     }
2625
2626     #-------------------------------------------
2627     # Format contents of string '$rinput_string'
2628     #-------------------------------------------
2629     my $routput_string = $self->process_iteration_layer($rinput_string);
2630
2631     #-------------------------------
2632     # All done if not in 'tidy' mode
2633     #-------------------------------
2634     if ( $rOpts->{'format'} ne 'tidy' ) {
2635         return;
2636     }
2637
2638     #---------------------
2639     # apply any postfilter
2640     #---------------------
2641     my $postfilter = $self->[_postfilter_];
2642     if ($postfilter) {
2643         my $output_string = $postfilter->( ${$routput_string} );
2644         $routput_string = \$output_string;
2645     }
2646
2647     if ( defined($digest_input) ) {
2648         my $digest_output = $md5_hex->( ${$routput_string} );
2649         $self->[_input_output_difference_] = $digest_output ne $digest_input;
2650     }
2651
2652     #-----------------------------------------------------
2653     # check for changes if requested by 'assert-...' flags
2654     #-----------------------------------------------------
2655     if ( $rOpts->{'assert-tidy'} ) {
2656         if ( $self->[_input_output_difference_] ) {
2657             my $diff_msg =
2658               compare_string_buffers( \$saved_input_buf, $routput_string );
2659             $logger_object->warning(<<EOM);
2660 assertion failure: '--assert-tidy' is set but output differs from input
2661 EOM
2662             $logger_object->interrupt_logfile();
2663             $logger_object->warning( $diff_msg . "\n" );
2664             $logger_object->resume_logfile();
2665         }
2666     }
2667
2668     if ( $rOpts->{'assert-untidy'} ) {
2669         if ( !$self->[_input_output_difference_] ) {
2670             $logger_object->warning(
2671 "assertion failure: '--assert-untidy' is set but output equals input\n"
2672             );
2673         }
2674     }
2675
2676     #----------------------------------------
2677     # do --line-range-tidy line recombination
2678     #----------------------------------------
2679     if ( @input_lines_pre || @input_lines_post ) {
2680         my $str_pre       = join EMPTY_STRING, @input_lines_pre;
2681         my $str_post      = join EMPTY_STRING, @input_lines_post;
2682         my $output_string = $str_pre . ${$routput_string} . $str_post;
2683         $routput_string = \$output_string;
2684     }
2685
2686     #-----------------------------------------
2687     # handle a '--noadd-terminal-newline' flag
2688     #-----------------------------------------
2689     if ($chomp_terminal_newline) {
2690         chomp ${$routput_string};
2691     }
2692
2693     #-------------------------------------------------------------
2694     # handle --preserve-line-endings or -output-line-endings flags
2695     #-------------------------------------------------------------
2696     # The native line separator has been used in all intermediate
2697     # iterations and filter operations until here so that string
2698     # operations work ok.
2699     if ( $self->[_line_separator_] ne "\n" ) {
2700         my $line_separator = $self->[_line_separator_];
2701         my @output_lines   = split /^/, ${$routput_string};
2702         foreach my $line (@output_lines) {
2703
2704             # must check chomp because last line might not have a newline
2705             # if --noadd-terminal-newline is also set (c283)
2706             if ( chomp $line ) {
2707                 $line .= $line_separator;
2708             }
2709         }
2710         my $output_string = join EMPTY_STRING, @output_lines;
2711         $routput_string = \$output_string;
2712     }
2713
2714     return $routput_string;
2715 } ## end sub process_filter_layer
2716
2717 # For safety, set an upper bound on number of iterations before stopping.
2718 # The average number of iterations is 2. No known cases exceed 4.
2719 use constant ITERATION_LIMIT => 6;
2720
2721 sub process_iteration_layer {
2722
2723     my ( $self, $rinput_string ) = @_;
2724
2725     # This is the iteration layer of processing.
2726     # Do all formatting, iterating if requested, on the source $rinput_string
2727     # Output depends on format type:
2728     #   For 'tidy' formatting, output goes to sink object
2729     #   For 'html' formatting, output goes to the ultimate destination
2730     #   For 'user' formatting, user formatter handles output
2731
2732     # Total formatting is done with these layers of subroutines:
2733     #   perltidy                - main routine; checks run parameters
2734     #   process_all_files       - main loop to process all files;
2735     #   process_filter_layer    - do any pre and post processing
2736     #  *process_iteration_layer - do any iterations on formatting; *THIS LAYER
2737     #   process_single_case     - solves one formatting problem
2738
2739     # Data Flow in this layer:
2740     #      $rinput_string -> [ loop over iterations ] -> $routput_string
2741
2742     my $diagnostics_object = $self->[_diagnostics_object_];
2743     my $display_name       = $self->[_display_name_];
2744     my $fileroot           = $self->[_fileroot_];
2745     my $is_encoded_data    = $self->[_is_encoded_data_];
2746     my $length_function    = $self->[_length_function_];
2747     my $logger_object      = $self->[_logger_object_];
2748     my $rOpts              = $self->[_rOpts_];
2749     my $user_formatter     = $self->[_user_formatter_];
2750
2751     # make a debugger object if requested
2752     my $debugger_object;
2753     if ( $rOpts->{DEBUG} ) {
2754         my $debug_file = $self->[_debugfile_stream_]
2755           || $fileroot . $self->make_file_extension('DEBUG');
2756         $debugger_object =
2757           Perl::Tidy::Debugger->new( $debug_file, $is_encoded_data );
2758     }
2759
2760     # make a tee file handle if requested
2761     my $fh_tee;
2762     my $tee_file;
2763     if (   $rOpts->{'tee-pod'}
2764         || $rOpts->{'tee-block-comments'}
2765         || $rOpts->{'tee-side-comments'} )
2766     {
2767         $tee_file = $self->[_teefile_stream_]
2768           || $fileroot . $self->make_file_extension('TEE');
2769         $fh_tee = Perl::Tidy::streamhandle( $tee_file, 'w', $is_encoded_data );
2770         if ( !$fh_tee ) {
2771             Warn("couldn't open TEE file $tee_file: $OS_ERROR\n");
2772         }
2773     }
2774
2775     # vars for iterations and convergence test
2776     my $max_iterations = 1;
2777     my $convergence_log_message;
2778     my %saw_md5;
2779
2780     # Only 'tidy' formatting can use multiple iterations
2781     if ( $rOpts->{'format'} eq 'tidy' ) {
2782
2783         # check iteration count and quietly fix if necessary:
2784         # - iterations option only applies to code beautification mode
2785         # - the convergence check should stop most runs on iteration 2, and
2786         #   virtually all on iteration 3.  We allow up to ITERATION_LIMIT.
2787         $max_iterations = $rOpts->{'iterations'};
2788         if ( !defined($max_iterations)
2789             || $max_iterations <= 0 )
2790         {
2791             $max_iterations = 1;
2792         }
2793
2794         if ( $max_iterations > ITERATION_LIMIT ) {
2795             $max_iterations = ITERATION_LIMIT;
2796         }
2797
2798         # get starting MD5 sum for convergence test
2799         if ( $max_iterations > 1 ) {
2800             my $digest = $md5_hex->( ${$rinput_string} );
2801             $saw_md5{$digest} = 0;
2802         }
2803     }
2804
2805     # save objects to allow redirecting output during iterations
2806     my $logger_object_final = $logger_object;
2807     my $iteration_of_formatter_convergence;
2808     my $routput_string;
2809
2810     #---------------------
2811     # Loop over iterations
2812     #---------------------
2813     foreach my $iter ( 1 .. $max_iterations ) {
2814
2815         $rstatus->{'iteration_count'} += 1;
2816
2817         # create a string to capture the output
2818         my $sink_buffer = EMPTY_STRING;
2819         $routput_string = \$sink_buffer;
2820
2821         # Save logger, debugger and tee output only on pass 1 because:
2822         # (1) line number references must be to the starting
2823         # source, not an intermediate result, and
2824         # (2) we need to know if there are errors so we can stop the
2825         # iterations early if necessary.
2826         # (3) the tee option only works on first pass if comments are also
2827         # being deleted.
2828         if ( $iter > 1 ) {
2829
2830             $debugger_object->close_debug_file()
2831               if ($debugger_object);
2832
2833             if (   $fh_tee
2834                 && $fh_tee->can('close')
2835                 && !ref($tee_file)
2836                 && $tee_file ne '-' )
2837             {
2838                 $fh_tee->close()
2839                   or Warn("couldn't close TEE file $tee_file: $OS_ERROR\n");
2840             }
2841
2842             $debugger_object = undef;
2843             $logger_object   = undef;
2844             $fh_tee          = undef;
2845         }
2846
2847         #---------------------------------
2848         # create a formatter for this file
2849         #---------------------------------
2850
2851         my $formatter;
2852
2853         if ($user_formatter) {
2854             $formatter = $user_formatter;
2855         }
2856         elsif ( $rOpts->{'format'} eq 'html' ) {
2857
2858             my $html_toc_extension =
2859               $self->make_file_extension( $rOpts->{'html-toc-extension'},
2860                 'toc' );
2861
2862             my $html_src_extension =
2863               $self->make_file_extension( $rOpts->{'html-src-extension'},
2864                 'src' );
2865
2866             $formatter = Perl::Tidy::HtmlWriter->new(
2867                 input_file         => $fileroot,
2868                 html_file          => $self->[_output_file_],
2869                 extension          => $self->[_actual_output_extension_],
2870                 html_toc_extension => $html_toc_extension,
2871                 html_src_extension => $html_src_extension,
2872             );
2873         }
2874         elsif ( $rOpts->{'format'} eq 'tidy' ) {
2875             $formatter = Perl::Tidy::Formatter->new(
2876                 logger_object      => $logger_object,
2877                 diagnostics_object => $diagnostics_object,
2878                 sink_object        => $routput_string,
2879                 length_function    => $length_function,
2880                 is_encoded_data    => $is_encoded_data,
2881                 fh_tee             => $fh_tee,
2882             );
2883         }
2884         else {
2885             Die("I don't know how to do -format=$rOpts->{'format'}\n");
2886         }
2887
2888         if ( !$formatter ) {
2889             Die("Unable to continue with $rOpts->{'format'} formatting\n");
2890         }
2891
2892         #-----------------------------------
2893         # create the tokenizer for this file
2894         #-----------------------------------
2895         my $tokenizer = Perl::Tidy::Tokenizer->new(
2896             source_object      => $rinput_string,
2897             logger_object      => $logger_object,
2898             debugger_object    => $debugger_object,
2899             diagnostics_object => $diagnostics_object,
2900             rOpts              => $rOpts,
2901             starting_level     => $rOpts->{'starting-indentation-level'},
2902         );
2903
2904         #---------------------------------
2905         # do processing for this iteration
2906         #---------------------------------
2907         $self->process_single_case( $tokenizer, $formatter );
2908
2909         #--------------
2910         # report errors
2911         #--------------
2912
2913         # see if the formatter is converged
2914         if (   $max_iterations > 1
2915             && !defined($iteration_of_formatter_convergence)
2916             && $formatter->can('get_convergence_check') )
2917         {
2918             if ( $formatter->get_convergence_check() ) {
2919                 $iteration_of_formatter_convergence = $iter;
2920                 $rstatus->{'converged'} = 1;
2921             }
2922         }
2923
2924         # line source for next iteration (if any) comes from the current
2925         # temporary output buffer
2926         if ( $iter < $max_iterations ) {
2927
2928             $rinput_string = \$sink_buffer;
2929
2930             # stop iterations if errors or converged
2931             my $stop_now = $self->[_input_copied_verbatim_];
2932             $stop_now ||= $tokenizer->get_unexpected_error_count();
2933             my $stopping_on_error = $stop_now;
2934             if ($stop_now) {
2935                 $convergence_log_message = <<EOM;
2936 Stopping iterations because of severe errors.
2937 EOM
2938             }
2939
2940             # or do convergence test
2941             else {
2942
2943                 # stop if the formatter has converged
2944                 $stop_now ||= defined($iteration_of_formatter_convergence);
2945
2946                 my $digest = $md5_hex->($sink_buffer);
2947                 if ( !defined( $saw_md5{$digest} ) ) {
2948                     $saw_md5{$digest} = $iter;
2949                 }
2950
2951                 # do a second iteration if all ok and requested by formatter
2952                 # to allow delayed adding/deleting of commas (git156, git143)
2953                 elsif ( $iter == 1
2954                     && !$stop_now
2955                     && $formatter->can('want_second_iteration')
2956                     && $formatter->want_second_iteration() )
2957                 {
2958                     ## deja vu, but do not set $stop_now
2959                     $saw_md5{$digest} = $iter;
2960                 }
2961                 else {
2962
2963                     # Deja vu, stop iterating
2964
2965                     $stop_now = 1;
2966                     my $iterm = $iter - 1;
2967                     if ( $saw_md5{$digest} != $iterm ) {
2968
2969                         # Blinking (oscillating) between two or more stable
2970                         # end states.  This is unlikely to occur with normal
2971                         # parameters, but it can occur in stress testing
2972                         # with extreme parameter values, such as very short
2973                         # maximum line lengths.  We want to catch and fix
2974                         # them when they happen.
2975                         $rstatus->{'blinking'} = 1;
2976                         $convergence_log_message = <<EOM;
2977 BLINKER. Output for iteration $iter same as for $saw_md5{$digest}.
2978 EOM
2979                         $stopping_on_error ||= $convergence_log_message;
2980                         DEVEL_MODE
2981                           && print {*STDERR} $convergence_log_message;
2982                         $diagnostics_object->write_diagnostics(
2983                             $convergence_log_message)
2984                           if $diagnostics_object;
2985
2986 # Uncomment to search for blinking states
2987 # Warn( "$display_name: blinking; iter $iter same as for $saw_md5{$digest}\n" );
2988
2989                     }
2990                     else {
2991                         $convergence_log_message = <<EOM;
2992 Converged.  Output for iteration $iter same as for iter $iterm.
2993 EOM
2994                         $diagnostics_object->write_diagnostics(
2995                             $convergence_log_message)
2996                           if $diagnostics_object && $iterm > 2;
2997                         $rstatus->{'converged'} = 1;
2998                     }
2999                 }
3000             }
3001
3002             if ($stop_now) {
3003
3004                 if (DEVEL_MODE) {
3005
3006                     if ( defined($iteration_of_formatter_convergence) ) {
3007
3008                         # This message cannot appear unless the formatter
3009                         # convergence test above is temporarily skipped for
3010                         # testing.
3011                         if ( $iteration_of_formatter_convergence < $iter - 1 ) {
3012                             print {*STDERR}
3013 "STRANGE Early conv in $display_name: Stopping on it=$iter, converged in formatter on $iteration_of_formatter_convergence\n";
3014                         }
3015                     }
3016                     elsif ( !$stopping_on_error ) {
3017
3018                         # The md5 sum implies convergence but the convergence
3019                         # was not detected by the Formatter.  This is not
3020                         # critical but should be investigated.  It happened
3021                         # once when a line break was placed before a phantom
3022                         # comma under -qwaf, and has been fixed.
3023                         print {*STDERR}
3024 "STRANGE no conv in $display_name: stopping on it=$iter, but not converged in formatter\n";
3025                     }
3026                     else {
3027                         ## looks ok
3028                     }
3029                 }
3030
3031                 # we are stopping the iterations early;
3032                 last;
3033             }
3034         } ## end if ( $iter < $max_iterations)
3035     } ## end loop over iterations for one source file
3036
3037     $debugger_object->close_debug_file()
3038       if $debugger_object;
3039
3040     if (   $fh_tee
3041         && $fh_tee->can('close')
3042         && !ref($tee_file)
3043         && $tee_file ne '-' )
3044     {
3045         $fh_tee->close()
3046           or Warn("couldn't close TEE file $tee_file: $OS_ERROR\n");
3047     }
3048
3049     # leave logger object open for additional messages
3050     $logger_object = $logger_object_final;
3051     $logger_object->write_logfile_entry($convergence_log_message)
3052       if $convergence_log_message;
3053
3054     return $routput_string;
3055
3056 } ## end sub process_iteration_layer
3057
3058 sub process_single_case {
3059
3060     my ( $self, $tokenizer, $formatter ) = @_;
3061
3062     # Run the formatter on a single defined case
3063
3064     # Total formatting is done with these layers of subroutines:
3065     #   perltidy                - main routine; checks run parameters
3066     #   process_all_files       - main loop to process all files;
3067     #   process_filter_layer    - do any pre and post processing;
3068     #   process_iteration_layer - do any iterations on formatting
3069     #  *process_single_case     - solve one formatting problem; *THIS LAYER
3070
3071     while ( my $line = $tokenizer->get_line() ) {
3072         $formatter->write_line($line);
3073     }
3074
3075     # user-defined formatters are possible, and may not have a
3076     # sub 'finish_formatting', so we have to check
3077     if ( $formatter->can('finish_formatting') ) {
3078         my $severe_error = $tokenizer->report_tokenization_errors();
3079         my $verbatim     = $formatter->finish_formatting($severe_error);
3080         $self->[_input_copied_verbatim_] = $verbatim;
3081     }
3082
3083     return;
3084 } ## end sub process_single_case
3085
3086 sub copy_buffer_to_external_ref {
3087
3088     my ( $self, $routput, $destination_stream ) = @_;
3089
3090     # Copy $routput to the final $destination_stream,
3091     # encoding if the flag $encode_destination_buffer is true.
3092
3093     # Data Flow:
3094     #    $destination_buffer -> [ encode? ] -> $destination_stream
3095
3096     my $destination_buffer = EMPTY_STRING;
3097     if ( ref($routput) eq 'ARRAY' ) {
3098         $destination_buffer = join EMPTY_STRING, @{$routput};
3099     }
3100     elsif ( ref($routput) eq 'SCALAR' ) {
3101         $destination_buffer = ${$routput};
3102     }
3103     else {
3104         Fatal(
3105             "'copy_buffer_to_external_ref' expecting ref to ARRAY or SCALAR\n");
3106     }
3107
3108     $rstatus->{'output_encoded_as'} = EMPTY_STRING;
3109     my $ref_destination_stream = ref($destination_stream);
3110
3111     # Encode output? Strings and arrays use special encoding rules; see:
3112     #   https://github.com/perltidy/perltidy/blob/master/docs/eos_flag.md
3113     my $encode_destination_buffer;
3114     if (   $ref_destination_stream eq 'SCALAR'
3115         || $ref_destination_stream eq 'ARRAY' )
3116     {
3117         my $rOpts = $self->[_rOpts_];
3118         $encode_destination_buffer =
3119           $rOpts->{'encode-output-strings'} && $self->[_decoded_input_as_];
3120     }
3121
3122     # An object with a print method will use file encoding rules
3123     elsif ( $ref_destination_stream->can('print') ) {
3124         $encode_destination_buffer = $self->[_is_encoded_data_];
3125     }
3126     else {
3127         confess <<EOM;
3128 ------------------------------------------------------------------------
3129 No 'print' method is defined for object of class '$ref_destination_stream'
3130 Please check your call to Perl::Tidy::perltidy. Trace follows.
3131 ------------------------------------------------------------------------
3132 EOM
3133     }
3134
3135     if ($encode_destination_buffer) {
3136         my $encoded_buffer;
3137         if (
3138             !eval {
3139                 $encoded_buffer =
3140                   Encode::encode( "UTF-8", $destination_buffer,
3141                     Encode::FB_CROAK | Encode::LEAVE_SRC );
3142                 1;
3143             }
3144           )
3145         {
3146
3147             Warn(
3148 "Error attempting to encode output string ref; encoding not done\n"
3149             );
3150         }
3151         else {
3152             $destination_buffer = $encoded_buffer;
3153             $rstatus->{'output_encoded_as'} = 'UTF-8';
3154         }
3155     }
3156
3157     # Send data for SCALAR, ARRAY & OBJ refs to its final destination
3158     if ( $ref_destination_stream eq 'SCALAR' ) {
3159         ${$destination_stream} = $destination_buffer;
3160     }
3161     elsif ( defined($destination_buffer) ) {
3162         my @lines = split /^/, $destination_buffer;
3163         if ( $ref_destination_stream eq 'ARRAY' ) {
3164             @{$destination_stream} = @lines;
3165         }
3166
3167         # destination stream must be an object with print method
3168         else {
3169             foreach my $line (@lines) {
3170                 $destination_stream->print($line);
3171             }
3172             if ( $ref_destination_stream->can('close') ) {
3173                 $destination_stream->close();
3174             }
3175         }
3176     }
3177     else {
3178
3179         # Empty destination buffer not going to a string ... could
3180         # happen for example if user deleted all pod or comments
3181     }
3182     return;
3183 } ## end sub copy_buffer_to_external_ref
3184
3185 } ## end of closure for sub perltidy
3186
3187 sub line_diff {
3188
3189     my ( $s1, $s2 ) = @_;
3190
3191     # Given two strings, Return
3192     #  $diff_marker = a string with caret (^) symbols indicating differences
3193     #  $pos1 = character position of first difference; pos1=-1 if no difference
3194
3195     # Form exclusive or of the strings, which has null characters where strings
3196     # have same common characters so non-null characters indicate character
3197     # differences.
3198     my $diff_marker = EMPTY_STRING;
3199     my $pos         = -1;
3200     my $pos1        = -1;
3201     if ( defined($s1) && defined($s2) ) {
3202         my $mask = $s1 ^ $s2;
3203
3204         while ( $mask =~ /[^\0]/g ) {
3205             my $pos_last = $pos;
3206             $pos = $LAST_MATCH_START[0];
3207             if ( $pos1 < 0 ) { $pos1 = $pos; }
3208             $diff_marker .= SPACE x ( $pos - $pos_last - 1 ) . '^';
3209
3210             # we could continue to mark all differences, but there is no point
3211             last;
3212         } ## end while ( $mask =~ /[^\0]/g)
3213     }
3214     return ( $diff_marker, $pos1 );
3215 } ## end sub line_diff
3216
3217 sub compare_string_buffers {
3218
3219     my ( $string_i, $string_o, ($max_diff_count) ) = @_;
3220
3221     # Compare input and output string buffers and return a brief text
3222     # description of the first difference.
3223
3224     # Given:
3225     #   $string_i = input string, or ref to input string
3226     #   $string_o = output string, or ref to output string
3227     #   $max_diff_count = optional maximum number of differences to show,
3228     #       default=1
3229     # Return:
3230     #   a string showing differences
3231
3232     my $rbufi = ref($string_i) ? $string_i : \$string_i;
3233     my $rbufo = ref($string_o) ? $string_o : \$string_o;
3234
3235     if ( !defined($max_diff_count) ) { $max_diff_count = 1 }
3236
3237     my ( @aryi, @aryo );
3238     my ( $leni, $leno ) = ( 0, 0 );
3239     if ( defined($rbufi) ) {
3240         $leni = length( ${$rbufi} );
3241         @aryi = split /^/, ${$rbufi};
3242     }
3243     if ( defined($rbufo) ) {
3244         $leno = length( ${$rbufo} );
3245         @aryo = split /^/, ${$rbufo};
3246     }
3247     my $nlines_i = @aryi;
3248     my $nlines_o = @aryo;
3249     my $msg      = <<EOM;
3250 Input   file length has $leni chars in $nlines_i lines
3251 Output  file length has $leno chars in $nlines_o lines
3252 EOM
3253     return $msg unless ( $leni && $leno );
3254
3255     my $truncate = sub {
3256         my ( $str, $lenmax ) = @_;
3257         if ( length($str) > $lenmax ) {
3258             $str = substr( $str, 0, $lenmax ) . "...";
3259         }
3260         return $str;
3261     }; ## end $truncate = sub
3262
3263     my $last_nonblank_line  = EMPTY_STRING;
3264     my $last_nonblank_count = 0;
3265
3266     # loop over lines until we find a difference
3267     my $count      = 0;
3268     my $diff_count = 0;
3269     while ( @aryi && @aryo ) {
3270         $count++;
3271         my $linei = shift @aryi;
3272         my $lineo = shift @aryo;
3273         chomp $linei;
3274         chomp $lineo;
3275         if ( $linei eq $lineo ) {
3276             if ( length($linei) ) {
3277                 $last_nonblank_line  = $linei;
3278                 $last_nonblank_count = $count;
3279             }
3280             next;
3281         }
3282
3283         #---------------------------
3284         # lines differ ... finish up
3285         #---------------------------
3286         my ( $line_diff, $pos1 ) = line_diff( $linei, $lineo );
3287         my $ch1    = $pos1 + 1;
3288         my $reason = "Files first differ at character $ch1 of line $count";
3289
3290         my ( $leading_ws_i, $leading_ws_o ) = ( EMPTY_STRING, EMPTY_STRING );
3291         if ( $linei =~ /^(\s+)/ ) { $leading_ws_i = $1; }
3292         if ( $lineo =~ /^(\s+)/ ) { $leading_ws_o = $1; }
3293         if ( $leading_ws_i ne $leading_ws_o ) {
3294             $reason .= "; leading whitespace differs";
3295             if ( $leading_ws_i =~ /\t/ ) {
3296                 $reason .= "; input has tab char";
3297             }
3298         }
3299         else {
3300             my ( $trailing_ws_i, $trailing_ws_o ) =
3301               ( EMPTY_STRING, EMPTY_STRING );
3302             if ( $linei =~ /(\s+)$/ ) { $trailing_ws_i = $1; }
3303             if ( $lineo =~ /(\s+)$/ ) { $trailing_ws_o = $1; }
3304             if ( $trailing_ws_i ne $trailing_ws_o ) {
3305                 $reason .= "; trailing whitespace differs";
3306             }
3307         }
3308         $msg .= $reason . "\n";
3309
3310         # limit string display length
3311         if ( $pos1 > 60 ) {
3312             my $drop = $pos1 - 40;
3313             $linei     = "..." . substr( $linei, $drop );
3314             $lineo     = "..." . substr( $lineo, $drop );
3315             $line_diff = SPACE x 3 . substr( $line_diff, $drop );
3316         }
3317         $linei              = $truncate->( $linei,              72 );
3318         $lineo              = $truncate->( $lineo,              72 );
3319         $last_nonblank_line = $truncate->( $last_nonblank_line, 72 );
3320
3321         if ($last_nonblank_line) {
3322             $msg .= <<EOM;
3323  $last_nonblank_count:$last_nonblank_line
3324 EOM
3325         }
3326         $line_diff = SPACE x ( 2 + length($count) ) . $line_diff;
3327         $msg .= <<EOM;
3328 <$count:$linei
3329 >$count:$lineo
3330 $line_diff
3331 EOM
3332         $diff_count++;
3333         last if ( $diff_count >= $max_diff_count );
3334     } ## end while ( @aryi && @aryo )
3335
3336     if ($diff_count) { return $msg }
3337
3338     #------------------------------------------------------
3339     # no differences found, see if one file has fewer lines
3340     #------------------------------------------------------
3341     if ( $nlines_i > $nlines_o ) {
3342         $msg .= <<EOM;
3343 Files initially match file but output file has fewer lines
3344 EOM
3345     }
3346     elsif ( $nlines_i < $nlines_o ) {
3347         $msg .= <<EOM;
3348 Files initially match file but input file has fewer lines
3349 EOM
3350     }
3351     else {
3352         $msg .= <<EOM;
3353 Text in lines of file match but checksums differ. Perhaps line endings differ.
3354 EOM
3355     }
3356     return $msg;
3357 } ## end sub compare_string_buffers
3358
3359 sub fileglob_to_re {
3360
3361     # modified (corrected) from version in find2perl
3362     my $x = shift;
3363     $x =~ s/([.\/^\$()])/\\$1/g;    # escape special characters
3364     $x =~ s/\*/.*/g;                # '*' -> '.*'
3365     $x =~ s/\?/./g;                 # '?' -> '.'
3366     return "^$x\\z";                # match whole word
3367 } ## end sub fileglob_to_re
3368
3369 sub make_logfile_header {
3370     my ( $rOpts, $config_file, $rraw_options, $Windows_type, $readable_options )
3371       = @_;
3372
3373     # Note: the punctuation variable '$]' is not in older versions of
3374     # English.pm so leave it as is to avoid failing installation tests.
3375     my $msg =
3376 "perltidy version $VERSION log file on a $OSNAME system, OLD_PERL_VERSION=$]\n";
3377     if ($Windows_type) {
3378         $msg .= "Windows type is $Windows_type\n";
3379     }
3380     my $options_string = join( SPACE, @{$rraw_options} );
3381
3382     if ( defined($config_file) ) {
3383         $msg .= "Found Configuration File >>> $config_file \n";
3384     }
3385     $msg .= "Configuration and command line parameters for this run:\n";
3386     $msg .= "$options_string\n";
3387
3388     if ( $rOpts->{'show-options'} ) {
3389         $rOpts->{'logfile'} = 1;    # force logfile to be saved
3390         $msg .= "Final parameter set for this run\n";
3391         $msg .= "------------------------------------\n";
3392
3393         $msg .= $readable_options;
3394
3395         $msg .= "------------------------------------\n";
3396     }
3397     $msg .= "To find error messages search for 'WARNING' with your editor\n";
3398     return $msg;
3399 } ## end sub make_logfile_header
3400
3401 sub generate_options {
3402
3403     ######################################################################
3404     # Generate and return references to:
3405     #  @option_string - the list of options to be passed to Getopt::Long
3406     #  @defaults - the list of default options
3407     #  %expansion - a hash showing how all abbreviations are expanded
3408     #  %category - a hash giving the general category of each option
3409     #  %option_range - a hash giving the valid ranges of certain options
3410
3411     # Note: a few options are not documented in the man page and usage
3412     # message. This is because these are deprecated, experimental or debug
3413     # options and may or may not be retained in future versions:
3414
3415     # These undocumented flags are accepted but not used:
3416     # --check-syntax
3417     # --fuzzy-line-length
3418     #
3419     # These undocumented flags are for debugging:
3420     # --recombine                           # used to debug line breaks
3421     # --short-concatenation-item-length     # used to break a '.' chain
3422     #
3423     ######################################################################
3424
3425     # here is a summary of the Getopt codes:
3426     # <none> does not take an argument
3427     # =s takes a mandatory string
3428     # :s takes an optional string  (DO NOT USE - filenames will get eaten up)
3429     # =i takes a mandatory integer
3430     # :i takes an optional integer (NOT RECOMMENDED - can cause trouble)
3431     # ! does not take an argument and may be negated
3432     #  i.e., -foo and -nofoo are allowed
3433     # a double dash signals the end of the options list
3434     #
3435     #-----------------------------------------------
3436     # Define the option string passed to GetOptions.
3437     #-----------------------------------------------
3438
3439     my @option_string   = ();
3440     my %expansion       = ();
3441     my %option_category = ();
3442     my %option_range    = ();
3443     my %integer_option_range;
3444
3445     # names of categories in manual
3446     # leading integers will allow sorting
3447     my @category_name = (
3448         '0. I/O control',
3449         '1. Basic formatting options',
3450         '2. Code indentation control',
3451         '3. Whitespace control',
3452         '4. Comment controls',
3453         '5. Linebreak controls',
3454         '6. Controlling list formatting',
3455         '7. Retaining or ignoring existing line breaks',
3456         '8. Blank line control',
3457         '9. Other controls',
3458         '10. HTML options',
3459         '11. pod2html options',
3460         '12. Controlling HTML properties',
3461         '13. Debugging',
3462     );
3463
3464     #  These options are parsed directly by perltidy:
3465     #    help h
3466     #    version v
3467     #  However, they are included in the option set so that they will
3468     #  be seen in the options dump.
3469
3470     # These long option names have no abbreviations or are treated specially
3471     @option_string = qw(
3472       html!
3473       noprofile
3474       no-profile
3475       npro
3476       recombine!
3477       notidy
3478     );
3479
3480     my $category = 13;    # Debugging
3481     foreach (@option_string) {
3482         my $opt = $_;     # must avoid changing the actual flag
3483         $opt =~ s/!$//;
3484         $option_category{$opt} = $category_name[$category];
3485     }
3486
3487     $category = 11;                                       # HTML
3488     $option_category{html} = $category_name[$category];
3489
3490     # routine to install and check options
3491     my $add_option = sub {
3492         my ( $long_name, $short_name, $flag ) = @_;
3493         push @option_string, $long_name . $flag;
3494         $option_category{$long_name} = $category_name[$category];
3495         if ($short_name) {
3496             if ( $expansion{$short_name} ) {
3497                 my $existing_name = $expansion{$short_name}->[0];
3498                 Die(
3499 "redefining abbreviation $short_name for $long_name; already used for $existing_name\n"
3500                 );
3501             }
3502             $expansion{$short_name} = [$long_name];
3503             if ( $flag eq '!' ) {
3504                 my $nshort_name = 'n' . $short_name;
3505                 my $nolong_name = 'no' . $long_name;
3506                 if ( $expansion{$nshort_name} ) {
3507                     my $existing_name = $expansion{$nshort_name}->[0];
3508                     Die(
3509 "attempting to redefine abbreviation $nshort_name for $nolong_name; already used for $existing_name\n"
3510                     );
3511                 }
3512                 $expansion{$nshort_name} = [$nolong_name];
3513             }
3514         }
3515         return;
3516     }; ## end $add_option = sub
3517
3518     # Install long option names which have a simple abbreviation.
3519     # Options with code '!' get standard negation ('no' for long names,
3520     # 'n' for abbreviations).  Categories follow the manual.
3521
3522     ###########################
3523     $category = 0;    # I/O_Control
3524     ###########################
3525     $add_option->( 'backup-and-modify-in-place', 'b',     '!' );
3526     $add_option->( 'backup-file-extension',      'bext',  '=s' );
3527     $add_option->( 'backup-method',              'bm',    '=s' );
3528     $add_option->( 'character-encoding',         'enc',   '=s' );
3529     $add_option->( 'force-read-binary',          'f',     '!' );
3530     $add_option->( 'format',                     'fmt',   '=s' );
3531     $add_option->( 'iterations',                 'it',    '=i' );
3532     $add_option->( 'logfile',                    'log',   '!' );
3533     $add_option->( 'logfile-gap',                'g',     ':i' );
3534     $add_option->( 'outfile',                    'o',     '=s' );
3535     $add_option->( 'output-file-extension',      'oext',  '=s' );
3536     $add_option->( 'output-path',                'opath', '=s' );
3537     $add_option->( 'profile',                    'pro',   '=s' );
3538     $add_option->( 'quiet',                      'q',     '!' );
3539     $add_option->( 'standard-error-output',      'se',    '!' );
3540     $add_option->( 'standard-output',            'st',    '!' );
3541     $add_option->( 'use-unicode-gcstring',       'gcs',   '!' );
3542     $add_option->( 'warning-output',             'w',     '!' );
3543     $add_option->( 'add-terminal-newline',       'atnl',  '!' );
3544     $add_option->( 'line-range-tidy',            'lrt',   '=s' );
3545     $add_option->( 'timeout-in-seconds',         'tos',   '=i' );
3546
3547     # options which are both toggle switches and values moved here
3548     # to hide from tidyview (which does not show category 0 flags):
3549     # -ole moved here from category 1
3550     # -sil moved here from category 2
3551     $add_option->( 'output-line-ending',         'ole', '=s' );
3552     $add_option->( 'starting-indentation-level', 'sil', '=i' );
3553
3554     ########################################
3555     $category = 1;    # Basic formatting options
3556     ########################################
3557     $add_option->( 'check-syntax',                 'syn',  '!' );
3558     $add_option->( 'entab-leading-whitespace',     'et',   '=i' );
3559     $add_option->( 'indent-columns',               'i',    '=i' );
3560     $add_option->( 'maximum-line-length',          'l',    '=i' );
3561     $add_option->( 'variable-maximum-line-length', 'vmll', '!' );
3562     $add_option->( 'whitespace-cycle',             'wc',   '=i' );
3563     $add_option->( 'perl-syntax-check-flags',      'pscf', '=s' );
3564     $add_option->( 'preserve-line-endings',        'ple',  '!' );
3565     $add_option->( 'tabs',                         't',    '!' );
3566     $add_option->( 'default-tabsize',              'dt',   '=i' );
3567     $add_option->( 'extended-syntax',              'xs',   '!' );
3568     $add_option->( 'assert-tidy',                  'ast',  '!' );
3569     $add_option->( 'assert-untidy',                'asu',  '!' );
3570     $add_option->( 'encode-output-strings',        'eos',  '!' );
3571     $add_option->( 'sub-alias-list',               'sal',  '=s' );
3572     $add_option->( 'grep-alias-list',              'gal',  '=s' );
3573     $add_option->( 'grep-alias-exclusion-list',    'gaxl', '=s' );
3574     $add_option->( 'use-feature',                  'uf',   '=s' );
3575
3576     ########################################
3577     $category = 2;    # Code indentation control
3578     ########################################
3579     $add_option->( 'continuation-indentation',             'ci',    '=i' );
3580     $add_option->( 'extended-continuation-indentation',    'xci',   '!' );
3581     $add_option->( 'minimize-continuation-indentation',    'mci',   '!' );
3582     $add_option->( 'line-up-parentheses',                  'lp',    '!' );
3583     $add_option->( 'extended-line-up-parentheses',         'xlp',   '!' );
3584     $add_option->( 'line-up-parentheses-exclusion-list',   'lpxl',  '=s' );
3585     $add_option->( 'line-up-parentheses-inclusion-list',   'lpil',  '=s' );
3586     $add_option->( 'outdent-keyword-list',                 'okwl',  '=s' );
3587     $add_option->( 'outdent-keywords',                     'okw',   '!' );
3588     $add_option->( 'outdent-labels',                       'ola',   '!' );
3589     $add_option->( 'outdent-long-quotes',                  'olq',   '!' );
3590     $add_option->( 'indent-closing-brace',                 'icb',   '!' );
3591     $add_option->( 'indent-leading-semicolon',             'ils',   '!' );
3592     $add_option->( 'closing-token-indentation',            'cti',   '=i' );
3593     $add_option->( 'closing-paren-indentation',            'cpi',   '=i' );
3594     $add_option->( 'closing-brace-indentation',            'cbi',   '=i' );
3595     $add_option->( 'closing-square-bracket-indentation',   'csbi',  '=i' );
3596     $add_option->( 'brace-left-and-indent',                'bli',   '!' );
3597     $add_option->( 'brace-left-and-indent-list',           'blil',  '=s' );
3598     $add_option->( 'brace-left-and-indent-exclusion-list', 'blixl', '=s' );
3599
3600     ########################################
3601     $category = 3;    # Whitespace control
3602     ########################################
3603     $add_option->( 'add-trailing-commas',                       'atc',   '!' );
3604     $add_option->( 'add-lone-trailing-commas',                  'altc',  '!' );
3605     $add_option->( 'add-semicolons',                            'asc',   '!' );
3606     $add_option->( 'add-whitespace',                            'aws',   '!' );
3607     $add_option->( 'block-brace-tightness',                     'bbt',   '=i' );
3608     $add_option->( 'brace-tightness',                           'bt',    '=i' );
3609     $add_option->( 'delete-old-whitespace',                     'dws',   '!' );
3610     $add_option->( 'delete-repeated-commas',                    'drc',   '!' );
3611     $add_option->( 'delete-trailing-commas',                    'dtc',   '!' );
3612     $add_option->( 'delete-lone-trailing-commas',               'dltc',  '!' );
3613     $add_option->( 'delete-weld-interfering-commas',            'dwic',  '!' );
3614     $add_option->( 'delete-semicolons',                         'dsm',   '!' );
3615     $add_option->( 'function-paren-vertical-alignment',         'fpva',  '!' );
3616     $add_option->( 'delay-trailing-comma-operations',           'dtco',  '!' );
3617     $add_option->( 'keyword-paren-inner-tightness',             'kpit',  '=i' );
3618     $add_option->( 'keyword-paren-inner-tightness-list',        'kpitl', '=s' );
3619     $add_option->( 'logical-padding',                           'lop',   '!' );
3620     $add_option->( 'multiple-token-tightness',                  'mutt',  '=s' );
3621     $add_option->( 'nospace-after-keyword',                     'nsak',  '=s' );
3622     $add_option->( 'nowant-left-space',                         'nwls',  '=s' );
3623     $add_option->( 'nowant-right-space',                        'nwrs',  '=s' );
3624     $add_option->( 'paren-tightness',                           'pt',    '=i' );
3625     $add_option->( 'space-after-keyword',                       'sak',   '=s' );
3626     $add_option->( 'space-for-semicolon',                       'sfs',   '!' );
3627     $add_option->( 'space-function-paren',                      'sfp',   '!' );
3628     $add_option->( 'space-keyword-paren',                       'skp',   '!' );
3629     $add_option->( 'space-terminal-semicolon',                  'sts',   '!' );
3630     $add_option->( 'square-bracket-tightness',                  'sbt',   '=i' );
3631     $add_option->( 'square-bracket-vertical-tightness',         'sbvt',  '=i' );
3632     $add_option->( 'square-bracket-vertical-tightness-closing', 'sbvtc', '=i' );
3633     $add_option->( 'tight-secret-operators',                    'tso',   '!' );
3634     $add_option->( 'trim-qw',                                   'tqw',   '!' );
3635     $add_option->( 'trim-pod',                                  'trp',   '!' );
3636     $add_option->( 'want-left-space',                           'wls',   '=s' );
3637     $add_option->( 'want-right-space',                          'wrs',   '=s' );
3638     $add_option->( 'want-trailing-commas',                      'wtc',   '=s' );
3639     $add_option->( 'space-prototype-paren',                     'spp',   '=i' );
3640     $add_option->( 'space-signature-paren',                     'ssp',   '=i' );
3641     $add_option->( 'valign-code',                               'vc',    '!' );
3642     $add_option->( 'valign-block-comments',                     'vbc',   '!' );
3643     $add_option->( 'valign-side-comments',                      'vsc',   '!' );
3644     $add_option->( 'valign-exclusion-list',                     'vxl',   '=s' );
3645     $add_option->( 'valign-inclusion-list',                     'vil',   '=s' );
3646     $add_option->( 'valign-if-unless',                          'viu',   '!' );
3647     $add_option->( 'valign-signed-numbers',                     'vsn',   '!' );
3648     $add_option->( 'valign-signed-numbers-limit',               'vsnl',  '=i' );
3649     $add_option->( 'valign-wide-equals',                        'vwe',   '!' );
3650     $add_option->( 'extended-block-tightness',                  'xbt',   '!' );
3651     $add_option->( 'extended-block-tightness-list',             'xbtl',  '=s' );
3652     $add_option->( 'qw-as-function',                            'qwaf',  '!' );
3653
3654     ########################################
3655     $category = 4;    # Comment controls
3656     ########################################
3657     $add_option->( 'closing-side-comment-else-flag',      'csce',  '=i' );
3658     $add_option->( 'closing-side-comment-interval',       'csci',  '=i' );
3659     $add_option->( 'closing-side-comment-list',           'cscl',  '=s' );
3660     $add_option->( 'closing-side-comment-exclusion-list', 'cscxl', '=s' );
3661     $add_option->( 'closing-side-comment-maximum-text',   'csct',  '=i' );
3662     $add_option->( 'closing-side-comment-prefix',         'cscp',  '=s' );
3663     $add_option->( 'closing-side-comment-warnings',       'cscw',  '!' );
3664     $add_option->( 'closing-side-comments',               'csc',   '!' );
3665     $add_option->( 'closing-side-comments-balanced',      'cscb',  '!' );
3666     $add_option->( 'code-skipping',                       'cs',    '!' );
3667     $add_option->( 'code-skipping-begin',                 'csb',   '=s' );
3668     $add_option->( 'code-skipping-end',                   'cse',   '=s' );
3669     $add_option->( 'format-skipping',                     'fs',    '!' );
3670     $add_option->( 'format-skipping-begin',               'fsb',   '=s' );
3671     $add_option->( 'format-skipping-end',                 'fse',   '=s' );
3672     $add_option->( 'hanging-side-comments',               'hsc',   '!' );
3673     $add_option->( 'indent-block-comments',               'ibc',   '!' );
3674     $add_option->( 'indent-spaced-block-comments',        'isbc',  '!' );
3675     $add_option->( 'fixed-position-side-comment',         'fpsc',  '=i' );
3676     $add_option->( 'minimum-space-to-comment',            'msc',   '=i' );
3677     $add_option->( 'non-indenting-braces',                'nib',   '!' );
3678     $add_option->( 'non-indenting-brace-prefix',          'nibp',  '=s' );
3679     $add_option->( 'outdent-long-comments',               'olc',   '!' );
3680     $add_option->( 'outdent-static-block-comments',       'osbc',  '!' );
3681     $add_option->( 'static-block-comment-prefix',         'sbcp',  '=s' );
3682     $add_option->( 'static-block-comments',               'sbc',   '!' );
3683     $add_option->( 'static-side-comment-prefix',          'sscp',  '=s' );
3684     $add_option->( 'static-side-comments',                'ssc',   '!' );
3685     $add_option->( 'ignore-side-comment-lengths',         'iscl',  '!' );
3686     $add_option->( 'ignore-perlcritic-comments',          'ipc',   '!' );
3687
3688     ########################################
3689     $category = 5;    # Linebreak controls
3690     ########################################
3691     $add_option->( 'add-newlines',                            'anl',   '!' );
3692     $add_option->( 'block-brace-vertical-tightness',          'bbvt',  '=i' );
3693     $add_option->( 'block-brace-vertical-tightness-list',     'bbvtl', '=s' );
3694     $add_option->( 'brace-follower-vertical-tightness',       'bfvt',  '=i' );
3695     $add_option->( 'brace-vertical-tightness',                'bvt',   '=i' );
3696     $add_option->( 'brace-vertical-tightness-closing',        'bvtc',  '=i' );
3697     $add_option->( 'cuddled-else',                            'ce',    '!' );
3698     $add_option->( 'cuddled-block-list',                      'cbl',   '=s' );
3699     $add_option->( 'cuddled-block-list-exclusive',            'cblx',  '!' );
3700     $add_option->( 'cuddled-break-option',                    'cbo',   '=i' );
3701     $add_option->( 'cuddled-paren-brace',                     'cpb',   '!' );
3702     $add_option->( 'delete-old-newlines',                     'dnl',   '!' );
3703     $add_option->( 'opening-brace-always-on-right',           'bar',   '!' );
3704     $add_option->( 'opening-brace-on-new-line',               'bl',    '!' );
3705     $add_option->( 'opening-hash-brace-right',                'ohbr',  '!' );
3706     $add_option->( 'opening-paren-right',                     'opr',   '!' );
3707     $add_option->( 'opening-square-bracket-right',            'osbr',  '!' );
3708     $add_option->( 'opening-anonymous-sub-brace-on-new-line', 'asbl',  '!' );
3709     $add_option->( 'opening-sub-brace-on-new-line',           'sbl',   '!' );
3710     $add_option->( 'paren-vertical-tightness',                'pvt',   '=i' );
3711     $add_option->( 'paren-vertical-tightness-closing',        'pvtc',  '=i' );
3712     $add_option->( 'weld-nested-containers',                  'wn',    '!' );
3713     $add_option->( 'weld-nested-exclusion-list',              'wnxl',  '=s' );
3714     $add_option->( 'weld-fat-comma',                          'wfc',   '!' );
3715     $add_option->( 'space-backslash-quote',                   'sbq',   '=i' );
3716     $add_option->( 'stack-closing-block-brace',               'scbb',  '!' );
3717     $add_option->( 'stack-closing-hash-brace',                'schb',  '!' );
3718     $add_option->( 'stack-closing-paren',                     'scp',   '!' );
3719     $add_option->( 'stack-closing-square-bracket',            'scsb',  '!' );
3720     $add_option->( 'stack-opening-hash-brace',                'sohb',  '!' );
3721     $add_option->( 'stack-opening-paren',                     'sop',   '!' );
3722     $add_option->( 'stack-opening-square-bracket',            'sosb',  '!' );
3723
3724     # FIXME: --vt and --vtc are actually expansions now, so these two lines
3725     # should eventually be removed.
3726     $add_option->( 'vertical-tightness',         'vt',  '=i' );
3727     $add_option->( 'vertical-tightness-closing', 'vtc', '=i' );
3728
3729     $add_option->( 'want-break-after',                       'wba',   '=s' );
3730     $add_option->( 'want-break-before',                      'wbb',   '=s' );
3731     $add_option->( 'break-after-all-operators',              'baao',  '!' );
3732     $add_option->( 'break-before-all-operators',             'bbao',  '!' );
3733     $add_option->( 'keep-interior-semicolons',               'kis',   '!' );
3734     $add_option->( 'one-line-block-semicolons',              'olbs',  '=i' );
3735     $add_option->( 'one-line-block-nesting',                 'olbn',  '=i' );
3736     $add_option->( 'one-line-block-exclusion-list',          'olbxl', '=s' );
3737     $add_option->( 'break-before-hash-brace',                'bbhb',  '=i' );
3738     $add_option->( 'break-before-hash-brace-and-indent',     'bbhbi', '=i' );
3739     $add_option->( 'break-before-square-bracket',            'bbsb',  '=i' );
3740     $add_option->( 'break-before-square-bracket-and-indent', 'bbsbi', '=i' );
3741     $add_option->( 'break-before-paren',                     'bbp',   '=i' );
3742     $add_option->( 'break-before-paren-and-indent',          'bbpi',  '=i' );
3743     $add_option->( 'brace-left-list',                        'bll',   '=s' );
3744     $add_option->( 'brace-left-exclusion-list',              'blxl',  '=s' );
3745     $add_option->( 'break-after-labels',                     'bal',   '=i' );
3746
3747     # This was an experiment mentioned in git #78, originally named -bopl. I
3748     # expanded it to also open logical blocks, based on git discussion #100,
3749     # and renamed it -bocp. It works, but will remain commented out due to
3750     # apparent lack of interest.
3751     # $add_option->( 'break-open-compact-parens', 'bocp', '=s' );
3752
3753     ########################################
3754     $category = 6;    # Controlling list formatting
3755     ########################################
3756     $add_option->( 'break-at-old-comma-breakpoints', 'boc',  '!' );
3757     $add_option->( 'break-at-trailing-comma-types',  'btct', '=s' );
3758     $add_option->( 'comma-arrow-breakpoints',        'cab',  '=i' );
3759     $add_option->( 'maximum-fields-per-table',       'mft',  '=i' );
3760
3761     ########################################
3762     $category = 7;    # Retaining or ignoring existing line breaks
3763     ########################################
3764     $add_option->( 'break-at-old-keyword-breakpoints',   'bok', '!' );
3765     $add_option->( 'break-at-old-logical-breakpoints',   'bol', '!' );
3766     $add_option->( 'break-at-old-method-breakpoints',    'bom', '!' );
3767     $add_option->( 'break-at-old-semicolon-breakpoints', 'bos', '!' );
3768     $add_option->( 'break-at-old-ternary-breakpoints',   'bot', '!' );
3769     $add_option->( 'break-at-old-attribute-breakpoints', 'boa', '!' );
3770     $add_option->( 'keep-old-breakpoints-before',        'kbb', '=s' );
3771     $add_option->( 'keep-old-breakpoints-after',         'kba', '=s' );
3772     $add_option->( 'ignore-old-breakpoints',             'iob', '!' );
3773
3774     ########################################
3775     $category = 8;    # Blank line control
3776     ########################################
3777     $add_option->( 'blanks-before-blocks',            'bbb',  '!' );
3778     $add_option->( 'blanks-before-comments',          'bbc',  '!' );
3779     $add_option->( 'blank-lines-before-subs',         'blbs', '=i' );
3780     $add_option->( 'blank-lines-before-packages',     'blbp', '=i' );
3781     $add_option->( 'long-block-line-count',           'lbl',  '=i' );
3782     $add_option->( 'maximum-consecutive-blank-lines', 'mbl',  '=i' );
3783     $add_option->( 'keep-old-blank-lines',            'kbl',  '=i' );
3784
3785     $add_option->( 'keyword-group-blanks-list',         'kgbl', '=s' );
3786     $add_option->( 'keyword-group-blanks-size',         'kgbs', '=s' );
3787     $add_option->( 'keyword-group-blanks-repeat-count', 'kgbr', '=i' );
3788     $add_option->( 'keyword-group-blanks-before',       'kgbb', '=i' );
3789     $add_option->( 'keyword-group-blanks-after',        'kgba', '=i' );
3790     $add_option->( 'keyword-group-blanks-inside',       'kgbi', '!' );
3791     $add_option->( 'keyword-group-blanks-delete',       'kgbd', '!' );
3792
3793     $add_option->( 'blank-lines-after-opening-block',       'blao',  '=i' );
3794     $add_option->( 'blank-lines-before-closing-block',      'blbc',  '=i' );
3795     $add_option->( 'blank-lines-after-opening-block-list',  'blaol', '=s' );
3796     $add_option->( 'blank-lines-before-closing-block-list', 'blbcl', '=s' );
3797
3798     ########################################
3799     $category = 9;    # Other controls
3800     ########################################
3801     $add_option->( 'warn-missing-else',            'wme',  '!' );
3802     $add_option->( 'add-missing-else',             'ame',  '!' );
3803     $add_option->( 'add-missing-else-comment',     'amec', '=s' );
3804     $add_option->( 'delete-block-comments',        'dbc',  '!' );
3805     $add_option->( 'delete-closing-side-comments', 'dcsc', '!' );
3806     $add_option->( 'delete-pod',                   'dp',   '!' );
3807     $add_option->( 'delete-side-comments',         'dsc',  '!' );
3808     $add_option->( 'tee-block-comments',           'tbc',  '!' );
3809     $add_option->( 'tee-pod',                      'tp',   '!' );
3810     $add_option->( 'tee-side-comments',            'tsc',  '!' );
3811     $add_option->( 'look-for-autoloader',          'lal',  '!' );
3812     $add_option->( 'look-for-hash-bang',           'x',    '!' );
3813     $add_option->( 'look-for-selfloader',          'lsl',  '!' );
3814     $add_option->( 'pass-version-line',            'pvl',  '!' );
3815     $add_option->( 'warn-variable-types',          'wvt',  '=s' );
3816     $add_option->( 'warn-variable-exclusion-list', 'wvxl', '=s' );
3817     $add_option->( 'want-call-parens',             'wcp',  '=s' );
3818     $add_option->( 'nowant-call-parens',           'nwcp', '=s' );
3819
3820     $add_option->( 'warn-mismatched-args',                  'wma',   '!' );
3821     $add_option->( 'warn-mismatched-arg-types',             'wmat',  '=s' );
3822     $add_option->( 'warn-mismatched-arg-undercount-cutoff', 'wmauc', '=i' );
3823     $add_option->( 'warn-mismatched-arg-overcount-cutoff',  'wmaoc', '=i' );
3824     $add_option->( 'warn-mismatched-arg-exclusion-list',    'wmaxl', '=s' );
3825     $add_option->( 'warn-mismatched-returns',               'wmr',   '!' );
3826     $add_option->( 'warn-mismatched-return-types',          'wmrt',  '=s' );
3827     $add_option->( 'warn-mismatched-return-exclusion-list', 'wmrxl', '=s' );
3828
3829     $add_option->( 'add-interbracket-arrows',       'aia', '!' );
3830     $add_option->( 'delete-interbracket-arrows',    'dia', '!' );
3831     $add_option->( 'warn-interbracket-arrows',      'wia', '!' );
3832     $add_option->( 'interbracket-arrow-style',      'ias', '=s' );
3833     $add_option->( 'interbracket-arrow-complexity', 'iac', '=i' );
3834
3835     ########################################
3836     $category = 13;    # Debugging
3837     ########################################
3838     $add_option->( 'DEBUG',                           'D',     '!' );
3839     $add_option->( 'dump-block-summary',              'dbs',   '!' );
3840     $add_option->( 'dump-block-minimum-lines',        'dbl',   '=i' );
3841     $add_option->( 'dump-block-types',                'dbt',   '=s' );
3842     $add_option->( 'dump-cuddled-block-list',         'dcbl',  '!' );
3843     $add_option->( 'dump-defaults',                   'ddf',   '!' );
3844     $add_option->( 'dump-integer-option-range',       'dior',  '!' );
3845     $add_option->( 'dump-long-names',                 'dln',   '!' );
3846     $add_option->( 'dump-mismatched-args',            'dma',   '!' );
3847     $add_option->( 'dump-mismatched-returns',         'dmr',   '!' );
3848     $add_option->( 'dump-mixed-call-parens',          'dmcp',  '!' );
3849     $add_option->( 'dump-options',                    'dop',   '!' );
3850     $add_option->( 'dump-profile',                    'dpro',  '!' );
3851     $add_option->( 'dump-short-names',                'dsn',   '!' );
3852     $add_option->( 'dump-token-types',                'dtt',   '!' );
3853     $add_option->( 'dump-unusual-variables',          'duv',   '!' );
3854     $add_option->( 'dump-unique-keys',                'duk',   '!' );
3855     $add_option->( 'dump-want-left-space',            'dwls',  '!' );
3856     $add_option->( 'dump-want-right-space',           'dwrs',  '!' );
3857     $add_option->( 'fuzzy-line-length',               'fll',   '!' );
3858     $add_option->( 'help',                            'h',     EMPTY_STRING );
3859     $add_option->( 'short-concatenation-item-length', 'scl',   '=i' );
3860     $add_option->( 'show-options',                    'opt',   '!' );
3861     $add_option->( 'timestamp',                       'ts',    '!' );
3862     $add_option->( 'version',                         'v',     EMPTY_STRING );
3863     $add_option->( 'memoize',                         'mem',   '!' );
3864     $add_option->( 'file-size-order',                 'fso',   '!' );
3865     $add_option->( 'maximum-file-size-mb',            'maxfs', '=i' );
3866     $add_option->( 'maximum-level-errors',            'maxle', '=i' );
3867     $add_option->( 'maximum-unexpected-errors',       'maxue', '=i' );
3868     $add_option->( 'integer-range-check',             'irc',   '=i' );
3869
3870     #---------------------------------------------------------------------
3871
3872     # The Perl::Tidy::HtmlWriter will add its own options to the string
3873     Perl::Tidy::HtmlWriter->make_getopt_long_names( \@option_string );
3874
3875     ########################################
3876     # Set categories 10, 11, 12
3877     ########################################
3878     # Based on their known order
3879     $category = 12;    # HTML properties
3880     foreach my $opt (@option_string) {
3881         my $long_name = $opt;
3882         $long_name =~ s/(!|=.*|:.*)$//;
3883         if ( !defined( $option_category{$long_name} ) ) {
3884             if ( $long_name =~ /^html-linked/ ) {
3885                 $category = 10;    # HTML options
3886             }
3887             elsif ( $long_name =~ /^pod2html/ ) {
3888                 $category = 11;    # Pod2html
3889             }
3890             else {
3891                 $category = 12;    # HTML properties
3892             }
3893             $option_category{$long_name} = $category_name[$category];
3894         }
3895     }
3896
3897     #------------------------------------------------------------------
3898     # DEFAULTS: Assign default values to the above options here, except
3899     # for 'outfile' and 'help'.
3900     # These settings should approximate the perlstyle(1) suggestions.
3901     #------------------------------------------------------------------
3902     my @defaults = qw(
3903       add-lone-trailing-commas
3904       add-newlines
3905       add-terminal-newline
3906       add-semicolons
3907       add-whitespace
3908       blanks-before-blocks
3909       blanks-before-comments
3910       blank-lines-before-subs=1
3911       blank-lines-before-packages=1
3912
3913       keyword-group-blanks-size=5
3914       keyword-group-blanks-repeat-count=0
3915       keyword-group-blanks-before=1
3916       keyword-group-blanks-after=1
3917       nokeyword-group-blanks-inside
3918       nokeyword-group-blanks-delete
3919
3920       block-brace-tightness=0
3921       block-brace-vertical-tightness=0
3922       brace-follower-vertical-tightness=1
3923       brace-tightness=1
3924       brace-vertical-tightness-closing=0
3925       brace-vertical-tightness=0
3926       break-after-labels=0
3927       break-at-old-logical-breakpoints
3928       break-at-old-ternary-breakpoints
3929       break-at-old-attribute-breakpoints
3930       break-at-old-keyword-breakpoints
3931       break-before-hash-brace=0
3932       break-before-hash-brace-and-indent=0
3933       break-before-square-bracket=0
3934       break-before-square-bracket-and-indent=0
3935       break-before-paren=0
3936       break-before-paren-and-indent=0
3937       comma-arrow-breakpoints=5
3938       nocheck-syntax
3939       character-encoding=guess
3940       closing-side-comment-interval=6
3941       closing-side-comment-maximum-text=20
3942       closing-side-comment-else-flag=0
3943       closing-side-comments-balanced
3944       closing-paren-indentation=0
3945       closing-brace-indentation=0
3946       closing-square-bracket-indentation=0
3947       continuation-indentation=2
3948       noextended-continuation-indentation
3949       cuddled-break-option=1
3950       delete-old-newlines
3951       delete-repeated-commas
3952       delete-lone-trailing-commas
3953       delete-semicolons
3954       dump-block-minimum-lines=20
3955       dump-block-types=sub
3956       extended-syntax
3957       encode-output-strings
3958       file-size-order
3959       function-paren-vertical-alignment
3960       fuzzy-line-length
3961       hanging-side-comments
3962       indent-block-comments
3963       indent-columns=4
3964       indent-leading-semicolon
3965       integer-range-check=2
3966       interbracket-arrow-complexity=1
3967       iterations=1
3968       keep-old-blank-lines=1
3969       keyword-paren-inner-tightness=1
3970       logical-padding
3971       long-block-line-count=8
3972       look-for-autoloader
3973       look-for-selfloader
3974       maximum-consecutive-blank-lines=1
3975       maximum-fields-per-table=0
3976       maximum-line-length=80
3977       maximum-file-size-mb=10
3978       maximum-level-errors=1
3979       maximum-unexpected-errors=0
3980       memoize
3981       minimum-space-to-comment=4
3982       warn-mismatched-arg-undercount-cutoff=4
3983       warn-mismatched-arg-overcount-cutoff=1
3984       nobrace-left-and-indent
3985       nocuddled-else
3986       nodelete-old-whitespace
3987       nohtml
3988       nologfile
3989       non-indenting-braces
3990       noquiet
3991       noshow-options
3992       nostatic-side-comments
3993       notabs
3994       nowarning-output
3995       one-line-block-semicolons=1
3996       one-line-block-nesting=0
3997       outdent-labels
3998       outdent-long-quotes
3999       outdent-long-comments
4000       paren-tightness=1
4001       paren-vertical-tightness-closing=0
4002       paren-vertical-tightness=0
4003       pass-version-line
4004       noweld-nested-containers
4005       recombine
4006       nouse-unicode-gcstring
4007       valign-code
4008       valign-block-comments
4009       valign-side-comments
4010       valign-signed-numbers
4011       valign-signed-numbers-limit=20
4012       short-concatenation-item-length=8
4013       space-for-semicolon
4014       space-backslash-quote=1
4015       space-prototype-paren=1
4016       space-signature-paren=1
4017       square-bracket-tightness=1
4018       square-bracket-vertical-tightness-closing=0
4019       square-bracket-vertical-tightness=0
4020       static-block-comments
4021       timestamp
4022       trim-qw
4023       format=tidy
4024       backup-method=copy
4025       backup-file-extension=bak
4026       code-skipping
4027       format-skipping
4028       default-tabsize=8
4029       timeout-in-seconds=10
4030
4031       whitespace-cycle=0
4032       entab-leading-whitespace=0
4033       blank-lines-before-closing-block=0
4034       blank-lines-after-opening-block=0
4035
4036       pod2html
4037       html-table-of-contents
4038       html-entities
4039     );
4040
4041     #---------------------------------------
4042     # Assign valid ranges to certain options
4043     #---------------------------------------
4044     # In the future, these may be used to make preliminary checks
4045     # hash keys are long names
4046     # If key or value is undefined:
4047     #   strings may have any value
4048     #   integer ranges are >=0
4049     # If value is defined:
4050     #   value is [qw(any valid words)] for strings
4051     #   value is [min, max] for integers
4052     #   if min is undefined, there is no lower limit
4053     #   if max is undefined, there is no upper limit
4054     # Parameters not listed here have defaults
4055     %option_range = (
4056         'format'                        => [ 'tidy', 'html', 'user' ],
4057         'output-line-ending'            => [ 'dos',  'win',  'mac', 'unix' ],
4058         'space-backslash-quote'         => [ 0,      2 ],
4059         'block-brace-tightness'         => [ 0,      2 ],
4060         'keyword-paren-inner-tightness' => [ 0,      2 ],
4061         'brace-tightness'               => [ 0,      2 ],
4062         'paren-tightness'               => [ 0,      2 ],
4063         'square-bracket-tightness'      => [ 0,      2 ],
4064
4065         'block-brace-vertical-tightness'            => [ 0, 2 ],
4066         'brace-follower-vertical-tightness'         => [ 0, 2 ],
4067         'brace-vertical-tightness'                  => [ 0, 2 ],
4068         'brace-vertical-tightness-closing'          => [ 0, 3 ],
4069         'paren-vertical-tightness'                  => [ 0, 2 ],
4070         'paren-vertical-tightness-closing'          => [ 0, 3 ],
4071         'square-bracket-vertical-tightness'         => [ 0, 2 ],
4072         'square-bracket-vertical-tightness-closing' => [ 0, 3 ],
4073         'vertical-tightness'                        => [ 0, 2 ],
4074         'vertical-tightness-closing'                => [ 0, 3 ],
4075
4076         'closing-brace-indentation'          => [ 0, 3 ],
4077         'closing-paren-indentation'          => [ 0, 3 ],
4078         'closing-square-bracket-indentation' => [ 0, 3 ],
4079         'closing-token-indentation'          => [ 0, 3 ],
4080
4081         'closing-side-comment-else-flag' => [ 0, 2 ],
4082         'comma-arrow-breakpoints'        => [ 0, 5 ],
4083
4084         'keyword-group-blanks-before' => [ 0, 2 ],
4085         'keyword-group-blanks-after'  => [ 0, 2 ],
4086
4087         'space-prototype-paren' => [ 0, 2 ],
4088         'space-signature-paren' => [ 0, 2 ],
4089         'break-after-labels'    => [ 0, 2 ],
4090     );
4091
4092     # Valid [min,max] ranges of all integer options (type '=i').  This hash is
4093     # replacing %option_range, above, for use by sub 'check_options'
4094     %integer_option_range = (
4095         'blank-lines-after-opening-block'           => [ 0, undef ],
4096         'blank-lines-before-closing-block'          => [ 0, undef ],
4097         'blank-lines-before-packages'               => [ 0, undef ],
4098         'blank-lines-before-subs'                   => [ 0, undef ],
4099         'block-brace-tightness'                     => [ 0, 2 ],
4100         'block-brace-vertical-tightness'            => [ 0, 2 ],
4101         'brace-follower-vertical-tightness'         => [ 0, 2 ],
4102         'brace-tightness'                           => [ 0, 2 ],
4103         'brace-vertical-tightness'                  => [ 0, 2 ],
4104         'brace-vertical-tightness-closing'          => [ 0, 3 ],
4105         'break-after-labels'                        => [ 0, 2 ],
4106         'break-before-hash-brace'                   => [ 0, 3 ],
4107         'break-before-hash-brace-and-indent'        => [ 0, 2 ],
4108         'break-before-paren'                        => [ 0, 3 ],
4109         'break-before-paren-and-indent'             => [ 0, 2 ],
4110         'break-before-square-bracket'               => [ 0, 3 ],
4111         'break-before-square-bracket-and-indent'    => [ 0, 2 ],
4112         'closing-brace-indentation'                 => [ 0, 3 ],
4113         'closing-paren-indentation'                 => [ 0, 3 ],
4114         'closing-side-comment-else-flag'            => [ 0, 2 ],
4115         'closing-side-comment-interval'             => [ 0, undef ],
4116         'closing-side-comment-maximum-text'         => [ 0, undef ],
4117         'closing-square-bracket-indentation'        => [ 0, 3 ],
4118         'closing-token-indentation'                 => [ 0, 3 ],
4119         'comma-arrow-breakpoints'                   => [ 0, 5 ],
4120         'continuation-indentation'                  => [ 0, undef ],
4121         'cuddled-break-option'                      => [ 0, 2 ],
4122         'default-tabsize'                           => [ 0, undef ],
4123         'dump-block-minimum-lines'                  => [ 0, undef ],
4124         'entab-leading-whitespace'                  => [ 0, undef ],
4125         'fixed-position-side-comment'               => [ 0, undef ],
4126         'indent-columns'                            => [ 0, undef ],
4127         'interbracket-arrow-complexity'             => [ 0, 2 ],
4128         'integer-range-check'                       => [ 0, 3 ],
4129         'iterations'                                => [ 0, undef ],
4130         'keep-old-blank-lines'                      => [ 0, 2 ],
4131         'keyword-group-blanks-after'                => [ 0, 2 ],
4132         'keyword-group-blanks-before'               => [ 0, 2 ],
4133         'keyword-group-blanks-repeat-count'         => [ 0, undef ],
4134         'keyword-paren-inner-tightness'             => [ 0, 2 ],
4135         'long-block-line-count'                     => [ 0, undef ],
4136         'maximum-consecutive-blank-lines'           => [ 0, undef ],
4137         'maximum-fields-per-table'                  => [ 0, undef ],
4138         'maximum-file-size-mb'                      => [ 0, undef ],
4139         'maximum-level-errors'                      => [ 0, undef ],
4140         'maximum-line-length'                       => [ 0, undef ],
4141         'maximum-unexpected-errors'                 => [ 0, undef ],
4142         'minimum-space-to-comment'                  => [ 0, undef ],
4143         'warn-mismatched-arg-undercount-cutoff'     => [ 0, undef ],
4144         'warn-mismatched-arg-overcount-cutoff'      => [ 0, undef ],
4145         'one-line-block-nesting'                    => [ 0, 1 ],
4146         'one-line-block-semicolons'                 => [ 0, 2 ],
4147         'paren-tightness'                           => [ 0, 2 ],
4148         'paren-vertical-tightness'                  => [ 0, 2 ],
4149         'paren-vertical-tightness-closing'          => [ 0, 3 ],
4150         'short-concatenation-item-length'           => [ 0, undef ],
4151         'space-backslash-quote'                     => [ 0, 2 ],
4152         'space-prototype-paren'                     => [ 0, 2 ],
4153         'space-signature-paren'                     => [ 0, 2 ],
4154         'square-bracket-tightness'                  => [ 0, 2 ],
4155         'square-bracket-vertical-tightness'         => [ 0, 2 ],
4156         'square-bracket-vertical-tightness-closing' => [ 0, 3 ],
4157         'starting-indentation-level'                => [ 0, undef ],
4158         'timeout-in-seconds'                        => [ 0, undef ],
4159         'vertical-tightness'                        => [ 0, 2 ],
4160         'vertical-tightness-closing'                => [ 0, 3 ],
4161         'valign-signed-numbers-limit'               => [ 0, undef ],
4162         'whitespace-cycle'                          => [ 0, undef ],
4163     );
4164
4165     # Enter default values into the integer option range table
4166     foreach my $opt (@defaults) {
4167         if ( $opt =~ /^(.*)=(\d+)$/ ) {
4168             my $key = $1;
4169             my $def = $2;
4170             if ( defined( $integer_option_range{$key} ) ) {
4171                 $integer_option_range{$key}->[2] = $def;
4172             }
4173         }
4174     }
4175
4176     # Enter special values which have undef as the default.
4177     # Note that cti, vt, and vtc are aliases which are included to work
4178     # around an old problem with msdos (see note in check_options).
4179     foreach my $key (
4180         qw(
4181         closing-token-indentation
4182         vertical-tightness
4183         vertical-tightness-closing
4184         fixed-position-side-comment
4185         starting-indentation-level
4186         )
4187       )
4188     {
4189         if ( defined( $integer_option_range{$key} )
4190             && @{ $integer_option_range{$key} } < 3 )
4191         {
4192             $integer_option_range{$key}->[2] = undef;
4193         }
4194     }
4195
4196     # Verify that only integers of type =i are in the above list during
4197     # development. This will guard against spelling errors.
4198     if (DEVEL_MODE) {
4199         my %option_flag;
4200         my $msg = EMPTY_STRING;
4201         foreach my $opt (@option_string) {
4202             my $key  = $opt;
4203             my $flag = EMPTY_STRING;
4204             if ( $key =~ /(.*)(!|=.*|:.*)$/ ) {
4205                 $key  = $1;
4206                 $flag = $2;
4207             }
4208             $option_flag{$key} = $flag;
4209         }
4210
4211         # Be sure all keys of %integer_option_range have option type '=i'
4212         foreach my $opt ( keys %integer_option_range ) {
4213             my $flag = $option_flag{$opt};
4214             if ( !defined($flag) ) { $flag = EMPTY_STRING }
4215             if ( $flag ne '=i' ) {
4216
4217                 # If this fault occurs, one of the items in the previous hash
4218                 # is not type =i, possibly due to incorrect spelling.
4219                 $msg .=
4220 "Option '$opt' has an entry in '%integer_option_range' but is not an integer\n";
4221             }
4222         }
4223
4224         # Be sure all '=i' options are in %integer_option_range. This is not
4225         # strictly necessary but helps insure that nothing was missed.
4226         foreach my $opt ( keys %option_flag ) {
4227             my $flag = $option_flag{$opt};
4228             next if ( $flag ne '=i' );
4229             if ( !defined( $integer_option_range{$opt} ) ) {
4230                 $msg .=
4231 "Integer option '$opt' is needs an entry in '%integer_option_range'\n";
4232             }
4233         }
4234
4235         # look for integer options without default values
4236         foreach my $opt ( keys %integer_option_range ) {
4237             if ( @{ $integer_option_range{$opt} } < 3 ) {
4238                 $msg .= "Integer option '$opt' does not have a default value\n";
4239             }
4240         }
4241
4242         if ($msg) {
4243             Fault($msg);
4244         }
4245     }
4246
4247     #-----------------------------------------------------------------------
4248     # Define abbreviations which will be expanded into the above primitives.
4249     # These may be defined recursively.
4250     #-----------------------------------------------------------------------
4251     %expansion = (
4252         %expansion,
4253         'freeze-newlines'    => [qw(noadd-newlines nodelete-old-newlines)],
4254         'fnl'                => [qw(freeze-newlines)],
4255         'freeze-whitespace'  => [qw(noadd-whitespace nodelete-old-whitespace)],
4256         'fws'                => [qw(freeze-whitespace)],
4257         'freeze-blank-lines' =>
4258           [qw(maximum-consecutive-blank-lines=0 keep-old-blank-lines=2)],
4259         'fbl'                => [qw(freeze-blank-lines)],
4260         'indent-only'        => [qw(freeze-newlines freeze-whitespace)],
4261         'outdent-long-lines' => [qw(outdent-long-quotes outdent-long-comments)],
4262         'nooutdent-long-lines' =>
4263           [qw(nooutdent-long-quotes nooutdent-long-comments)],
4264         'oll'                 => [qw(outdent-long-lines)],
4265         'noll'                => [qw(nooutdent-long-lines)],
4266         'io'                  => [qw(indent-only)],
4267         'delete-all-comments' =>
4268           [qw(delete-block-comments delete-side-comments delete-pod)],
4269         'nodelete-all-comments' =>
4270           [qw(nodelete-block-comments nodelete-side-comments nodelete-pod)],
4271         'dac'              => [qw(delete-all-comments)],
4272         'ndac'             => [qw(nodelete-all-comments)],
4273         'gnu'              => [qw(gnu-style)],
4274         'pbp'              => [qw(perl-best-practices)],
4275         'tee-all-comments' =>
4276           [qw(tee-block-comments tee-side-comments tee-pod)],
4277         'notee-all-comments' =>
4278           [qw(notee-block-comments notee-side-comments notee-pod)],
4279         'tac'   => [qw(tee-all-comments)],
4280         'ntac'  => [qw(notee-all-comments)],
4281         'html'  => [qw(format=html)],
4282         'nhtml' => [qw(format=tidy)],
4283         'tidy'  => [qw(format=tidy)],
4284
4285         'brace-left' => [qw(opening-brace-on-new-line)],
4286
4287         # -cb is now a synonym for -ce
4288         'cb'             => [qw(cuddled-else)],
4289         'cuddled-blocks' => [qw(cuddled-else)],
4290
4291         'utf8'  => [qw(character-encoding=utf8)],
4292         'UTF8'  => [qw(character-encoding=utf8)],
4293         'guess' => [qw(character-encoding=guess)],
4294
4295         'swallow-optional-blank-lines'   => [qw(kbl=0)],
4296         'noswallow-optional-blank-lines' => [qw(kbl=1)],
4297         'sob'                            => [qw(kbl=0)],
4298         'nsob'                           => [qw(kbl=1)],
4299
4300         'break-after-comma-arrows'   => [qw(cab=0)],
4301         'nobreak-after-comma-arrows' => [qw(cab=1)],
4302         'baa'                        => [qw(cab=0)],
4303         'nbaa'                       => [qw(cab=1)],
4304
4305         'blanks-before-subs'   => [qw(blbs=1 blbp=1)],
4306         'bbs'                  => [qw(blbs=1 blbp=1)],
4307         'noblanks-before-subs' => [qw(blbs=0 blbp=0)],
4308         'nbbs'                 => [qw(blbs=0 blbp=0)],
4309
4310         'keyword-group-blanks'   => [qw(kgbb=2 kgbi kgba=2)],
4311         'kgb'                    => [qw(kgbb=2 kgbi kgba=2)],
4312         'nokeyword-group-blanks' => [qw(kgbb=1 nkgbi kgba=1)],
4313         'nkgb'                   => [qw(kgbb=1 nkgbi kgba=1)],
4314
4315         'break-at-old-trinary-breakpoints' => [qw(bot)],
4316
4317         'cti=0' => [qw(cpi=0 cbi=0 csbi=0)],
4318         'cti=1' => [qw(cpi=1 cbi=1 csbi=1)],
4319         'cti=2' => [qw(cpi=2 cbi=2 csbi=2)],
4320         'icp'   => [qw(cpi=2 cbi=2 csbi=2)],
4321         'nicp'  => [qw(cpi=0 cbi=0 csbi=0)],
4322
4323         'closing-token-indentation=0' => [qw(cpi=0 cbi=0 csbi=0)],
4324         'closing-token-indentation=1' => [qw(cpi=1 cbi=1 csbi=1)],
4325         'closing-token-indentation=2' => [qw(cpi=2 cbi=2 csbi=2)],
4326         'indent-closing-paren'        => [qw(cpi=2 cbi=2 csbi=2)],
4327         'noindent-closing-paren'      => [qw(cpi=0 cbi=0 csbi=0)],
4328
4329         'vt=0' => [qw(pvt=0 bvt=0 sbvt=0)],
4330         'vt=1' => [qw(pvt=1 bvt=1 sbvt=1)],
4331         'vt=2' => [qw(pvt=2 bvt=2 sbvt=2)],
4332
4333         'vertical-tightness=0' => [qw(pvt=0 bvt=0 sbvt=0)],
4334         'vertical-tightness=1' => [qw(pvt=1 bvt=1 sbvt=1)],
4335         'vertical-tightness=2' => [qw(pvt=2 bvt=2 sbvt=2)],
4336
4337         'vtc=0' => [qw(pvtc=0 bvtc=0 sbvtc=0)],
4338         'vtc=1' => [qw(pvtc=1 bvtc=1 sbvtc=1)],
4339         'vtc=2' => [qw(pvtc=2 bvtc=2 sbvtc=2)],
4340
4341         'vertical-tightness-closing=0' => [qw(pvtc=0 bvtc=0 sbvtc=0)],
4342         'vertical-tightness-closing=1' => [qw(pvtc=1 bvtc=1 sbvtc=1)],
4343         'vertical-tightness-closing=2' => [qw(pvtc=2 bvtc=2 sbvtc=2)],
4344
4345         'otr'                   => [qw(opr ohbr osbr)],
4346         'opening-token-right'   => [qw(opr ohbr osbr)],
4347         'notr'                  => [qw(nopr nohbr nosbr)],
4348         'noopening-token-right' => [qw(nopr nohbr nosbr)],
4349
4350         'sot'                    => [qw(sop sohb sosb)],
4351         'nsot'                   => [qw(nsop nsohb nsosb)],
4352         'stack-opening-tokens'   => [qw(sop sohb sosb)],
4353         'nostack-opening-tokens' => [qw(nsop nsohb nsosb)],
4354
4355         'sct'                    => [qw(scp schb scsb)],
4356         'stack-closing-tokens'   => [qw(scp schb scsb)],
4357         'nsct'                   => [qw(nscp nschb nscsb)],
4358         'nostack-closing-tokens' => [qw(nscp nschb nscsb)],
4359
4360         'sac'                    => [qw(sot sct)],
4361         'nsac'                   => [qw(nsot nsct)],
4362         'stack-all-containers'   => [qw(sot sct)],
4363         'nostack-all-containers' => [qw(nsot nsct)],
4364
4365         'act=0'                      => [qw(pt=0 sbt=0 bt=0 bbt=0)],
4366         'act=1'                      => [qw(pt=1 sbt=1 bt=1 bbt=1)],
4367         'act=2'                      => [qw(pt=2 sbt=2 bt=2 bbt=2)],
4368         'all-containers-tightness=0' => [qw(pt=0 sbt=0 bt=0 bbt=0)],
4369         'all-containers-tightness=1' => [qw(pt=1 sbt=1 bt=1 bbt=1)],
4370         'all-containers-tightness=2' => [qw(pt=2 sbt=2 bt=2 bbt=2)],
4371
4372         'stack-opening-block-brace'   => [qw(bbvt=2 bbvtl=*)],
4373         'sobb'                        => [qw(bbvt=2 bbvtl=*)],
4374         'nostack-opening-block-brace' => [qw(bbvt=0)],
4375         'nsobb'                       => [qw(bbvt=0)],
4376
4377         'converge'   => [qw(it=4)],
4378         'noconverge' => [qw(it=1)],
4379         'conv'       => [qw(it=4)],
4380         'nconv'      => [qw(it=1)],
4381
4382         'valign'   => [qw(vc vsc vbc)],
4383         'novalign' => [qw(nvc nvsc nvbc)],
4384
4385         # NOTE: This is a possible future shortcut.  But it will remain
4386         # deactivated until the -lpxl flag is no longer experimental.
4387         # 'line-up-function-parentheses' => [ qw(lp), q#lpxl=[ { F(2# ],
4388         # 'lfp'                          => [qw(line-up-function-parentheses)],
4389
4390         # 'mangle' originally deleted pod and comments, but to keep it
4391         # reversible, it no longer does.  But if you really want to
4392         # delete them, just use:
4393         #   -mangle -dac
4394
4395         # An interesting use for 'mangle' is to do this:
4396         #    perltidy -mangle myfile.pl -st | perltidy -o myfile.pl.new
4397         # which will form as many one-line blocks as possible
4398
4399         'mangle' => [
4400             qw(
4401               keep-old-blank-lines=0
4402               delete-old-newlines
4403               delete-old-whitespace
4404               delete-semicolons
4405               indent-columns=0
4406               maximum-consecutive-blank-lines=0
4407               maximum-line-length=100000
4408               noadd-newlines
4409               noadd-semicolons
4410               noadd-whitespace
4411               noblanks-before-blocks
4412               blank-lines-before-subs=0
4413               blank-lines-before-packages=0
4414               notabs
4415             )
4416         ],
4417
4418         # 'extrude' originally deleted pod and comments, but to keep it
4419         # reversible, it no longer does.  But if you really want to
4420         # delete them, just use
4421         #   extrude -dac
4422         #
4423         # An interesting use for 'extrude' is to do this:
4424         #    perltidy -extrude myfile.pl -st | perltidy -o myfile.pl.new
4425         # which will break up all one-line blocks.
4426         'extrude' => [
4427             qw(
4428               ci=0
4429               delete-old-newlines
4430               delete-old-whitespace
4431               delete-semicolons
4432               indent-columns=0
4433               maximum-consecutive-blank-lines=0
4434               maximum-line-length=1
4435               noadd-semicolons
4436               noadd-whitespace
4437               noblanks-before-blocks
4438               blank-lines-before-subs=0
4439               blank-lines-before-packages=0
4440               nofuzzy-line-length
4441               notabs
4442               norecombine
4443             )
4444         ],
4445
4446         # this style tries to follow the GNU Coding Standards (which do
4447         # not really apply to perl but which are followed by some perl
4448         # programmers).
4449         'gnu-style' => [
4450             qw(
4451               lp bl noll pt=2 bt=2 sbt=2 cpi=1 csbi=1 cbi=1
4452             )
4453         ],
4454
4455         # Style suggested in Damian Conway's Perl Best Practices
4456         'perl-best-practices' => [
4457             qw(l=78 i=4 ci=4 st se vt=2 cti=0 pt=1 bt=1 sbt=1 bbt=1 nsfs nolq),
4458 q(wbb=% + - * / x != == >= <= =~ !~ < > | & = **= += *= &= <<= &&= -= /= |= >>= ||= //= .= %= ^= x=)
4459         ],
4460
4461         # Additional styles can be added here
4462     );
4463
4464     Perl::Tidy::HtmlWriter->make_abbreviated_names( \%expansion );
4465
4466     # Uncomment next line to dump all expansions for debugging:
4467     # dump_short_names(\%expansion);
4468     return ( \@option_string, \@defaults, \%expansion, \%option_category,
4469         \%option_range, \%integer_option_range );
4470
4471 } ## end sub generate_options
4472
4473 { #<<< closure process_command_line
4474
4475 # Memoize process_command_line. Given same @ARGV passed in, return same
4476 # values and same @ARGV back.
4477 # This patch was supplied by Jonathan Swartz Nov 2012 and significantly speeds
4478 # up masontidy (https://metacpan.org/module/masontidy)
4479
4480 my %process_command_line_cache;
4481
4482 sub process_command_line {
4483
4484     my @q = @_;
4485     my (
4486         $perltidyrc_stream,     $is_Windows_uu, $Windows_type_uu,
4487         $rpending_complaint_uu, $dump_options_type
4488     ) = @q;
4489
4490     # This is the outer sub which handles memoization
4491
4492     my $use_cache = !defined($perltidyrc_stream) && !$dump_options_type;
4493     if ($use_cache) {
4494         my $cache_key = join( chr(28), @ARGV );
4495         if ( my $result = $process_command_line_cache{$cache_key} ) {
4496             my ( $argv, @retvals ) = @{$result};
4497             @ARGV = @{$argv};
4498             return @retvals;
4499         }
4500         else {
4501             my @retvals = _process_command_line(@q);
4502             $process_command_line_cache{$cache_key} = [ \@ARGV, @retvals ]
4503               if $retvals[0]->{'memoize'};
4504             return @retvals;
4505         }
4506     }
4507     else {
4508         return _process_command_line(@q);
4509     }
4510 } ## end sub process_command_line
4511 } ## end closure process_command_line
4512
4513 # (note the underscore here)
4514 sub _process_command_line {
4515
4516     my (
4517         $perltidyrc_stream,  $is_Windows, $Windows_type,
4518         $rpending_complaint, $dump_options_type
4519     ) = @_;
4520
4521     # This is the inner sub which actually processes the command line
4522
4523     use Getopt::Long;
4524
4525     # Save any current Getopt::Long configuration
4526     # and set to Getopt::Long defaults.  Use eval to avoid
4527     # breaking old versions of Perl without these routines.
4528     # Previous configuration is reset at the exit of this routine.
4529     my $glc;
4530     if ( eval { $glc = Getopt::Long::Configure(); 1 } ) {
4531         my $ok = eval { Getopt::Long::ConfigDefaults(); 1 };
4532         if ( !$ok && DEVEL_MODE ) {
4533             Fault("Failed call to Getopt::Long::ConfigDefaults: $EVAL_ERROR\n");
4534         }
4535     }
4536     else { $glc = undef }
4537
4538     my ( $roption_string, $rdefaults, $rexpansion,
4539         $roption_category, $roption_range, $rinteger_option_range )
4540       = generate_options();
4541
4542     #--------------------------------------------------------------
4543     # set the defaults by passing the above list through GetOptions
4544     #--------------------------------------------------------------
4545     my %Opts = ();
4546     {
4547         local @ARGV = ();
4548
4549         # do not load the defaults if we are just dumping perltidyrc
4550         if ( $dump_options_type ne 'perltidyrc' ) {
4551             for my $i ( @{$rdefaults} ) { push @ARGV, "--" . $i }
4552         }
4553         if ( !GetOptions( \%Opts, @{$roption_string} ) ) {
4554             Die(
4555 "Programming Bug reported by 'GetOptions': error in setting default options"
4556             );
4557         }
4558     }
4559
4560     my @raw_options        = ();
4561     my $saw_ignore_profile = 0;
4562     my $saw_dump_profile   = 0;
4563     my $config_file;
4564
4565     #--------------------------------------------------------------
4566     # Take a first look at the command-line parameters.  Do as many
4567     # immediate dumps as possible, which can avoid confusion if the
4568     # perltidyrc file has an error.
4569     #--------------------------------------------------------------
4570     foreach my $i (@ARGV) {
4571
4572         $i =~ s/^--/-/;
4573         if ( $i =~ /^-(npro|noprofile|no-profile)$/ ) {
4574             $saw_ignore_profile = 1;
4575         }
4576
4577         # note: this must come before -pro and -profile, below:
4578         elsif ( $i =~ /^-(dump-profile|dpro)$/ ) {
4579             $saw_dump_profile = 1;
4580         }
4581         elsif ( $i =~ /^-(pro|profile)=(.+)/ ) {
4582             if ( defined($config_file) ) {
4583                 Warn(
4584 "Only one -pro=filename allowed, using '$2' instead of '$config_file'\n"
4585                 );
4586             }
4587             $config_file = $2;
4588
4589             # resolve <dir>/.../<file>, meaning look upwards from directory
4590             if ( defined($config_file) ) {
4591                 if ( my ( $start_dir, $search_file ) =
4592                     ( $config_file =~ m{^(.*)\.\.\./(.*)$} ) )
4593                 {
4594                     $start_dir = '.' if !$start_dir;
4595                     $start_dir = Cwd::realpath($start_dir);
4596                     my $found_file =
4597                       find_file_upwards( $start_dir, $search_file );
4598                     if ( defined($found_file) ) {
4599                         $config_file = $found_file;
4600                     }
4601                 }
4602             }
4603             if ( !-e $config_file ) {
4604                 Die(
4605                     "cannot find file given with -pro=$config_file: $OS_ERROR\n"
4606                 );
4607             }
4608         }
4609         elsif ( $i =~ /^-(pro|profile)=?$/ ) {
4610             Die("usage: -pro=filename or --profile=filename, no spaces\n");
4611         }
4612         elsif ( $i =~ /^-(?: help | [ h \? ] )$/xi ) {
4613             usage();
4614             Exit(0);
4615         }
4616         elsif ( $i =~ /^-(version|v)$/ ) {
4617             show_version();
4618             Exit(0);
4619         }
4620         elsif ( $i =~ /^-(dump-defaults|ddf)$/ ) {
4621             dump_defaults( @{$rdefaults} );
4622             Exit(0);
4623         }
4624         elsif ( $i =~ /^-(dump-integer-option-range|dior)$/ ) {
4625             dump_integer_option_range($rinteger_option_range);
4626             Exit(0);
4627         }
4628         elsif ( $i =~ /^-(dump-long-names|dln)$/ ) {
4629             dump_long_names( @{$roption_string} );
4630             Exit(0);
4631         }
4632         elsif ( $i =~ /^-(dump-short-names|dsn)$/ ) {
4633             dump_short_names($rexpansion);
4634             Exit(0);
4635         }
4636         elsif ( $i =~ /^-(dump-token-types|dtt)$/ ) {
4637             Perl::Tidy::Tokenizer->dump_token_types(*STDOUT);
4638             Exit(0);
4639         }
4640         else {
4641             ## no more special cases
4642         }
4643     }
4644
4645     # The above commands processed before disambiguation and then Exited.  So
4646     # we need to check below to see if the user entered something like
4647     # '-dump-t' or '-he'. This will slip past here and not get processed.
4648     my %early_exit_commands = (
4649         'help'                      => 'h',
4650         'version'                   => 'v',
4651         'dump-defaults'             => 'ddf',
4652         'dump-integer-option-range' => 'dior',
4653         'dump-long-names'           => 'dln',
4654         'dump-short-names'          => 'dsn',
4655         'dump-token-types'          => 'dtt',
4656     );
4657
4658     if ( $saw_dump_profile && $saw_ignore_profile ) {
4659         Warn("No profile to dump because of -npro\n");
4660         Exit(1);
4661     }
4662
4663     #----------------------------------------
4664     # read any .perltidyrc configuration file
4665     #----------------------------------------
4666     if ( !$saw_ignore_profile ) {
4667
4668         # resolve possible conflict between $perltidyrc_stream passed
4669         # as call parameter to perltidy and -pro=filename on command
4670         # line.
4671         if ($perltidyrc_stream) {
4672             if ( defined($config_file) ) {
4673                 Warn(<<EOM);
4674  Conflict: a perltidyrc configuration file was specified both as this
4675  perltidy call parameter: $perltidyrc_stream
4676  and with this -profile=$config_file.
4677  Using -profile=$config_file.
4678 EOM
4679             }
4680             else {
4681                 $config_file = $perltidyrc_stream;
4682             }
4683         }
4684
4685         # look for a config file if we don't have one yet
4686         my $rconfig_file_chatter;
4687         ${$rconfig_file_chatter} = EMPTY_STRING;
4688         if ( !defined($config_file) ) {
4689             $config_file =
4690               find_config_file( $is_Windows, $Windows_type,
4691                 $rconfig_file_chatter, $rpending_complaint );
4692         }
4693
4694         # open any config file
4695         my $rconfig_string;
4696         if ( defined($config_file) ) {
4697             $rconfig_string = stream_slurp($config_file);
4698             if ( !defined($rconfig_string) ) {
4699                 Die(
4700 "exiting because profile '$config_file' could not be opened\n"
4701                 );
4702             }
4703             filter_unknown_options(
4704                 $rconfig_string, $roption_category,
4705                 $rexpansion,     $rconfig_file_chatter
4706             );
4707         }
4708         if ($saw_dump_profile) {
4709             dump_config_file( $rconfig_string, $config_file,
4710                 $rconfig_file_chatter );
4711             Exit(0);
4712         }
4713
4714         if ( defined($rconfig_string) ) {
4715
4716             my ( $rconfig_list, $death_message ) =
4717               read_config_file( $rconfig_string, $config_file, $rexpansion );
4718             Die($death_message) if ($death_message);
4719
4720             # process any .perltidyrc parameters right now so we can
4721             # localize errors
4722             if ( @{$rconfig_list} ) {
4723                 local @ARGV = @{$rconfig_list};
4724
4725                 expand_command_abbreviations( $rexpansion, \@raw_options,
4726                     $config_file );
4727
4728                 if ( !GetOptions( \%Opts, @{$roption_string} ) ) {
4729                     Die(
4730 "Error in this config file: $config_file  \nUse -npro to ignore this file, -dpro to dump it, -h for help'\n"
4731                     );
4732                 }
4733
4734                 # Anything left in this local @ARGV is an error and must be
4735                 # invalid bare words from the configuration file.  We cannot
4736                 # check this earlier because bare words may have been valid
4737                 # values for parameters.  We had to wait for GetOptions to have
4738                 # a look at @ARGV.
4739                 if (@ARGV) {
4740                     my $count = @ARGV;
4741                     my $str   = EMPTY_STRING;
4742                     foreach my $param (@ARGV) {
4743                         if ( length($str) < 70 ) {
4744                             if ($str) { $str .= ', ' }
4745                             $str .= "'$param'";
4746                         }
4747                         else {
4748                             $str .= ", ...";
4749                             last;
4750                         }
4751                     }
4752                     Die(<<EOM);
4753 There are $count unrecognized values in the configuration file '$config_file':
4754 $str
4755 Use leading dashes for parameters.  Use -npro to ignore this file.
4756 EOM
4757                 }
4758
4759                 # Undo any options which cause premature exit.  They are not
4760                 # appropriate for a config file, and it could be hard to
4761                 # diagnose the cause of the premature exit.
4762
4763                 # These are options include dump switches of the form
4764                 # '--dump-xxx-xxx!'.
4765                 my @dump_commands =
4766                   grep { /^(dump-.*)!$/ } @{$roption_string};
4767                 foreach (@dump_commands) { s/!$// }
4768
4769                 # Here is a current list of these @dump_commands:
4770                 #  dump-block-summary
4771                 #  dump-cuddled-block-list
4772                 #  dump-defaults
4773                 #  dump-integer-option-range
4774                 #  dump-long-names
4775                 #  dump-mismatched-args
4776                 #  dump-mismatched-returns
4777                 #  dump-mixed-call-parens
4778                 #  dump-options
4779                 #  dump-profile
4780                 #  dump-short-names
4781                 #  dump-token-types
4782                 #  dump-unusual-variables
4783                 #  dump-want-left-space
4784                 #  dump-want-right-space
4785
4786                 # The following two dump configuration parameters which
4787                 # take =i or =s would still be allowed:
4788                 #  dump-block-minimum-lines',        'dbl',   '=i' );
4789                 #  dump-block-types',                'dbt',   '=s' );
4790
4791                 foreach my $cmd (
4792                     @dump_commands,
4793                     qw{
4794                     help
4795                     stylesheet
4796                     version
4797                     }
4798                   )
4799                 {
4800                     if ( defined( $Opts{$cmd} ) ) {
4801                         delete $Opts{$cmd};
4802                         Warn("ignoring --$cmd in config file: $config_file\n");
4803                     }
4804                 }
4805             }
4806         }
4807     }
4808
4809     #----------------------------------------
4810     # now process the command line parameters
4811     #----------------------------------------
4812     expand_command_abbreviations( $rexpansion, \@raw_options, $config_file );
4813
4814     local $SIG{'__WARN__'} = sub { Warn( $_[0] ) };
4815     if ( !GetOptions( \%Opts, @{$roption_string} ) ) {
4816         Die("Error on command line; for help try 'perltidy -h'\n");
4817     }
4818
4819     # Catch ambiguous entries which should have exited above (c333)
4820     foreach my $long_name ( keys %early_exit_commands ) {
4821         if ( $Opts{$long_name} ) {
4822             my $short_name = $early_exit_commands{$long_name};
4823             Die(<<EOM);
4824 Ambiguous entry; please enter '--$long_name' or '-$short_name'
4825 EOM
4826         }
4827     }
4828
4829     # reset Getopt::Long configuration back to its previous value
4830     if ( defined($glc) ) {
4831         my $ok = eval { Getopt::Long::Configure($glc); 1 };
4832         if ( !$ok && DEVEL_MODE ) {
4833             Fault("Could not reset Getopt::Long configuration: $EVAL_ERROR\n");
4834         }
4835     }
4836
4837     return ( \%Opts, $config_file, \@raw_options, $roption_string,
4838         $rexpansion, $roption_category, $roption_range,
4839         $rinteger_option_range );
4840 } ## end sub _process_command_line
4841
4842 sub make_grep_alias_string {
4843
4844     my ($rOpts) = @_;
4845
4846     # pre-process the --grep-alias-list parameter
4847
4848     # Defaults: list operators in List::Util
4849     # Possible future additions:  pairfirst pairgrep pairmap
4850     my $default_string = join SPACE,
4851       qw( all any first none notall reduce reductions );
4852
4853     # make a hash of any excluded words
4854     my %is_excluded_word;
4855     my $exclude_string = $rOpts->{'grep-alias-exclusion-list'};
4856     if ($exclude_string) {
4857         $exclude_string =~ s/,/ /g;    # allow commas
4858         $exclude_string =~ s/^\s+//;
4859         $exclude_string =~ s/\s+$//;
4860         my @q = split /\s+/, $exclude_string;
4861         @is_excluded_word{@q} = (1) x scalar(@q);
4862     }
4863
4864     # The special option -gaxl='*' removes all defaults
4865     if ( $is_excluded_word{'*'} ) { $default_string = EMPTY_STRING }
4866
4867     # combine the defaults and any input list
4868     my $input_string = $rOpts->{'grep-alias-list'};
4869     if ($input_string) { $input_string .= SPACE . $default_string }
4870     else               { $input_string = $default_string }
4871
4872     # Now make the final list of unique grep alias words
4873     $input_string =~ s/,/ /g;    # allow commas
4874     $input_string =~ s/^\s+//;
4875     $input_string =~ s/\s+$//;
4876     my @word_list = split /\s+/, $input_string;
4877     my @filtered_word_list;
4878     my %seen;
4879
4880     foreach my $word (@word_list) {
4881         if ($word) {
4882             if ( $word !~ /^\w[\w\d]*$/ ) {
4883                 Warn(
4884                     "unexpected word in --grep-alias-list: '$word' - ignoring\n"
4885                 );
4886             }
4887             if ( !$seen{$word} && !$is_excluded_word{$word} ) {
4888                 $seen{$word}++;
4889                 push @filtered_word_list, $word;
4890             }
4891         }
4892     }
4893     my $joined_words = join SPACE, @filtered_word_list;
4894     $rOpts->{'grep-alias-list'} = $joined_words;
4895     return;
4896 } ## end sub make_grep_alias_string
4897
4898 sub cleanup_word_list {
4899
4900     my ( $rOpts, $option_name, $rforced_words ) = @_;
4901
4902     # Clean up the list of words in a user option to simplify use by
4903     # later routines (delete repeats, replace commas with single space,
4904     # remove non-words)
4905
4906     # Given:
4907     #   $rOpts - the global option hash
4908     #   $option_name - hash key of this option
4909     #   $rforced_words - ref to list of any words to be added
4910
4911     # Returns:
4912     #   \%seen - hash of the final list of words
4913
4914     my %seen;
4915     my @input_list;
4916
4917     my $input_string = $rOpts->{$option_name};
4918     if ( defined($input_string) && length($input_string) ) {
4919         $input_string =~ s/,/ /g;    # allow commas
4920         $input_string =~ s/^\s+//;
4921         $input_string =~ s/\s+$//;
4922         @input_list = split /\s+/, $input_string;
4923     }
4924
4925     if ($rforced_words) {
4926         push @input_list, @{$rforced_words};
4927     }
4928
4929     my @filtered_word_list;
4930     foreach my $word (@input_list) {
4931         if ($word) {
4932
4933             # look for obviously bad words
4934             if ( $word =~ /^\d/ || $word !~ /^\w[\w\d]*$/ ) {
4935                 Warn("unexpected '$option_name' word '$word' - ignoring\n");
4936             }
4937             if ( !$seen{$word} ) {
4938                 $seen{$word}++;
4939                 push @filtered_word_list, $word;
4940             }
4941         }
4942     }
4943     $rOpts->{$option_name} = join SPACE, @filtered_word_list;
4944     return \%seen;
4945 } ## end sub cleanup_word_list
4946
4947 sub check_options {
4948
4949     my ( $self, $num_files, $rinteger_option_range ) = @_;
4950
4951     # Check options at a high level. Note that other modules have their
4952     # own sub 'check_options' for lower level checking.
4953
4954     # Input parameters:
4955     #  $num_files = the number of files to be processed in this call to
4956     #     perltidy, needed for error checks.
4957     #  $rinteger_option-range = hash with valid ranges of parameters which
4958     #     take an integer
4959
4960     my $rOpts = $self->[_rOpts_];
4961
4962     #------------------------------------------------------------
4963     # check and handle any interactions among the basic options..
4964     #------------------------------------------------------------
4965
4966     # Since perltidy only encodes in utf8, problems can occur if we let it
4967     # decode anything else.  See discussions for issue git #83.
4968     my $encoding = $rOpts->{'character-encoding'};
4969     if ( $encoding !~ /^\s*(?:guess|none|utf8|utf-8)\s*$/i ) {
4970         Die(<<EOM);
4971 --character-encoding = '$encoding' is not allowed; the options are: 'none', 'guess', 'utf8'
4972 EOM
4973     }
4974
4975     my $integer_range_check = $rOpts->{'integer-range-check'};
4976     if (   !defined($integer_range_check)
4977         || $integer_range_check < 0
4978         || $integer_range_check > 3 )
4979     {
4980         $integer_range_check = 2;
4981     }
4982
4983     # Check for integer values out of bounds as follows:
4984     #  $integer_range_check=
4985     #    0 => skip check completely (for stress-testing perltidy only)
4986     #    1 => quietly reset bad values to defaults
4987     #    2 => issue warning and reset bad values defaults [DEFAULT]
4988     #    3 => stop if any values are out of bounds
4989     if ($integer_range_check) {
4990         my $Error_message;
4991         foreach my $opt ( keys %{$rinteger_option_range} ) {
4992             my $range = $rinteger_option_range->{$opt};
4993             next unless defined($range);
4994             my ( $min, $max, $default ) = @{$range};
4995
4996             my $val = $rOpts->{$opt};
4997             if ( defined($min) && defined($val) && $val < $min ) {
4998                 $Error_message .= "--$opt=$val but should be >= $min";
4999                 if ( $integer_range_check < 3 ) {
5000                     $rOpts->{$opt} = $default;
5001                     my $def = defined($default) ? $default : 'undef';
5002                     $Error_message .= "; using default $def";
5003                 }
5004                 $Error_message .= "\n";
5005             }
5006             if ( defined($max) && defined($val) && $val > $max ) {
5007                 $Error_message .= "--$opt=$val but should be <= $max";
5008                 if ( $integer_range_check < 3 ) {
5009                     $rOpts->{$opt} = $default;
5010                     my $def = defined($default) ? $default : 'undef';
5011                     $Error_message .= "; using default $def";
5012                 }
5013                 $Error_message .= "\n";
5014             }
5015         }
5016         if ($Error_message) {
5017             if ( $integer_range_check == 1 ) {
5018                 ## no warning
5019             }
5020             elsif ( $integer_range_check == 2 ) {
5021                 Warn($Error_message);
5022             }
5023             else {
5024                 Die($Error_message);
5025             }
5026         }
5027     }
5028
5029     # Note that -vt, -vtc, and -cti are abbreviations. But under
5030     # msdos, an unquoted input parameter like vtc=1 will be
5031     # seen as 2 parameters, vtc and 1, so the abbreviations
5032     # won't be seen.  Therefore, we will catch them here if
5033     # they get through.
5034     if ( defined( $rOpts->{'vertical-tightness'} ) ) {
5035         my $vt = $rOpts->{'vertical-tightness'};
5036         $rOpts->{'paren-vertical-tightness'}          = $vt;
5037         $rOpts->{'square-bracket-vertical-tightness'} = $vt;
5038         $rOpts->{'brace-vertical-tightness'}          = $vt;
5039     }
5040
5041     if ( defined( $rOpts->{'vertical-tightness-closing'} ) ) {
5042         my $vtc = $rOpts->{'vertical-tightness-closing'};
5043         $rOpts->{'paren-vertical-tightness-closing'}          = $vtc;
5044         $rOpts->{'square-bracket-vertical-tightness-closing'} = $vtc;
5045         $rOpts->{'brace-vertical-tightness-closing'}          = $vtc;
5046     }
5047
5048     if ( defined( $rOpts->{'closing-token-indentation'} ) ) {
5049         my $cti = $rOpts->{'closing-token-indentation'};
5050         $rOpts->{'closing-square-bracket-indentation'} = $cti;
5051         $rOpts->{'closing-brace-indentation'}          = $cti;
5052         $rOpts->{'closing-paren-indentation'}          = $cti;
5053     }
5054
5055     # Syntax checking is no longer supported due to concerns about executing
5056     # code in BEGIN blocks.  The flag is still accepted for backwards
5057     # compatibility but is ignored if set.
5058     $rOpts->{'check-syntax'} = 0;
5059
5060     my $check_blank_count = sub {
5061         my ( $key, $abbrev ) = @_;
5062         if ( $rOpts->{$key} ) {
5063             if ( $rOpts->{$key} < 0 ) {
5064                 $rOpts->{$key} = 0;
5065                 Warn("negative value of $abbrev, setting 0\n");
5066             }
5067             if ( $rOpts->{$key} > 100 ) {
5068                 Warn("unreasonably large value of $abbrev, reducing\n");
5069                 $rOpts->{$key} = 100;
5070             }
5071         }
5072         return;
5073     }; ## end $check_blank_count = sub
5074
5075     # check for reasonable number of blank lines and fix to avoid problems
5076     $check_blank_count->( 'blank-lines-before-subs',          '-blbs' );
5077     $check_blank_count->( 'blank-lines-before-packages',      '-blbp' );
5078     $check_blank_count->( 'blank-lines-after-block-opening',  '-blao' );
5079     $check_blank_count->( 'blank-lines-before-block-closing', '-blbc' );
5080
5081     # setting a non-negative logfile gap causes logfile to be saved
5082     if ( defined( $rOpts->{'logfile-gap'} ) && $rOpts->{'logfile-gap'} >= 0 ) {
5083         $rOpts->{'logfile'} = 1;
5084     }
5085
5086     # set short-cut flag when only indentation is to be done.
5087     # Note that the user may or may not have already set the
5088     # indent-only flag.
5089     if (   !$rOpts->{'add-whitespace'}
5090         && !$rOpts->{'delete-old-whitespace'}
5091         && !$rOpts->{'add-newlines'}
5092         && !$rOpts->{'delete-old-newlines'} )
5093     {
5094         $rOpts->{'indent-only'} = 1;
5095     }
5096
5097     # -isbc implies -ibc
5098     if ( $rOpts->{'indent-spaced-block-comments'} ) {
5099         $rOpts->{'indent-block-comments'} = 1;
5100     }
5101
5102     # -bar cannot be used with -bl or -bli; arbitrarily keep -bar
5103     if ( $rOpts->{'opening-brace-always-on-right'} ) {
5104
5105         if ( $rOpts->{'opening-brace-on-new-line'} ) {
5106             Warn(<<EOM);
5107  Conflict: you specified both 'opening-brace-always-on-right' (-bar) and
5108   'opening-brace-on-new-line' (-bl).  Ignoring -bl.
5109 EOM
5110             $rOpts->{'opening-brace-on-new-line'} = 0;
5111         }
5112         if ( $rOpts->{'brace-left-and-indent'} ) {
5113             Warn(<<EOM);
5114  Conflict: you specified both 'opening-brace-always-on-right' (-bar) and
5115   '--brace-left-and-indent' (-bli).  Ignoring -bli.
5116 EOM
5117             $rOpts->{'brace-left-and-indent'} = 0;
5118         }
5119     }
5120
5121     # it simplifies things if -bl is 0 rather than undefined
5122     if ( !defined( $rOpts->{'opening-brace-on-new-line'} ) ) {
5123         $rOpts->{'opening-brace-on-new-line'} = 0;
5124     }
5125
5126     if ( $rOpts->{'entab-leading-whitespace'} ) {
5127         if ( $rOpts->{'entab-leading-whitespace'} < 0 ) {
5128             Warn("-et=n must use a positive integer; ignoring -et\n");
5129             $rOpts->{'entab-leading-whitespace'} = undef;
5130         }
5131
5132         # entab leading whitespace has priority over the older 'tabs' option
5133         if ( $rOpts->{'tabs'} ) {
5134
5135             # The following warning could be added but would annoy a lot of
5136             # users who have a perltidyrc with both -t and -et=n.  So instead
5137             # there is a note in the manual that -et overrides -t.
5138             ##Warn("-tabs and -et=n conflict; ignoring -tabs\n");
5139             $rOpts->{'tabs'} = 0;
5140         }
5141     }
5142
5143     # set a default tabsize to be used in guessing the starting indentation
5144     # level if and only if this run does not use tabs and the old code does
5145     # use tabs
5146     if ( $rOpts->{'default-tabsize'} ) {
5147         if ( $rOpts->{'default-tabsize'} < 0 ) {
5148             Warn("negative value of -dt, setting 0\n");
5149             $rOpts->{'default-tabsize'} = 0;
5150         }
5151         if ( $rOpts->{'default-tabsize'} > 20 ) {
5152             Warn("unreasonably large value of -dt, reducing\n");
5153             $rOpts->{'default-tabsize'} = 20;
5154         }
5155     }
5156     else {
5157         $rOpts->{'default-tabsize'} = 8;
5158     }
5159
5160     # Check and clean up any sub-alias-list
5161     if ( defined( $rOpts->{'sub-alias-list'} )
5162         && length( $rOpts->{'sub-alias-list'} ) )
5163     {
5164         my @forced_words;
5165
5166         # include 'sub' for convenience if this option is used
5167         push @forced_words, 'sub';
5168
5169         cleanup_word_list( $rOpts, 'sub-alias-list', \@forced_words );
5170     }
5171
5172     make_grep_alias_string($rOpts);
5173
5174     # Turn on fuzzy-line-length unless this is an extrude run, as determined
5175     # by the -i and -ci settings. Otherwise blinkers can form (case b935).
5176     # This is an undocumented parameter used only for stress-testing when
5177     # --extrude is set.
5178     if ( !$rOpts->{'fuzzy-line-length'} ) {
5179         if (   $rOpts->{'maximum-line-length'} != 1
5180             || $rOpts->{'continuation-indentation'} != 0 )
5181         {
5182             $rOpts->{'fuzzy-line-length'} = 1;
5183         }
5184     }
5185
5186     # Large values of -scl can cause convergence problems, issue c167
5187     if ( $rOpts->{'short-concatenation-item-length'} > 12 ) {
5188         $rOpts->{'short-concatenation-item-length'} = 12;
5189     }
5190
5191     # The freeze-whitespace option is currently a derived option which has its
5192     # own key
5193     $rOpts->{'freeze-whitespace'} = !$rOpts->{'add-whitespace'}
5194       && !$rOpts->{'delete-old-whitespace'};
5195
5196     # Turn off certain options if whitespace is frozen
5197     # Note: vertical alignment will be automatically shut off
5198     if ( $rOpts->{'freeze-whitespace'} ) {
5199         $rOpts->{'logical-padding'} = 0;
5200     }
5201
5202     # Define the default line ending, before any -ple option is applied
5203     $self->[_line_separator_default_] = get_line_separator_default($rOpts);
5204
5205     $self->[_line_tidy_begin_] = undef;
5206     $self->[_line_tidy_end_]   = undef;
5207     my $line_range_tidy = $rOpts->{'line-range-tidy'};
5208     if ($line_range_tidy) {
5209
5210         if ( $num_files > 1 ) {
5211             Die(<<EOM);
5212 --line-range-tidy expects no more than 1 filename in the arg list but saw $num_files filenames
5213 EOM
5214         }
5215
5216         $line_range_tidy =~ s/\s+//g;
5217         if ( $line_range_tidy =~ /^(\d+):(\d+)?$/ ) {
5218             my $n1 = $1;
5219             my $n2 = $2;
5220             if ( $n1 < 1 ) {
5221                 Die(<<EOM);
5222 --line-range-tidy=n1:n2 expects starting line number n1>=1 but n1=$n1
5223 EOM
5224             }
5225             if ( defined($n2) && $n2 < $n1 ) {
5226                 Die(<<EOM);
5227 --line-range-tidy=n1:n2 expects ending line number n2>=n1 but n1=$n1 and n2=$n2
5228 EOM
5229             }
5230             $self->[_line_tidy_begin_] = $n1;
5231             $self->[_line_tidy_end_]   = $n2;
5232         }
5233         else {
5234             Die(
5235 "unrecognized 'line-range-tidy'; expecting format '-lrt=n1:n2'\n"
5236             );
5237         }
5238     }
5239
5240     return;
5241 } ## end sub check_options
5242
5243 sub find_file_upwards {
5244
5245     my ( $search_dir, $search_file ) = @_;
5246
5247     # This implements the ... upward search for a file
5248
5249     $search_dir  =~ s{/+$}{};
5250     $search_file =~ s{^/+}{};
5251
5252     while (1) {
5253         my $try_path = "$search_dir/$search_file";
5254         if ( -f $try_path ) {
5255             return $try_path;
5256         }
5257         elsif ( $search_dir eq '/' ) {
5258             return;
5259         }
5260         else {
5261             $search_dir = dirname($search_dir);
5262         }
5263     } ## end while (1)
5264
5265     # This return is for Perl-Critic.
5266     # We shouldn't get out of the while loop without a return
5267     return;
5268 } ## end sub find_file_upwards
5269
5270 sub expand_command_abbreviations {
5271
5272     # go through @ARGV and expand any abbreviations
5273     # note that @ARGV has been localized
5274
5275     my ( $rexpansion, $rraw_options, $config_file ) = @_;
5276
5277     # set a pass limit to prevent an infinite loop;
5278     # 10 should be plenty, but it may be increased to allow deeply
5279     # nested expansions.
5280     my $max_passes = 10;
5281
5282     # keep looping until all expansions have been converted into actual
5283     # dash parameters..
5284     foreach my $pass_count ( 0 .. $max_passes ) {
5285         my @new_argv     = ();
5286         my $abbrev_count = 0;
5287
5288         # loop over each item in @ARGV..
5289         foreach my $word (@ARGV) {
5290
5291             # convert any leading 'no-' to just 'no'
5292             if ( $word =~ /^(-[-]?no)-(.*)/ ) { $word = $1 . $2 }
5293
5294             # if it is a dash flag (instead of a file name)..
5295             if ( $word =~ /^-[-]?([\w\-]+)(.*)/ ) {
5296
5297                 my $abr   = $1;
5298                 my $flags = $2;
5299
5300                 # save the raw input for debug output in case of circular refs
5301                 if ( $pass_count == 0 ) {
5302                     push( @{$rraw_options}, $word );
5303                 }
5304
5305                 # recombine abbreviation and flag, if necessary,
5306                 # to allow abbreviations with arguments such as '-vt=1'
5307                 if ( $rexpansion->{ $abr . $flags } ) {
5308                     $abr   = $abr . $flags;
5309                     $flags = EMPTY_STRING;
5310                 }
5311
5312                 # if we see this dash item in the expansion hash..
5313                 if ( $rexpansion->{$abr} ) {
5314                     $abbrev_count++;
5315
5316                     # stuff all of the words that it expands to into the
5317                     # new arg list for the next pass
5318                     foreach my $abbrev ( @{ $rexpansion->{$abr} } ) {
5319                         next unless $abbrev;    # for safety; shouldn't happen
5320                         push( @new_argv, '--' . $abbrev . $flags );
5321                     }
5322                 }
5323
5324                 # not in expansion hash, must be actual long name
5325                 else {
5326                     push( @new_argv, $word );
5327                 }
5328             }
5329
5330             # not a dash item, so just save it for the next pass
5331             else {
5332                 push( @new_argv, $word );
5333             }
5334         } ## end of this pass
5335
5336         # update parameter list @ARGV to the new one
5337         @ARGV = @new_argv;
5338         last if ( !$abbrev_count );
5339
5340         # make sure we are not in an infinite loop
5341         if ( $pass_count == $max_passes ) {
5342             local $LIST_SEPARATOR = ')(';
5343             Warn(<<EOM);
5344 I'm tired. We seem to be in an infinite loop trying to expand aliases.
5345 Here are the raw options;
5346 (rraw_options)
5347 EOM
5348             my $num = @new_argv;
5349             if ( $num < 50 ) {
5350                 Warn(<<EOM);
5351 After $max_passes passes here is ARGV
5352 (@new_argv)
5353 EOM
5354             }
5355             else {
5356                 Warn(<<EOM);
5357 After $max_passes passes ARGV has $num entries
5358 EOM
5359             }
5360
5361             if ( defined($config_file) ) {
5362                 Die(<<"DIE");
5363 Please check your configuration file $config_file for circular-references.
5364 To deactivate it, use -npro.
5365 DIE
5366             }
5367             else {
5368                 Die(<<'DIE');
5369 Program bug - circular-references in the %expansion hash, probably due to
5370 a recent program change.
5371 DIE
5372             }
5373         } ## end of check for circular references
5374     } ## end of loop over all passes
5375     return;
5376 } ## end sub expand_command_abbreviations
5377
5378 # Debug routine -- this will dump the expansion hash
5379 sub dump_short_names {
5380     my $rexpansion = shift;
5381     print {*STDOUT} <<EOM;
5382 List of short names.  This list shows how all abbreviations are
5383 translated into other abbreviations and, eventually, into long names.
5384 New abbreviations may be defined in a .perltidyrc file.
5385 For a list of all long names, use perltidy --dump-long-names (-dln).
5386 --------------------------------------------------------------------------
5387 EOM
5388     foreach my $abbrev ( sort keys %{$rexpansion} ) {
5389         my @list = @{ $rexpansion->{$abbrev} };
5390         print {*STDOUT} "$abbrev --> @list\n";
5391     }
5392     return;
5393 } ## end sub dump_short_names
5394
5395 sub check_vms_filename {
5396
5397     # given a valid filename (the perltidy input file)
5398     # create a modified filename and separator character
5399     # suitable for VMS.
5400     #
5401     # Contributed by Michael Cartmell
5402     #
5403     my $filename = shift;
5404     my ( $base, $path ) = fileparse($filename);
5405
5406     # remove explicit ; version
5407     $base =~ s/;-?\d*$//
5408
5409       # remove explicit . version ie two dots in filename NB ^ escapes a dot
5410       or $base =~ s{(          # begin capture $1
5411                   (?:^|[^^])\. # match a dot not preceded by a caret
5412                   (?:          # followed by nothing
5413                     |          # or
5414                     .*[^^]     # anything ending in a non caret
5415                   )
5416                 )              # end capture $1
5417                 \.-?\d*$       # match . version number
5418               }{$1}x;
5419
5420     # normalize filename, if there are no unescaped dots then append one
5421     $base .= '.' unless ( $base =~ /(?:^|[^^])\./ );
5422
5423     # if we don't already have an extension then we just append the extension
5424     my $separator = ( $base =~ /\.$/ ) ? EMPTY_STRING : "_";
5425     return ( $path . $base, $separator );
5426 } ## end sub check_vms_filename
5427
5428 sub Win_OS_Type {
5429
5430     my $rpending_complaint = shift;
5431
5432     # Returns a string that determines what MS OS we are on.
5433     # Returns win32s,95,98,Me,NT3.51,NT4,2000,XP/.Net,Win2003
5434     # Returns blank string if not an MS system.
5435     # Original code contributed by: Yves Orton
5436     # We need to know this to decide where to look for config files
5437
5438     # TODO: are these more standard names?
5439     # Win32s Win95 Win98 WinMe WinNT3.51 WinNT4 Win2000 WinXP/.Net Win2003
5440
5441     my $os = EMPTY_STRING;
5442     return $os unless ( $OSNAME =~ /win32|dos/i );    # is it a MS box?
5443
5444     # Systems built from Perl source may not have Win32.pm
5445     # But probably have Win32::GetOSVersion() anyway so the
5446     # following line is not 'required':
5447     # return $os unless eval('require Win32');
5448
5449     # Use the standard API call to determine the version
5450     my ( $undef, $major, $minor, $build, $id );
5451     my $ok = eval {
5452         ( $undef, $major, $minor, $build, $id ) = Win32::GetOSVersion();
5453         1;
5454     };
5455     if ( !$ok && DEVEL_MODE ) {
5456         Fault("Could not cal Win32::GetOSVersion(): $EVAL_ERROR\n");
5457     }
5458
5459     #
5460     #    NAME                   ID   MAJOR  MINOR
5461     #    Windows NT 4           2      4       0
5462     #    Windows 2000           2      5       0
5463     #    Windows XP             2      5       1
5464     #    Windows Server 2003    2      5       2
5465
5466     return "win32s" unless $id;    # If id==0 then its a win32s box.
5467     $os = {                        # Magic numbers from MSDN
5468                                    # documentation of GetOSVersion
5469         1 => {
5470             0  => "95",
5471             10 => "98",
5472             90 => "Me",
5473         },
5474         2 => {
5475             0  => "2000",      # or NT 4, see below
5476             1  => "XP/.Net",
5477             2  => "Win2003",
5478             51 => "NT3.51",
5479         },
5480     }->{$id}->{$minor};
5481
5482     # If $os is undefined, the above code is out of date.  Suggested updates
5483     # are welcome.
5484     if ( !defined($os) ) {
5485         $os = EMPTY_STRING;
5486
5487         # Deactivated this message 20180322 because it was needlessly
5488         # causing some test scripts to fail.  Need help from someone
5489         # with expertise in Windows to decide what is possible with windows.
5490         ${$rpending_complaint} .= <<EOS if (0);
5491 Error trying to discover Win_OS_Type: $id:$major:$minor Has no name of record!
5492 We won't be able to look for a system-wide config file.
5493 EOS
5494     }
5495
5496     # Unfortunately the logic used for the various versions isn't so clever..
5497     # so we have to handle an outside case.
5498     return ( $os eq "2000" && $major != 5 ) ? "NT4" : $os;
5499 } ## end sub Win_OS_Type
5500
5501 sub look_for_Windows {
5502
5503     # determine Windows sub-type and location of
5504     # system-wide configuration files
5505     my $rpending_complaint = shift;
5506     my $is_Windows         = ( $OSNAME =~ /win32|dos/i );
5507     my $Windows_type;
5508     $Windows_type = Win_OS_Type($rpending_complaint) if $is_Windows;
5509     return ( $is_Windows, $Windows_type );
5510 } ## end sub look_for_Windows
5511
5512 sub find_config_file {
5513
5514     # look for a .perltidyrc configuration file
5515     # For Windows also look for a file named perltidy.ini
5516     my ( $is_Windows, $Windows_type, $rconfig_file_chatter,
5517         $rpending_complaint )
5518       = @_;
5519
5520     ${$rconfig_file_chatter} .= "# Config file search...system reported as:";
5521     if ($is_Windows) {
5522         ${$rconfig_file_chatter} .= "Windows $Windows_type\n";
5523     }
5524     else {
5525         ${$rconfig_file_chatter} .= " $OSNAME\n";
5526     }
5527
5528     # sub to check file existence and record all tests
5529     my $exists_config_file = sub {
5530         my $config_file = shift;
5531         return 0 unless defined($config_file);
5532         ${$rconfig_file_chatter} .= "# Testing: $config_file\n";
5533         return -f $config_file;
5534     }; ## end $exists_config_file = sub
5535
5536     # Sub to search upward for config file
5537     my $resolve_config_file = sub {
5538
5539         # resolve <dir>/.../<file>, meaning look upwards from directory
5540         my $config_file = shift;
5541         if ( defined($config_file) ) {
5542             if ( my ( $start_dir, $search_file ) =
5543                 ( $config_file =~ m{^(.*)\.\.\./(.*)$} ) )
5544             {
5545                 ${$rconfig_file_chatter} .=
5546                   "# Searching Upward: $config_file\n";
5547                 $start_dir = '.' if !$start_dir;
5548                 $start_dir = Cwd::realpath($start_dir);
5549                 my $found_file = find_file_upwards( $start_dir, $search_file );
5550                 if ( defined($found_file) ) {
5551                     $config_file = $found_file;
5552                     ${$rconfig_file_chatter} .= "# Found: $config_file\n";
5553                 }
5554             }
5555         }
5556         return $config_file;
5557     }; ## end $resolve_config_file = sub
5558
5559     my $config_file;
5560
5561     # look in current directory first
5562     $config_file = ".perltidyrc";
5563     return $config_file if $exists_config_file->($config_file);
5564     if ($is_Windows) {
5565         $config_file = "perltidy.ini";
5566         return $config_file if $exists_config_file->($config_file);
5567     }
5568
5569     # Default environment vars.
5570     my @envs = qw( PERLTIDY HOME );
5571
5572     # Check the NT/2k/XP locations, first a local machine def, then a
5573     # network def
5574     push @envs, qw( USERPROFILE HOMESHARE ) if $OSNAME =~ /win32/i;
5575
5576     # Now go through the environment ...
5577     foreach my $var (@envs) {
5578         ${$rconfig_file_chatter} .= "# Examining: \$ENV{$var}";
5579         if ( defined( $ENV{$var} ) ) {
5580             ${$rconfig_file_chatter} .= " = $ENV{$var}\n";
5581
5582             # test ENV{ PERLTIDY } as file:
5583             if ( $var eq 'PERLTIDY' ) {
5584                 $config_file = "$ENV{$var}";
5585                 $config_file = $resolve_config_file->($config_file);
5586                 return $config_file if $exists_config_file->($config_file);
5587             }
5588
5589             # test ENV as directory:
5590             $config_file = File::Spec->catfile( $ENV{$var}, ".perltidyrc" );
5591             $config_file = $resolve_config_file->($config_file);
5592             return $config_file if $exists_config_file->($config_file);
5593
5594             if ($is_Windows) {
5595                 $config_file =
5596                   File::Spec->catfile( $ENV{$var}, "perltidy.ini" );
5597                 $config_file = $resolve_config_file->($config_file);
5598                 return $config_file if $exists_config_file->($config_file);
5599             }
5600         }
5601         else {
5602             ${$rconfig_file_chatter} .= "\n";
5603         }
5604     }
5605
5606     # then look for a system-wide definition
5607     # where to look varies with OS
5608     if ($is_Windows) {
5609
5610         if ($Windows_type) {
5611             my ( $os_uu, $system, $allusers ) =
5612               Win_Config_Locs( $rpending_complaint, $Windows_type );
5613
5614             # Check All Users directory, if there is one.
5615             # i.e. C:\Documents and Settings\User\perltidy.ini
5616             if ($allusers) {
5617
5618                 $config_file = File::Spec->catfile( $allusers, ".perltidyrc" );
5619                 return $config_file if $exists_config_file->($config_file);
5620
5621                 $config_file = File::Spec->catfile( $allusers, "perltidy.ini" );
5622                 return $config_file if $exists_config_file->($config_file);
5623             }
5624
5625             # Check system directory.
5626             # retain old code in case someone has been able to create
5627             # a file with a leading period.
5628             $config_file = File::Spec->catfile( $system, ".perltidyrc" );
5629             return $config_file if $exists_config_file->($config_file);
5630
5631             $config_file = File::Spec->catfile( $system, "perltidy.ini" );
5632             return $config_file if $exists_config_file->($config_file);
5633         }
5634     }
5635
5636     # Place to add customization code for other systems
5637     elsif ( $OSNAME eq 'OS2' ) {
5638     }
5639     elsif ( $OSNAME eq 'MacOS' ) {
5640     }
5641     elsif ( $OSNAME eq 'VMS' ) {
5642     }
5643
5644     # Assume some kind of Unix
5645     else {
5646
5647         $config_file = "/usr/local/etc/perltidyrc";
5648         return $config_file if $exists_config_file->($config_file);
5649
5650         $config_file = "/etc/perltidyrc";
5651         return $config_file if $exists_config_file->($config_file);
5652     }
5653
5654     # Couldn't find a config file
5655     return;
5656 } ## end sub find_config_file
5657
5658 sub Win_Config_Locs {
5659
5660     # In scalar context returns the OS name (95 98 ME NT3.51 NT4 2000 XP),
5661     # or undef if its not a win32 OS.  In list context returns OS, System
5662     # Directory, and All Users Directory.  All Users will be empty on a
5663     # 9x/Me box.  Contributed by: Yves Orton.
5664
5665     my ( $rpending_complaint, $os ) = @_;
5666     if ( !$os ) { $os = Win_OS_Type($rpending_complaint) }
5667
5668     return unless $os;
5669
5670     my $system   = EMPTY_STRING;
5671     my $allusers = EMPTY_STRING;
5672
5673     if ( $os =~ /9[58]|Me/ ) {
5674         $system = "C:/Windows";
5675     }
5676     elsif ( $os =~ /NT|XP|200?/ ) {
5677         $system = ( $os =~ /XP/ ) ? "C:/Windows/" : "C:/WinNT/";
5678         $allusers =
5679           ( $os =~ /NT/ )
5680           ? "C:/WinNT/profiles/All Users/"
5681           : "C:/Documents and Settings/All Users/";
5682     }
5683     else {
5684
5685         # This currently would only happen on a win32s computer.  I don't have
5686         # one to test, so I am unsure how to proceed.  Suggestions welcome!
5687         ${$rpending_complaint} .=
5688 "I dont know a sensible place to look for config files on an $os system.\n";
5689         return;
5690     }
5691     return ( $os, $system, $allusers );
5692 } ## end sub Win_Config_Locs
5693
5694 sub dump_config_file {
5695     my ( $rconfig_string, $config_file, $rconfig_file_chatter ) = @_;
5696     print {*STDOUT} "${$rconfig_file_chatter}";
5697     if ($rconfig_string) {
5698         my @lines = split /^/, ${$rconfig_string};
5699         print {*STDOUT} "# Dump of file: '$config_file'\n";
5700         foreach my $line (@lines) { print {*STDOUT} $line }
5701     }
5702     else {
5703         print {*STDOUT} "# ...no config file found\n";
5704     }
5705     return;
5706 } ## end sub dump_config_file
5707
5708 sub filter_unknown_options {
5709
5710     my (
5711         $rconfig_string, $roption_category,
5712         $rexpansion,     $rconfig_file_chatter
5713     ) = @_;
5714
5715     # Look through the configuration file for lines beginning with '---' and
5716     # - remove the line if the option is unknown, or
5717     # - remove the extra dash if the option is known
5718     # See git #146 for discussion
5719
5720     # Given:
5721     #   $rconfig_string = string ref to a .perltidyrc configuration file
5722     #   $roption_category = ref to hash with long_names as key
5723     #   $rexpansion = ref to hash with abbreviations as key
5724     #   $rconfig_file_chatter = messages displayed in --dump-profile
5725     #
5726     # Update:
5727     #   $rconfig_string and $rconfig_file_chatter
5728
5729     # quick check to skip most files
5730     if ( ${$rconfig_string} !~ /^\s*---\w/m ) { return }
5731
5732     my $new_config_string;
5733     my $change_notices = EMPTY_STRING;
5734     my @lines          = split /^/, ${$rconfig_string};
5735     foreach my $line (@lines) {
5736         chomp $line;
5737
5738         # look for lines beginning with '---'
5739         if ( $line && $line =~ /^\s*---(\w[\w-]*)/ ) {
5740             my $word = $1;
5741
5742             # first look for a long name or an abbreviation
5743             my $is_known = $roption_category->{$word} || $rexpansion->{$word};
5744
5745             # then look for prefix 'no' or 'no-' on a long name
5746             if ( !$is_known && $word =~ s/^no-?// ) {
5747                 $is_known = $roption_category->{$word};
5748             }
5749
5750             if ( !$is_known ) {
5751                 $change_notices .= "#  removing unknown option line $line\n";
5752                 next;
5753             }
5754             else {
5755                 $change_notices .= "#  accepting and fixing line $line\n";
5756                 $line =~ s/-//;
5757             }
5758         }
5759         $new_config_string .= $line . "\n";
5760     }
5761
5762     if ($change_notices) {
5763         ${$rconfig_file_chatter} .= "# Filter operations:\n" . $change_notices;
5764         ${$rconfig_string} = $new_config_string;
5765     }
5766     return;
5767 } ## end sub filter_unknown_options
5768
5769 sub read_config_file {
5770
5771     my ( $rconfig_string, $config_file, $rexpansion ) = @_;
5772
5773     # Read and process the contents of a perltidyrc command file
5774
5775     # Given:
5776     #   $rconfig_string = ref to the file as a string
5777     #   $config_file = name of the file, for error reporting
5778     #   $rexpansion = ref to hash of abbreviations; if this config file defines
5779     #                 any abbreviations they will be added to it
5780
5781     # Return:
5782     #   \@config_list = ref to final parameters and values which will be
5783     #     placed in @ARGV for processing by GetOptions
5784     #   $death_message = error message returned if a fatal error occurs
5785     my @config_list = ();
5786
5787     # remove side comments and join multiline quotes
5788     my ( $rline_hash, $death_message ) =
5789       strip_comments_and_join_quotes( $rconfig_string, $config_file );
5790
5791     # file is bad if non-empty $death_message is returned
5792     if ($death_message) {
5793         return ( \@config_list, $death_message );
5794     }
5795
5796     my $name = undef;
5797     my $opening_brace_line;
5798     foreach my $item ( @{$rline_hash} ) {
5799         my $line    = $item->{line};
5800         my $line_no = $item->{line_no};
5801         $line =~ s/^\s+//;
5802         $line =~ s/\s+$//;
5803         next unless ( length($line) );
5804
5805         my $body = $line;
5806
5807         # Look for complete or partial abbreviation definition of the form
5808         #     name { body }   or  name {   or    name { body
5809         # See rules in perltidy's perldoc page
5810         # Section: Other Controls - Creating a new abbreviation
5811         if ( $line =~ /^(?: (\w+) \s* \{ ) (.*)? $/x ) {
5812             ( $name, $body ) = ( $1, $2 );
5813
5814             # Cannot start new abbreviation unless old abbreviation is complete
5815             last if ($opening_brace_line);
5816
5817             $opening_brace_line = $line_no unless ( $body && $body =~ s/\}$// );
5818
5819             # handle a new alias definition
5820             if ( $rexpansion->{$name} ) {
5821                 local $LIST_SEPARATOR = ')(';
5822                 my @names = sort keys %{$rexpansion};
5823                 $death_message =
5824                     "Here is a list of all installed aliases\n(@names)\n"
5825                   . "Attempting to redefine alias ($name) in config file $config_file line $INPUT_LINE_NUMBER\n";
5826                 last;
5827             }
5828             $rexpansion->{$name} = [];
5829         }
5830
5831         # leading opening braces not allowed
5832         elsif ( $line =~ /^{/ ) {
5833             $opening_brace_line = undef;
5834             $death_message =
5835               "Unexpected '{' at line $line_no in config file '$config_file'\n";
5836             last;
5837         }
5838
5839         # Look for abbreviation closing:    body }   or    }
5840         elsif ( $line =~ /^(.*)?\}$/ ) {
5841             $body = $1;
5842             if ($opening_brace_line) {
5843                 $opening_brace_line = undef;
5844             }
5845             else {
5846                 $death_message =
5847 "Unexpected '}' at line $line_no in config file '$config_file'\n";
5848                 last;
5849             }
5850         }
5851         else {
5852             # no abbreviations to untangle
5853         }
5854
5855         # Now store any parameters
5856         if ($body) {
5857
5858             my ( $rbody_parts, $msg ) = parse_args($body);
5859             if ($msg) {
5860                 $death_message = <<EOM;
5861 Error reading file '$config_file' at line number $line_no.
5862 $msg
5863 Please fix this line or use -npro to avoid reading this file
5864 EOM
5865                 last;
5866             }
5867
5868             if ($name) {
5869
5870                 # remove leading dashes if this is an alias
5871                 foreach ( @{$rbody_parts} ) { s/^\-+//; }
5872                 push @{ $rexpansion->{$name} }, @{$rbody_parts};
5873             }
5874             else {
5875                 push( @config_list, @{$rbody_parts} );
5876             }
5877         }
5878     }
5879
5880     if ($opening_brace_line) {
5881         $death_message =
5882 "Didn't see a '}' to match the '{' at line $opening_brace_line in config file '$config_file'\n";
5883     }
5884     return ( \@config_list, $death_message );
5885 } ## end sub read_config_file
5886
5887 sub strip_comments_and_join_quotes {
5888
5889     my ( $rconfig_string, $config_file ) = @_;
5890
5891     # Tasks:
5892     # 1. Strip comments from .perltidyrc lines
5893     # 2. Join lines which are spanned by a quote
5894
5895     # Given:
5896     #   $rconfig_string = the configuration file
5897     #   $config_file = filename, for error messages
5898     # Return:
5899     #   $rline_hash = hash with modified lines and their input numbers
5900     #   $msg = any error message; code will die on any message.
5901
5902     # return variables
5903     my $msg        = EMPTY_STRING;
5904     my $rline_hash = [];
5905
5906     # quote state variables
5907     my $quote_char          = EMPTY_STRING;
5908     my $quote_start_line    = EMPTY_STRING;
5909     my $quote_start_line_no = -1;
5910     my $in_string           = EMPTY_STRING;
5911     my $out_string          = EMPTY_STRING;
5912
5913     my @lines   = split /^/, ${$rconfig_string};
5914     my $line_no = 0;
5915
5916     # loop over lines
5917     foreach my $line (@lines) {
5918         $line_no++;
5919         $line =~ s/^\s+//;
5920         $line =~ s/\s+$//;
5921         next unless ( length($line) );
5922
5923         if ( !$quote_char ) {
5924
5925             # skip a full-line comment
5926             if ( substr( $line, 0, 1 ) eq '#' ) {
5927                 next;
5928             }
5929             $in_string  = $line;
5930             $out_string = EMPTY_STRING;
5931         }
5932         else {
5933
5934             # treat previous newline as a space
5935             $in_string = SPACE . $line;
5936         }
5937
5938         # loop over string characters
5939         #  $in_string  = the input string
5940         #  $out_string = the output string
5941         #  $quote_char = quote character being sought
5942         while (1) {
5943
5944             # accumulating characters not in quote
5945             if ( !$quote_char ) {
5946
5947                 if ( $in_string =~ /\G([\"\'])/gc ) {
5948
5949                     # starting new quote..
5950                     $out_string .= $1;
5951                     $quote_char          = $1;
5952                     $quote_start_line_no = $line_no;
5953                     $quote_start_line    = $line;
5954                 }
5955                 elsif ( $in_string =~ /\G#/gc ) {
5956
5957                     # A space is required before the # of a side comment
5958                     # This allows something like:
5959                     #    -sbcp=#
5960                     # Otherwise, it would have to be quoted:
5961                     #    -sbcp='#'
5962                     if ( !length($out_string) || $out_string =~ s/\s+$// ) {
5963                         last;
5964                     }
5965                     $out_string .= '#';
5966                 }
5967                 elsif ( $in_string =~ /\G([^\#\'\"]+)/gc ) {
5968
5969                     # neither quote nor side comment
5970                     $out_string .= $1;
5971                 }
5972                 else {
5973
5974                     # end of line
5975                     last;
5976                 }
5977             }
5978
5979             # looking for ending quote character
5980             else {
5981                 if ( $in_string =~ /\G($quote_char)/gc ) {
5982
5983                     # end of quote
5984                     $out_string .= $1;
5985                     $quote_char = EMPTY_STRING;
5986                 }
5987                 elsif ( $in_string =~ /\G([^$quote_char]+)/gc ) {
5988
5989                     # accumulate quoted text
5990                     $out_string .= $1;
5991                 }
5992                 else {
5993
5994                     # end of line
5995                     last;
5996                 }
5997             }
5998         } ## end while (1)
5999
6000         if ( !$quote_char ) {
6001             push @{$rline_hash},
6002               {
6003                 line    => $out_string,
6004                 line_no => $line_no,
6005               };
6006         }
6007
6008     } ## end loop over lines
6009
6010     if ($quote_char) {
6011         my $max_len = 80;
6012         if ( length($quote_start_line) > $max_len ) {
6013             $quote_start_line =
6014               substr( $quote_start_line, 0, $max_len - 3 ) . '...';
6015         }
6016         $msg = <<EOM;
6017 Error: hit EOF reading file '$config_file' looking for end of quoted text
6018 which started at line $quote_start_line_no with quote character <$quote_char>:
6019 $quote_start_line
6020 Please fix or use -npro to avoid reading this file
6021 EOM
6022     }
6023     return ( $rline_hash, $msg );
6024 } ## end sub strip_comments_and_join_quotes
6025
6026 sub parse_args {
6027
6028     # Parse a command string containing multiple string with possible
6029     # quotes, into individual commands.  It might look like this, for example:
6030     #
6031     #    -wba=" + - "  -some-thing -wbb='. && ||'
6032     #
6033     # There is no need, at present, to handle escaped quote characters.
6034     # (They are not perltidy tokens, so needn't be in strings).
6035
6036     my ($body)     = @_;
6037     my @body_parts = ();
6038     my $quote_char = EMPTY_STRING;
6039     my $part       = EMPTY_STRING;
6040     my $msg        = EMPTY_STRING;
6041
6042     # Check for external call with undefined $body - added to fix
6043     # github issue Perl-Tidy-Sweetened issue #23
6044     if ( !defined($body) ) { $body = EMPTY_STRING }
6045
6046     while (1) {
6047
6048         # looking for ending quote character
6049         if ($quote_char) {
6050             if ( $body =~ /\G($quote_char)/gc ) {
6051                 $quote_char = EMPTY_STRING;
6052             }
6053             elsif ( $body =~ /\G(.)/gc ) {
6054                 $part .= $1;
6055             }
6056
6057             # error..we reached the end without seeing the ending quote char
6058             else {
6059                 if ( length($part) ) { push @body_parts, $part; }
6060                 $msg = <<EOM;
6061 Did not see ending quote character <$quote_char> in this text:
6062 $body
6063 EOM
6064                 last;
6065             }
6066         }
6067
6068         # accumulating characters and looking for start of a quoted string
6069         else {
6070             if ( $body =~ /\G([\"\'])/gc ) {
6071                 $quote_char = $1;
6072             }
6073             elsif ( $body =~ /\G(\s+)/gc ) {
6074                 if ( length($part) ) { push @body_parts, $part; }
6075                 $part = EMPTY_STRING;
6076             }
6077             elsif ( $body =~ /\G(.)/gc ) {
6078                 $part .= $1;
6079             }
6080             else {
6081                 if ( length($part) ) { push @body_parts, $part; }
6082                 last;
6083             }
6084         }
6085     } ## end while (1)
6086     return ( \@body_parts, $msg );
6087 } ## end sub parse_args
6088
6089 sub dump_long_names {
6090
6091     my @names = @_;
6092     print {*STDOUT} <<EOM;
6093 # Command line long names (passed to GetOptions)
6094 #--------------------------------------------------
6095 # here is a summary of the Getopt codes:
6096 # <none> does not take an argument
6097 # =s takes a mandatory string
6098 # :s takes an optional string
6099 # =i takes a mandatory integer
6100 # :i takes an optional integer
6101 # ! does not take an argument and may be negated
6102 #  i.e., -foo and -nofoo are allowed
6103 # a double dash signals the end of the options list
6104 #
6105 #--------------------------------------------------
6106 EOM
6107
6108     foreach my $name ( sort @names ) { print {*STDOUT} "$name\n" }
6109     return;
6110 } ## end sub dump_long_names
6111
6112 sub dump_integer_option_range {
6113     my ($rinteger_option_range) = @_;
6114     print {*STDOUT} "Option, min, max, default\n";
6115     foreach my $key ( sort keys %{$rinteger_option_range} ) {
6116         my ( $min, $max, $default ) = @{ $rinteger_option_range->{$key} };
6117         foreach ( $min, $max, $default ) {
6118             $_ = 'undef' unless defined($_);
6119         }
6120         print {*STDOUT} "$key, $min, $max, $default\n";
6121     }
6122     return;
6123 } ## end sub dump_integer_option_range
6124
6125 sub dump_defaults {
6126     my @defaults = @_;
6127     print {*STDOUT} "Default command line options:\n";
6128     foreach my $line ( sort @defaults ) { print {*STDOUT} "$line\n" }
6129     return;
6130 } ## end sub dump_defaults
6131
6132 sub readable_options {
6133
6134     # return options for this run as a string which could be
6135     # put in a perltidyrc file
6136     my ( $rOpts, $roption_string ) = @_;
6137     my %Getopt_flags;
6138     my $rGetopt_flags    = \%Getopt_flags;
6139     my $readable_options = "# Final parameter set for this run.\n";
6140     $readable_options .=
6141       "# See utility 'perltidyrc_dump.pl' for nicer formatting.\n";
6142     foreach my $opt ( @{$roption_string} ) {
6143         my $flag = EMPTY_STRING;
6144         if ( $opt =~ /(.*)(!|=.*)$/ ) {
6145             $opt  = $1;
6146             $flag = $2;
6147         }
6148         if ( defined( $rOpts->{$opt} ) ) {
6149             $rGetopt_flags->{$opt} = $flag;
6150         }
6151     }
6152     foreach my $key ( sort keys %{$rOpts} ) {
6153         my $flag   = $rGetopt_flags->{$key};
6154         my $value  = $rOpts->{$key};
6155         my $prefix = '--';
6156         my $suffix = EMPTY_STRING;
6157         if ($flag) {
6158             if ( $flag =~ /^=/ ) {
6159                 if ( $value !~ /^\d+$/ ) { $value = '"' . $value . '"' }
6160                 $suffix = "=" . $value;
6161             }
6162             elsif ( $flag =~ /^!/ ) {
6163                 $prefix .= "no" unless ($value);
6164             }
6165             else {
6166
6167                 # shouldn't happen
6168                 $readable_options .=
6169                   "# ERROR in dump_options: unrecognized flag $flag for $key\n";
6170             }
6171         }
6172         $readable_options .= $prefix . $key . $suffix . "\n";
6173     }
6174     return $readable_options;
6175 } ## end sub readable_options
6176
6177 sub show_version {
6178     print {*STDOUT} <<"EOM";
6179 This is perltidy, v$VERSION
6180
6181 Copyright 2000-2025 by Steve Hancock
6182
6183 Perltidy is free software and may be copied under the terms of the GNU
6184 General Public License, which is included in the distribution files.
6185
6186 Documentation can be found using 'man perltidy'
6187 or at GitHub      https://perltidy.github.io/perltidy/
6188 or at metacpan    https://metacpan.org/pod/distribution/Perl-Tidy/bin/perltidy
6189 or at Sourceforge https://perltidy.sourceforge.net
6190 EOM
6191     return;
6192 } ## end sub show_version
6193
6194 sub usage {
6195
6196     print {*STDOUT} <<EOF;
6197 This is perltidy version $VERSION, a perl script indenter.  Usage:
6198
6199     perltidy [ options ] file1 file2 file3 ...
6200             (output goes to file1.tdy, file2.tdy, file3.tdy, ...)
6201     perltidy [ options ] file1 -o outfile
6202     perltidy [ options ] file1 -st >outfile
6203     perltidy [ options ] <infile >outfile
6204
6205 Options have short and long forms. Short forms are shown; see
6206 man pages for long forms.  Note: '=s' indicates a required string,
6207 and '=n' indicates a required integer.
6208
6209 I/O control
6210  -h      show this help
6211  -o=file name of the output file (only if single input file)
6212  -oext=s change output extension from 'tdy' to s
6213  -opath=path  change path to be 'path' for output files
6214  -b      backup original to .bak and modify file in-place
6215  -bext=s change default backup extension from 'bak' to s
6216  -q      deactivate error messages (for running under editor)
6217  -w      include non-critical warning messages in the .ERR error output
6218  -log    save .LOG file, which has useful diagnostics
6219  -f      force perltidy to read a binary file
6220  -g      like -log but writes more detailed .LOG file, for debugging scripts
6221  -opt    write the set of options actually used to a .LOG file
6222  -npro   ignore .perltidyrc configuration command file
6223  -pro=file   read configuration commands from file instead of .perltidyrc
6224  -st     send output to standard output, STDOUT
6225  -se     send all error output to standard error output, STDERR
6226  -v      display version number to standard output and quit
6227
6228 Basic Options:
6229  -i=n    use n columns per indentation level (default n=4)
6230  -t      tabs: use one tab character per indentation level, not recommended
6231  -nt     no tabs: use n spaces per indentation level (default)
6232  -et=n   entab leading whitespace n spaces per tab; not recommended
6233  -io     "indent only": just do indentation, no other formatting.
6234  -sil=n  set starting indentation level to n;  use if auto detection fails
6235  -ole=s  specify output line ending (s=dos or win, mac, unix)
6236  -ple    keep output line endings same as input (input must be filename)
6237
6238 Whitespace Control
6239  -fws    freeze whitespace; this disables all whitespace changes
6240            and disables the following switches:
6241  -bt=n   sets brace tightness,  n= (0 = loose, 1=default, 2 = tight)
6242  -bbt    same as -bt but for code block braces; same as -bt if not given
6243  -bbvt   block braces vertically tight; use with -bl or -bli
6244  -bbvtl=s  make -bbvt to apply to selected list of block types
6245  -pt=n   paren tightness (n=0, 1 or 2)
6246  -sbt=n  square bracket tightness (n=0, 1, or 2)
6247  -bvt=n  brace vertical tightness,
6248          n=(0=open, 1=close unless multiple steps on a line, 2=always close)
6249  -pvt=n  paren vertical tightness (see -bvt for n)
6250  -sbvt=n square bracket vertical tightness (see -bvt for n)
6251  -bvtc=n closing brace vertical tightness:
6252          n=(0=open, 1=sometimes close, 2=always close)
6253  -pvtc=n closing paren vertical tightness, see -bvtc for n.
6254  -sbvtc=n closing square bracket vertical tightness, see -bvtc for n.
6255  -ci=n   sets continuation indentation=n,  default is n=2 spaces
6256  -lp     line up parentheses, brackets, and non-BLOCK braces
6257  -sfs    add space before semicolon in for( ; ; )
6258  -aws    allow perltidy to add whitespace (default)
6259  -dws    delete all old non-essential whitespace
6260  -icb    indent closing brace of a code block
6261  -cti=n  closing indentation of paren, square bracket, or non-block brace:
6262          n=0 none, =1 align with opening, =2 one full indentation level
6263  -icp    equivalent to -cti=2
6264  -wls=s  want space left of tokens in string; i.e. -nwls='+ - * /'
6265  -wrs=s  want space right of tokens in string;
6266  -sts    put space before terminal semicolon of a statement
6267  -sak=s  put space between keywords given in s and '(';
6268  -nsak=s no space between keywords in s and '('; i.e. -nsak='my our local'
6269
6270 Line Break Control
6271  -fnl    freeze newlines; this disables all line break changes
6272             and disables the following switches:
6273  -anl    add newlines;  ok to introduce new line breaks
6274  -bbs    add blank line before subs and packages
6275  -bbc    add blank line before block comments
6276  -bbb    add blank line between major blocks
6277  -kbl=n  keep old blank lines? 0=no, 1=some, 2=all
6278  -mbl=n  maximum consecutive blank lines to output (default=1)
6279  -ce     cuddled else; use this style: '} else {'
6280  -cb     cuddled blocks (other than 'if-elsif-else')
6281  -cbl=s  list of blocks to cuddled, default 'try-catch-finally'
6282  -dnl    delete old newlines (default)
6283  -l=n    maximum line length;  default n=80
6284  -bl     opening brace on new line
6285  -sbl    opening sub brace on new line.  value of -bl is used if not given.
6286  -bli    opening brace on new line and indented
6287  -bar    opening brace always on right, even for long clauses
6288  -vt=n   vertical tightness (requires -lp); n controls break after opening
6289          token: 0=never  1=no break if next line balanced   2=no break
6290  -vtc=n  vertical tightness of closing container; n controls if closing
6291          token starts new line: 0=always  1=not unless list  1=never
6292  -wba=s  want break after tokens in string; i.e. wba=': .'
6293  -wbb=s  want break before tokens in string
6294  -wn     weld nested: combines opening and closing tokens when both are adjacent
6295  -wnxl=s weld nested exclusion list: provides some control over the types of
6296          containers which can be welded
6297
6298 Following Old Breakpoints
6299  -kis    keep interior semicolons.  Allows multiple statements per line.
6300  -boc    break at old comma breaks: turns off all automatic list formatting
6301  -bol    break at old logical breakpoints: or, and, ||, && (default)
6302  -bom    break at old method call breakpoints: ->
6303  -bok    break at old list keyword breakpoints such as map, sort (default)
6304  -bot    break at old conditional (ternary ?:) operator breakpoints (default)
6305  -boa    break at old attribute breakpoints
6306  -cab=n  break at commas after a comma-arrow (=>):
6307          n=0 break at all commas after =>
6308          n=1 stable: break unless this breaks an existing one-line container
6309          n=2 break only if a one-line container cannot be formed
6310          n=3 do not treat commas after => specially at all
6311
6312 Comment controls
6313  -ibc    indent block comments (default)
6314  -isbc   indent spaced block comments; may indent unless no leading space
6315  -msc=n  minimum desired spaces to side comment, default 4
6316  -fpsc=n fix position for side comments; default 0;
6317  -csc    add or update closing side comments after closing BLOCK brace
6318  -dcsc   delete closing side comments created by a -csc command
6319  -cscp=s change closing side comment prefix to be other than '## end'
6320  -cscl=s change closing side comment to apply to selected list of blocks
6321  -csci=n minimum number of lines needed to apply a -csc tag, default n=6
6322  -csct=n maximum number of columns of appended text, default n=20
6323  -cscw   causes warning if old side comment is overwritten with -csc
6324
6325  -sbc    use 'static block comments' identified by leading '##' (default)
6326  -sbcp=s change static block comment identifier to be other than '##'
6327  -osbc   outdent static block comments
6328
6329  -ssc    use 'static side comments' identified by leading '##' (default)
6330  -sscp=s change static side comment identifier to be other than '##'
6331
6332 Delete selected text
6333  -dac    delete all comments AND pod
6334  -dbc    delete block comments
6335  -dsc    delete side comments
6336  -dp     delete pod
6337
6338 Send selected text to a '.TEE' file
6339  -tac    tee all comments AND pod
6340  -tbc    tee block comments
6341  -tsc    tee side comments
6342  -tp     tee pod
6343
6344 Outdenting
6345  -olq    outdent long quoted strings (default)
6346  -olc    outdent a long block comment line
6347  -ola    outdent statement labels
6348  -okw    outdent control keywords (redo, next, last, goto, return)
6349  -okwl=s specify alternative keywords for -okw command
6350
6351 Other controls
6352  -mft=n  maximum fields per table; default n=0 (no limit)
6353  -x      do not format lines before hash-bang line (i.e., for VMS)
6354  -asc    allows perltidy to add a ';' when missing (default)
6355  -dsm    allows perltidy to delete an unnecessary ';'  (default)
6356
6357 Combinations of other parameters
6358  -gnu     attempt to follow GNU Coding Standards as applied to perl
6359  -mangle  remove as many newlines as possible (but keep comments and pods)
6360  -extrude  insert as many newlines as possible
6361
6362 Dump and die, debugging
6363  -dop    dump options used in this run to standard output and quit
6364  -ddf    dump default options to standard output and quit
6365  -dsn    dump all option short names to standard output and quit
6366  -dln    dump option long names to standard output and quit
6367  -dpro   dump whatever configuration file is in effect to standard output
6368  -dtt    dump all token types to standard output and quit
6369
6370 HTML
6371  -html write an html file (see 'man perl2web' for many options)
6372        Note: when -html is used, no indentation or formatting are done.
6373        Hint: try perltidy -html -css=mystyle.css filename.pl
6374        and edit mystyle.css to change the appearance of filename.html.
6375        -nnn gives line numbers
6376        -pre only writes out <pre>..</pre> code section
6377        -toc places a table of contents to subs at the top (default)
6378        -pod passes pod text through pod2html (default)
6379        -frm write html as a frame (3 files)
6380        -text=s extra extension for table of contents if -frm, default='toc'
6381        -sext=s extra extension for file content if -frm, default='src'
6382
6383 A prefix of "n" negates short form toggle switches, and a prefix of "no"
6384 negates the long forms.  For example, -nasc means don't add missing
6385 semicolons.
6386
6387 If you are unable to see this entire text, try "perltidy -h | more"
6388 For more detailed information, and additional options, try "man perltidy",
6389 or see https://metacpan.org/pod/distribution/Perl-Tidy/bin/perltidy
6390 EOF
6391
6392     return;
6393 } ## end sub usage
6394
6395 1;