use
5.008001;
local
$OUTPUT_AUTOFLUSH
= 1;
$VERSION
@ISA
@EXPORT
}
;
@ISA
=
qw( Exporter )
;
@EXPORT
=
qw( &perltidy )
;
_mode_
=> 2,
_uid_
=> 4,
_gid_
=> 5,
_atime_
=> 8,
_mtime_
=> 9,
};
BEGIN {
$VERSION
=
'20250311'
;
}
{
my
@unique_hash_keys_uu
=
qw( html-toc-extension html-src-extension * )
;
}
sub
DESTROY {
my
$self
=
shift
;
return
;
}
sub
AUTOLOAD {
our
$AUTOLOAD
;
return
if
(
$AUTOLOAD
=~ /\bDESTROY$/ );
my
(
$pkg
,
$fname
,
$lno
) =
caller
();
print
{
*STDERR
}
<<EOM;
======================================================================
Unexpected call to Autoload looking for sub $AUTOLOAD
Called from package: '$pkg'
Called from File '$fname' at line '$lno'
This error is probably due to a recent programming change
======================================================================
EOM
exit
1;
}
sub
streamhandle {
my
(
$filename
,
$mode
, (
$is_encoded_data
) ) =
@_
;
$mode
=
lc
(
$mode
);
if
(
$mode
ne
'w'
) {
if
( DEVEL_MODE ||
$mode
ne
'r'
) {
Fault(
"streamhandle called in unexpected mode '$mode'\n"
);
}
}
my
$ref
=
ref
(
$filename
);
my
$New
;
my
$fh
;
if
(
$ref
) {
if
(
$ref
eq
'ARRAY'
) {
$New
=
sub
{ Perl::Tidy::IOScalarArray->new(
$filename
,
$mode
) };
}
elsif
(
$ref
eq
'SCALAR'
) {
$New
=
sub
{ Perl::Tidy::IOScalar->new(
$filename
,
$mode
) };
}
else
{
if
(
$mode
eq
'r'
) {
if
(
$ref
->can(
'getline'
) ) {
$New
=
sub
{
$filename
};
}
else
{
$New
=
sub
{
undef
};
confess
<<EOM;
------------------------------------------------------------------------
No 'getline' method is defined for object of class '$ref'
Please check your call to Perl::Tidy::perltidy. Trace follows.
------------------------------------------------------------------------
EOM
}
}
if
(
$mode
eq
'w'
) {
if
(
$ref
->can(
'print'
) ) {
$New
=
sub
{
$filename
};
}
else
{
$New
=
sub
{
undef
};
confess
<<EOM;
------------------------------------------------------------------------
No 'print' method is defined for object of class '$ref'
Please check your call to Perl::Tidy::perltidy. Trace follows.
------------------------------------------------------------------------
EOM
}
}
}
}
else
{
if
(
$filename
eq
'-'
) {
$New
=
sub
{
$mode
eq
'w'
?
*STDOUT
:
*STDIN
}
}
else
{
$New
=
sub
{ IO::File->new(
$filename
,
$mode
) };
}
}
$fh
=
$New
->(
$filename
,
$mode
);
if
( !
$fh
) {
Warn(
"Couldn't open file:'$filename' in mode:$mode : $OS_ERROR\n"
);
}
else
{
if
(
ref
(
$fh
) eq
'IO::File'
) {
if
(
$is_encoded_data
) {
binmode
$fh
,
":raw:encoding(UTF-8)"
; }
else
{
binmode
$fh
}
}
elsif
(
$filename
eq
'-'
) {
if
(
$is_encoded_data
) {
binmode
STDOUT,
":raw:encoding(UTF-8)"
; }
else
{
binmode
STDOUT }
}
else
{
if
(DEVEL_MODE) {
my
$ref_fh
=
ref
(
$fh
);
Fault(
<<EOM);
unexpected streamhandle state for file='$filename' mode='$mode' ref(fh)=$ref_fh
EOM
}
}
}
return
$fh
;
}
sub
stream_slurp {
my
(
$filename
, (
$timeout_in_seconds
) ) =
@_
;
my
$ref
=
ref
(
$filename
);
my
$rinput_string
;
if
(
$ref
) {
if
(
$ref
eq
'ARRAY'
) {
my
$buf
=
join
EMPTY_STRING, @{
$filename
};
$rinput_string
= \
$buf
;
}
elsif
(
$ref
eq
'SCALAR'
) {
$rinput_string
=
$filename
;
}
else
{
if
(
$ref
->can(
'getline'
) ) {
my
$buf
= EMPTY_STRING;
while
(
defined
(
my
$line
=
$filename
->getline() ) ) {
$buf
.=
$line
;
}
$rinput_string
= \
$buf
;
}
else
{
confess
<<EOM;
------------------------------------------------------------------------
No 'getline' method is defined for object of class '$ref'
Please check your call to Perl::Tidy::perltidy. Trace follows.
------------------------------------------------------------------------
EOM
}
}
}
else
{
if
(
$filename
eq
'-'
) {
local
$INPUT_RECORD_SEPARATOR
=
undef
;
my
$buf
;
if
(
$timeout_in_seconds
&&
$timeout_in_seconds
> 0 ) {
eval
{
local
$SIG
{ALRM} =
sub
{
die
"alarm\n"
};
alarm
(
$timeout_in_seconds
);
$buf
= <>;
alarm
(0);
1;
}
or Die(
"Timeout reading stdin using -tos=$timeout_in_seconds seconds. Use -tos=0 to skip timeout check.\n"
);
}
else
{
$buf
= <>;
}
$rinput_string
= \
$buf
;
}
else
{
if
(
open
(
my
$fh
,
'<'
,
$filename
) ) {
local
$INPUT_RECORD_SEPARATOR
=
undef
;
my
$buf
= <
$fh
>;
$fh
->
close
() or Warn(
"Cannot close $filename\n"
);
$rinput_string
= \
$buf
;
}
else
{
Warn(
"Cannot open $filename: $OS_ERROR\n"
);
return
;
}
}
}
return
$rinput_string
;
}
{
my
$Warn_count
;
my
$fh_stderr
;
my
$loaded_unicode_gcstring
;
my
$rstatus
;
sub
Warn_count_bump {
$Warn_count
++;
return
}
sub
Warn_msg {
my
$msg
=
shift
;
$fh_stderr
->
print
(
$msg
);
return
}
sub
Warn {
my
$msg
=
shift
;
$fh_stderr
->
print
(
$msg
);
$Warn_count
++;
return
}
sub
is_char_mode {
my
(
$string
) =
@_
;
return
1
if
( utf8::is_utf8(
$string
) );
return
;
}
my
$md5_hex
=
sub
{
my
(
$buf
) =
@_
;
my
$octets
= Encode::encode(
"utf8"
,
$buf
);
my
$digest
= md5_hex(
$octets
);
return
$digest
;
};
sub
get_iteration_count {
return
$rstatus
->{iteration_count};
}
my
%is_known_markup_word
;
BEGIN {
my
@q
=
qw( ?xml !doctype !-- html meta )
;
@is_known_markup_word
{
@q
} = (1) x
scalar
(
@q
);
}
sub
is_not_perl {
my
(
$rinput_string
,
$input_file
,
$is_named_file
) =
@_
;
my
$text
;
if
( ${
$rinput_string
} =~ m/\s*\<\s*([\?\!]?[\-\w]+)/ ) {
$text
= $1 }
else
{
return
}
return
1
if
(
$is_known_markup_word
{
lc
(
$text
) } );
return
if
( !
$is_named_file
);
return
1
if
(
$input_file
=~ /html?$/i );
return
;
}
BEGIN {
my
$i
= 0;
_actual_output_extension_
=>
$i
++,
_debugfile_stream_
=>
$i
++,
_decoded_input_as_
=>
$i
++,
_destination_stream_
=>
$i
++,
_diagnostics_object_
=>
$i
++,
_display_name_
=>
$i
++,
_file_extension_separator_
=>
$i
++,
_fileroot_
=>
$i
++,
_is_encoded_data_
=>
$i
++,
_length_function_
=>
$i
++,
_line_separator_default_
=>
$i
++,
_line_separator_
=>
$i
++,
_line_tidy_begin_
=>
$i
++,
_line_tidy_end_
=>
$i
++,
_logger_object_
=>
$i
++,
_output_file_
=>
$i
++,
_postfilter_
=>
$i
++,
_prefilter_
=>
$i
++,
_rOpts_
=>
$i
++,
_saw_pbp_
=>
$i
++,
_teefile_stream_
=>
$i
++,
_user_formatter_
=>
$i
++,
_input_copied_verbatim_
=>
$i
++,
_input_output_difference_
=>
$i
++,
_dump_to_stdout_
=>
$i
++,
};
}
sub
perltidy {
my
%input_hash
=
@_
;
my
%defaults
= (
argv
=>
undef
,
destination
=>
undef
,
formatter
=>
undef
,
logfile
=>
undef
,
errorfile
=>
undef
,
teefile
=>
undef
,
debugfile
=>
undef
,
perltidyrc
=>
undef
,
source
=>
undef
,
stderr
=>
undef
,
dump_options
=>
undef
,
dump_options_type
=>
undef
,
dump_getopt_flags
=>
undef
,
dump_options_category
=>
undef
,
dump_abbreviations
=>
undef
,
prefilter
=>
undef
,
postfilter
=>
undef
,
);
$rstatus
= {
file_count
=> 0,
opt_format
=> EMPTY_STRING,
opt_encoding
=> EMPTY_STRING,
opt_encode_output
=> EMPTY_STRING,
opt_max_iterations
=> EMPTY_STRING,
input_name
=> EMPTY_STRING,
output_name
=> EMPTY_STRING,
char_mode_source
=> 0,
char_mode_used
=> 0,
input_decoded_as
=> EMPTY_STRING,
output_encoded_as
=> EMPTY_STRING,
gcs_used
=> 0,
iteration_count
=> 0,
converged
=> 0,
blinking
=> 0,
};
$Warn_count
= 0;
local
@ARGV
=
@ARGV
;
local
*STDERR
=
*STDERR
;
if
(
my
@bad_keys
=
grep
{ !
exists
$defaults
{
$_
} }
keys
%input_hash
) {
local
$LIST_SEPARATOR
=
')('
;
my
@good_keys
=
sort
keys
%defaults
;
@bad_keys
=
sort
@bad_keys
;
confess
<<EOM;
------------------------------------------------------------------------
Unknown perltidy parameter : (@bad_keys)
perltidy only understands : (@good_keys)
------------------------------------------------------------------------
EOM
}
my
$get_hash_ref
=
sub
{
my
(
$key
) =
@_
;
my
$hash_ref
=
$input_hash
{
$key
};
if
(
defined
(
$hash_ref
) ) {
if
(
ref
(
$hash_ref
) ne
'HASH'
) {
my
$what
=
ref
(
$hash_ref
);
my
$but_is
=
$what
?
"but is ref to $what"
:
"but is not a reference"
;
croak
<<EOM;
------------------------------------------------------------------------
error in call to perltidy:
-$key must be reference to HASH $but_is
------------------------------------------------------------------------
EOM
}
}
return
$hash_ref
;
};
%input_hash
= (
%defaults
,
%input_hash
);
my
$argv
=
$input_hash
{
'argv'
};
my
$destination_stream
=
$input_hash
{
'destination'
};
my
$perltidyrc_stream
=
$input_hash
{
'perltidyrc'
};
my
$source_stream
=
$input_hash
{
'source'
};
my
$stderr_stream
=
$input_hash
{
'stderr'
};
my
$user_formatter
=
$input_hash
{
'formatter'
};
my
$prefilter
=
$input_hash
{
'prefilter'
};
my
$postfilter
=
$input_hash
{
'postfilter'
};
if
(
$stderr_stream
) {
$fh_stderr
= Perl::Tidy::streamhandle(
$stderr_stream
,
'w'
);
if
( !
$fh_stderr
) {
croak
<<EOM;
------------------------------------------------------------------------
Unable to redirect STDERR to $stderr_stream
Please check value of -stderr in call to perltidy
------------------------------------------------------------------------
EOM
}
}
else
{
$fh_stderr
=
*STDERR
;
}
my
$self
= [];
bless
$self
, __PACKAGE__;
sub
Exit {
my
$flag
=
shift
;
if
(
$flag
) {
goto
ERROR_EXIT }
else
{
goto
NORMAL_EXIT }
croak
"unexpected return to sub Exit"
;
}
sub
Die {
my
$msg
=
shift
;
Warn(
$msg
);
Exit(1);
croak
"unexpected return from sub Exit"
;
}
sub
Fault {
my
(
$msg
) =
@_
;
my
(
$package0_uu
,
$filename0_uu
,
$line0
,
$subroutine0_uu
) =
caller
(0);
my
(
$package1_uu
,
$filename1
,
$line1
,
$subroutine1
) =
caller
(1);
my
(
$package2_uu
,
$filename2_uu
,
$line2_uu
,
$subroutine2
) =
caller
(2);
my
$pkg
= __PACKAGE__;
my
$input_stream_name
=
$rstatus
->{
'input_name'
};
$input_stream_name
=
'(unknown)'
unless
(
$input_stream_name
);
Die(
<<EOM);
==============================================================================
While operating on input stream with name: '$input_stream_name'
A fault was detected at line $line0 of sub '$subroutine1'
in file '$filename1'
which was called from line $line1 of sub '$subroutine2'
Message: '$msg'
This is probably an error introduced by a recent programming change.
$pkg reports VERSION='$VERSION'.
==============================================================================
EOM
croak
"unexpected return from sub Die"
;
}
my
$dump_options_type
=
$input_hash
{
'dump_options_type'
};
my
$dump_options
=
$get_hash_ref
->(
'dump_options'
);
my
$dump_getopt_flags
=
$get_hash_ref
->(
'dump_getopt_flags'
);
my
$dump_options_category
=
$get_hash_ref
->(
'dump_options_category'
);
my
$dump_abbreviations
=
$get_hash_ref
->(
'dump_abbreviations'
);
if
(
defined
(
$dump_options
) ) {
if
( !
defined
(
$dump_options_type
) ) {
$dump_options_type
=
'perltidyrc'
;
}
if
(
$dump_options_type
ne
'perltidyrc'
&&
$dump_options_type
ne
'full'
)
{
croak
<<EOM;
------------------------------------------------------------------------
Please check value of -dump_options_type in call to perltidy;
saw: '$dump_options_type'
expecting: 'perltidyrc' or 'full'
------------------------------------------------------------------------
EOM
}
}
else
{
$dump_options_type
= EMPTY_STRING;
}
if
(
$user_formatter
) {
$destination_stream
= \
my
$tmp
;
}
if
(
defined
(
$argv
) ) {
my
$rargv
=
ref
(
$argv
);
if
(
$rargv
eq
'SCALAR'
) {
$argv
= ${
$argv
};
$rargv
=
undef
}
if
(
$rargv
) {
if
(
$rargv
eq
'ARRAY'
) {
@ARGV
= @{
$argv
};
}
else
{
croak
<<EOM;
------------------------------------------------------------------------
Please check value of -argv in call to perltidy;
it must be a string or ref to ARRAY but is: $rargv
------------------------------------------------------------------------
EOM
}
}
else
{
my
(
$rargv_str
,
$msg
) = parse_args(
$argv
);
if
(
$msg
) {
Die(
<<EOM);
Error parsing this string passed to to perltidy with 'argv':
$msg
EOM
}
@ARGV
= @{
$rargv_str
};
}
}
my
$rpending_complaint
;
${
$rpending_complaint
} = EMPTY_STRING;
my
$rpending_logfile_message
;
${
$rpending_logfile_message
} = EMPTY_STRING;
my
(
$is_Windows
,
$Windows_type
) = look_for_Windows(
$rpending_complaint
);
my
$dot
;
my
$dot_pattern
;
if
(
$OSNAME
eq
'VMS'
) {
$dot
=
'_'
;
$dot_pattern
=
'_'
;
}
else
{
$dot
=
'.'
;
$dot_pattern
=
'\.'
;
}
$self
->[_file_extension_separator_] =
$dot
;
my
@ARGV_saved
;
if
(
@ARGV
> 1 ) {
@ARGV_saved
= (
$ARGV
[-2],
$ARGV
[-1] );
}
my
$wvt_in_args
=
grep
{ /-(wvt|
warn
-variable-types)=/ }
@ARGV
;
my
(
$rOpts
,
$config_file
,
$rraw_options
,
$roption_string
,
$rexpansion
,
$roption_category
,
$rinteger_option_range
)
= process_command_line(
$perltidyrc_stream
,
$is_Windows
,
$Windows_type
,
$rpending_complaint
,
$dump_options_type
,
);
my
@Arg_files
=
@ARGV
;
$self
->[_rOpts_] =
$rOpts
;
my
$saw_pbp
=
grep
{
$_
eq
'-pbp'
||
$_
eq
'-perl-best-practices'
} @{
$rraw_options
};
$self
->[_saw_pbp_] =
$saw_pbp
;
my
$quit_now
= 0;
if
(
defined
(
$dump_getopt_flags
) ) {
$quit_now
= 1;
foreach
my
$op
( @{
$roption_string
} ) {
my
$opt
=
$op
;
my
$flag
= EMPTY_STRING;
if
(
$opt
=~ /(.*)(!|=.*|:.*)$/ ) {
$opt
= $1;
$flag
= $2;
}
$dump_getopt_flags
->{
$opt
} =
$flag
;
}
}
if
(
defined
(
$dump_options_category
) ) {
$quit_now
= 1;
%{
$dump_options_category
} = %{
$roption_category
};
}
if
(
defined
(
$dump_abbreviations
) ) {
$quit_now
= 1;
%{
$dump_abbreviations
} = %{
$rexpansion
};
}
if
(
defined
(
$dump_options
) ) {
$quit_now
= 1;
%{
$dump_options
} = %{
$rOpts
};
}
Exit(0)
if
(
$quit_now
);
my
$readable_options
= readable_options(
$rOpts
,
$roption_string
);
if
(
$rOpts
->{
'dump-options'
} ) {
print
{
*STDOUT
}
$readable_options
;
Exit(0);
}
my
$num_files
=
@Arg_files
;
foreach
my
$opt_name
(
qw(
dump-block-summary
dump-unusual-variables
dump-mixed-call-parens
dump-mismatched-args
dump-mismatched-returns
dump-unique-keys
dump-hash-keys
dump-similar-keys
)
)
{
if
(
$rOpts
->{
$opt_name
} ) {
$self
->[_dump_to_stdout_] = 1;
if
(
$num_files
!= 1 ) {
Die(
<<EOM);
--$opt_name expects 1 filename in the arg list but saw $num_files filenames
EOM
}
}
}
$self
->check_options(
$num_files
,
$rinteger_option_range
);
if
(
$user_formatter
) {
$rOpts
->{
'format'
} =
'user'
;
}
my
%default_file_extension
= (
tidy
=>
'tdy'
,
html
=>
'html'
,
user
=> EMPTY_STRING,
);
$rstatus
->{
'opt_format'
} =
$rOpts
->{
'format'
};
$rstatus
->{
'opt_max_iterations'
} =
$rOpts
->{
'iterations'
};
$rstatus
->{
'opt_encode_output'
} =
$rOpts
->{
'encode-output-strings'
} ?
'eos'
:
'neos'
;
if
( !
exists
$default_file_extension
{
$rOpts
->{
'format'
} } ) {
my
$formats
=
join
SPACE,
sort
map
{
"'"
.
$_
.
"'"
}
keys
%default_file_extension
;
my
$fmt
=
$rOpts
->{
'format'
};
Die(
"-format='$fmt' but must be one of: $formats\n"
);
}
my
$output_extension
=
$self
->make_file_extension(
$rOpts
->{
'output-file-extension'
},
$default_file_extension
{
$rOpts
->{
'format'
} } );
my
(
$in_place_modify
,
$backup_extension
,
$delete_backup
) =
$self
->check_in_place_modify(
$source_stream
,
$destination_stream
);
my
$line_range_clipped
=
$rOpts
->{
'line-range-tidy'
}
&& (
$self
->[_line_tidy_begin_] > 1
||
defined
(
$self
->[_line_tidy_end_] ) );
Perl::Tidy::Formatter::check_options(
$rOpts
,
$wvt_in_args
,
$num_files
,
$line_range_clipped
);
Perl::Tidy::Tokenizer::check_options(
$rOpts
);
Perl::Tidy::VerticalAligner::check_options(
$rOpts
);
if
(
$rOpts
->{
'format'
} eq
'html'
) {
Perl::Tidy::HtmlWriter->check_options(
$rOpts
);
}
if
( !
$num_files
&&
@ARGV_saved
> 1 ) {
my
$opt_test
=
$ARGV_saved
[-2];
my
$file_test
=
$ARGV_saved
[-1];
if
(
$opt_test
=~ s/^[-]+//
&&
$file_test
!~ /^[-]/
&&
$file_test
!~ /^\d+$/
&& -e
$file_test
)
{
my
%is_option_with_file_parameter
;
my
@qf
=
qw( outfile profile )
;
@is_option_with_file_parameter
{
@qf
} = (1) x
scalar
(
@qf
);
my
$long_name
;
my
$exp
=
$rexpansion
->{
$opt_test
};
if
( !
$exp
) {
$long_name
=
$opt_test
}
elsif
( @{
$exp
} == 1 ) {
$long_name
=
$exp
->[0] }
else
{ }
if
(
$long_name
&&
defined
(
$rOpts
->{
$long_name
} )
&&
$rOpts
->{
$long_name
} eq
$file_test
&& !
$is_option_with_file_parameter
{
$long_name
} )
{
Die(
<<EOM);
Stopping on possible missing string parameter for '-$opt_test':
This parameter takes a string and has been set equal to file '$file_test',
and formatted output will go to standard output. If this is actually correct,
you can skip this message by entering this as '-$opt_test=$file_test'.
EOM
}
}
}
my
$forbidden_file_extensions
=
"(($dot_pattern)(LOG|DEBUG|ERR|TEE)"
;
if
(
$output_extension
) {
my
$ext
=
quotemeta
(
$output_extension
);
$forbidden_file_extensions
.=
"|$ext"
;
}
if
(
$in_place_modify
&&
$backup_extension
) {
my
$ext
=
quotemeta
(
$backup_extension
);
$forbidden_file_extensions
.=
"|$ext"
;
}
$forbidden_file_extensions
.=
')$'
;
my
$diagnostics_object
=
undef
;
if
(DIAGNOSTICS) {
$diagnostics_object
= Perl::Tidy::Diagnostics->new();
}
if
(
$source_stream
) {
if
(
@Arg_files
> 0 ) {
Die(
"You may not specify any filenames when a source array is given\n"
);
}
unshift
(
@Arg_files
,
$source_stream
);
$source_stream
=
undef
unless
(
ref
(
$source_stream
) );
}
elsif
( !
@Arg_files
) {
unshift
(
@Arg_files
,
'-'
);
}
else
{
my
@updated_files
;
foreach
my
$input_file
(
@Arg_files
) {
if
( -e
$input_file
) {
push
@updated_files
,
$input_file
;
}
else
{
if
(
$input_file
=~ /([\?\*\[\{])/ ) {
my
$ifile
=
$input_file
;
if
(
$ifile
=~ /^\'(.+)\'$/ ) {
$ifile
= $1 }
if
(
$ifile
=~ /^\"(.+)\"$/ ) {
$ifile
= $1 }
my
$pattern
= fileglob_to_re(
$ifile
);
my
$dh
;
if
(
opendir
(
$dh
,
'./'
) ) {
my
@files
=
grep
{ /
$pattern
/ && !-d }
readdir
(
$dh
);
closedir
(
$dh
);
next
unless
(
@files
);
push
@updated_files
,
@files
;
next
;
}
}
Warn(
"skipping file: '$input_file': no matches found\n"
);
next
;
}
}
@Arg_files
=
@updated_files
;
if
( !
@Arg_files
) {
Die(
"no matching input files found\n"
);
}
}
if
( !
$rOpts
->{
'use-unicode-gcstring'
} ) {
$loaded_unicode_gcstring
= 0;
}
if
(
@Arg_files
> 1 ) {
my
%seen
= ();
@Arg_files
=
grep
{ !
$seen
{
$_
}++ }
@Arg_files
;
}
if
(
@Arg_files
> 1 &&
$rOpts
->{
'file-size-order'
} ) {
@Arg_files
=
map
{
$_
->[0] }
sort
{
$a
->[1] <=>
$b
->[1] }
map
{ [
$_
, -e
$_
? -s
$_
: 0 ] }
@Arg_files
;
}
my
$logfile_header
= make_logfile_header(
$rOpts
,
$config_file
,
$rraw_options
,
$Windows_type
,
$readable_options
);
$self
->[_diagnostics_object_] =
$diagnostics_object
;
$self
->[_postfilter_] =
$postfilter
;
$self
->[_prefilter_] =
$prefilter
;
$self
->[_user_formatter_] =
$user_formatter
;
$self
->process_all_files(
{
rinput_hash
=> \
%input_hash
,
rfiles
=> \
@Arg_files
,
line_range_clipped
=>
$line_range_clipped
,
source_stream
=>
$source_stream
,
output_extension
=>
$output_extension
,
forbidden_file_extensions
=>
$forbidden_file_extensions
,
in_place_modify
=>
$in_place_modify
,
backup_extension
=>
$backup_extension
,
delete_backup
=>
$delete_backup
,
logfile_header
=>
$logfile_header
,
rpending_complaint
=>
$rpending_complaint
,
rpending_logfile_message
=>
$rpending_logfile_message
,
}
);
NORMAL_EXIT:
my
$ret
=
$Warn_count
? 2 : 0;
return
wantarray
? (
$ret
,
$rstatus
) :
$ret
;
ERROR_EXIT:
return
wantarray
? ( 1,
$rstatus
) : 1;
}
sub
make_file_extension {
my
(
$self
,
$extension
, (
$default
) ) =
@_
;
$extension
= EMPTY_STRING
unless
(
defined
(
$extension
) );
$extension
=~ s/^\s+//;
$extension
=~ s/\s+$//;
if
(
length
(
$extension
) == 0 ) {
$extension
=
$default
;
$extension
= EMPTY_STRING
unless
(
defined
(
$extension
) );
$extension
=~ s/^\s+//;
$extension
=~ s/\s+$//;
}
if
(
$extension
=~ /^[a-zA-Z0-9]/ ) {
my
$dot
=
$self
->[_file_extension_separator_];
$extension
=
$dot
.
$extension
;
}
return
$extension
;
}
sub
check_in_place_modify {
my
(
$self
,
$source_stream
,
$destination_stream
) =
@_
;
my
$rOpts
=
$self
->[_rOpts_];
my
$in_place_modify
=
$rOpts
->{
'backup-and-modify-in-place'
}
&&
$rOpts
->{
'format'
} eq
'tidy'
;
my
(
$backup_extension
,
$delete_backup
);
if
(
$in_place_modify
) {
if
(
$rOpts
->{
'standard-output'
}
||
$destination_stream
||
ref
(
$source_stream
)
||
$rOpts
->{
'outfile'
}
||
defined
(
$rOpts
->{
'output-path'
} ) )
{
$in_place_modify
= 0;
}
}
if
(
$in_place_modify
) {
my
$bext
=
$rOpts
->{
'backup-file-extension'
};
$delete_backup
= (
$rOpts
->{
'backup-file-extension'
} =~ s/\///g );
if
(
$delete_backup
> 1 ) {
Die(
"-bext=$bext contains more than one '/'\n"
);
}
$backup_extension
=
$self
->make_file_extension(
$rOpts
->{
'backup-file-extension'
},
'bak'
);
}
my
$backup_method
=
$rOpts
->{
'backup-method'
};
if
(
defined
(
$backup_method
)
&&
$backup_method
ne
'copy'
&&
$backup_method
ne
'move'
)
{
Die(
"Unexpected --backup-method='$backup_method'; must be one of: 'move', 'copy'\n"
);
}
return
(
$in_place_modify
,
$backup_extension
,
$delete_backup
);
}
sub
backup_method_copy {
my
(
$self
,
$input_file
,
$routput_string
,
$backup_extension
,
$delete_backup
)
=
@_
;
my
$backup_file
=
$input_file
.
$backup_extension
;
if
( !-f
$input_file
) {
Die(
"problem with -b backing up input file '$input_file': not a file\n"
);
}
if
( -f
$backup_file
) {
unlink
(
$backup_file
)
or Die(
"unable to remove previous '$backup_file' for -b option; check permissions: $OS_ERROR\n"
);
}
File::Copy::copy(
$input_file
,
$backup_file
)
or Die(
"File::Copy failed trying to backup source: $OS_ERROR"
);
my
@input_file_stat
=
stat
(
$input_file
);
my
$in_place_modify
= 1;
$self
->set_output_file_permissions(
$backup_file
, \
@input_file_stat
,
$in_place_modify
);
my
(
$read_time
,
$write_time
) =
@input_file_stat
[ _atime_, _mtime_ ];
if
(
defined
(
$write_time
) ) {
utime
(
$read_time
,
$write_time
,
$backup_file
)
|| Warn(
"error setting times for backup file '$backup_file'\n"
);
}
open
(
my
$fout
,
">"
,
$input_file
)
or Die(
"problem re-opening $input_file for write for -b option; check file and directory permissions: $OS_ERROR\n"
);
if
(
$self
->[_is_encoded_data_] ) {
binmode
$fout
,
":raw:encoding(UTF-8)"
}
else
{
binmode
$fout
}
if
(
ref
(
$routput_string
) eq
'SCALAR'
) {
$fout
->
print
( ${
$routput_string
} )
or Die(
"cannot print to '$input_file' with -b option: $OS_ERROR\n"
);
}
else
{
my
$ref
=
ref
(
$routput_string
);
Die(
<<EOM);
Programming error: unable to print to '$input_file' with -b option:
unexpected ref type '$ref'; expecting 'ARRAY' or 'SCALAR'
EOM
}
$fout
->
close
()
or Die(
"cannot close '$input_file' with -b option: $OS_ERROR\n"
);
$self
->set_output_file_permissions(
$input_file
, \
@input_file_stat
,
$in_place_modify
);
if
( !
$self
->[_input_output_difference_] &&
defined
(
$write_time
) ) {
utime
(
$read_time
,
$write_time
,
$input_file
)
|| Warn(
"error setting times for '$input_file'\n"
);
}
if
(
$delete_backup
&& -f
$backup_file
) {
if
(
$delete_backup
> 1
&&
$self
->[_logger_object_]->get_warning_count() )
{
$delete_backup
= 1;
}
if
( !-s
$input_file
&& -s
$backup_file
&&
$delete_backup
== 1 ) {
Warn(
"output file '$input_file' missing or zero length; original '$backup_file' not deleted\n"
);
}
else
{
unlink
(
$backup_file
)
or Die(
"unable to remove backup file '$backup_file' for -b option; check permissions: $OS_ERROR\n"
);
}
}
if
(DEVEL_MODE) {
my
@output_file_stat
=
stat
(
$input_file
);
my
$inode_input
=
$input_file_stat
[1];
my
$inode_output
=
$output_file_stat
[1];
if
(
$inode_input
!=
$inode_output
) {
Fault(
<<EOM);
inode changed with -bm=copy for file '$input_file': inode_input=$inode_input inode_output=$inode_output
EOM
}
}
return
;
}
sub
backup_method_move {
my
(
$self
,
$input_file
,
$routput_string
,
$backup_extension
,
$delete_backup
)
=
@_
;
my
$backup_name
=
$input_file
.
$backup_extension
;
if
( !-f
$input_file
) {
Die(
"problem with -b backing up input file '$input_file': not a file\n"
);
}
if
( -f
$backup_name
) {
unlink
(
$backup_name
)
or Die(
"unable to remove previous '$backup_name' for -b option; check permissions: $OS_ERROR\n"
);
}
my
@input_file_stat
=
stat
(
$input_file
);
if
( -l
$input_file
) {
File::Copy::copy(
$input_file
,
$backup_name
)
or Die(
"File::Copy failed trying to backup source: $OS_ERROR"
);
}
else
{
rename
(
$input_file
,
$backup_name
)
or Die(
"problem renaming $input_file to $backup_name for -b option: $OS_ERROR\n"
);
}
open
(
my
$fout
,
">"
,
$input_file
)
or Die(
"problem re-opening $input_file for write for -b option; check file and directory permissions: $OS_ERROR\n"
);
if
(
$self
->[_is_encoded_data_] ) {
binmode
$fout
,
":raw:encoding(UTF-8)"
}
else
{
binmode
$fout
}
if
(
ref
(
$routput_string
) eq
'SCALAR'
) {
$fout
->
print
( ${
$routput_string
} )
or Die(
"cannot print to '$input_file' with -b option: $OS_ERROR\n"
);
}
else
{
my
$ref
=
ref
(
$routput_string
);
Die(
<<EOM);
Programming error: unable to print to '$input_file' with -b option:
unexpected ref type '$ref'; expecting 'ARRAY' or 'SCALAR'
EOM
}
$fout
->
close
()
or Die(
"cannot close '$input_file' with -b option: $OS_ERROR\n"
);
my
$in_place_modify
= 1;
$self
->set_output_file_permissions(
$input_file
, \
@input_file_stat
,
$in_place_modify
);
my
(
$read_time
,
$write_time
) =
@input_file_stat
[ _atime_, _mtime_ ];
if
( !
$self
->[_input_output_difference_] &&
defined
(
$write_time
) ) {
utime
(
$read_time
,
$write_time
,
$input_file
)
|| Warn(
"error setting times for '$input_file'\n"
);
}
if
(
$delete_backup
&& -f
$backup_name
) {
if
(
$delete_backup
> 1
&&
$self
->[_logger_object_]->get_warning_count() )
{
$delete_backup
= 1;
}
if
( !-s
$input_file
&& -s
$backup_name
&&
$delete_backup
== 1 ) {
Warn(
"output file '$input_file' missing or zero length; original '$backup_name' not deleted\n"
);
}
else
{
unlink
(
$backup_name
)
or Die(
"unable to remove previous '$backup_name' for -b option; check permissions: $OS_ERROR\n"
);
}
}
return
;
}
sub
set_output_file_permissions {
my
(
$self
,
$output_file
,
$rinput_file_stat
,
$in_place_modify
) =
@_
;
my
(
$mode_i
,
$uid_i
,
$gid_i
) =
@{
$rinput_file_stat
}[ _mode_, _uid_, _gid_ ];
my
(
$uid_o
,
$gid_o
) = (
stat
(
$output_file
) )[ _uid_, _gid_ ];
my
$input_file_permissions
=
$mode_i
& OCT_7777;
my
$output_file_permissions
=
$input_file_permissions
;
if
(
$uid_i
!=
$uid_o
||
$gid_i
!=
$gid_o
) {
if
(
$in_place_modify
&&
chown
(
$uid_i
,
$gid_i
,
$output_file
) )
{
}
else
{
$output_file_permissions
=
$mode_i
& OCT_777;
if
(
$input_file_permissions
!=
$output_file_permissions
) {
Warn(
"Unable to copy setuid and/or setgid bits for output file '$output_file'\n"
);
}
}
}
if
( !
$in_place_modify
) {
$output_file_permissions
|= OCT_600;
}
if
( !
chmod
(
$output_file_permissions
,
$output_file
) ) {
my
$operm
=
sprintf
(
"%04o"
,
$output_file_permissions
);
Warn(
"Unable to set permissions for output file '$output_file' to $operm\n"
);
}
return
;
}
sub
get_decoded_string_buffer {
my
(
$self
,
$input_file
,
$display_name
) =
@_
;
my
$rOpts
=
$self
->[_rOpts_];
my
$rinput_string
=
stream_slurp(
$input_file
,
$rOpts
->{
'timeout-in-seconds'
} );
return
unless
(
defined
(
$rinput_string
) );
if
( !
length
( ${
$rinput_string
} ) ) {
}
if
(
$input_file
eq
'-'
) {
my
$size_in_mb
=
length
( ${
$rinput_string
} ) / ( CONST_1024 * CONST_1024 );
my
$maximum_file_size_mb
=
$rOpts
->{
'maximum-file-size-mb'
};
if
(
$size_in_mb
>
$maximum_file_size_mb
) {
$size_in_mb
=
sprintf
(
"%0.1f"
,
$size_in_mb
);
Warn(
"skipping file: <stdin>: size $size_in_mb MB exceeds limit $maximum_file_size_mb; use -maxfs=i to change\n"
);
return
;
}
}
$rinput_string
=
$self
->set_line_separator(
$rinput_string
);
my
$encoding_in
= EMPTY_STRING;
my
$rOpts_character_encoding
=
$rOpts
->{
'character-encoding'
};
my
$encoding_log_message
;
my
$decoded_input_as
= EMPTY_STRING;
$rstatus
->{
'char_mode_source'
} = 0;
if
( is_char_mode( ${
$rinput_string
} ) ) {
$encoding_in
=
"utf8"
;
$rstatus
->{
'char_mode_source'
} = 1;
}
elsif
( !
$rOpts_character_encoding
||
$rOpts_character_encoding
eq
'none'
)
{
}
elsif
(
lc
(
$rOpts_character_encoding
) eq
'guess'
) {
my
$decoder
;
if
( ${
$rinput_string
} =~ /[^[:ascii:]]/ ) {
$decoder
= guess_encoding( ${
$rinput_string
},
'utf8'
);
}
if
(
$decoder
&&
ref
(
$decoder
) ) {
$encoding_in
=
$decoder
->name;
if
(
$encoding_in
ne
'UTF-8'
&&
$encoding_in
ne
'utf8'
) {
$encoding_in
= EMPTY_STRING;
$encoding_log_message
.=
<<EOM;
Guessed encoding '$encoding_in' is not utf8; no encoding will be used
EOM
}
else
{
my
$buf
;
if
( !
eval
{
$buf
=
$decoder
->decode( ${
$rinput_string
} ); 1 } )
{
$encoding_log_message
.=
<<EOM;
Guessed encoding '$encoding_in' but decoding was unsuccessful; no encoding is used
EOM
Warn(
"file: $display_name: bad guess to decode source as $encoding_in\n"
);
$encoding_in
= EMPTY_STRING;
}
else
{
$encoding_log_message
.=
<<EOM;
Guessed encoding '$encoding_in' successfully decoded
EOM
$decoded_input_as
=
$encoding_in
;
$rinput_string
= \
$buf
;
}
}
}
else
{
$encoding_log_message
.=
<<EOM;
Does not look like utf8 encoded text so processing as raw bytes
EOM
}
}
else
{
$encoding_in
=
$rOpts_character_encoding
;
my
$buf
;
if
(
!
eval
{
$buf
= Encode::decode(
$encoding_in
, ${
$rinput_string
},
Encode::FB_CROAK | Encode::LEAVE_SRC );
1;
}
)
{
Warn(
"skipping file: $display_name: Unable to decode source as $encoding_in\n"
);
return
;
}
else
{
$encoding_log_message
.=
<<EOM;
Specified encoding '$encoding_in' successfully decoded
EOM
$decoded_input_as
=
$encoding_in
;
$rinput_string
= \
$buf
;
}
}
my
$is_encoded_data
=
$encoding_in
?
'utf8'
: EMPTY_STRING;
$self
->[_is_encoded_data_] =
$is_encoded_data
;
if
(
$is_encoded_data
) {
${
$rinput_string
} =~ s/^\x{FEFF}//;
}
$rstatus
->{
'input_name'
} =
$display_name
;
$rstatus
->{
'opt_encoding'
} =
$rOpts_character_encoding
;
$rstatus
->{
'char_mode_used'
} =
$encoding_in
? 1 : 0;
$rstatus
->{
'input_decoded_as'
} =
$decoded_input_as
;
my
$length_function
;
if
(
$is_encoded_data
) {
if
( !
defined
(
$loaded_unicode_gcstring
) ) {
$loaded_unicode_gcstring
= 1;
}
else
{
$loaded_unicode_gcstring
= 0;
if
(
$rOpts
->{
'use-unicode-gcstring'
} ) {
Warn(
<<EOM);
----------------------
Unable to load Unicode::GCString: $EVAL_ERROR
Processing continues but some vertical alignment may be poor
To prevent this warning message, you can either:
- install module Unicode::GCString, or
- remove '--use-unicode-gcstring' or '-gcs' from your perltidyrc or command line
----------------------
EOM
}
}
}
if
(
$loaded_unicode_gcstring
) {
$length_function
=
sub
{
return
Unicode::GCString->new(
$_
[0] )->columns;
};
$encoding_log_message
.=
<<EOM;
Using 'Unicode::GCString' to measure horizontal character widths
EOM
$rstatus
->{
'gcs_used'
} = 1;
}
}
return
(
$rinput_string
,
$is_encoded_data
,
$decoded_input_as
,
$encoding_log_message
,
$length_function
,
);
}
{
my
$LF
;
my
$CR
;
my
$CRLF
;
BEGIN {
$LF
=
chr
(10);
$CR
=
chr
(13);
$CRLF
=
$CR
.
$LF
;
}
sub
get_line_separator_default {
my
(
$rOpts
) =
@_
;
my
$line_separator_default
=
"\n"
;
my
$ole
=
$rOpts
->{
'output-line-ending'
};
if
(
$ole
) {
my
%endings
= (
dos
=>
$CRLF
,
win
=>
$CRLF
,
mac
=>
$CR
,
unix
=>
$LF
,
);
$line_separator_default
=
$endings
{
lc
(
$ole
) };
if
( !
$line_separator_default
) {
my
$str
=
join
SPACE,
keys
%endings
;
Die(
<<EOM);
Unrecognized line ending '$ole'; expecting one of: $str
EOM
}
if
(
$rOpts
->{
'preserve-line-endings'
} ) {
Warn(
"Ignoring -ple; conflicts with -ole\n"
);
$rOpts
->{
'preserve-line-endings'
} =
undef
;
}
}
return
$line_separator_default
;
}
sub
set_line_separator {
my
(
$self
,
$rinput_string
) =
@_
;
my
$rOpts
=
$self
->[_rOpts_];
my
$line_separator
=
$self
->[_line_separator_default_];
my
$input_line_separator
;
my
$str
=
substr
( ${
$rinput_string
}, 0, CONST_1024 );
if
(
$str
) {
if
(
$str
=~ m/((
$CR
|
$LF
)+)/ ) {
my
$test
= $1;
if
(
$test
=~ /^(
$CRLF
)+\z/ ) {
$input_line_separator
=
$CRLF
;
}
elsif
(
$test
=~ /^(
$CR
)+\z/ ) {
$input_line_separator
=
$CR
;
}
elsif
(
$test
=~ /^(
$LF
)+\z/ ) {
$input_line_separator
=
$LF
;
}
else
{ }
}
else
{ }
}
if
(
defined
(
$input_line_separator
) ) {
if
(
$rOpts
->{
'preserve-line-endings'
} ) {
$line_separator
=
$input_line_separator
;
}
if
(
$input_line_separator
ne
"\n"
) {
my
@lines
=
split
/^/, ${
$rinput_string
};
if
(
$input_line_separator
eq
$CR
) {
if
(
@lines
== 1 ) {
@lines
=
map
{
$_
.
"\n"
}
split
/
$CR
/, ${
$rinput_string
};
if
(
@lines
> 1 ) {
my
$buf
=
join
EMPTY_STRING,
@lines
;
$rinput_string
= \
$buf
;
}
}
}
elsif
( (
$input_line_separator
eq
$CRLF
) && (
"\n"
eq
$LF
) ) {
foreach
my
$line
(
@lines
) {
$line
=~ s/
$CRLF
$/\n/ }
my
$buf
=
join
EMPTY_STRING,
@lines
;
$rinput_string
= \
$buf
;
}
else
{
}
}
}
$self
->[_line_separator_] =
$line_separator
;
return
$rinput_string
;
}
}
sub
process_all_files {
my
(
$self
,
$rcall_hash
) =
@_
;
my
$rinput_hash
=
$rcall_hash
->{rinput_hash};
my
$rfiles
=
$rcall_hash
->{rfiles};
my
$line_range_clipped
=
$rcall_hash
->{line_range_clipped};
my
$source_stream
=
$rcall_hash
->{source_stream};
my
$output_extension
=
$rcall_hash
->{output_extension};
my
$forbidden_file_extensions
=
$rcall_hash
->{forbidden_file_extensions};
my
$in_place_modify
=
$rcall_hash
->{in_place_modify};
my
$backup_extension
=
$rcall_hash
->{backup_extension};
my
$delete_backup
=
$rcall_hash
->{delete_backup};
my
$logfile_header
=
$rcall_hash
->{logfile_header};
my
$rpending_complaint
=
$rcall_hash
->{rpending_complaint};
my
$rpending_logfile_message
=
$rcall_hash
->{rpending_logfile_message};
my
$rOpts
=
$self
->[_rOpts_];
my
$dot
=
$self
->[_file_extension_separator_];
my
$diagnostics_object
=
$self
->[_diagnostics_object_];
my
$destination_stream
=
$rinput_hash
->{
'destination'
};
my
$errorfile_stream
=
$rinput_hash
->{
'errorfile'
};
my
$logfile_stream
=
$rinput_hash
->{
'logfile'
};
my
$teefile_stream
=
$rinput_hash
->{
'teefile'
};
my
$debugfile_stream
=
$rinput_hash
->{
'debugfile'
};
my
$number_of_files
= @{
$rfiles
};
foreach
my
$input_file
( @{
$rfiles
} ) {
my
$fileroot
;
my
@input_file_stat
;
my
$display_name
;
if
(
$source_stream
) {
$fileroot
=
"perltidy"
;
$display_name
=
"<source_stream>"
;
if
( !
defined
(
$logfile_stream
) ) {
$logfile_stream
= \
my
$tmp
;
}
if
( !
defined
(
$teefile_stream
) ) {
$teefile_stream
= \
my
$tmp
;
}
if
( !
defined
(
$debugfile_stream
) ) {
$debugfile_stream
= \
my
$tmp
;
}
}
elsif
(
$input_file
eq
'-'
) {
$fileroot
=
"perltidy"
;
$display_name
=
"<stdin>"
;
$in_place_modify
= 0;
}
else
{
$fileroot
=
$input_file
;
$display_name
=
$input_file
;
if
( !-e
$input_file
) {
Warn(
"skipping file: '$input_file': no matches found\n"
);
next
;
}
if
( !-f
$input_file
) {
Warn(
"skipping file: $input_file: not a regular file\n"
);
next
;
}
if
( !-s
$input_file
) {
Warn(
"skipping file: $input_file: Zero size\n"
);
next
;
}
my
$size_in_mb
= ( -s
$input_file
) / ( CONST_1024 * CONST_1024 );
my
$maximum_file_size_mb
=
$rOpts
->{
'maximum-file-size-mb'
};
if
(
$size_in_mb
>
$maximum_file_size_mb
) {
$size_in_mb
=
sprintf
(
"%0.1f"
,
$size_in_mb
);
Warn(
"skipping file: $input_file: size $size_in_mb MB exceeds limit $maximum_file_size_mb; use -maxfs=i to change\n"
);
next
;
}
if
( !-T
$input_file
&& !
$rOpts
->{
'force-read-binary'
} ) {
Warn(
"skipping file: $input_file: Non-text (override with -f)\n"
);
next
;
}
if
(
$in_place_modify
&& !-w
$input_file
) {
my
$backup_method
=
$rOpts
->{
'backup-method'
};
if
(
defined
(
$backup_method
) &&
$backup_method
eq
'copy'
) {
Warn(
"skipping file '$input_file' for -b option: file reported as non-writable\n"
);
next
;
}
}
$fileroot
=
$input_file
;
@input_file_stat
=
stat
(
$input_file
);
if
(
$OSNAME
eq
'VMS'
) {
(
$fileroot
,
$dot
) = check_vms_filename(
$fileroot
);
$self
->[_file_extension_separator_] =
$dot
;
}
if
(
defined
(
$rOpts
->{
'output-path'
} ) ) {
my
(
$base
,
$old_path_uu
) = fileparse(
$fileroot
);
my
$new_path
=
$rOpts
->{
'output-path'
};
if
( !-d
$new_path
) {
mkdir
(
$new_path
)
or
Die(
"unable to create directory $new_path: $OS_ERROR\n"
);
}
my
$path
=
$new_path
;
$fileroot
= File::Spec->catfile(
$path
,
$base
);
if
( !
$fileroot
) {
Die(
<<EOM);
------------------------------------------------------------------------
Problem combining $new_path and $base to make a filename; check -opath
------------------------------------------------------------------------
EOM
}
}
}
if
(
!
$source_stream
&& (
$input_file
=~ /
$forbidden_file_extensions
/
||
$input_file
eq
'DIAGNOSTICS'
)
)
{
Warn(
"skipping file: $input_file: wrong extension\n"
);
next
;
}
my
(
$rinput_string
,
$is_encoded_data
,
$decoded_input_as
,
$encoding_log_message
,
$length_function
,
) =
$self
->get_decoded_string_buffer(
$input_file
,
$display_name
);
next
if
( !
defined
(
$rinput_string
) );
if
( ${
$rinput_string
} =~ /^\s*<[^<>]/ ) {
my
$is_named_file
=
$number_of_files
> 0 && !
$line_range_clipped
;
if
( is_not_perl(
$rinput_string
,
$input_file
,
$is_named_file
) ) {
Warn(
"skipping file: $input_file: does not look like Perl code\n"
);
next
;
}
}
$diagnostics_object
->set_input_file(
$input_file
)
if
(
$diagnostics_object
);
my
$output_file
;
my
$output_name
= EMPTY_STRING;
my
$actual_output_extension
;
if
(
$rOpts
->{
'outfile'
} ) {
if
(
$number_of_files
<= 1 ) {
if
(
$rOpts
->{
'standard-output'
} ) {
my
$saw_pbp
=
$self
->[_saw_pbp_];
my
$msg
=
"You may not use -o and -st together"
;
$msg
.=
" (-pbp contains -st; see manual)"
if
(
$saw_pbp
);
Die(
"$msg\n"
);
}
if
(
$destination_stream
) {
Die(
"You may not specify a destination array and -o together\n"
);
}
if
(
defined
(
$rOpts
->{
'output-path'
} ) ) {
Die(
"You may not specify -o and -opath together\n"
);
}
if
(
defined
(
$rOpts
->{
'output-file-extension'
} ) ) {
Die(
"You may not specify -o and -oext together\n"
);
}
$output_file
=
$rOpts
->{outfile};
$output_name
=
$output_file
;
if
(
$output_file
=~ /^-/ ) {
Die(
"You must specify a valid filename after -o\n"
);
}
if
(
@input_file_stat
&& (
$output_file
eq
$input_file
) ) {
Die(
"Use 'perltidy -b $input_file' to modify in-place\n"
);
}
}
else
{
Die(
"You may not use -o with more than one input file\n"
);
}
}
elsif
(
$rOpts
->{
'standard-output'
} ) {
if
(
$destination_stream
) {
my
$saw_pbp
=
$self
->[_saw_pbp_];
my
$msg
=
"You may not specify a destination array and -st together\n"
;
$msg
.=
" (-pbp contains -st; see manual)"
if
(
$saw_pbp
);
Die(
"$msg\n"
);
}
$output_file
=
'-'
;
$output_name
=
"<stdout>"
;
if
(
$number_of_files
<= 1 ) {
}
else
{
Die(
"You may not use -st with more than one input file\n"
);
}
}
elsif
(
$destination_stream
) {
$output_file
=
$destination_stream
;
$output_name
=
"<destination_stream>"
;
}
elsif
(
$source_stream
) {
$output_file
=
'-'
;
$output_name
=
"<stdout>"
;
}
elsif
(
$input_file
eq
'-'
) {
$output_file
=
'-'
;
$output_name
=
"<stdout>"
;
}
else
{
if
(
$in_place_modify
) {
$output_name
=
$display_name
;
}
else
{
$actual_output_extension
=
$output_extension
;
$output_file
=
$fileroot
.
$output_extension
;
$output_name
=
$output_file
;
}
}
if
(
$is_encoded_data
&&
$self
->[_dump_to_stdout_] ) {
binmode
*STDOUT
,
':encoding(UTF-8)'
;
}
$rstatus
->{
'file_count'
} += 1;
$rstatus
->{
'output_name'
} =
$output_name
;
$rstatus
->{
'iteration_count'
} = 0;
$rstatus
->{
'converged'
} = 0;
my
$warning_file
=
$fileroot
.
$dot
.
"ERR"
;
if
(
$errorfile_stream
) {
$warning_file
=
$errorfile_stream
}
my
$log_file
=
$fileroot
.
$dot
.
"LOG"
;
if
(
$logfile_stream
) {
$log_file
=
$logfile_stream
}
my
$logger_object
= Perl::Tidy::Logger->new(
rOpts
=>
$rOpts
,
log_file
=>
$log_file
,
warning_file
=>
$warning_file
,
fh_stderr
=>
$fh_stderr
,
display_name
=>
$display_name
,
is_encoded_data
=>
$is_encoded_data
,
);
$logger_object
->write_logfile_entry(
$logfile_header
);
$logger_object
->write_logfile_entry(
$encoding_log_message
)
if
(
$encoding_log_message
);
if
( ${
$rpending_logfile_message
} ) {
$logger_object
->write_logfile_entry( ${
$rpending_logfile_message
} );
}
if
( ${
$rpending_complaint
} ) {
$logger_object
->complain( ${
$rpending_complaint
} );
}
$self
->[_actual_output_extension_] =
$actual_output_extension
;
$self
->[_debugfile_stream_] =
$debugfile_stream
;
$self
->[_decoded_input_as_] =
$decoded_input_as
;
$self
->[_destination_stream_] =
$destination_stream
;
$self
->[_display_name_] =
$display_name
;
$self
->[_fileroot_] =
$fileroot
;
$self
->[_is_encoded_data_] =
$is_encoded_data
;
$self
->[_length_function_] =
$length_function
;
$self
->[_logger_object_] =
$logger_object
;
$self
->[_output_file_] =
$output_file
;
$self
->[_teefile_stream_] =
$teefile_stream
;
$self
->[_input_copied_verbatim_] = 0;
$self
->[_input_output_difference_] = 1;
my
$routput_string
=
$self
->process_filter_layer(
$rinput_string
);
if
(
$rOpts
->{
'format'
} eq
'tidy'
&&
defined
(
$routput_string
) ) {
$self
->write_tidy_output(
{
routput_string
=>
$routput_string
,
rinput_file_stat
=> \
@input_file_stat
,
in_place_modify
=>
$in_place_modify
,
input_file
=>
$input_file
,
backup_extension
=>
$backup_extension
,
delete_backup
=>
$delete_backup
,
}
);
}
$logger_object
->finish()
if
(
$logger_object
);
}
return
;
}
sub
write_tidy_output {
my
(
$self
,
$rcall_hash
) =
@_
;
my
$routput_string
=
$rcall_hash
->{routput_string};
my
$rinput_file_stat
=
$rcall_hash
->{rinput_file_stat};
my
$in_place_modify
=
$rcall_hash
->{in_place_modify};
my
$input_file
=
$rcall_hash
->{input_file};
my
$backup_extension
=
$rcall_hash
->{backup_extension};
my
$delete_backup
=
$rcall_hash
->{delete_backup};
my
$rOpts
=
$self
->[_rOpts_];
my
$is_encoded_data
=
$self
->[_is_encoded_data_];
my
$output_file
=
$self
->[_output_file_];
if
(
$in_place_modify
) {
if
( !
$self
->[_input_copied_verbatim_] ) {
my
$backup_method
=
$rOpts
->{
'backup-method'
};
if
(
defined
(
$backup_method
) &&
$backup_method
eq
'copy'
) {
$self
->backup_method_copy(
$input_file
,
$routput_string
,
$backup_extension
,
$delete_backup
);
}
else
{
$self
->backup_method_move(
$input_file
,
$routput_string
,
$backup_extension
,
$delete_backup
);
}
}
}
elsif
(
ref
(
$output_file
) ) {
$self
->copy_buffer_to_external_ref(
$routput_string
,
$output_file
);
}
else
{
if
(
$output_file
eq
'-'
) {
my
$fh
=
*STDOUT
;
if
(
$is_encoded_data
) {
binmode
$fh
,
":raw:encoding(UTF-8)"
}
else
{
binmode
$fh
}
$fh
->
print
( ${
$routput_string
} );
}
else
{
if
(
open
(
my
$fh
,
'>'
,
$output_file
) ) {
if
(
$is_encoded_data
) {
binmode
$fh
,
":raw:encoding(UTF-8)"
}
else
{
binmode
$fh
}
$fh
->
print
( ${
$routput_string
} );
$fh
->
close
() or Die(
"Cannot close '$output_file': $OS_ERROR\n"
);
}
else
{
Die(
"Cannot open $output_file to write: $OS_ERROR\n"
);
}
if
(
$output_file
&& -f
$output_file
&& !-l
$output_file
) {
if
( @{
$rinput_file_stat
} ) {
$self
->set_output_file_permissions(
$output_file
,
\@{
$rinput_file_stat
},
$in_place_modify
);
}
}
}
if
(
$is_encoded_data
) {
$rstatus
->{
'output_encoded_as'
} =
'UTF-8'
;
}
}
return
;
}
sub
process_filter_layer {
my
(
$self
,
$rinput_string
) =
@_
;
if
( !
defined
(
$rinput_string
) ) {
Fault(
"bad call: the source string ref \$rinput_string is undefined\n"
);
}
if
(
ref
(
$rinput_string
) ne
'SCALAR'
) {
Fault(
"bad call: the source string ref is not SCALAR\n"
);
}
my
$rOpts
=
$self
->[_rOpts_];
my
$logger_object
=
$self
->[_logger_object_];
my
@input_lines_pre
;
my
@input_lines_post
;
my
$digest_input
;
my
$saved_input_buf
;
my
$chomp_terminal_newline
;
if
(
$rOpts
->{
'format'
} eq
'tidy'
) {
my
$line_tidy_begin
=
$self
->[_line_tidy_begin_];
if
(
$line_tidy_begin
) {
my
@input_lines
=
split
/^/, ${
$rinput_string
};
my
$num
=
@input_lines
;
if
(
$line_tidy_begin
>
$num
) {
Die(
<<EOM);
#--line-range-tidy=n1:n2 has n1=$line_tidy_begin which exceeds max line number of $num
EOM
}
else
{
my
$line_tidy_end
=
$self
->[_line_tidy_end_];
if
( !
defined
(
$line_tidy_end
) ||
$line_tidy_end
>
$num
) {
$line_tidy_end
=
$num
;
}
my
$input_string
=
join
EMPTY_STRING,
@input_lines
[
$line_tidy_begin
- 1 ..
$line_tidy_end
- 1 ];
$rinput_string
= \
$input_string
;
@input_lines_pre
=
@input_lines
[ 0 ..
$line_tidy_begin
- 2 ];
@input_lines_post
=
@input_lines
[
$line_tidy_end
..
$num
- 1 ];
}
}
if
(
$rOpts
->{
'assert-tidy'
}
||
$rOpts
->{
'assert-untidy'
}
||
$rOpts
->{
'backup-and-modify-in-place'
} )
{
$digest_input
=
$md5_hex
->( ${
$rinput_string
} );
$saved_input_buf
= ${
$rinput_string
};
}
$chomp_terminal_newline
= !
$rOpts
->{
'add-terminal-newline'
}
&&
substr
( ${
$rinput_string
}, -1, 1 ) !~ /\n/;
}
my
$prefilter
=
$self
->[_prefilter_];
if
(
$prefilter
) {
my
$input_string
=
$prefilter
->( ${
$rinput_string
} );
$rinput_string
= \
$input_string
;
}
my
$routput_string
=
$self
->process_iteration_layer(
$rinput_string
);
if
(
$rOpts
->{
'format'
} ne
'tidy'
) {
return
;
}
my
$postfilter
=
$self
->[_postfilter_];
if
(
$postfilter
) {
my
$output_string
=
$postfilter
->( ${
$routput_string
} );
$routput_string
= \
$output_string
;
}
if
(
defined
(
$digest_input
) ) {
my
$digest_output
=
$md5_hex
->( ${
$routput_string
} );
$self
->[_input_output_difference_] =
$digest_output
ne
$digest_input
;
}
if
(
$rOpts
->{
'assert-tidy'
} ) {
if
(
$self
->[_input_output_difference_] ) {
my
$diff_msg
=
compare_string_buffers( \
$saved_input_buf
,
$routput_string
);
$logger_object
->warning(
<<EOM);
assertion failure: '--assert-tidy' is set but output differs from input
EOM
$logger_object
->interrupt_logfile();
$logger_object
->warning(
$diff_msg
.
"\n"
);
$logger_object
->resume_logfile();
}
}
if
(
$rOpts
->{
'assert-untidy'
} ) {
if
( !
$self
->[_input_output_difference_] ) {
$logger_object
->warning(
"assertion failure: '--assert-untidy' is set but output equals input\n"
);
}
}
if
(
@input_lines_pre
||
@input_lines_post
) {
my
$str_pre
=
join
EMPTY_STRING,
@input_lines_pre
;
my
$str_post
=
join
EMPTY_STRING,
@input_lines_post
;
my
$output_string
=
$str_pre
. ${
$routput_string
} .
$str_post
;
$routput_string
= \
$output_string
;
}
if
(
$chomp_terminal_newline
) {
chomp
${
$routput_string
};
}
if
(
$self
->[_line_separator_] ne
"\n"
) {
my
$line_separator
=
$self
->[_line_separator_];
my
@output_lines
=
split
/^/, ${
$routput_string
};
foreach
my
$line
(
@output_lines
) {
if
(
chomp
$line
) {
$line
.=
$line_separator
;
}
}
my
$output_string
=
join
EMPTY_STRING,
@output_lines
;
$routput_string
= \
$output_string
;
}
return
$routput_string
;
}
sub
process_iteration_layer {
my
(
$self
,
$rinput_string
) =
@_
;
my
$diagnostics_object
=
$self
->[_diagnostics_object_];
my
$display_name
=
$self
->[_display_name_];
my
$fileroot
=
$self
->[_fileroot_];
my
$is_encoded_data
=
$self
->[_is_encoded_data_];
my
$length_function
=
$self
->[_length_function_];
my
$logger_object
=
$self
->[_logger_object_];
my
$rOpts
=
$self
->[_rOpts_];
my
$user_formatter
=
$self
->[_user_formatter_];
my
$debugger_object
;
if
(
$rOpts
->{DEBUG} ) {
my
$debug_file
=
$self
->[_debugfile_stream_]
||
$fileroot
.
$self
->make_file_extension(
'DEBUG'
);
$debugger_object
=
Perl::Tidy::Debugger->new(
$debug_file
,
$is_encoded_data
);
}
my
$fh_tee
;
my
$tee_file
;
if
(
$rOpts
->{
'tee-pod'
}
||
$rOpts
->{
'tee-block-comments'
}
||
$rOpts
->{
'tee-side-comments'
} )
{
$tee_file
=
$self
->[_teefile_stream_]
||
$fileroot
.
$self
->make_file_extension(
'TEE'
);
$fh_tee
= Perl::Tidy::streamhandle(
$tee_file
,
'w'
,
$is_encoded_data
);
if
( !
$fh_tee
) {
Warn(
"couldn't open TEE file $tee_file: $OS_ERROR\n"
);
}
}
my
$max_iterations
= 1;
my
$convergence_log_message
;
my
%saw_md5
;
if
(
$rOpts
->{
'format'
} eq
'tidy'
) {
$max_iterations
=
$rOpts
->{
'iterations'
};
if
( !
defined
(
$max_iterations
)
||
$max_iterations
<= 0 )
{
$max_iterations
= 1;
}
if
(
$max_iterations
> ITERATION_LIMIT ) {
$max_iterations
= ITERATION_LIMIT;
}
if
(
$max_iterations
> 1 ) {
my
$digest
=
$md5_hex
->( ${
$rinput_string
} );
$saw_md5
{
$digest
} = 0;
}
}
my
$logger_object_final
=
$logger_object
;
my
$iteration_of_formatter_convergence
;
my
$routput_string
;
foreach
my
$iter
( 1 ..
$max_iterations
) {
$rstatus
->{
'iteration_count'
} += 1;
my
$sink_buffer
= EMPTY_STRING;
$routput_string
= \
$sink_buffer
;
if
(
$iter
> 1 ) {
$debugger_object
->close_debug_file()
if
(
$debugger_object
);
if
(
$fh_tee
&&
$fh_tee
->can(
'close'
)
&& !
ref
(
$tee_file
)
&&
$tee_file
ne
'-'
)
{
$fh_tee
->
close
()
or Warn(
"couldn't close TEE file $tee_file: $OS_ERROR\n"
);
}
$debugger_object
=
undef
;
$logger_object
=
undef
;
$fh_tee
=
undef
;
}
my
$formatter
;
if
(
$user_formatter
) {
$formatter
=
$user_formatter
;
}
elsif
(
$rOpts
->{
'format'
} eq
'html'
) {
my
$html_toc_extension
=
$self
->make_file_extension(
$rOpts
->{
'html-toc-extension'
},
'toc'
);
my
$html_src_extension
=
$self
->make_file_extension(
$rOpts
->{
'html-src-extension'
},
'src'
);
$formatter
= Perl::Tidy::HtmlWriter->new(
input_file
=>
$fileroot
,
html_file
=>
$self
->[_output_file_],
extension
=>
$self
->[_actual_output_extension_],
html_toc_extension
=>
$html_toc_extension
,
html_src_extension
=>
$html_src_extension
,
);
}
elsif
(
$rOpts
->{
'format'
} eq
'tidy'
) {
$formatter
= Perl::Tidy::Formatter->new(
logger_object
=>
$logger_object
,
diagnostics_object
=>
$diagnostics_object
,
sink_object
=>
$routput_string
,
length_function
=>
$length_function
,
is_encoded_data
=>
$is_encoded_data
,
fh_tee
=>
$fh_tee
,
);
}
else
{
Die(
"I don't know how to do -format=$rOpts->{'format'}\n"
);
}
if
( !
$formatter
) {
Die(
"Unable to continue with $rOpts->{'format'} formatting\n"
);
}
my
$tokenizer
= Perl::Tidy::Tokenizer->new(
source_object
=>
$rinput_string
,
logger_object
=>
$logger_object
,
debugger_object
=>
$debugger_object
,
diagnostics_object
=>
$diagnostics_object
,
rOpts
=>
$rOpts
,
starting_level
=>
$rOpts
->{
'starting-indentation-level'
},
);
$self
->process_single_case(
$tokenizer
,
$formatter
);
if
(
$max_iterations
> 1
&& !
defined
(
$iteration_of_formatter_convergence
)
&&
$formatter
->can(
'get_convergence_check'
) )
{
if
(
$formatter
->get_convergence_check() ) {
$iteration_of_formatter_convergence
=
$iter
;
$rstatus
->{
'converged'
} = 1;
}
}
if
(
$iter
<
$max_iterations
) {
$rinput_string
= \
$sink_buffer
;
my
$stop_now
=
$self
->[_input_copied_verbatim_];
$stop_now
||=
$tokenizer
->get_unexpected_error_count();
my
$stopping_on_error
=
$stop_now
;
if
(
$stop_now
) {
$convergence_log_message
=
<<EOM;
Stopping iterations because of severe errors.
EOM
}
else
{
$stop_now
||=
defined
(
$iteration_of_formatter_convergence
);
my
$digest
=
$md5_hex
->(
$sink_buffer
);
if
( !
defined
(
$saw_md5
{
$digest
} ) ) {
$saw_md5
{
$digest
} =
$iter
;
}
elsif
(
$iter
== 1
&& !
$stop_now
&&
$formatter
->can(
'want_second_iteration'
)
&&
$formatter
->want_second_iteration() )
{
$saw_md5
{
$digest
} =
$iter
;
}
else
{
$stop_now
= 1;
my
$iterm
=
$iter
- 1;
if
(
$saw_md5
{
$digest
} !=
$iterm
) {
$rstatus
->{
'blinking'
} = 1;
$convergence_log_message
=
<<EOM;
BLINKER. Output for iteration $iter same as for $saw_md5{$digest}.
EOM
$stopping_on_error
||=
$convergence_log_message
;
DEVEL_MODE
&&
print
{
*STDERR
}
$convergence_log_message
;
$diagnostics_object
->write_diagnostics(
$convergence_log_message
)
if
(
$diagnostics_object
);
}
else
{
$convergence_log_message
=
<<EOM;
Converged. Output for iteration $iter same as for iter $iterm.
EOM
$diagnostics_object
->write_diagnostics(
$convergence_log_message
)
if
(
$diagnostics_object
&&
$iterm
> 2 );
$rstatus
->{
'converged'
} = 1;
}
}
}
if
(
$stop_now
) {
if
(DEVEL_MODE) {
if
(
defined
(
$iteration_of_formatter_convergence
) ) {
if
(
$iteration_of_formatter_convergence
<
$iter
- 1 ) {
print
{
*STDERR
}
"STRANGE Early conv in $display_name: Stopping on it=$iter, converged in formatter on $iteration_of_formatter_convergence\n"
;
}
}
elsif
( !
$stopping_on_error
) {
print
{
*STDERR
}
"STRANGE no conv in $display_name: stopping on it=$iter, but not converged in formatter\n"
;
}
else
{
}
}
last
;
}
}
}
$debugger_object
->close_debug_file()
if
(
$debugger_object
);
if
(
$fh_tee
&&
$fh_tee
->can(
'close'
)
&& !
ref
(
$tee_file
)
&&
$tee_file
ne
'-'
)
{
$fh_tee
->
close
()
or Warn(
"couldn't close TEE file $tee_file: $OS_ERROR\n"
);
}
$logger_object
=
$logger_object_final
;
$logger_object
->write_logfile_entry(
$convergence_log_message
)
if
(
$convergence_log_message
);
return
$routput_string
;
}
sub
process_single_case {
my
(
$self
,
$tokenizer
,
$formatter
) =
@_
;
while
(
my
$line
=
$tokenizer
->get_line() ) {
$formatter
->write_line(
$line
);
}
if
(
$formatter
->can(
'finish_formatting'
) ) {
my
$severe_error
=
$tokenizer
->report_tokenization_errors();
my
$verbatim
=
$formatter
->finish_formatting(
$severe_error
);
$self
->[_input_copied_verbatim_] =
$verbatim
;
}
return
;
}
sub
copy_buffer_to_external_ref {
my
(
$self
,
$routput
,
$destination_stream
) =
@_
;
my
$destination_buffer
= EMPTY_STRING;
if
(
ref
(
$routput
) eq
'ARRAY'
) {
$destination_buffer
=
join
EMPTY_STRING, @{
$routput
};
}
elsif
(
ref
(
$routput
) eq
'SCALAR'
) {
$destination_buffer
= ${
$routput
};
}
else
{
Fatal(
"'copy_buffer_to_external_ref' expecting ref to ARRAY or SCALAR\n"
);
}
$rstatus
->{
'output_encoded_as'
} = EMPTY_STRING;
my
$ref_destination_stream
=
ref
(
$destination_stream
);
my
$encode_destination_buffer
;
if
(
$ref_destination_stream
eq
'SCALAR'
||
$ref_destination_stream
eq
'ARRAY'
)
{
my
$rOpts
=
$self
->[_rOpts_];
$encode_destination_buffer
=
$rOpts
->{
'encode-output-strings'
} &&
$self
->[_decoded_input_as_];
}
elsif
(
$ref_destination_stream
->can(
'print'
) ) {
$encode_destination_buffer
=
$self
->[_is_encoded_data_];
}
else
{
confess
<<EOM;
------------------------------------------------------------------------
No 'print' method is defined for object of class '$ref_destination_stream'
Please check your call to Perl::Tidy::perltidy. Trace follows.
------------------------------------------------------------------------
EOM
}
if
(
$encode_destination_buffer
) {
my
$encoded_buffer
;
if
(
!
eval
{
$encoded_buffer
=
Encode::encode(
"UTF-8"
,
$destination_buffer
,
Encode::FB_CROAK | Encode::LEAVE_SRC );
1;
}
)
{
Warn(
"Error attempting to encode output string ref; encoding not done\n"
);
}
else
{
$destination_buffer
=
$encoded_buffer
;
$rstatus
->{
'output_encoded_as'
} =
'UTF-8'
;
}
}
if
(
$ref_destination_stream
eq
'SCALAR'
) {
${
$destination_stream
} =
$destination_buffer
;
}
elsif
(
defined
(
$destination_buffer
) ) {
my
@lines
=
split
/^/,
$destination_buffer
;
if
(
$ref_destination_stream
eq
'ARRAY'
) {
@{
$destination_stream
} =
@lines
;
}
else
{
foreach
my
$line
(
@lines
) {
$destination_stream
->
print
(
$line
);
}
if
(
$ref_destination_stream
->can(
'close'
) ) {
$destination_stream
->
close
();
}
}
}
else
{
}
return
;
}
}
sub
line_diff {
my
(
$s1
,
$s2
) =
@_
;
my
$diff_marker
= EMPTY_STRING;
my
$pos
= -1;
my
$pos1
= -1;
if
(
defined
(
$s1
) &&
defined
(
$s2
) ) {
my
$mask
=
$s1
^
$s2
;
while
(
$mask
=~ /[^\0]/g ) {
my
$pos_last
=
$pos
;
$pos
=
$LAST_MATCH_START
[0];
if
(
$pos1
< 0 ) {
$pos1
=
$pos
; }
$diff_marker
.= SPACE x (
$pos
-
$pos_last
- 1 ) .
'^'
;
last
;
}
}
return
(
$diff_marker
,
$pos1
);
}
sub
compare_string_buffers {
my
(
$string_i
,
$string_o
, (
$max_diff_count
) ) =
@_
;
my
$rbufi
=
ref
(
$string_i
) ?
$string_i
: \
$string_i
;
my
$rbufo
=
ref
(
$string_o
) ?
$string_o
: \
$string_o
;
if
( !
defined
(
$max_diff_count
) ) {
$max_diff_count
= 1 }
my
(
@aryi
,
@aryo
);
my
(
$leni
,
$leno
) = ( 0, 0 );
if
(
defined
(
$rbufi
) ) {
$leni
=
length
( ${
$rbufi
} );
@aryi
=
split
/^/, ${
$rbufi
};
}
if
(
defined
(
$rbufo
) ) {
$leno
=
length
( ${
$rbufo
} );
@aryo
=
split
/^/, ${
$rbufo
};
}
my
$nlines_i
=
@aryi
;
my
$nlines_o
=
@aryo
;
my
$msg
=
<<EOM;
Input file length has $leni chars in $nlines_i lines
Output file length has $leno chars in $nlines_o lines
EOM
return
$msg
unless
(
$leni
&&
$leno
);
my
$truncate
=
sub
{
my
(
$str
,
$lenmax
) =
@_
;
if
(
length
(
$str
) >
$lenmax
) {
$str
=
substr
(
$str
, 0,
$lenmax
) .
"..."
;
}
return
$str
;
};
my
$last_nonblank_line
= EMPTY_STRING;
my
$last_nonblank_count
= 0;
my
$count
= 0;
my
$diff_count
= 0;
while
(
@aryi
&&
@aryo
) {
$count
++;
my
$linei
=
shift
@aryi
;
my
$lineo
=
shift
@aryo
;
chomp
$linei
;
chomp
$lineo
;
if
(
$linei
eq
$lineo
) {
if
(
length
(
$linei
) ) {
$last_nonblank_line
=
$linei
;
$last_nonblank_count
=
$count
;
}
next
;
}
my
(
$line_diff
,
$pos1
) = line_diff(
$linei
,
$lineo
);
my
$ch1
=
$pos1
+ 1;
my
$reason
=
"Files first differ at character $ch1 of line $count"
;
my
(
$leading_ws_i
,
$leading_ws_o
) = ( EMPTY_STRING, EMPTY_STRING );
if
(
$linei
=~ /^(\s+)/ ) {
$leading_ws_i
= $1; }
if
(
$lineo
=~ /^(\s+)/ ) {
$leading_ws_o
= $1; }
if
(
$leading_ws_i
ne
$leading_ws_o
) {
$reason
.=
"; leading whitespace differs"
;
if
(
$leading_ws_i
=~ /\t/ ) {
$reason
.=
"; input has tab char"
;
}
}
else
{
my
(
$trailing_ws_i
,
$trailing_ws_o
) =
( EMPTY_STRING, EMPTY_STRING );
if
(
$linei
=~ /(\s+)$/ ) {
$trailing_ws_i
= $1; }
if
(
$lineo
=~ /(\s+)$/ ) {
$trailing_ws_o
= $1; }
if
(
$trailing_ws_i
ne
$trailing_ws_o
) {
$reason
.=
"; trailing whitespace differs"
;
}
}
$msg
.=
$reason
.
"\n"
;
if
(
$pos1
> 60 ) {
my
$drop
=
$pos1
- 40;
$linei
=
"..."
.
substr
(
$linei
,
$drop
);
$lineo
=
"..."
.
substr
(
$lineo
,
$drop
);
$line_diff
= SPACE x 3 .
substr
(
$line_diff
,
$drop
);
}
$linei
=
$truncate
->(
$linei
, 72 );
$lineo
=
$truncate
->(
$lineo
, 72 );
$last_nonblank_line
=
$truncate
->(
$last_nonblank_line
, 72 );
if
(
$last_nonblank_line
) {
$msg
.=
<<EOM;
$last_nonblank_count:$last_nonblank_line
EOM
}
$line_diff
= SPACE x ( 2 +
length
(
$count
) ) .
$line_diff
;
$msg
.=
<<EOM;
<$count:$linei
>$count:$lineo
$line_diff
EOM
$diff_count
++;
last
if
(
$diff_count
>=
$max_diff_count
);
}
if
(
$diff_count
) {
return
$msg
}
if
(
$nlines_i
>
$nlines_o
) {
$msg
.=
<<EOM;
Files initially match file but output file has fewer lines
EOM
}
elsif
(
$nlines_i
<
$nlines_o
) {
$msg
.=
<<EOM;
Files initially match file but input file has fewer lines
EOM
}
else
{
$msg
.=
<<EOM;
Text in lines of file match but checksums differ. Perhaps line endings differ.
EOM
}
return
$msg
;
}
sub
fileglob_to_re {
my
$x
=
shift
;
$x
=~ s/([.\/^\$()])/\\$1/g;
$x
=~ s/\*/.*/g;
$x
=~ s/\?/./g;
return
"^$x\\z"
;
}
sub
make_logfile_header {
my
(
$rOpts
,
$config_file
,
$rraw_options
,
$Windows_type
,
$readable_options
)
=
@_
;
my
$msg
=
"perltidy version $VERSION log file on a $OSNAME system, OLD_PERL_VERSION=$]\n"
;
if
(
$Windows_type
) {
$msg
.=
"Windows type is $Windows_type\n"
;
}
my
$options_string
=
join
( SPACE, @{
$rraw_options
} );
if
(
defined
(
$config_file
) ) {
$msg
.=
"Found Configuration File >>> $config_file \n"
;
}
$msg
.=
"Configuration and command line parameters for this run:\n"
;
$msg
.=
"$options_string\n"
;
if
(
$rOpts
->{
'show-options'
} ) {
$rOpts
->{
'logfile'
} = 1;
$msg
.=
"Final parameter set for this run\n"
;
$msg
.=
"------------------------------------\n"
;
$msg
.=
$readable_options
;
$msg
.=
"------------------------------------\n"
;
}
$msg
.=
"To find error messages search for 'WARNING' with your editor\n"
;
return
$msg
;
}
sub
generate_options {
my
@option_string
= ();
my
%expansion
= ();
my
%option_category
= ();
my
%integer_option_range
;
my
@category_name
= (
'0. I/O control'
,
'1. Basic formatting options'
,
'2. Code indentation control'
,
'3. Whitespace control'
,
'4. Comment controls'
,
'5. Linebreak controls'
,
'6. Controlling list formatting'
,
'7. Retaining or ignoring existing line breaks'
,
'8. Blank line control'
,
'9. Other controls'
,
'10. HTML options'
,
'11. pod2html options'
,
'12. Controlling HTML properties'
,
'13. Debugging'
,
);
@option_string
=
qw(
html!
noprofile
nopro
no-profile
npro
recombine!
notidy
)
;
my
$category
= 13;
foreach
(
@option_string
) {
my
$opt
=
$_
;
$opt
=~ s/!$//;
$option_category
{
$opt
} =
$category_name
[
$category
];
}
$category
= 11;
$option_category
{html} =
$category_name
[
$category
];
my
$add_option
=
sub
{
my
(
$long_name
,
$short_name
,
$flag
) =
@_
;
push
@option_string
,
$long_name
.
$flag
;
$option_category
{
$long_name
} =
$category_name
[
$category
];
if
(
$short_name
) {
if
(
$expansion
{
$short_name
} ) {
my
$existing_name
=
$expansion
{
$short_name
}->[0];
Die(
"redefining abbreviation $short_name for $long_name; already used for $existing_name\n"
);
}
$expansion
{
$short_name
} = [
$long_name
];
if
(
$flag
eq
'!'
) {
my
$nshort_name
=
'n'
.
$short_name
;
my
$nolong_name
=
'no'
.
$long_name
;
if
(
$expansion
{
$nshort_name
} ) {
my
$existing_name
=
$expansion
{
$nshort_name
}->[0];
Die(
"attempting to redefine abbreviation $nshort_name for $nolong_name; already used for $existing_name\n"
);
}
$expansion
{
$nshort_name
} = [
$nolong_name
];
}
}
return
;
};
$category
= 0;
$add_option
->(
'backup-and-modify-in-place'
,
'b'
,
'!'
);
$add_option
->(
'backup-file-extension'
,
'bext'
,
'=s'
);
$add_option
->(
'backup-method'
,
'bm'
,
'=s'
);
$add_option
->(
'character-encoding'
,
'enc'
,
'=s'
);
$add_option
->(
'force-read-binary'
,
'f'
,
'!'
);
$add_option
->(
'format'
,
'fmt'
,
'=s'
);
$add_option
->(
'iterations'
,
'it'
,
'=i'
);
$add_option
->(
'logfile'
,
'log'
,
'!'
);
$add_option
->(
'logfile-gap'
,
'g'
,
':i'
);
$add_option
->(
'outfile'
,
'o'
,
'=s'
);
$add_option
->(
'output-file-extension'
,
'oext'
,
'=s'
);
$add_option
->(
'output-path'
,
'opath'
,
'=s'
);
$add_option
->(
'profile'
,
'pro'
,
'=s'
);
$add_option
->(
'quiet'
,
'q'
,
'!'
);
$add_option
->(
'standard-error-output'
,
'se'
,
'!'
);
$add_option
->(
'standard-output'
,
'st'
,
'!'
);
$add_option
->(
'use-unicode-gcstring'
,
'gcs'
,
'!'
);
$add_option
->(
'warning-output'
,
'w'
,
'!'
);
$add_option
->(
'add-terminal-newline'
,
'atnl'
,
'!'
);
$add_option
->(
'line-range-tidy'
,
'lrt'
,
'=s'
);
$add_option
->(
'timeout-in-seconds'
,
'tos'
,
'=i'
);
$add_option
->(
'output-line-ending'
,
'ole'
,
'=s'
);
$add_option
->(
'starting-indentation-level'
,
'sil'
,
'=i'
);
$category
= 1;
$add_option
->(
'check-syntax'
,
'syn'
,
'!'
);
$add_option
->(
'entab-leading-whitespace'
,
'et'
,
'=i'
);
$add_option
->(
'indent-columns'
,
'i'
,
'=i'
);
$add_option
->(
'maximum-line-length'
,
'l'
,
'=i'
);
$add_option
->(
'variable-maximum-line-length'
,
'vmll'
,
'!'
);
$add_option
->(
'whitespace-cycle'
,
'wc'
,
'=i'
);
$add_option
->(
'perl-syntax-check-flags'
,
'pscf'
,
'=s'
);
$add_option
->(
'preserve-line-endings'
,
'ple'
,
'!'
);
$add_option
->(
'tabs'
,
't'
,
'!'
);
$add_option
->(
'default-tabsize'
,
'dt'
,
'=i'
);
$add_option
->(
'extended-syntax'
,
'xs'
,
'!'
);
$add_option
->(
'assert-tidy'
,
'ast'
,
'!'
);
$add_option
->(
'assert-untidy'
,
'asu'
,
'!'
);
$add_option
->(
'encode-output-strings'
,
'eos'
,
'!'
);
$add_option
->(
'sub-alias-list'
,
'sal'
,
'=s'
);
$add_option
->(
'grep-alias-list'
,
'gal'
,
'=s'
);
$add_option
->(
'grep-alias-exclusion-list'
,
'gaxl'
,
'=s'
);
$add_option
->(
'use-feature'
,
'uf'
,
'=s'
);
$category
= 2;
$add_option
->(
'continuation-indentation'
,
'ci'
,
'=i'
);
$add_option
->(
'extended-continuation-indentation'
,
'xci'
,
'!'
);
$add_option
->(
'minimize-continuation-indentation'
,
'mci'
,
'!'
);
$add_option
->(
'line-up-parentheses'
,
'lp'
,
'!'
);
$add_option
->(
'extended-line-up-parentheses'
,
'xlp'
,
'!'
);
$add_option
->(
'line-up-parentheses-exclusion-list'
,
'lpxl'
,
'=s'
);
$add_option
->(
'line-up-parentheses-inclusion-list'
,
'lpil'
,
'=s'
);
$add_option
->(
'outdent-keyword-list'
,
'okwl'
,
'=s'
);
$add_option
->(
'outdent-keywords'
,
'okw'
,
'!'
);
$add_option
->(
'outdent-labels'
,
'ola'
,
'!'
);
$add_option
->(
'outdent-long-quotes'
,
'olq'
,
'!'
);
$add_option
->(
'indent-closing-brace'
,
'icb'
,
'!'
);
$add_option
->(
'indent-leading-semicolon'
,
'ils'
,
'!'
);
$add_option
->(
'closing-token-indentation'
,
'cti'
,
'=i'
);
$add_option
->(
'closing-paren-indentation'
,
'cpi'
,
'=i'
);
$add_option
->(
'closing-brace-indentation'
,
'cbi'
,
'=i'
);
$add_option
->(
'closing-square-bracket-indentation'
,
'csbi'
,
'=i'
);
$add_option
->(
'brace-left-and-indent'
,
'bli'
,
'!'
);
$add_option
->(
'brace-left-and-indent-list'
,
'blil'
,
'=s'
);
$add_option
->(
'brace-left-and-indent-exclusion-list'
,
'blixl'
,
'=s'
);
$category
= 3;
$add_option
->(
'add-trailing-commas'
,
'atc'
,
'!'
);
$add_option
->(
'add-lone-trailing-commas'
,
'altc'
,
'!'
);
$add_option
->(
'add-semicolons'
,
'asc'
,
'!'
);
$add_option
->(
'add-whitespace'
,
'aws'
,
'!'
);
$add_option
->(
'block-brace-tightness'
,
'bbt'
,
'=i'
);
$add_option
->(
'brace-tightness'
,
'bt'
,
'=i'
);
$add_option
->(
'delete-old-whitespace'
,
'dws'
,
'!'
);
$add_option
->(
'delete-repeated-commas'
,
'drc'
,
'!'
);
$add_option
->(
'delete-trailing-commas'
,
'dtc'
,
'!'
);
$add_option
->(
'delete-lone-trailing-commas'
,
'dltc'
,
'!'
);
$add_option
->(
'delete-weld-interfering-commas'
,
'dwic'
,
'!'
);
$add_option
->(
'delete-semicolons'
,
'dsm'
,
'!'
);
$add_option
->(
'function-paren-vertical-alignment'
,
'fpva'
,
'!'
);
$add_option
->(
'delay-trailing-comma-operations'
,
'dtco'
,
'!'
);
$add_option
->(
'keyword-paren-inner-tightness'
,
'kpit'
,
'=i'
);
$add_option
->(
'keyword-paren-inner-tightness-list'
,
'kpitl'
,
'=s'
);
$add_option
->(
'logical-padding'
,
'lop'
,
'!'
);
$add_option
->(
'multiple-token-tightness'
,
'mutt'
,
'=s'
);
$add_option
->(
'nospace-after-keyword'
,
'nsak'
,
'=s'
);
$add_option
->(
'nowant-left-space'
,
'nwls'
,
'=s'
);
$add_option
->(
'nowant-right-space'
,
'nwrs'
,
'=s'
);
$add_option
->(
'paren-tightness'
,
'pt'
,
'=i'
);
$add_option
->(
'space-after-keyword'
,
'sak'
,
'=s'
);
$add_option
->(
'space-for-semicolon'
,
'sfs'
,
'!'
);
$add_option
->(
'space-function-paren'
,
'sfp'
,
'!'
);
$add_option
->(
'space-keyword-paren'
,
'skp'
,
'!'
);
$add_option
->(
'space-terminal-semicolon'
,
'sts'
,
'!'
);
$add_option
->(
'square-bracket-tightness'
,
'sbt'
,
'=i'
);
$add_option
->(
'square-bracket-vertical-tightness'
,
'sbvt'
,
'=i'
);
$add_option
->(
'square-bracket-vertical-tightness-closing'
,
'sbvtc'
,
'=i'
);
$add_option
->(
'tight-secret-operators'
,
'tso'
,
'!'
);
$add_option
->(
'trim-qw'
,
'tqw'
,
'!'
);
$add_option
->(
'trim-pod'
,
'trp'
,
'!'
);
$add_option
->(
'want-left-space'
,
'wls'
,
'=s'
);
$add_option
->(
'want-right-space'
,
'wrs'
,
'=s'
);
$add_option
->(
'want-trailing-commas'
,
'wtc'
,
'=s'
);
$add_option
->(
'space-prototype-paren'
,
'spp'
,
'=i'
);
$add_option
->(
'space-signature-paren'
,
'ssp'
,
'=i'
);
$add_option
->(
'valign-code'
,
'vc'
,
'!'
);
$add_option
->(
'valign-block-comments'
,
'vbc'
,
'!'
);
$add_option
->(
'valign-side-comments'
,
'vsc'
,
'!'
);
$add_option
->(
'valign-exclusion-list'
,
'vxl'
,
'=s'
);
$add_option
->(
'valign-inclusion-list'
,
'vil'
,
'=s'
);
$add_option
->(
'valign-if-unless'
,
'viu'
,
'!'
);
$add_option
->(
'valign-signed-numbers'
,
'vsn'
,
'!'
);
$add_option
->(
'valign-signed-numbers-limit'
,
'vsnl'
,
'=i'
);
$add_option
->(
'valign-wide-equals'
,
'vwe'
,
'!'
);
$add_option
->(
'extended-block-tightness'
,
'xbt'
,
'!'
);
$add_option
->(
'extended-block-tightness-list'
,
'xbtl'
,
'=s'
);
$add_option
->(
'qw-as-function'
,
'qwaf'
,
'!'
);
$category
= 4;
$add_option
->(
'closing-side-comment-else-flag'
,
'csce'
,
'=i'
);
$add_option
->(
'closing-side-comment-interval'
,
'csci'
,
'=i'
);
$add_option
->(
'closing-side-comment-list'
,
'cscl'
,
'=s'
);
$add_option
->(
'closing-side-comment-exclusion-list'
,
'cscxl'
,
'=s'
);
$add_option
->(
'closing-side-comment-maximum-text'
,
'csct'
,
'=i'
);
$add_option
->(
'closing-side-comment-prefix'
,
'cscp'
,
'=s'
);
$add_option
->(
'closing-side-comment-warnings'
,
'cscw'
,
'!'
);
$add_option
->(
'closing-side-comments'
,
'csc'
,
'!'
);
$add_option
->(
'closing-side-comments-balanced'
,
'cscb'
,
'!'
);
$add_option
->(
'code-skipping'
,
'cs'
,
'!'
);
$add_option
->(
'code-skipping-begin'
,
'csb'
,
'=s'
);
$add_option
->(
'code-skipping-end'
,
'cse'
,
'=s'
);
$add_option
->(
'format-skipping'
,
'fs'
,
'!'
);
$add_option
->(
'format-skipping-begin'
,
'fsb'
,
'=s'
);
$add_option
->(
'format-skipping-end'
,
'fse'
,
'=s'
);
$add_option
->(
'hanging-side-comments'
,
'hsc'
,
'!'
);
$add_option
->(
'indent-block-comments'
,
'ibc'
,
'!'
);
$add_option
->(
'indent-spaced-block-comments'
,
'isbc'
,
'!'
);
$add_option
->(
'fixed-position-side-comment'
,
'fpsc'
,
'=i'
);
$add_option
->(
'minimum-space-to-comment'
,
'msc'
,
'=i'
);
$add_option
->(
'non-indenting-braces'
,
'nib'
,
'!'
);
$add_option
->(
'non-indenting-brace-prefix'
,
'nibp'
,
'=s'
);
$add_option
->(
'outdent-long-comments'
,
'olc'
,
'!'
);
$add_option
->(
'outdent-static-block-comments'
,
'osbc'
,
'!'
);
$add_option
->(
'static-block-comment-prefix'
,
'sbcp'
,
'=s'
);
$add_option
->(
'static-block-comments'
,
'sbc'
,
'!'
);
$add_option
->(
'static-side-comment-prefix'
,
'sscp'
,
'=s'
);
$add_option
->(
'static-side-comments'
,
'ssc'
,
'!'
);
$add_option
->(
'ignore-side-comment-lengths'
,
'iscl'
,
'!'
);
$add_option
->(
'ignore-perlcritic-comments'
,
'ipc'
,
'!'
);
$category
= 5;
$add_option
->(
'add-newlines'
,
'anl'
,
'!'
);
$add_option
->(
'block-brace-vertical-tightness'
,
'bbvt'
,
'=i'
);
$add_option
->(
'block-brace-vertical-tightness-list'
,
'bbvtl'
,
'=s'
);
$add_option
->(
'brace-follower-vertical-tightness'
,
'bfvt'
,
'=i'
);
$add_option
->(
'brace-vertical-tightness'
,
'bvt'
,
'=i'
);
$add_option
->(
'brace-vertical-tightness-closing'
,
'bvtc'
,
'=i'
);
$add_option
->(
'cuddled-else'
,
'ce'
,
'!'
);
$add_option
->(
'cuddled-block-list'
,
'cbl'
,
'=s'
);
$add_option
->(
'cuddled-block-list-exclusive'
,
'cblx'
,
'!'
);
$add_option
->(
'cuddled-break-option'
,
'cbo'
,
'=i'
);
$add_option
->(
'cuddled-paren-brace'
,
'cpb'
,
'!'
);
$add_option
->(
'delete-old-newlines'
,
'dnl'
,
'!'
);
$add_option
->(
'opening-brace-always-on-right'
,
'bar'
,
'!'
);
$add_option
->(
'opening-brace-on-new-line'
,
'bl'
,
'!'
);
$add_option
->(
'opening-hash-brace-right'
,
'ohbr'
,
'!'
);
$add_option
->(
'opening-paren-right'
,
'opr'
,
'!'
);
$add_option
->(
'opening-square-bracket-right'
,
'osbr'
,
'!'
);
$add_option
->(
'opening-anonymous-sub-brace-on-new-line'
,
'asbl'
,
'!'
);
$add_option
->(
'opening-sub-brace-on-new-line'
,
'sbl'
,
'!'
);
$add_option
->(
'paren-vertical-tightness'
,
'pvt'
,
'=i'
);
$add_option
->(
'paren-vertical-tightness-closing'
,
'pvtc'
,
'=i'
);
$add_option
->(
'weld-nested-containers'
,
'wn'
,
'!'
);
$add_option
->(
'weld-nested-exclusion-list'
,
'wnxl'
,
'=s'
);
$add_option
->(
'weld-fat-comma'
,
'wfc'
,
'!'
);
$add_option
->(
'space-backslash-quote'
,
'sbq'
,
'=i'
);
$add_option
->(
'stack-closing-block-brace'
,
'scbb'
,
'!'
);
$add_option
->(
'stack-closing-hash-brace'
,
'schb'
,
'!'
);
$add_option
->(
'stack-closing-paren'
,
'scp'
,
'!'
);
$add_option
->(
'stack-closing-square-bracket'
,
'scsb'
,
'!'
);
$add_option
->(
'stack-opening-hash-brace'
,
'sohb'
,
'!'
);
$add_option
->(
'stack-opening-paren'
,
'sop'
,
'!'
);
$add_option
->(
'stack-opening-square-bracket'
,
'sosb'
,
'!'
);
$add_option
->(
'vertical-tightness'
,
'vt'
,
'=i'
);
$add_option
->(
'vertical-tightness-closing'
,
'vtc'
,
'=i'
);
$add_option
->(
'want-break-after'
,
'wba'
,
'=s'
);
$add_option
->(
'want-break-before'
,
'wbb'
,
'=s'
);
$add_option
->(
'break-after-all-operators'
,
'baao'
,
'!'
);
$add_option
->(
'break-before-all-operators'
,
'bbao'
,
'!'
);
$add_option
->(
'keep-interior-semicolons'
,
'kis'
,
'!'
);
$add_option
->(
'one-line-block-semicolons'
,
'olbs'
,
'=i'
);
$add_option
->(
'one-line-block-nesting'
,
'olbn'
,
'=i'
);
$add_option
->(
'one-line-block-exclusion-list'
,
'olbxl'
,
'=s'
);
$add_option
->(
'break-before-hash-brace'
,
'bbhb'
,
'=i'
);
$add_option
->(
'break-before-hash-brace-and-indent'
,
'bbhbi'
,
'=i'
);
$add_option
->(
'break-before-square-bracket'
,
'bbsb'
,
'=i'
);
$add_option
->(
'break-before-square-bracket-and-indent'
,
'bbsbi'
,
'=i'
);
$add_option
->(
'break-before-paren'
,
'bbp'
,
'=i'
);
$add_option
->(
'break-before-paren-and-indent'
,
'bbpi'
,
'=i'
);
$add_option
->(
'brace-left-list'
,
'bll'
,
'=s'
);
$add_option
->(
'brace-left-exclusion-list'
,
'blxl'
,
'=s'
);
$add_option
->(
'break-after-labels'
,
'bal'
,
'=i'
);
$add_option
->(
'pack-operator-types'
,
'pot'
,
'=s'
);
$category
= 6;
$add_option
->(
'break-at-old-comma-breakpoints'
,
'boc'
,
'!'
);
$add_option
->(
'break-at-trailing-comma-types'
,
'btct'
,
'=s'
);
$add_option
->(
'comma-arrow-breakpoints'
,
'cab'
,
'=i'
);
$add_option
->(
'maximum-fields-per-table'
,
'mft'
,
'=i'
);
$category
= 7;
$add_option
->(
'break-at-old-keyword-breakpoints'
,
'bok'
,
'!'
);
$add_option
->(
'break-at-old-logical-breakpoints'
,
'bol'
,
'!'
);
$add_option
->(
'break-at-old-method-breakpoints'
,
'bom'
,
'!'
);
$add_option
->(
'break-at-old-semicolon-breakpoints'
,
'bos'
,
'!'
);
$add_option
->(
'break-at-old-ternary-breakpoints'
,
'bot'
,
'!'
);
$add_option
->(
'break-at-old-attribute-breakpoints'
,
'boa'
,
'!'
);
$add_option
->(
'keep-old-breakpoints-before'
,
'kbb'
,
'=s'
);
$add_option
->(
'keep-old-breakpoints-after'
,
'kba'
,
'=s'
);
$add_option
->(
'ignore-old-breakpoints'
,
'iob'
,
'!'
);
$category
= 8;
$add_option
->(
'blanks-before-blocks'
,
'bbb'
,
'!'
);
$add_option
->(
'blanks-before-comments'
,
'bbc'
,
'!'
);
$add_option
->(
'blank-lines-before-subs'
,
'blbs'
,
'=i'
);
$add_option
->(
'blank-lines-before-packages'
,
'blbp'
,
'=i'
);
$add_option
->(
'long-block-line-count'
,
'lbl'
,
'=i'
);
$add_option
->(
'maximum-consecutive-blank-lines'
,
'mbl'
,
'=i'
);
$add_option
->(
'keep-old-blank-lines'
,
'kbl'
,
'=i'
);
$add_option
->(
'keep-old-blank-lines-exceptions'
,
'kblx'
,
'=s'
);
$add_option
->(
'keyword-group-blanks-list'
,
'kgbl'
,
'=s'
);
$add_option
->(
'keyword-group-blanks-size'
,
'kgbs'
,
'=s'
);
$add_option
->(
'keyword-group-blanks-repeat-count'
,
'kgbr'
,
'=i'
);
$add_option
->(
'keyword-group-blanks-before'
,
'kgbb'
,
'=i'
);
$add_option
->(
'keyword-group-blanks-after'
,
'kgba'
,
'=i'
);
$add_option
->(
'keyword-group-blanks-inside'
,
'kgbi'
,
'!'
);
$add_option
->(
'keyword-group-blanks-delete'
,
'kgbd'
,
'!'
);
$add_option
->(
'blank-lines-after-opening-block'
,
'blao'
,
'=i'
);
$add_option
->(
'blank-lines-before-closing-block'
,
'blbc'
,
'=i'
);
$add_option
->(
'blank-lines-after-opening-block-list'
,
'blaol'
,
'=s'
);
$add_option
->(
'blank-lines-before-closing-block-list'
,
'blbcl'
,
'=s'
);
$category
= 9;
$add_option
->(
'warn-missing-else'
,
'wme'
,
'!'
);
$add_option
->(
'add-missing-else'
,
'ame'
,
'!'
);
$add_option
->(
'add-missing-else-comment'
,
'amec'
,
'=s'
);
$add_option
->(
'delete-block-comments'
,
'dbc'
,
'!'
);
$add_option
->(
'delete-closing-side-comments'
,
'dcsc'
,
'!'
);
$add_option
->(
'delete-pod'
,
'dp'
,
'!'
);
$add_option
->(
'delete-side-comments'
,
'dsc'
,
'!'
);
$add_option
->(
'tee-block-comments'
,
'tbc'
,
'!'
);
$add_option
->(
'tee-pod'
,
'tp'
,
'!'
);
$add_option
->(
'tee-side-comments'
,
'tsc'
,
'!'
);
$add_option
->(
'look-for-autoloader'
,
'lal'
,
'!'
);
$add_option
->(
'look-for-hash-bang'
,
'x'
,
'!'
);
$add_option
->(
'look-for-selfloader'
,
'lsl'
,
'!'
);
$add_option
->(
'pass-version-line'
,
'pvl'
,
'!'
);
$add_option
->(
'warn-variable-types'
,
'wvt'
,
'=s'
);
$add_option
->(
'warn-variable-exclusion-list'
,
'wvxl'
,
'=s'
);
$add_option
->(
'want-call-parens'
,
'wcp'
,
'=s'
);
$add_option
->(
'nowant-call-parens'
,
'nwcp'
,
'=s'
);
$add_option
->(
'warn-unique-keys'
,
'wuk'
,
'!'
);
$add_option
->(
'warn-unique-keys-cutoff'
,
'wukc'
,
'=i'
);
$add_option
->(
'warn-mismatched-args'
,
'wma'
,
'!'
);
$add_option
->(
'warn-mismatched-arg-types'
,
'wmat'
,
'=s'
);
$add_option
->(
'warn-mismatched-arg-undercount-cutoff'
,
'wmauc'
,
'=i'
);
$add_option
->(
'warn-mismatched-arg-overcount-cutoff'
,
'wmaoc'
,
'=i'
);
$add_option
->(
'warn-mismatched-arg-exclusion-list'
,
'wmaxl'
,
'=s'
);
$add_option
->(
'warn-mismatched-returns'
,
'wmr'
,
'!'
);
$add_option
->(
'warn-mismatched-return-types'
,
'wmrt'
,
'=s'
);
$add_option
->(
'warn-mismatched-return-exclusion-list'
,
'wmrxl'
,
'=s'
);
$add_option
->(
'warn-similar-keys'
,
'wsk'
,
'!'
);
$add_option
->(
'add-interbracket-arrows'
,
'aia'
,
'!'
);
$add_option
->(
'delete-interbracket-arrows'
,
'dia'
,
'!'
);
$add_option
->(
'warn-interbracket-arrows'
,
'wia'
,
'!'
);
$add_option
->(
'interbracket-arrow-style'
,
'ias'
,
'=s'
);
$add_option
->(
'interbracket-arrow-complexity'
,
'iac'
,
'=i'
);
$category
= 13;
$add_option
->(
'DEBUG'
,
'D'
,
'!'
);
$add_option
->(
'dump-block-summary'
,
'dbs'
,
'!'
);
$add_option
->(
'dump-block-minimum-lines'
,
'dbl'
,
'=i'
);
$add_option
->(
'dump-block-types'
,
'dbt'
,
'=s'
);
$add_option
->(
'dump-cuddled-block-list'
,
'dcbl'
,
'!'
);
$add_option
->(
'dump-defaults'
,
'ddf'
,
'!'
);
$add_option
->(
'dump-hash-keys'
,
'dhk'
,
'!'
);
$add_option
->(
'dump-integer-option-range'
,
'dior'
,
'!'
);
$add_option
->(
'dump-long-names'
,
'dln'
,
'!'
);
$add_option
->(
'dump-mismatched-args'
,
'dma'
,
'!'
);
$add_option
->(
'dump-mismatched-returns'
,
'dmr'
,
'!'
);
$add_option
->(
'dump-mixed-call-parens'
,
'dmcp'
,
'!'
);
$add_option
->(
'dump-options'
,
'dop'
,
'!'
);
$add_option
->(
'dump-profile'
,
'dpro'
,
'!'
);
$add_option
->(
'dump-short-names'
,
'dsn'
,
'!'
);
$add_option
->(
'dump-similar-keys'
,
'dsk'
,
'!'
);
$add_option
->(
'dump-token-types'
,
'dtt'
,
'!'
);
$add_option
->(
'dump-unusual-variables'
,
'duv'
,
'!'
);
$add_option
->(
'dump-unique-keys'
,
'duk'
,
'!'
);
$add_option
->(
'dump-want-left-space'
,
'dwls'
,
'!'
);
$add_option
->(
'dump-want-right-space'
,
'dwrs'
,
'!'
);
$add_option
->(
'fuzzy-line-length'
,
'fll'
,
'!'
);
$add_option
->(
'help'
,
'h'
, EMPTY_STRING );
$add_option
->(
'short-concatenation-item-length'
,
'scl'
,
'=i'
);
$add_option
->(
'show-options'
,
'opt'
,
'!'
);
$add_option
->(
'timestamp'
,
'ts'
,
'!'
);
$add_option
->(
'version'
,
'v'
, EMPTY_STRING );
$add_option
->(
'memoize'
,
'mem'
,
'!'
);
$add_option
->(
'file-size-order'
,
'fso'
,
'!'
);
$add_option
->(
'maximum-file-size-mb'
,
'maxfs'
,
'=i'
);
$add_option
->(
'maximum-level-errors'
,
'maxle'
,
'=i'
);
$add_option
->(
'maximum-unexpected-errors'
,
'maxue'
,
'=i'
);
$add_option
->(
'integer-range-check'
,
'irc'
,
'=i'
);
$add_option
->(
'similar-keys-maximum-difference'
,
'skmd'
,
'=i'
);
$add_option
->(
'similar-keys-minimum-length'
,
'skml'
,
'=i'
);
$add_option
->(
'similar-keys-maximum-pairs'
,
'skmp'
,
'=i'
);
Perl::Tidy::HtmlWriter->make_getopt_long_names( \
@option_string
);
$category
= 12;
foreach
my
$opt
(
@option_string
) {
my
$long_name
=
$opt
;
$long_name
=~ s/(!|=.*|:.*)$//;
if
( !
defined
(
$option_category
{
$long_name
} ) ) {
if
(
$long_name
=~ /^html-linked/ ) {
$category
= 10;
}
elsif
(
$long_name
=~ /^pod2html/ ) {
$category
= 11;
}
else
{
$category
= 12;
}
$option_category
{
$long_name
} =
$category_name
[
$category
];
}
}
my
@defaults
=
qw(
add-lone-trailing-commas
add-newlines
add-terminal-newline
add-semicolons
add-whitespace
blanks-before-blocks
blanks-before-comments
keyword-group-blanks-size=5
nokeyword-group-blanks-inside
nokeyword-group-blanks-delete
break-at-old-logical-breakpoints
break-at-old-ternary-breakpoints
break-at-old-attribute-breakpoints
break-at-old-keyword-breakpoints
nocheck-syntax
character-encoding=guess
closing-side-comments-balanced
noextended-continuation-indentation
delete-old-newlines
delete-repeated-commas
delete-lone-trailing-commas
delete-semicolons
dump-block-types=sub
extended-syntax
encode-output-strings
file-size-order
function-paren-vertical-alignment
fuzzy-line-length
hanging-side-comments
indent-block-comments
indent-leading-semicolon
logical-padding
look-for-autoloader
look-for-selfloader
memoize
nobrace-left-and-indent
nocuddled-else
nodelete-old-whitespace
nohtml
nologfile
non-indenting-braces
noquiet
noshow-options
nostatic-side-comments
notabs
nowarning-output
outdent-labels
outdent-long-quotes
outdent-long-comments
pass-version-line
noweld-nested-containers
recombine
nouse-unicode-gcstring
valign-code
valign-block-comments
valign-side-comments
valign-signed-numbers
space-for-semicolon
static-block-comments
timestamp
trim-qw
format=tidy
backup-method=copy
backup-file-extension=bak
code-skipping
format-skipping
pod2html
html-table-of-contents
html-entities
)
;
%integer_option_range
= (
'blank-lines-after-opening-block'
=> [ 0,
undef
, 0 ],
'blank-lines-before-closing-block'
=> [ 0,
undef
, 0 ],
'blank-lines-before-packages'
=> [ 0,
undef
, 1 ],
'blank-lines-before-subs'
=> [ 0,
undef
, 1 ],
'block-brace-tightness'
=> [ 0, 2, 0 ],
'block-brace-vertical-tightness'
=> [ 0, 2, 0 ],
'brace-follower-vertical-tightness'
=> [ 0, 2, 1 ],
'brace-tightness'
=> [ 0, 2, 1 ],
'brace-vertical-tightness'
=> [ 0, 2, 0 ],
'brace-vertical-tightness-closing'
=> [ 0, 3, 0 ],
'break-after-labels'
=> [ 0, 2, 0 ],
'break-before-hash-brace'
=> [ 0, 3, 0 ],
'break-before-hash-brace-and-indent'
=> [ 0, 2, 0 ],
'break-before-paren'
=> [ 0, 3, 0 ],
'break-before-paren-and-indent'
=> [ 0, 2, 0 ],
'break-before-square-bracket'
=> [ 0, 3, 0 ],
'break-before-square-bracket-and-indent'
=> [ 0, 2, 0 ],
'closing-brace-indentation'
=> [ 0, 3, 0 ],
'closing-paren-indentation'
=> [ 0, 3, 0 ],
'closing-side-comment-else-flag'
=> [ 0, 2, 0 ],
'closing-side-comment-interval'
=> [ 0,
undef
, 6 ],
'closing-side-comment-maximum-text'
=> [ 0,
undef
, 20 ],
'closing-square-bracket-indentation'
=> [ 0, 3, 0 ],
'closing-token-indentation'
=> [ 0, 3,
undef
],
'comma-arrow-breakpoints'
=> [ 0, 5, 5 ],
'continuation-indentation'
=> [ 0,
undef
, 2 ],
'cuddled-break-option'
=> [ 0, 2, 1 ],
'default-tabsize'
=> [ 0,
undef
, 8 ],
'dump-block-minimum-lines'
=> [ 0,
undef
, 20 ],
'entab-leading-whitespace'
=> [ 0,
undef
, 0 ],
'fixed-position-side-comment'
=> [ 0,
undef
,
undef
],
'indent-columns'
=> [ 0,
undef
, 4 ],
'integer-range-check'
=> [ 0, 3, 2 ],
'interbracket-arrow-complexity'
=> [ 0, 2, 1 ],
'iterations'
=> [ 0,
undef
, 1 ],
'keep-old-blank-lines'
=> [ 0, 2, 1 ],
'keyword-group-blanks-after'
=> [ 0, 2, 1 ],
'keyword-group-blanks-before'
=> [ 0, 2, 1 ],
'keyword-group-blanks-repeat-count'
=> [ 0,
undef
, 0 ],
'keyword-paren-inner-tightness'
=> [ 0, 2, 1 ],
'long-block-line-count'
=> [ 0,
undef
, 8 ],
'maximum-consecutive-blank-lines'
=> [ 0,
undef
, 1 ],
'maximum-fields-per-table'
=> [ 0,
undef
, 0 ],
'maximum-file-size-mb'
=> [ 0,
undef
, 10 ],
'maximum-level-errors'
=> [ 0,
undef
, 1 ],
'maximum-line-length'
=> [ 0,
undef
, 80 ],
'maximum-unexpected-errors'
=> [ 0,
undef
, 0 ],
'minimum-space-to-comment'
=> [ 0,
undef
, 4 ],
'one-line-block-nesting'
=> [ 0, 1, 0 ],
'one-line-block-semicolons'
=> [ 0, 2, 1 ],
'paren-tightness'
=> [ 0, 2, 1 ],
'paren-vertical-tightness'
=> [ 0, 2, 0 ],
'paren-vertical-tightness-closing'
=> [ 0, 3, 0 ],
'short-concatenation-item-length'
=> [ 0,
undef
, 8 ],
'similar-keys-maximum-difference'
=> [ 1,
undef
, 1 ],
'similar-keys-maximum-pairs'
=> [ 1,
undef
, 25 ],
'similar-keys-minimum-length'
=> [ 1,
undef
, 4 ],
'space-backslash-quote'
=> [ 0, 2, 1 ],
'space-prototype-paren'
=> [ 0, 2, 1 ],
'space-signature-paren'
=> [ 0, 2, 1 ],
'square-bracket-tightness'
=> [ 0, 2, 1 ],
'square-bracket-vertical-tightness'
=> [ 0, 2, 0 ],
'square-bracket-vertical-tightness-closing'
=> [ 0, 3, 0 ],
'starting-indentation-level'
=> [ 0,
undef
,
undef
],
'timeout-in-seconds'
=> [ 0,
undef
, 10 ],
'valign-signed-numbers-limit'
=> [ 0,
undef
, 20 ],
'vertical-tightness'
=> [ 0, 2,
undef
],
'vertical-tightness-closing'
=> [ 0, 3,
undef
],
'warn-mismatched-arg-overcount-cutoff'
=> [ 0,
undef
, 1 ],
'warn-mismatched-arg-undercount-cutoff'
=> [ 0,
undef
, 4 ],
'warn-unique-keys-cutoff'
=> [ 1,
undef
, 1 ],
'whitespace-cycle'
=> [ 0,
undef
, 0 ],
);
foreach
my
$key
(
keys
%integer_option_range
) {
my
$val
=
$integer_option_range
{
$key
}->[2];
if
(
defined
(
$val
) ) {
push
@defaults
,
"$key=$val"
;
}
}
if
(DEVEL_MODE) {
my
%option_flag
;
my
$msg
= EMPTY_STRING;
foreach
my
$opt
(
@option_string
) {
my
$key
=
$opt
;
my
$flag
= EMPTY_STRING;
if
(
$key
=~ /(.*)(!|=.*|:.*)$/ ) {
$key
= $1;
$flag
= $2;
}
$option_flag
{
$key
} =
$flag
;
}
foreach
my
$opt
(
keys
%integer_option_range
) {
my
$flag
=
$option_flag
{
$opt
};
if
( !
defined
(
$flag
) ) {
$flag
= EMPTY_STRING }
if
(
$flag
ne
'=i'
) {
$msg
.=
"Option '$opt' has an entry in '%integer_option_range' but is not an integer\n"
;
}
}
foreach
my
$opt
(
keys
%option_flag
) {
my
$flag
=
$option_flag
{
$opt
};
next
if
(
$flag
ne
'=i'
);
if
( !
defined
(
$integer_option_range
{
$opt
} ) ) {
$msg
.=
"Integer option '$opt' is needs an entry in '%integer_option_range'\n"
;
}
}
foreach
my
$opt
(
keys
%integer_option_range
) {
if
( @{
$integer_option_range
{
$opt
} } < 3 ) {
$msg
.=
"Integer option '$opt' does not have a default value\n"
;
}
}
if
(
$msg
) {
Fault(
$msg
);
}
}
%expansion
= (
%expansion
,
'freeze-newlines'
=> [
qw(noadd-newlines nodelete-old-newlines)
],
'fnl'
=> [
qw(freeze-newlines)
],
'freeze-whitespace'
=> [
qw(noadd-whitespace nodelete-old-whitespace)
],
'fws'
=> [
qw(freeze-whitespace)
],
'freeze-blank-lines'
=>
[
qw(maximum-consecutive-blank-lines=0 keep-old-blank-lines=2)
],
'fbl'
=> [
qw(freeze-blank-lines)
],
'indent-only'
=> [
qw(freeze-newlines freeze-whitespace)
],
'outdent-long-lines'
=> [
qw(outdent-long-quotes outdent-long-comments)
],
'nooutdent-long-lines'
=>
[
qw(nooutdent-long-quotes nooutdent-long-comments)
],
'oll'
=> [
qw(outdent-long-lines)
],
'noll'
=> [
qw(nooutdent-long-lines)
],
'io'
=> [
qw(indent-only)
],
'delete-all-comments'
=>
[
qw(delete-block-comments delete-side-comments delete-pod)
],
'nodelete-all-comments'
=>
[
qw(nodelete-block-comments nodelete-side-comments nodelete-pod)
],
'dac'
=> [
qw(delete-all-comments)
],
'ndac'
=> [
qw(nodelete-all-comments)
],
'gnu'
=> [
qw(gnu-style)
],
'pbp'
=> [
qw(perl-best-practices)
],
'tee-all-comments'
=>
[
qw(tee-block-comments tee-side-comments tee-pod)
],
'notee-all-comments'
=>
[
qw(notee-block-comments notee-side-comments notee-pod)
],
'tac'
=> [
qw(tee-all-comments)
],
'ntac'
=> [
qw(notee-all-comments)
],
'html'
=> [
qw(format=html)
],
'nhtml'
=> [
qw(format=tidy)
],
'tidy'
=> [
qw(format=tidy)
],
'brace-left'
=> [
qw(opening-brace-on-new-line)
],
'cb'
=> [
qw(cuddled-else)
],
'cuddled-blocks'
=> [
qw(cuddled-else)
],
'utf8'
=> [
qw(character-encoding=utf8)
],
'UTF8'
=> [
qw(character-encoding=utf8)
],
'guess'
=> [
qw(character-encoding=guess)
],
'swallow-optional-blank-lines'
=> [
qw(kbl=0)
],
'noswallow-optional-blank-lines'
=> [
qw(kbl=1)
],
'sob'
=> [
qw(kbl=0)
],
'nsob'
=> [
qw(kbl=1)
],
'break-after-comma-arrows'
=> [
qw(cab=0)
],
'nobreak-after-comma-arrows'
=> [
qw(cab=1)
],
'baa'
=> [
qw(cab=0)
],
'nbaa'
=> [
qw(cab=1)
],
'blanks-before-subs'
=> [
qw(blbs=1 blbp=1)
],
'bbs'
=> [
qw(blbs=1 blbp=1)
],
'noblanks-before-subs'
=> [
qw(blbs=0 blbp=0)
],
'nbbs'
=> [
qw(blbs=0 blbp=0)
],
'keyword-group-blanks'
=> [
qw(kgbb=2 kgbi kgba=2)
],
'kgb'
=> [
qw(kgbb=2 kgbi kgba=2)
],
'nokeyword-group-blanks'
=> [
qw(kgbb=1 nkgbi kgba=1)
],
'nkgb'
=> [
qw(kgbb=1 nkgbi kgba=1)
],
'break-at-old-trinary-breakpoints'
=> [
qw(bot)
],
'cti=0'
=> [
qw(cpi=0 cbi=0 csbi=0)
],
'cti=1'
=> [
qw(cpi=1 cbi=1 csbi=1)
],
'cti=2'
=> [
qw(cpi=2 cbi=2 csbi=2)
],
'icp'
=> [
qw(cpi=2 cbi=2 csbi=2)
],
'nicp'
=> [
qw(cpi=0 cbi=0 csbi=0)
],
'closing-token-indentation=0'
=> [
qw(cpi=0 cbi=0 csbi=0)
],
'closing-token-indentation=1'
=> [
qw(cpi=1 cbi=1 csbi=1)
],
'closing-token-indentation=2'
=> [
qw(cpi=2 cbi=2 csbi=2)
],
'indent-closing-paren'
=> [
qw(cpi=2 cbi=2 csbi=2)
],
'noindent-closing-paren'
=> [
qw(cpi=0 cbi=0 csbi=0)
],
'vt=0'
=> [
qw(pvt=0 bvt=0 sbvt=0)
],
'vt=1'
=> [
qw(pvt=1 bvt=1 sbvt=1)
],
'vt=2'
=> [
qw(pvt=2 bvt=2 sbvt=2)
],
'vertical-tightness=0'
=> [
qw(pvt=0 bvt=0 sbvt=0)
],
'vertical-tightness=1'
=> [
qw(pvt=1 bvt=1 sbvt=1)
],
'vertical-tightness=2'
=> [
qw(pvt=2 bvt=2 sbvt=2)
],
'vtc=0'
=> [
qw(pvtc=0 bvtc=0 sbvtc=0)
],
'vtc=1'
=> [
qw(pvtc=1 bvtc=1 sbvtc=1)
],
'vtc=2'
=> [
qw(pvtc=2 bvtc=2 sbvtc=2)
],
'vtc=3'
=> [
qw(pvtc=3 bvtc=3 sbvtc=3)
],
'vertical-tightness-closing=0'
=> [
qw(pvtc=0 bvtc=0 sbvtc=0)
],
'vertical-tightness-closing=1'
=> [
qw(pvtc=1 bvtc=1 sbvtc=1)
],
'vertical-tightness-closing=2'
=> [
qw(pvtc=2 bvtc=2 sbvtc=2)
],
'vertical-tightness-closing=3'
=> [
qw(pvtc=3 bvtc=3 sbvtc=3)
],
'otr'
=> [
qw(opr ohbr osbr)
],
'opening-token-right'
=> [
qw(opr ohbr osbr)
],
'notr'
=> [
qw(nopr nohbr nosbr)
],
'noopening-token-right'
=> [
qw(nopr nohbr nosbr)
],
'sot'
=> [
qw(sop sohb sosb)
],
'nsot'
=> [
qw(nsop nsohb nsosb)
],
'stack-opening-tokens'
=> [
qw(sop sohb sosb)
],
'nostack-opening-tokens'
=> [
qw(nsop nsohb nsosb)
],
'sct'
=> [
qw(scp schb scsb)
],
'stack-closing-tokens'
=> [
qw(scp schb scsb)
],
'nsct'
=> [
qw(nscp nschb nscsb)
],
'nostack-closing-tokens'
=> [
qw(nscp nschb nscsb)
],
'sac'
=> [
qw(sot sct)
],
'nsac'
=> [
qw(nsot nsct)
],
'stack-all-containers'
=> [
qw(sot sct)
],
'nostack-all-containers'
=> [
qw(nsot nsct)
],
'act=0'
=> [
qw(pt=0 sbt=0 bt=0 bbt=0)
],
'act=1'
=> [
qw(pt=1 sbt=1 bt=1 bbt=1)
],
'act=2'
=> [
qw(pt=2 sbt=2 bt=2 bbt=2)
],
'all-containers-tightness=0'
=> [
qw(pt=0 sbt=0 bt=0 bbt=0)
],
'all-containers-tightness=1'
=> [
qw(pt=1 sbt=1 bt=1 bbt=1)
],
'all-containers-tightness=2'
=> [
qw(pt=2 sbt=2 bt=2 bbt=2)
],
'stack-opening-block-brace'
=> [
qw(bbvt=2 bbvtl=*)
],
'sobb'
=> [
qw(bbvt=2 bbvtl=*)
],
'nostack-opening-block-brace'
=> [
qw(bbvt=0)
],
'nsobb'
=> [
qw(bbvt=0)
],
'converge'
=> [
qw(it=4)
],
'noconverge'
=> [
qw(it=1)
],
'conv'
=> [
qw(it=4)
],
'nconv'
=> [
qw(it=1)
],
'valign'
=> [
qw(vc vsc vbc)
],
'novalign'
=> [
qw(nvc nvsc nvbc)
],
'mangle'
=> [
qw(
keep-old-blank-lines=0
delete-old-newlines
delete-old-whitespace
delete-semicolons
indent-columns=0
maximum-consecutive-blank-lines=0
maximum-line-length=100000
noadd-newlines
noadd-semicolons
noadd-whitespace
noblanks-before-blocks
blank-lines-before-subs=0
blank-lines-before-packages=0
notabs
)
],
'extrude'
=> [
qw(
ci=0
delete-old-newlines
delete-old-whitespace
delete-semicolons
indent-columns=0
maximum-consecutive-blank-lines=0
maximum-line-length=1
noadd-semicolons
noadd-whitespace
noblanks-before-blocks
blank-lines-before-subs=0
blank-lines-before-packages=0
nofuzzy-line-length
notabs
norecombine
)
],
'gnu-style'
=> [
qw(
lp bl noll pt=2 bt=2 sbt=2 cpi=1 csbi=1 cbi=1
)
],
'perl-best-practices'
=> [
qw(l=78 i=4 ci=4 st se vt=2 cti=0 pt=1 bt=1 sbt=1 bbt=1 nsfs nolq)
,
q(wbb=% + - * / x != == >= <= =~ !~ < > | & = **= += *= &= <<= &&= -= /= |= >>= ||= //= .= %= ^= x=)
],
);
Perl::Tidy::HtmlWriter->make_abbreviated_names( \
%expansion
);
return
( \
@option_string
, \
@defaults
, \
%expansion
, \
%option_category
,
\
%integer_option_range
);
}
{
my
%process_command_line_cache
;
sub
process_command_line {
my
@q
=
@_
;
my
(
$perltidyrc_stream
,
$is_Windows_uu
,
$Windows_type_uu
,
$rpending_complaint_uu
,
$dump_options_type
) =
@q
;
my
$use_cache
= !
defined
(
$perltidyrc_stream
) && !
$dump_options_type
;
if
(
$use_cache
) {
my
$cache_key
=
join
(
chr
(28),
@ARGV
);
if
(
my
$result
=
$process_command_line_cache
{
$cache_key
} ) {
my
(
$argv
,
@retvals
) = @{
$result
};
@ARGV
= @{
$argv
};
return
@retvals
;
}
else
{
my
@retvals
= _process_command_line(
@q
);
$process_command_line_cache
{
$cache_key
} = [ \
@ARGV
,
@retvals
]
if
(
$retvals
[0]->{
'memoize'
} );
return
@retvals
;
}
}
else
{
return
_process_command_line(
@q
);
}
}
}
sub
_process_command_line {
my
(
$perltidyrc_stream
,
$is_Windows
,
$Windows_type
,
$rpending_complaint
,
$dump_options_type
) =
@_
;
my
$glc
;
if
(
eval
{
$glc
= Getopt::Long::Configure(); 1 } ) {
my
$ok
=
eval
{ Getopt::Long::ConfigDefaults(); 1 };
if
( !
$ok
&& DEVEL_MODE ) {
Fault(
"Failed call to Getopt::Long::ConfigDefaults: $EVAL_ERROR\n"
);
}
}
else
{
$glc
=
undef
}
my
(
$roption_string
,
$rdefaults
,
$rexpansion
,
$roption_category
,
$rinteger_option_range
)
= generate_options();
my
%Opts
= ();
{
local
@ARGV
= ();
if
(
$dump_options_type
ne
'perltidyrc'
) {
for
my
$i
( @{
$rdefaults
} ) {
push
@ARGV
,
"--"
.
$i
}
}
if
( !GetOptions( \
%Opts
, @{
$roption_string
} ) ) {
Die(
"Programming Bug reported by 'GetOptions': error in setting default options"
);
}
}
my
@raw_options
= ();
my
$saw_ignore_profile
= 0;
my
$saw_dump_profile
= 0;
my
$config_file
;
foreach
my
$i
(
@ARGV
) {
$i
=~ s/^--/-/;
if
(
$i
=~ /^-(npro|noprofile|nopro|
no
-profile)$/ ) {
$saw_ignore_profile
= 1;
}
elsif
(
$i
=~ /^-(
dump
-profile|dpro)$/ ) {
$saw_dump_profile
= 1;
}
elsif
(
$i
=~ /^-(pro|profile)=(.+)/ ) {
if
(
defined
(
$config_file
) ) {
Warn(
"Only one -pro=filename allowed, using '$2' instead of '$config_file'\n"
);
}
$config_file
= $2;
if
(
defined
(
$config_file
) ) {
if
(
my
(
$start_dir
,
$search_file
) =
(
$config_file
=~ m{^(.*)\.\.\./(.*)$} ) )
{
$start_dir
=
'.'
if
( !
$start_dir
);
$start_dir
= Cwd::realpath(
$start_dir
);
my
$found_file
=
find_file_upwards(
$start_dir
,
$search_file
);
if
(
defined
(
$found_file
) ) {
$config_file
=
$found_file
;
}
}
}
if
( !-e
$config_file
) {
Die(
"cannot find file given with -pro=$config_file: $OS_ERROR\n"
);
}
}
elsif
(
$i
=~ /^-(pro|profile)=?$/ ) {
Die(
"usage: -pro=filename or --profile=filename, no spaces\n"
);
}
elsif
(
$i
=~ /^-(?: help | [ h \? ] )$/xi ) {
usage();
Exit(0);
}
elsif
(
$i
=~ /^-(version|v)$/ ) {
show_version();
Exit(0);
}
elsif
(
$i
=~ /^-(
dump
-defaults|ddf)$/ ) {
dump_defaults( @{
$rdefaults
} );
Exit(0);
}
elsif
(
$i
=~ /^-(
dump
-integer-option-range|dior)$/ ) {
dump_integer_option_range(
$rinteger_option_range
);
Exit(0);
}
elsif
(
$i
=~ /^-(
dump
-long-names|dln)$/ ) {
dump_long_names( @{
$roption_string
} );
Exit(0);
}
elsif
(
$i
=~ /^-(
dump
-short-names|dsn)$/ ) {
dump_short_names(
$rexpansion
);
Exit(0);
}
elsif
(
$i
=~ /^-(
dump
-token-types|dtt)$/ ) {
Perl::Tidy::Tokenizer->dump_token_types(
*STDOUT
);
Exit(0);
}
else
{
}
}
my
%early_exit_commands
= (
'help'
=>
'h'
,
'version'
=>
'v'
,
'dump-defaults'
=>
'ddf'
,
'dump-integer-option-range'
=>
'dior'
,
'dump-long-names'
=>
'dln'
,
'dump-short-names'
=>
'dsn'
,
'dump-token-types'
=>
'dtt'
,
);
if
(
$saw_dump_profile
&&
$saw_ignore_profile
) {
Warn(
"No profile to dump because of -npro\n"
);
Exit(1);
}
if
( !
$saw_ignore_profile
) {
if
(
$perltidyrc_stream
) {
if
(
defined
(
$config_file
) ) {
Warn(
<<EOM);
Conflict: a perltidyrc configuration file was specified both as this
perltidy call parameter: $perltidyrc_stream
and with this -profile=$config_file.
Using -profile=$config_file.
EOM
}
else
{
$config_file
=
$perltidyrc_stream
;
}
}
my
$rconfig_file_chatter
;
${
$rconfig_file_chatter
} = EMPTY_STRING;
if
( !
defined
(
$config_file
) ) {
$config_file
=
find_config_file(
$is_Windows
,
$Windows_type
,
$rconfig_file_chatter
,
$rpending_complaint
);
}
my
$rconfig_string
;
if
(
defined
(
$config_file
) ) {
$rconfig_string
= stream_slurp(
$config_file
);
if
( !
defined
(
$rconfig_string
) ) {
Die(
"exiting because profile '$config_file' could not be opened\n"
);
}
filter_unknown_options(
$rconfig_string
,
$roption_category
,
$rexpansion
,
$rconfig_file_chatter
);
}
if
(
$saw_dump_profile
) {
dump_config_file(
$rconfig_string
,
$config_file
,
$rconfig_file_chatter
);
Exit(0);
}
if
(
defined
(
$rconfig_string
) ) {
my
(
$rconfig_list
,
$death_message
) =
read_config_file(
$rconfig_string
,
$config_file
,
$rexpansion
);
Die(
$death_message
)
if
(
$death_message
);
if
( @{
$rconfig_list
} ) {
local
@ARGV
= @{
$rconfig_list
};
expand_command_abbreviations(
$rexpansion
, \
@raw_options
,
$config_file
);
if
( !GetOptions( \
%Opts
, @{
$roption_string
} ) ) {
Die(
"Error in this config file: $config_file \nUse -npro to ignore this file, -dpro to dump it, -h for help'\n"
);
}
if
(
@ARGV
) {
my
$count
=
@ARGV
;
my
$str
= EMPTY_STRING;
foreach
my
$param
(
@ARGV
) {
if
(
length
(
$str
) < 70 ) {
if
(
$str
) {
$str
.=
', '
}
$str
.=
"'$param'"
;
}
else
{
$str
.=
", ..."
;
last
;
}
}
Die(
<<EOM);
There are $count unrecognized values in the configuration file '$config_file':
$str
Use leading dashes for parameters. Use -npro to ignore this file.
EOM
}
my
@dump_commands
=
grep
{ /^(
dump
-.*)!$/ } @{
$roption_string
};
foreach
(
@dump_commands
) { s/!$// }
foreach
my
$cmd
(
@dump_commands
,
qw{
help
stylesheet
version
}
)
{
if
(
defined
(
$Opts
{
$cmd
} ) ) {
delete
$Opts
{
$cmd
};
Warn(
"ignoring --$cmd in config file: $config_file\n"
);
}
}
}
}
}
expand_command_abbreviations(
$rexpansion
, \
@raw_options
,
$config_file
);
local
$SIG
{
'__WARN__'
} =
sub
{ Warn(
$_
[0] ) };
if
( !GetOptions( \
%Opts
, @{
$roption_string
} ) ) {
Die(
"Error on command line; for help try 'perltidy -h'\n"
);
}
foreach
my
$long_name
(
keys
%early_exit_commands
) {
if
(
$Opts
{
$long_name
} ) {
my
$short_name
=
$early_exit_commands
{
$long_name
};
Die(
<<EOM);
Ambiguous entry; please enter '--$long_name' or '-$short_name'
EOM
}
}
if
(
defined
(
$glc
) ) {
my
$ok
=
eval
{ Getopt::Long::Configure(
$glc
); 1 };
if
( !
$ok
&& DEVEL_MODE ) {
Fault(
"Could not reset Getopt::Long configuration: $EVAL_ERROR\n"
);
}
}
return
( \
%Opts
,
$config_file
, \
@raw_options
,
$roption_string
,
$rexpansion
,
$roption_category
,
$rinteger_option_range
);
}
sub
make_grep_alias_string {
my
(
$rOpts
) =
@_
;
my
$default_string
=
join
SPACE,
qw( all any first none notall reduce reductions )
;
my
%is_excluded_word
;
my
$exclude_string
=
$rOpts
->{
'grep-alias-exclusion-list'
};
if
(
$exclude_string
) {
$exclude_string
=~ s/,/ /g;
$exclude_string
=~ s/^\s+//;
$exclude_string
=~ s/\s+$//;
my
@q
=
split
/\s+/,
$exclude_string
;
@is_excluded_word
{
@q
} = (1) x
scalar
(
@q
);
}
if
(
$is_excluded_word
{
'*'
} ) {
$default_string
= EMPTY_STRING }
my
$input_string
=
$rOpts
->{
'grep-alias-list'
};
if
(
$input_string
) {
$input_string
.= SPACE .
$default_string
}
else
{
$input_string
=
$default_string
}
$input_string
=~ s/,/ /g;
$input_string
=~ s/^\s+//;
$input_string
=~ s/\s+$//;
my
@word_list
=
split
/\s+/,
$input_string
;
my
@filtered_word_list
;
my
%seen
;
foreach
my
$word
(
@word_list
) {
if
(
$word
) {
if
(
$word
!~ /^\w[\w\d]*$/ ) {
Warn(
"unexpected word in --grep-alias-list: '$word' - ignoring\n"
);
}
if
( !
$seen
{
$word
} && !
$is_excluded_word
{
$word
} ) {
$seen
{
$word
}++;
push
@filtered_word_list
,
$word
;
}
}
}
my
$joined_words
=
join
SPACE,
@filtered_word_list
;
$rOpts
->{
'grep-alias-list'
} =
$joined_words
;
return
;
}
sub
cleanup_word_list {
my
(
$rOpts
,
$option_name
,
$rforced_words
) =
@_
;
my
%seen
;
my
@input_list
;
my
$input_string
=
$rOpts
->{
$option_name
};
if
(
defined
(
$input_string
) &&
length
(
$input_string
) ) {
$input_string
=~ s/,/ /g;
$input_string
=~ s/^\s+//;
$input_string
=~ s/\s+$//;
@input_list
=
split
/\s+/,
$input_string
;
}
if
(
$rforced_words
) {
push
@input_list
, @{
$rforced_words
};
}
my
@filtered_word_list
;
foreach
my
$word
(
@input_list
) {
if
(
$word
) {
if
(
$word
=~ /^\d/ ||
$word
!~ /^\w[\w\d]*$/ ) {
Warn(
"unexpected '$option_name' word '$word' - ignoring\n"
);
}
if
( !
$seen
{
$word
} ) {
$seen
{
$word
}++;
push
@filtered_word_list
,
$word
;
}
}
}
$rOpts
->{
$option_name
} =
join
SPACE,
@filtered_word_list
;
return
\
%seen
;
}
sub
check_options {
my
(
$self
,
$num_files
,
$rinteger_option_range
) =
@_
;
my
$rOpts
=
$self
->[_rOpts_];
my
$encoding
=
$rOpts
->{
'character-encoding'
};
if
(
$encoding
!~ /^\s*(?:guess|none|utf8|utf-8)\s*$/i ) {
Die(
<<EOM);
--character-encoding = '$encoding' is not allowed; the options are: 'none', 'guess', 'utf8'
EOM
}
my
$integer_range_check
=
$rOpts
->{
'integer-range-check'
};
if
( !
defined
(
$integer_range_check
)
||
$integer_range_check
< 0
||
$integer_range_check
> 3 )
{
$integer_range_check
= 2;
}
if
(
$integer_range_check
) {
my
$Error_message
;
foreach
my
$opt
(
keys
%{
$rinteger_option_range
} ) {
my
$range
=
$rinteger_option_range
->{
$opt
};
next
unless
(
defined
(
$range
) );
my
(
$min
,
$max
,
$default
) = @{
$range
};
my
$val
=
$rOpts
->{
$opt
};
if
(
defined
(
$min
) &&
defined
(
$val
) &&
$val
<
$min
) {
$Error_message
.=
"--$opt=$val but should be >= $min"
;
if
(
$integer_range_check
< 3 ) {
$rOpts
->{
$opt
} =
$default
;
my
$def
=
defined
(
$default
) ?
$default
:
'undef'
;
$Error_message
.=
"; using default $def"
;
}
$Error_message
.=
"\n"
;
}
if
(
defined
(
$max
) &&
defined
(
$val
) &&
$val
>
$max
) {
$Error_message
.=
"--$opt=$val but should be <= $max"
;
if
(
$integer_range_check
< 3 ) {
$rOpts
->{
$opt
} =
$default
;
my
$def
=
defined
(
$default
) ?
$default
:
'undef'
;
$Error_message
.=
"; using default $def"
;
}
$Error_message
.=
"\n"
;
}
}
if
(
$Error_message
) {
if
(
$integer_range_check
== 1 ) {
}
elsif
(
$integer_range_check
== 2 ) {
Warn(
$Error_message
);
}
else
{
Die(
$Error_message
);
}
}
}
if
(
defined
(
$rOpts
->{
'vertical-tightness'
} ) ) {
my
$vt
=
$rOpts
->{
'vertical-tightness'
};
$rOpts
->{
'paren-vertical-tightness'
} =
$vt
;
$rOpts
->{
'square-bracket-vertical-tightness'
} =
$vt
;
$rOpts
->{
'brace-vertical-tightness'
} =
$vt
;
}
if
(
defined
(
$rOpts
->{
'vertical-tightness-closing'
} ) ) {
my
$vtc
=
$rOpts
->{
'vertical-tightness-closing'
};
$rOpts
->{
'paren-vertical-tightness-closing'
} =
$vtc
;
$rOpts
->{
'square-bracket-vertical-tightness-closing'
} =
$vtc
;
$rOpts
->{
'brace-vertical-tightness-closing'
} =
$vtc
;
}
if
(
defined
(
$rOpts
->{
'closing-token-indentation'
} ) ) {
my
$cti
=
$rOpts
->{
'closing-token-indentation'
};
$rOpts
->{
'closing-square-bracket-indentation'
} =
$cti
;
$rOpts
->{
'closing-brace-indentation'
} =
$cti
;
$rOpts
->{
'closing-paren-indentation'
} =
$cti
;
}
$rOpts
->{
'check-syntax'
} = 0;
my
$check_blank_count
=
sub
{
my
(
$key
,
$abbrev
) =
@_
;
if
(
$rOpts
->{
$key
} ) {
if
(
$rOpts
->{
$key
} < 0 ) {
$rOpts
->{
$key
} = 0;
Warn(
"negative value of $abbrev, setting 0\n"
);
}
if
(
$rOpts
->{
$key
} > 100 ) {
Warn(
"unreasonably large value of $abbrev, reducing\n"
);
$rOpts
->{
$key
} = 100;
}
}
return
;
};
$check_blank_count
->(
'blank-lines-before-subs'
,
'-blbs'
);
$check_blank_count
->(
'blank-lines-before-packages'
,
'-blbp'
);
$check_blank_count
->(
'blank-lines-after-block-opening'
,
'-blao'
);
$check_blank_count
->(
'blank-lines-before-block-closing'
,
'-blbc'
);
if
(
defined
(
$rOpts
->{
'logfile-gap'
} ) &&
$rOpts
->{
'logfile-gap'
} >= 0 ) {
$rOpts
->{
'logfile'
} = 1;
}
if
( !
$rOpts
->{
'add-whitespace'
}
&& !
$rOpts
->{
'delete-old-whitespace'
}
&& !
$rOpts
->{
'add-newlines'
}
&& !
$rOpts
->{
'delete-old-newlines'
} )
{
$rOpts
->{
'indent-only'
} = 1;
}
if
(
$rOpts
->{
'indent-spaced-block-comments'
} ) {
$rOpts
->{
'indent-block-comments'
} = 1;
}
if
(
$rOpts
->{
'opening-brace-always-on-right'
} ) {
if
(
$rOpts
->{
'opening-brace-on-new-line'
} ) {
Warn(
<<EOM);
Conflict: you specified both 'opening-brace-always-on-right' (-bar) and
'opening-brace-on-new-line' (-bl). Ignoring -bl.
EOM
$rOpts
->{
'opening-brace-on-new-line'
} = 0;
}
if
(
$rOpts
->{
'brace-left-and-indent'
} ) {
Warn(
<<EOM);
Conflict: you specified both 'opening-brace-always-on-right' (-bar) and
'--brace-left-and-indent' (-bli). Ignoring -bli.
EOM
$rOpts
->{
'brace-left-and-indent'
} = 0;
}
}
if
( !
defined
(
$rOpts
->{
'opening-brace-on-new-line'
} ) ) {
$rOpts
->{
'opening-brace-on-new-line'
} = 0;
}
if
(
$rOpts
->{
'entab-leading-whitespace'
} ) {
if
(
$rOpts
->{
'entab-leading-whitespace'
} < 0 ) {
Warn(
"-et=n must use a positive integer; ignoring -et\n"
);
$rOpts
->{
'entab-leading-whitespace'
} =
undef
;
}
if
(
$rOpts
->{
'tabs'
} ) {
$rOpts
->{
'tabs'
} = 0;
}
}
if
(
$rOpts
->{
'default-tabsize'
} ) {
if
(
$rOpts
->{
'default-tabsize'
} < 0 ) {
Warn(
"negative value of -dt, setting 0\n"
);
$rOpts
->{
'default-tabsize'
} = 0;
}
if
(
$rOpts
->{
'default-tabsize'
} > 20 ) {
Warn(
"unreasonably large value of -dt, reducing\n"
);
$rOpts
->{
'default-tabsize'
} = 20;
}
}
else
{
$rOpts
->{
'default-tabsize'
} = 8;
}
if
(
defined
(
$rOpts
->{
'sub-alias-list'
} )
&&
length
(
$rOpts
->{
'sub-alias-list'
} ) )
{
my
@forced_words
;
push
@forced_words
,
'sub'
;
cleanup_word_list(
$rOpts
,
'sub-alias-list'
, \
@forced_words
);
}
make_grep_alias_string(
$rOpts
);
if
( !
$rOpts
->{
'fuzzy-line-length'
} ) {
if
(
$rOpts
->{
'maximum-line-length'
} != 1
||
$rOpts
->{
'continuation-indentation'
} != 0 )
{
$rOpts
->{
'fuzzy-line-length'
} = 1;
}
}
if
(
$rOpts
->{
'short-concatenation-item-length'
} > 12 ) {
$rOpts
->{
'short-concatenation-item-length'
} = 12;
}
$rOpts
->{
'freeze-whitespace'
} = !
$rOpts
->{
'add-whitespace'
}
&& !
$rOpts
->{
'delete-old-whitespace'
};
if
(
$rOpts
->{
'freeze-whitespace'
} ) {
$rOpts
->{
'logical-padding'
} = 0;
}
$self
->[_line_separator_default_] = get_line_separator_default(
$rOpts
);
$self
->[_line_tidy_begin_] =
undef
;
$self
->[_line_tidy_end_] =
undef
;
my
$line_range_tidy
=
$rOpts
->{
'line-range-tidy'
};
if
(
$line_range_tidy
) {
if
(
$num_files
> 1 ) {
Die(
<<EOM);
--line-range-tidy expects no more than 1 filename in the arg list but saw $num_files filenames
EOM
}
$line_range_tidy
=~ s/\s+//g;
if
(
$line_range_tidy
=~ /^(\d+):(\d+)?$/ ) {
my
$n1
= $1;
my
$n2
= $2;
if
(
$n1
< 1 ) {
Die(
<<EOM);
--line-range-tidy=n1:n2 expects starting line number n1>=1 but n1=$n1
EOM
}
if
(
defined
(
$n2
) &&
$n2
<
$n1
) {
Die(
<<EOM);
--line-range-tidy=n1:n2 expects ending line number n2>=n1 but n1=$n1 and n2=$n2
EOM
}
$self
->[_line_tidy_begin_] =
$n1
;
$self
->[_line_tidy_end_] =
$n2
;
}
else
{
Die(
"unrecognized 'line-range-tidy'; expecting format '-lrt=n1:n2'\n"
);
}
}
return
;
}
sub
find_file_upwards {
my
(
$search_dir
,
$search_file
) =
@_
;
$search_dir
=~ s{/+$}{};
$search_file
=~ s{^/+}{};
while
(1) {
my
$try_path
=
"$search_dir/$search_file"
;
if
( -f
$try_path
) {
return
$try_path
;
}
elsif
(
$search_dir
eq
'/'
) {
return
;
}
else
{
$search_dir
= dirname(
$search_dir
);
}
}
return
;
}
sub
expand_command_abbreviations {
my
(
$rexpansion
,
$rraw_options
,
$config_file
) =
@_
;
my
$max_passes
= 10;
foreach
my
$pass_count
( 0 ..
$max_passes
) {
my
@new_argv
= ();
my
$abbrev_count
= 0;
foreach
my
$word
(
@ARGV
) {
if
(
$word
=~ /^(-[-]?
no
)-(.*)/ ) {
$word
= $1 . $2 }
if
(
$word
=~ /^-[-]?([\w\-]+)(.*)/ ) {
my
$abr
= $1;
my
$flags
= $2;
if
(
$pass_count
== 0 ) {
push
( @{
$rraw_options
},
$word
);
}
if
(
$rexpansion
->{
$abr
.
$flags
} ) {
$abr
=
$abr
.
$flags
;
$flags
= EMPTY_STRING;
}
if
(
$rexpansion
->{
$abr
} ) {
$abbrev_count
++;
foreach
my
$abbrev
( @{
$rexpansion
->{
$abr
} } ) {
next
unless
(
$abbrev
);
push
(
@new_argv
,
'--'
.
$abbrev
.
$flags
);
}
}
else
{
push
(
@new_argv
,
$word
);
}
}
else
{
push
(
@new_argv
,
$word
);
}
}
@ARGV
=
@new_argv
;
last
if
( !
$abbrev_count
);
if
(
$pass_count
==
$max_passes
) {
local
$LIST_SEPARATOR
=
')('
;
Warn(
<<EOM);
I'm tired. We seem to be in an infinite loop trying to expand aliases.
Here are the raw options;
(rraw_options)
EOM
my
$num
=
@new_argv
;
if
(
$num
< 50 ) {
Warn(
<<EOM);
After $max_passes passes here is ARGV
(@new_argv)
EOM
}
else
{
Warn(
<<EOM);
After $max_passes passes ARGV has $num entries
EOM
}
if
(
defined
(
$config_file
) ) {
Die(
<<"DIE");
Please check your configuration file $config_file for circular-references.
To deactivate it, use -npro.
DIE
}
else
{
Die(
<<'DIE');
Program bug - circular-references in the %expansion hash, probably due to
a recent program change.
DIE
}
}
}
return
;
}
sub
dump_short_names {
my
$rexpansion
=
shift
;
print
{
*STDOUT
}
<<EOM;
List of short names. This list shows how all abbreviations are
translated into other abbreviations and, eventually, into long names.
New abbreviations may be defined in a .perltidyrc file.
For a list of all long names, use perltidy --dump-long-names (-dln).
--------------------------------------------------------------------------
EOM
foreach
my
$abbrev
(
sort
keys
%{
$rexpansion
} ) {
my
@list
= @{
$rexpansion
->{
$abbrev
} };
print
{
*STDOUT
}
"$abbrev --> @list\n"
;
}
return
;
}
sub
check_vms_filename {
my
$filename
=
shift
;
my
(
$base
,
$path
) = fileparse(
$filename
);
$base
=~ s/;-?\d*$//
or
$base
=~ s{(
(?:^|[^^])\.
(?:
|
.*[^^]
)
)
\.-?\d*$
}{$1}x;
$base
.=
'.'
unless
(
$base
=~ /(?:^|[^^])\./ );
my
$separator
= (
$base
=~ /\.$/ ) ? EMPTY_STRING :
"_"
;
return
(
$path
.
$base
,
$separator
);
}
sub
Win_OS_Type {
my
$rpending_complaint
=
shift
;
my
$os
= EMPTY_STRING;
return
$os
unless
(
$OSNAME
=~ /win32|dos/i );
my
(
$undef
,
$major
,
$minor
,
$build
,
$id
);
my
$ok
=
eval
{
(
$undef
,
$major
,
$minor
,
$build
,
$id
) = Win32::GetOSVersion();
1;
};
if
( !
$ok
&& DEVEL_MODE ) {
Fault(
"Could not cal Win32::GetOSVersion(): $EVAL_ERROR\n"
);
}
return
"win32s"
unless
(
$id
);
$os
= {
1
=> {
0
=>
"95"
,
10
=>
"98"
,
90
=>
"Me"
,
},
2
=> {
0
=>
"2000"
,
1
=>
"XP/.Net"
,
2
=>
"Win2003"
,
51
=>
"NT3.51"
,
},
}->{
$id
}->{
$minor
};
if
( !
defined
(
$os
) ) {
$os
= EMPTY_STRING;
${
$rpending_complaint
} .=
<<EOS if (0);
Error trying to discover Win_OS_Type: $id:$major:$minor Has no name of record!
We won't be able to look for a system-wide config file.
EOS
}
return
(
$os
eq
"2000"
&&
$major
!= 5 ) ?
"NT4"
:
$os
;
}
sub
look_for_Windows {
my
$rpending_complaint
=
shift
;
my
$is_Windows
= (
$OSNAME
=~ /win32|dos/i );
my
$Windows_type
;
$Windows_type
= Win_OS_Type(
$rpending_complaint
)
if
(
$is_Windows
);
return
(
$is_Windows
,
$Windows_type
);
}
sub
find_config_file {
my
(
$is_Windows
,
$Windows_type
,
$rconfig_file_chatter
,
$rpending_complaint
)
=
@_
;
${
$rconfig_file_chatter
} .=
"# Config file search...system reported as:"
;
if
(
$is_Windows
) {
${
$rconfig_file_chatter
} .=
"Windows $Windows_type\n"
;
}
else
{
${
$rconfig_file_chatter
} .=
" $OSNAME\n"
;
}
my
$exists_config_file
=
sub
{
my
$config_file
=
shift
;
return
0
unless
(
defined
(
$config_file
) );
${
$rconfig_file_chatter
} .=
"# Testing: $config_file\n"
;
return
-f
$config_file
;
};
my
$resolve_config_file
=
sub
{
my
$config_file
=
shift
;
if
(
defined
(
$config_file
) ) {
if
(
my
(
$start_dir
,
$search_file
) =
(
$config_file
=~ m{^(.*)\.\.\./(.*)$} ) )
{
${
$rconfig_file_chatter
} .=
"# Searching Upward: $config_file\n"
;
$start_dir
=
'.'
if
( !
$start_dir
);
$start_dir
= Cwd::realpath(
$start_dir
);
my
$found_file
= find_file_upwards(
$start_dir
,
$search_file
);
if
(
defined
(
$found_file
) ) {
$config_file
=
$found_file
;
${
$rconfig_file_chatter
} .=
"# Found: $config_file\n"
;
}
}
}
return
$config_file
;
};
my
$config_file
;
$config_file
=
".perltidyrc"
;
return
$config_file
if
(
$exists_config_file
->(
$config_file
) );
if
(
$is_Windows
) {
$config_file
=
"perltidy.ini"
;
return
$config_file
if
(
$exists_config_file
->(
$config_file
) );
}
my
@envs
=
qw( PERLTIDY HOME )
;
push
@envs
,
qw( USERPROFILE HOMESHARE )
if
(
$OSNAME
=~ /win32/i );
foreach
my
$var
(
@envs
) {
${
$rconfig_file_chatter
} .=
"# Examining: \$ENV{$var}"
;
if
(
defined
(
$ENV
{
$var
} ) ) {
${
$rconfig_file_chatter
} .=
" = $ENV{$var}\n"
;
if
(
$var
eq
'PERLTIDY'
) {
$config_file
=
"$ENV{$var}"
;
$config_file
=
$resolve_config_file
->(
$config_file
);
return
$config_file
if
(
$exists_config_file
->(
$config_file
) );
}
$config_file
= File::Spec->catfile(
$ENV
{
$var
},
".perltidyrc"
);
$config_file
=
$resolve_config_file
->(
$config_file
);
return
$config_file
if
(
$exists_config_file
->(
$config_file
) );
if
(
$is_Windows
) {
$config_file
=
File::Spec->catfile(
$ENV
{
$var
},
"perltidy.ini"
);
$config_file
=
$resolve_config_file
->(
$config_file
);
return
$config_file
if
(
$exists_config_file
->(
$config_file
) );
}
}
else
{
${
$rconfig_file_chatter
} .=
"\n"
;
}
}
if
(
$is_Windows
) {
if
(
$Windows_type
) {
my
(
$os_uu
,
$system
,
$allusers
) =
Win_Config_Locs(
$rpending_complaint
,
$Windows_type
);
if
(
$allusers
) {
$config_file
= File::Spec->catfile(
$allusers
,
".perltidyrc"
);
return
$config_file
if
(
$exists_config_file
->(
$config_file
) );
$config_file
= File::Spec->catfile(
$allusers
,
"perltidy.ini"
);
return
$config_file
if
(
$exists_config_file
->(
$config_file
) );
}
$config_file
= File::Spec->catfile(
$system
,
".perltidyrc"
);
return
$config_file
if
(
$exists_config_file
->(
$config_file
) );
$config_file
= File::Spec->catfile(
$system
,
"perltidy.ini"
);
return
$config_file
if
(
$exists_config_file
->(
$config_file
) );
}
}
elsif
(
$OSNAME
eq
'OS2'
) {
}
elsif
(
$OSNAME
eq
'MacOS'
) {
}
elsif
(
$OSNAME
eq
'VMS'
) {
}
else
{
$config_file
=
"/usr/local/etc/perltidyrc"
;
return
$config_file
if
(
$exists_config_file
->(
$config_file
) );
$config_file
=
"/etc/perltidyrc"
;
return
$config_file
if
(
$exists_config_file
->(
$config_file
) );
}
return
;
}
sub
Win_Config_Locs {
my
(
$rpending_complaint
,
$os
) =
@_
;
if
( !
$os
) {
$os
= Win_OS_Type(
$rpending_complaint
) }
return
unless
(
$os
);
my
$system
= EMPTY_STRING;
my
$allusers
= EMPTY_STRING;
if
(
$os
=~ /9[58]|Me/ ) {
$system
=
"C:/Windows"
;
}
elsif
(
$os
=~ /NT|XP|200?/ ) {
$system
= (
$os
=~ /XP/ ) ?
"C:/Windows/"
:
"C:/WinNT/"
;
$allusers
=
(
$os
=~ /NT/ )
?
"C:/WinNT/profiles/All Users/"
:
"C:/Documents and Settings/All Users/"
;
}
else
{
${
$rpending_complaint
} .=
"I don't know a sensible place to look for config files on an $os system.\n"
;
return
;
}
return
(
$os
,
$system
,
$allusers
);
}
sub
dump_config_file {
my
(
$rconfig_string
,
$config_file
,
$rconfig_file_chatter
) =
@_
;
print
{
*STDOUT
}
"${$rconfig_file_chatter}"
;
if
(
$rconfig_string
) {
my
@lines
=
split
/^/, ${
$rconfig_string
};
print
{
*STDOUT
}
"# Dump of file: '$config_file'\n"
;
foreach
my
$line
(
@lines
) {
print
{
*STDOUT
}
$line
}
}
else
{
print
{
*STDOUT
}
"# ...no config file found\n"
;
}
return
;
}
sub
filter_unknown_options {
my
(
$rconfig_string
,
$roption_category
,
$rexpansion
,
$rconfig_file_chatter
) =
@_
;
if
( ${
$rconfig_string
} !~ /^\s*---\w/m ) {
return
}
my
$new_config_string
;
my
$change_notices
= EMPTY_STRING;
my
@lines
=
split
/^/, ${
$rconfig_string
};
foreach
my
$line
(
@lines
) {
chomp
$line
;
if
(
$line
&&
$line
=~ /^\s*---(\w[\w-]*)/ ) {
my
$word
= $1;
my
$is_known
=
$roption_category
->{
$word
} ||
$rexpansion
->{
$word
};
if
( !
$is_known
&&
$word
=~ s/^
no
-?// ) {
$is_known
=
$roption_category
->{
$word
};
}
if
( !
$is_known
) {
$change_notices
.=
"# removing unknown option line $line\n"
;
next
;
}
else
{
$change_notices
.=
"# accepting and fixing line $line\n"
;
$line
=~ s/-//;
}
}
$new_config_string
.=
$line
.
"\n"
;
}
if
(
$change_notices
) {
${
$rconfig_file_chatter
} .=
"# Filter operations:\n"
.
$change_notices
;
${
$rconfig_string
} =
$new_config_string
;
}
return
;
}
sub
read_config_file {
my
(
$rconfig_string
,
$config_file
,
$rexpansion
) =
@_
;
my
@config_list
= ();
my
(
$rline_hash
,
$death_message
) =
strip_comments_and_join_quotes(
$rconfig_string
,
$config_file
);
if
(
$death_message
) {
return
( \
@config_list
,
$death_message
);
}
my
$name
=
undef
;
my
$opening_brace_line
;
foreach
my
$item
( @{
$rline_hash
} ) {
my
$line
=
$item
->{line};
my
$line_no
=
$item
->{line_no};
$line
=~ s/^\s+//;
$line
=~ s/\s+$//;
next
unless
(
length
(
$line
) );
my
$body
=
$line
;
if
(
$line
=~ /^(?: (\w+) \s* \{ ) (.*)? $/x ) {
(
$name
,
$body
) = ( $1, $2 );
last
if
(
$opening_brace_line
);
$opening_brace_line
=
$line_no
unless
(
$body
&&
$body
=~ s/\}$// );
if
(
$rexpansion
->{
$name
} ) {
local
$LIST_SEPARATOR
=
')('
;
my
@names
=
sort
keys
%{
$rexpansion
};
$death_message
=
"Here is a list of all installed aliases\n(@names)\n"
.
"Attempting to redefine alias ($name) in config file $config_file line $INPUT_LINE_NUMBER\n"
;
last
;
}
$rexpansion
->{
$name
} = [];
}
elsif
(
$line
=~ /^{/ ) {
$opening_brace_line
=
undef
;
$death_message
=
"Unexpected '{' at line $line_no in config file '$config_file'\n"
;
last
;
}
elsif
(
$line
=~ /^(.*)?\}$/ ) {
$body
= $1;
if
(
$opening_brace_line
) {
$opening_brace_line
=
undef
;
}
else
{
$death_message
=
"Unexpected '}' at line $line_no in config file '$config_file'\n"
;
last
;
}
}
else
{
}
if
(
$body
) {
my
(
$rbody_parts
,
$msg
) = parse_args(
$body
);
if
(
$msg
) {
$death_message
=
<<EOM;
Error reading file '$config_file' at line number $line_no.
$msg
Please fix this line or use -npro to avoid reading this file
EOM
last
;
}
if
(
$name
) {
foreach
( @{
$rbody_parts
} ) { s/^\-+//; }
push
@{
$rexpansion
->{
$name
} }, @{
$rbody_parts
};
}
else
{
push
(
@config_list
, @{
$rbody_parts
} );
}
}
}
if
(
$opening_brace_line
) {
$death_message
=
"Didn't see a '}' to match the '{' at line $opening_brace_line in config file '$config_file'\n"
;
}
return
( \
@config_list
,
$death_message
);
}
sub
strip_comments_and_join_quotes {
my
(
$rconfig_string
,
$config_file
) =
@_
;
my
$msg
= EMPTY_STRING;
my
$rline_hash
= [];
my
$quote_char
= EMPTY_STRING;
my
$quote_start_line
= EMPTY_STRING;
my
$quote_start_line_no
= -1;
my
$in_string
= EMPTY_STRING;
my
$out_string
= EMPTY_STRING;
my
@lines
=
split
/^/, ${
$rconfig_string
};
my
$line_no
= 0;
foreach
my
$line
(
@lines
) {
$line_no
++;
$line
=~ s/^\s+//;
$line
=~ s/\s+$//;
next
unless
(
length
(
$line
) );
if
( !
$quote_char
) {
if
(
substr
(
$line
, 0, 1 ) eq
'#'
) {
next
;
}
$in_string
=
$line
;
$out_string
= EMPTY_STRING;
}
else
{
$in_string
= SPACE .
$line
;
}
while
(1) {
if
( !
$quote_char
) {
if
(
$in_string
=~ /\G([\"\'])/gc ) {
$out_string
.= $1;
$quote_char
= $1;
$quote_start_line_no
=
$line_no
;
$quote_start_line
=
$line
;
}
elsif
(
$in_string
=~ /\G
if
( !
length
(
$out_string
) ||
$out_string
=~ s/\s+$// ) {
last
;
}
$out_string
.=
'#'
;
}
elsif
(
$in_string
=~ /\G([^\
$out_string
.= $1;
}
else
{
last
;
}
}
else
{
if
(
$in_string
=~ /\G(
$quote_char
)/gc ) {
$out_string
.= $1;
$quote_char
= EMPTY_STRING;
}
elsif
(
$in_string
=~ /\G([^
$quote_char
]+)/gc ) {
$out_string
.= $1;
}
else
{
last
;
}
}
}
if
( !
$quote_char
) {
push
@{
$rline_hash
},
{
line
=>
$out_string
,
line_no
=>
$line_no
,
};
}
}
if
(
$quote_char
) {
my
$max_len
= 80;
if
(
length
(
$quote_start_line
) >
$max_len
) {
$quote_start_line
=
substr
(
$quote_start_line
, 0,
$max_len
- 3 ) .
'...'
;
}
$msg
=
<<EOM;
Error: hit EOF reading file '$config_file' looking for end of quoted text
which started at line $quote_start_line_no with quote character <$quote_char>:
$quote_start_line
Please fix or use -npro to avoid reading this file
EOM
}
return
(
$rline_hash
,
$msg
);
}
sub
parse_args {
my
(
$body
) =
@_
;
my
@body_parts
= ();
my
$quote_char
= EMPTY_STRING;
my
$part
= EMPTY_STRING;
my
$msg
= EMPTY_STRING;
if
( !
defined
(
$body
) ) {
$body
= EMPTY_STRING }
while
(1) {
if
(
$quote_char
) {
if
(
$body
=~ /\G(
$quote_char
)/gc ) {
$quote_char
= EMPTY_STRING;
}
elsif
(
$body
=~ /\G(.)/gc ) {
$part
.= $1;
}
else
{
if
(
length
(
$part
) ) {
push
@body_parts
,
$part
; }
$msg
=
<<EOM;
Did not see ending quote character <$quote_char> in this text:
$body
EOM
last
;
}
}
else
{
if
(
$body
=~ /\G([\"\'])/gc ) {
$quote_char
= $1;
}
elsif
(
$body
=~ /\G(\s+)/gc ) {
if
(
length
(
$part
) ) {
push
@body_parts
,
$part
; }
$part
= EMPTY_STRING;
}
elsif
(
$body
=~ /\G(.)/gc ) {
$part
.= $1;
}
else
{
if
(
length
(
$part
) ) {
push
@body_parts
,
$part
; }
last
;
}
}
}
return
( \
@body_parts
,
$msg
);
}
sub
dump_long_names {
my
@names
=
@_
;
print
{
*STDOUT
}
<<EOM;
# Command line long names (passed to GetOptions)
#--------------------------------------------------
# here is a summary of the Getopt codes:
# <none> does not take an argument
# =s takes a mandatory string
# :s takes an optional string
# =i takes a mandatory integer
# :i takes an optional integer
# ! does not take an argument and may be negated
# i.e., -foo and -nofoo are allowed
# a double dash signals the end of the options list
#
#--------------------------------------------------
EOM
foreach
my
$name
(
sort
@names
) {
print
{
*STDOUT
}
"$name\n"
}
return
;
}
sub
dump_integer_option_range {
my
(
$rinteger_option_range
) =
@_
;
print
{
*STDOUT
}
"Option, min, max, default\n"
;
foreach
my
$key
(
sort
keys
%{
$rinteger_option_range
} ) {
my
(
$min
,
$max
,
$default
) = @{
$rinteger_option_range
->{
$key
} };
foreach
(
$min
,
$max
,
$default
) {
$_
=
'undef'
unless
(
defined
(
$_
) );
}
print
{
*STDOUT
}
"$key, $min, $max, $default\n"
;
}
return
;
}
sub
dump_defaults {
my
@defaults
=
@_
;
print
{
*STDOUT
}
"Default command line options:\n"
;
foreach
my
$line
(
sort
@defaults
) {
print
{
*STDOUT
}
"$line\n"
}
return
;
}
sub
readable_options {
my
(
$rOpts
,
$roption_string
) =
@_
;
my
%Getopt_flags
;
my
$rGetopt_flags
= \
%Getopt_flags
;
my
$readable_options
=
"# Final parameter set for this run.\n"
;
$readable_options
.=
"# See utility 'perltidyrc_dump.pl' for nicer formatting.\n"
;
foreach
my
$opt
( @{
$roption_string
} ) {
my
$flag
= EMPTY_STRING;
if
(
$opt
=~ /(.*)(!|=.*)$/ ) {
$opt
= $1;
$flag
= $2;
}
if
(
defined
(
$rOpts
->{
$opt
} ) ) {
$rGetopt_flags
->{
$opt
} =
$flag
;
}
}
foreach
my
$key
(
sort
keys
%{
$rOpts
} ) {
my
$flag
=
$rGetopt_flags
->{
$key
};
my
$value
=
$rOpts
->{
$key
};
my
$prefix
=
'--'
;
my
$suffix
= EMPTY_STRING;
if
(
$flag
) {
if
(
$flag
=~ /^=/ ) {
if
(
$value
!~ /^\d+$/ ) {
$value
=
'"'
.
$value
.
'"'
}
$suffix
=
"="
.
$value
;
}
elsif
(
$flag
=~ /^!/ ) {
$prefix
.=
"no"
unless
(
$value
);
}
else
{
$readable_options
.=
"# ERROR in dump_options: unrecognized flag $flag for $key\n"
;
}
}
$readable_options
.=
$prefix
.
$key
.
$suffix
.
"\n"
;
}
return
$readable_options
;
}
sub
show_version {
print
{
*STDOUT
}
<<"EOM";
This is perltidy, v$VERSION
Copyright 2000-2025 by Steve Hancock
Perltidy is free software and may be copied under the terms of the GNU
General Public License, which is included in the distribution files.
Documentation can be found using 'man perltidy'
EOM
return
;
}
sub
usage {
print
{
*STDOUT
}
<<EOF;
This is perltidy version $VERSION, a perl script indenter. Usage:
perltidy [ options ] file1 file2 file3 ...
(output goes to file1.tdy, file2.tdy, file3.tdy, ...)
perltidy [ options ] file1 -o outfile
perltidy [ options ] file1 -st >outfile
perltidy [ options ] <infile >outfile
Options have short and long forms. Short forms are shown; see
man pages for long forms. Note: '=s' indicates a required string,
and '=n' indicates a required integer.
I/O control
-h show this help
-o=file name of the output file (only if single input file)
-oext=s change output extension from 'tdy' to s
-opath=path change path to be 'path' for output files
-b backup original to .bak and modify file in-place
-bext=s change default backup extension from 'bak' to s
-q deactivate error messages (for running under editor)
-w include non-critical warning messages in the .ERR error output
-log save .LOG file, which has useful diagnostics
-f force perltidy to read a binary file
-g like -log but writes more detailed .LOG file, for debugging scripts
-opt write the set of options actually used to a .LOG file
-npro ignore .perltidyrc configuration command file
-pro=file read configuration commands from file instead of .perltidyrc
-st send output to standard output, STDOUT
-se send all error output to standard error output, STDERR
-v display version number to standard output and quit
Basic Options:
-i=n use n columns per indentation level (default n=4)
-t tabs: use one tab character per indentation level, not recommended
-nt no tabs: use n spaces per indentation level (default)
-et=n entab leading whitespace n spaces per tab; not recommended
-io "indent only": just do indentation, no other formatting.
-sil=n set starting indentation level to n; use if auto detection fails
-ole=s specify output line ending (s=dos or win, mac, unix)
-ple keep output line endings same as input (input must be filename)
Whitespace Control
-fws freeze whitespace; this disables all whitespace changes
and disables the following switches:
-bt=n sets brace tightness, n= (0 = loose, 1=default, 2 = tight)
-bbt same as -bt but for code block braces; same as -bt if not given
-bbvt block braces vertically tight; use with -bl or -bli
-bbvtl=s make -bbvt to apply to selected list of block types
-pt=n paren tightness (n=0, 1 or 2)
-sbt=n square bracket tightness (n=0, 1, or 2)
-bvt=n brace vertical tightness,
n=(0=open, 1=close unless multiple steps on a line, 2=always close)
-pvt=n paren vertical tightness (see -bvt for n)
-sbvt=n square bracket vertical tightness (see -bvt for n)
-bvtc=n closing brace vertical tightness:
n=(0=open, 1=sometimes close, 2=always close)
-pvtc=n closing paren vertical tightness, see -bvtc for n.
-sbvtc=n closing square bracket vertical tightness, see -bvtc for n.
-ci=n sets continuation indentation=n, default is n=2 spaces
-lp line up parentheses, brackets, and non-BLOCK braces
-sfs add space before semicolon in for( ; ; )
-aws allow perltidy to add whitespace (default)
-dws delete all old non-essential whitespace
-icb indent closing brace of a code block
-cti=n closing indentation of paren, square bracket, or non-block brace:
n=0 none, =1 align with opening, =2 one full indentation level
-icp equivalent to -cti=2
-wls=s want space left of tokens in string; i.e. -nwls='+ - * /'
-wrs=s want space right of tokens in string;
-sts put space before terminal semicolon of a statement
-sak=s put space between keywords given in s and '(';
-nsak=s no space between keywords in s and '('; i.e. -nsak='my our local'
Line Break Control
-fnl freeze newlines; this disables all line break changes
and disables the following switches:
-anl add newlines; ok to introduce new line breaks
-bbs add blank line before subs and packages
-bbc add blank line before block comments
-bbb add blank line between major blocks
-kbl=n keep old blank lines? 0=no, 1=some, 2=all
-mbl=n maximum consecutive blank lines to output (default=1)
-ce cuddled else; use this style: '} else {'
-cb cuddled blocks (other than 'if-elsif-else')
-cbl=s list of blocks to cuddled, default 'try-catch-finally'
-dnl delete old newlines (default)
-l=n maximum line length; default n=80
-bl opening brace on new line
-sbl opening sub brace on new line. value of -bl is used if not given.
-bli opening brace on new line and indented
-bar opening brace always on right, even for long clauses
-vt=n vertical tightness (requires -lp); n controls break after opening
token: 0=never 1=no break if next line balanced 2=no break
-vtc=n vertical tightness of closing container; n controls if closing
token starts new line: 0=always 1=not unless list 1=never
-wba=s want break after tokens in string; i.e. wba=': .'
-wbb=s want break before tokens in string
-wn weld nested: combines opening and closing tokens when both are adjacent
-wnxl=s weld nested exclusion list: provides some control over the types of
containers which can be welded
Following Old Breakpoints
-kis keep interior semicolons. Allows multiple statements per line.
-boc break at old comma breaks: turns off all automatic list formatting
-bol break at old logical breakpoints: or, and, ||, && (default)
-bom break at old method call breakpoints: ->
-bok break at old list keyword breakpoints such as map, sort (default)
-bot break at old conditional (ternary ?:) operator breakpoints (default)
-boa break at old attribute breakpoints
-cab=n break at commas after a comma-arrow (=>):
n=0 break at all commas after =>
n=1 stable: break unless this breaks an existing one-line container
n=2 break only if a one-line container cannot be formed
n=3 do not treat commas after => specially at all
Comment controls
-ibc indent block comments (default)
-isbc indent spaced block comments; may indent unless no leading space
-msc=n minimum desired spaces to side comment, default 4
-fpsc=n fix position for side comments; default 0;
-csc add or update closing side comments after closing BLOCK brace
-dcsc delete closing side comments created by a -csc command
-cscp=s change closing side comment prefix to be other than '## end'
-cscl=s change closing side comment to apply to selected list of blocks
-csci=n minimum number of lines needed to apply a -csc tag, default n=6
-csct=n maximum number of columns of appended text, default n=20
-cscw causes warning if old side comment is overwritten with -csc
-sbc use 'static block comments' identified by leading '##' (default)
-sbcp=s change static block comment identifier to be other than '##'
-osbc outdent static block comments
-ssc use 'static side comments' identified by leading '##' (default)
-sscp=s change static side comment identifier to be other than '##'
Delete selected text
-dac delete all comments AND pod
-dbc delete block comments
-dsc delete side comments
-dp delete pod
Send selected text to a '.TEE' file
-tac tee all comments AND pod
-tbc tee block comments
-tsc tee side comments
-tp tee pod
Outdenting
-olq outdent long quoted strings (default)
-olc outdent a long block comment line
-ola outdent statement labels
-okw outdent control keywords (redo, next, last, goto, return)
-okwl=s specify alternative keywords for -okw command
Other controls
-mft=n maximum fields per table; default n=0 (no limit)
-x do not format lines before hash-bang line (i.e., for VMS)
-asc allows perltidy to add a ';' when missing (default)
-dsm allows perltidy to delete an unnecessary ';' (default)
Combinations of other parameters
-gnu attempt to follow GNU Coding Standards as applied to perl
-mangle remove as many newlines as possible (but keep comments and pods)
-extrude insert as many newlines as possible
Dump and die, debugging
-dop dump options used in this run to standard output and quit
-ddf dump default options to standard output and quit
-dsn dump all option short names to standard output and quit
-dln dump option long names to standard output and quit
-dpro dump whatever configuration file is in effect to standard output
-dtt dump all token types to standard output and quit
HTML
-html write an html file (see 'man perl2web' for many options)
Note: when -html is used, no indentation or formatting are done.
Hint: try perltidy -html -css=mystyle.css filename.pl
and edit mystyle.css to change the appearance of filename.html.
-nnn gives line numbers
-pre only writes out <pre>..</pre> code section
-toc places a table of contents to subs at the top (default)
-pod passes pod text through pod2html (default)
-frm write html as a frame (3 files)
-text=s extra extension for table of contents if -frm, default='toc'
-sext=s extra extension for file content if -frm, default='src'
A prefix of "n" negates short form toggle switches, and a prefix of "no"
negates the long forms. For example, -nasc means don't add missing
semicolons.
If you are unable to see this entire text, try "perltidy -h | more"
For more detailed information, and additional options, try "man perltidy",
EOF
return
;
}
1;