Mineplex/.FILES USED TO GET TO WHERE WE ARE PRESENTLY/xampp/perl/vendor/lib/Perl/Tidy.pm

4212 lines
157 KiB
Perl
Raw Normal View History

2023-05-17 21:44:01 +00:00
#
###########################################################-
#
# perltidy - a perl script indenter and formatter
#
# Copyright (c) 2000-2020 by Steve Hancock
# Distributed under the GPL license agreement; see file COPYING
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#
# For brief instructions, try 'perltidy -h'.
# For more complete documentation, try 'man perltidy'
# or visit http://perltidy.sourceforge.net
#
# This script is an example of the default style. It was formatted with:
#
# perltidy Tidy.pm
#
# Code Contributions: See ChangeLog.html for a complete history.
# Michael Cartmell supplied code for adaptation to VMS and helped with
# v-strings.
# Hugh S. Myers supplied sub streamhandle and the supporting code to
# create a Perl::Tidy module which can operate on strings, arrays, etc.
# Yves Orton supplied coding to help detect Windows versions.
# Axel Rose supplied a patch for MacPerl.
# Sebastien Aperghis-Tramoni supplied a patch for the defined or operator.
# Dan Tyrell contributed a patch for binary I/O.
# Ueli Hugenschmidt contributed a patch for -fpsc
# Sam Kington supplied a patch to identify the initial indentation of
# entabbed code.
# jonathan swartz supplied patches for:
# * .../ pattern, which looks upwards from directory
# * --notidy, to be used in directories where we want to avoid
# accidentally tidying
# * prefilter and postfilter
# * iterations option
#
# Many others have supplied key ideas, suggestions, and bug reports;
# see the CHANGES file.
#
############################################################
package Perl::Tidy;
# perlver reports minimum version needed is 5.8.0
# 5.004 needed for IO::File
# 5.008 needed for wide characters
use 5.008;
use warnings;
use strict;
use Exporter;
use Carp;
use Digest::MD5 qw(md5_hex);
use Perl::Tidy::Debugger;
use Perl::Tidy::DevNull;
use Perl::Tidy::Diagnostics;
use Perl::Tidy::FileWriter;
use Perl::Tidy::Formatter;
use Perl::Tidy::HtmlWriter;
use Perl::Tidy::IOScalar;
use Perl::Tidy::IOScalarArray;
use Perl::Tidy::IndentationItem;
use Perl::Tidy::LineSink;
use Perl::Tidy::LineSource;
use Perl::Tidy::Logger;
use Perl::Tidy::Tokenizer;
use Perl::Tidy::VerticalAligner;
local $| = 1;
use vars qw{
$VERSION
@ISA
@EXPORT
$missing_file_spec
$fh_stderr
$Warn_count
};
@ISA = qw( Exporter );
@EXPORT = qw( &perltidy );
use Cwd;
use Encode ();
use Encode::Guess;
use IO::File;
use File::Basename;
use File::Copy;
use File::Temp qw(tempfile);
BEGIN {
# Release version is the approximate YYMMDD of the release.
# Development version is (Last Release).(Development Number)
# To make the number continually increasing, the Development Number is a 2
# digit number starting at 01 after a release is continually bumped along
# at significant points during development. If it ever reaches 99 then the
# Release version must be bumped, and it is probably past time for a
# release anyway.
$VERSION = '20200619';
}
sub streamhandle {
# given filename and mode (r or w), create an object which:
# has a 'getline' method if mode='r', and
# has a 'print' method if mode='w'.
# The objects also need a 'close' method.
#
# How the object is made:
#
# if $filename is: Make object using:
# ---------------- -----------------
# '-' (STDIN if mode = 'r', STDOUT if mode='w')
# string IO::File
# ARRAY ref Perl::Tidy::IOScalarArray (formerly IO::ScalarArray)
# STRING ref Perl::Tidy::IOScalar (formerly IO::Scalar)
# object object
# (check for 'print' method for 'w' mode)
# (check for 'getline' method for 'r' mode)
# An optional flag $is_encoded_data may be given, as follows:
# Case 1. Any non-empty string: encoded data is being transferred, set
# encoding to be utf8 for files and for stdin.
# Case 2. Not given, or an empty string: unencoded binary data is being
# transferred, set binary mode for files and for stdin.
my ( $filename, $mode, $is_encoded_data ) = @_;
my $ref = ref($filename);
my $New;
my $fh;
# handle a reference
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 {
# Accept an object with a getline method for reading. Note:
# IO::File is built-in and does not respond to the defined
# operator. If this causes trouble, the check can be
# skipped and we can just let it crash if there is no
# getline.
if ( $mode =~ /[rR]/ ) {
# RT#97159; part 1 of 2: updated to use 'can'
##if ( $ref eq 'IO::File' || defined &{ $ref . "::getline" } ) {
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
}
}
# Accept an object with a print method for writing.
# See note above about IO::File
if ( $mode =~ /[wW]/ ) {
# RT#97159; part 2 of 2: updated to use 'can'
##if ( $ref eq 'IO::File' || defined &{ $ref . "::print" } ) {
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
}
}
}
}
# handle a string
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 : $!\n");
}
else {
# Case 1: handle encoded data
if ($is_encoded_data) {
if ( ref($fh) eq 'IO::File' ) {
$fh->binmode(":raw:encoding(UTF-8)");
}
elsif ( $fh eq '-' ) {
binmode STDOUT, ":raw:encoding(UTF-8)";
}
}
# Case 2: handle unencoded data
else {
if ( ref($fh) eq 'IO::File' ) { $fh->binmode(); }
elsif ( $fh eq '-' ) { binmode STDOUT }
}
}
return $fh, ( $ref or $filename );
}
sub find_input_line_ending {
# Peek at a file and return first line ending character.
# Return undefined value in case of any trouble.
my ($input_file) = @_;
my $ending;
# silently ignore input from object or stdin
if ( ref($input_file) || $input_file eq '-' ) {
return $ending;
}
my $fh;
open( $fh, '<', $input_file ) || return $ending;
binmode $fh;
my $buf;
read( $fh, $buf, 1024 );
close $fh;
if ( $buf && $buf =~ /([\012\015]+)/ ) {
my $test = $1;
# dos
if ( $test =~ /^(\015\012)+$/ ) { $ending = "\015\012" }
# mac
elsif ( $test =~ /^\015+$/ ) { $ending = "\015" }
# unix
elsif ( $test =~ /^\012+$/ ) { $ending = "\012" }
# unknown
else { }
}
# no ending seen
else { }
return $ending;
}
sub catfile {
# concatenate a path and file basename
# returns undef in case of error
my @parts = @_;
BEGIN {
eval { require File::Spec };
$missing_file_spec = $@;
}
# use File::Spec if we can
unless ($missing_file_spec) {
return File::Spec->catfile(@parts);
}
# Perl 5.004 systems may not have File::Spec so we'll make
# a simple try. We assume File::Basename is available.
# return if not successful.
my $name = pop @parts;
my $path = join '/', @parts;
my $test_file = $path . $name;
my ( $test_name, $test_path ) = fileparse($test_file);
return $test_file if ( $test_name eq $name );
return if ( $^O eq 'VMS' );
# this should work at least for Windows and Unix:
$test_file = $path . '/' . $name;
( $test_name, $test_path ) = fileparse($test_file);
return $test_file if ( $test_name eq $name );
return;
}
# Here is a map of the flow of data from the input source to the output
# line sink:
#
# LineSource-->Tokenizer-->Formatter-->VerticalAligner-->FileWriter-->
# input groups output
# lines tokens lines of lines lines
# lines
#
# The names correspond to the package names responsible for the unit processes.
#
# The overall process is controlled by the "main" package.
#
# LineSource is the stream of input lines
#
# Tokenizer analyzes a line and breaks it into tokens, peeking ahead
# if necessary. A token is any section of the input line which should be
# manipulated as a single entity during formatting. For example, a single
# ',' character is a token, and so is an entire side comment. It handles
# the complexities of Perl syntax, such as distinguishing between '<<' as
# a shift operator and as a here-document, or distinguishing between '/'
# as a divide symbol and as a pattern delimiter.
#
# Formatter inserts and deletes whitespace between tokens, and breaks
# sequences of tokens at appropriate points as output lines. It bases its
# decisions on the default rules as modified by any command-line options.
#
# VerticalAligner collects groups of lines together and tries to line up
# certain tokens, such as '=>', '#', and '=' by adding whitespace.
#
# FileWriter simply writes lines to the output stream.
#
# The Logger package, not shown, records significant events and warning
# messages. It writes a .LOG file, which may be saved with a
# '-log' or a '-g' flag.
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_options_range => undef,
dump_abbreviations => undef,
prefilter => undef,
postfilter => undef,
);
# don't overwrite callers ARGV
local @ARGV = @ARGV;
local *STDERR = *STDERR;
if ( my @bad_keys = grep { !exists $defaults{$_} } keys %input_hash ) {
local $" = ')(';
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) ) {
unless ( ref($hash_ref) eq '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 $errorfile_stream = $input_hash{'errorfile'};
my $logfile_stream = $input_hash{'logfile'};
my $teefile_stream = $input_hash{'teefile'};
my $debugfile_stream = $input_hash{'debugfile'};
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, my $stderr_file ) =
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;
}
sub Warn { my $msg = shift; $fh_stderr->print($msg); $Warn_count++; return }
sub Exit {
my $flag = shift;
if ($flag) { goto ERROR_EXIT }
else { goto NORMAL_EXIT }
croak "unexpectd return to Exit";
}
sub Die {
my $msg = shift;
Warn($msg);
Exit(1);
croak "unexpected return to Die";
}
my $md5_hex = sub {
my ($buf) = @_;
# Evaluate the MD5 sum for a string
# Patch for [rt.cpan.org #88020]
# Use utf8::encode since md5_hex() only operates on bytes.
# my $digest = md5_hex( utf8::encode($sink_buffer) );
# Note added 20180114: the above patch did not work correctly. I'm not
# sure why. But switching to the method recommended in the Perl 5
# documentation for Encode worked. According to this we can either use
# $octets = encode_utf8($string) or equivalently
# $octets = encode("utf8",$string)
# and then calculate the checksum. So:
my $octets = Encode::encode( "utf8", $buf );
my $digest = md5_hex($octets);
return $digest;
};
# extract various dump parameters
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');
my $dump_options_range = $get_hash_ref->('dump_options_range');
# validate dump_options_type
if ( defined($dump_options) ) {
unless ( defined($dump_options_type) ) {
$dump_options_type = 'perltidyrc';
}
unless ( $dump_options_type =~ /^(perltidyrc|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 = "";
}
if ($user_formatter) {
# if the user defines a formatter, there is no output stream,
# but we need a null stream to keep coding simple
$destination_stream = Perl::Tidy::DevNull->new();
}
# see if ARGV is overridden
if ( defined($argv) ) {
my $rargv = ref $argv;
if ( $rargv eq 'SCALAR' ) { $argv = ${$argv}; $rargv = undef }
# ref to ARRAY
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
}
}
# string
else {
my ( $rargv, $msg ) = parse_args($argv);
if ($msg) {
Die(<<EOM);
Error parsing this string passed to to perltidy with 'argv':
$msg
EOM
}
@ARGV = @{$rargv};
}
}
my $rpending_complaint;
${$rpending_complaint} = "";
my $rpending_logfile_message;
${$rpending_logfile_message} = "";
my ( $is_Windows, $Windows_type ) = look_for_Windows($rpending_complaint);
# VMS file names are restricted to a 40.40 format, so we append _tdy
# instead of .tdy, etc. (but see also sub check_vms_filename)
my $dot;
my $dot_pattern;
if ( $^O eq 'VMS' ) {
$dot = '_';
$dot_pattern = '_';
}
else {
$dot = '.';
$dot_pattern = '\.'; # must escape for use in regex
}
#---------------------------------------------------------------
# get command line options
#---------------------------------------------------------------
my ( $rOpts, $config_file, $rraw_options, $roption_string,
$rexpansion, $roption_category, $roption_range )
= process_command_line(
$perltidyrc_stream, $is_Windows, $Windows_type,
$rpending_complaint, $dump_options_type,
);
my $saw_extrude = ( grep { m/^-extrude$/ } @{$rraw_options} ) ? 1 : 0;
my $saw_pbp =
( grep { m/^-(pbp|perl-best-practices)$/ } @{$rraw_options} ) ? 1 : 0;
#---------------------------------------------------------------
# Handle requests to dump information
#---------------------------------------------------------------
# return or exit immediately after all dumps
my $quit_now = 0;
# Getopt parameters and their flags
if ( defined($dump_getopt_flags) ) {
$quit_now = 1;
foreach my $op ( @{$roption_string} ) {
my $opt = $op;
my $flag = "";
# Examples:
# some-option=s
# some-option=i
# some-option:i
# some-option!
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_options_range) ) {
$quit_now = 1;
%{$dump_options_range} = %{$roption_range};
}
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);
# make printable string of options for this run as possible diagnostic
my $readable_options = readable_options( $rOpts, $roption_string );
# dump from command line
if ( $rOpts->{'dump-options'} ) {
print STDOUT $readable_options;
Exit(0);
}
#---------------------------------------------------------------
# check parameters and their interactions
#---------------------------------------------------------------
my $tabsize =
check_options( $rOpts, $is_Windows, $Windows_type, $rpending_complaint );
if ($user_formatter) {
$rOpts->{'format'} = 'user';
}
# there must be one entry here for every possible format
my %default_file_extension = (
tidy => 'tdy',
html => 'html',
user => '',
);
# be sure we have a valid output format
unless ( exists $default_file_extension{ $rOpts->{'format'} } ) {
my $formats = join ' ',
sort map { "'" . $_ . "'" } keys %default_file_extension;
my $fmt = $rOpts->{'format'};
Die("-format='$fmt' but must be one of: $formats\n");
}
my $output_extension = make_extension( $rOpts->{'output-file-extension'},
$default_file_extension{ $rOpts->{'format'} }, $dot );
# If the backup extension contains a / character then the backup should
# be deleted when the -b option is used. On older versions of
# perltidy this will generate an error message due to an illegal
# file name.
#
# A backup file will still be generated but will be deleted
# at the end. If -bext='/' then this extension will be
# the default 'bak'. Otherwise it will be whatever characters
# remains after all '/' characters are removed. For example:
# -bext extension slashes
# '/' bak 1
# '/delete' delete 1
# 'delete/' delete 1
# '/dev/null' devnull 2 (Currently not allowed)
my $bext = $rOpts->{'backup-file-extension'};
my $delete_backup = ( $rOpts->{'backup-file-extension'} =~ s/\///g );
# At present only one forward slash is allowed. In the future multiple
# slashes may be allowed to allow for other options
if ( $delete_backup > 1 ) {
Die("-bext=$bext contains more than one '/'\n");
}
my $backup_extension =
make_extension( $rOpts->{'backup-file-extension'}, 'bak', $dot );
my $html_toc_extension =
make_extension( $rOpts->{'html-toc-extension'}, 'toc', $dot );
my $html_src_extension =
make_extension( $rOpts->{'html-src-extension'}, 'src', $dot );
# check for -b option;
# silently ignore unless beautify mode
my $in_place_modify = $rOpts->{'backup-and-modify-in-place'}
&& $rOpts->{'format'} eq 'tidy';
# Turn off -b with warnings in case of conflicts with other options.
# NOTE: Do this silently, without warnings, if there is a source or
# destination stream, or standard output is used. This is because the -b
# flag may have been in a .perltidyrc file and warnings break
# Test::NoWarnings. See email discussion with Merijn Brand 26 Feb 2014.
if ($in_place_modify) {
if ( $rOpts->{'standard-output'}
|| $destination_stream
|| ref $source_stream
|| $rOpts->{'outfile'}
|| defined( $rOpts->{'output-path'} ) )
{
$in_place_modify = 0;
}
}
Perl::Tidy::Formatter::check_options($rOpts);
Perl::Tidy::Tokenizer::check_options($rOpts);
if ( $rOpts->{'format'} eq 'html' ) {
Perl::Tidy::HtmlWriter->check_options($rOpts);
}
# make the pattern of file extensions that we shouldn't touch
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 .= ')$';
# Create a diagnostics object if requested;
# This is only useful for code development
my $diagnostics_object = undef;
if ( $rOpts->{'DIAGNOSTICS'} ) {
$diagnostics_object = Perl::Tidy::Diagnostics->new();
}
# no filenames should be given if input is from an array
if ($source_stream) {
if ( @ARGV > 0 ) {
Die(
"You may not specify any filenames when a source array is given\n"
);
}
# we'll stuff the source array into ARGV
unshift( @ARGV, $source_stream );
# No special treatment for source stream which is a filename.
# This will enable checks for binary files and other bad stuff.
$source_stream = undef unless ref($source_stream);
}
# use stdin by default if no source array and no args
else {
unshift( @ARGV, '-' ) unless @ARGV;
}
# Flag for loading module Unicode::GCString for evaluating text width:
# undef = ok to use but not yet loaded
# 0 = do not use; failed to load or not wanted
# 1 = successfully loaded and ok to use
# The module is not actually loaded unless/until it is needed
my $loaded_unicode_gcstring;
if ( !$rOpts->{'use-unicode-gcstring'} ) {
$loaded_unicode_gcstring = 0;
}
#---------------------------------------------------------------
# Ready to go...
# main loop to process all files in argument list
#---------------------------------------------------------------
my $number_of_files = @ARGV;
my $formatter = undef;
my $tokenizer = undef;
# If requested, process in order of increasing file size
# This can significantly reduce perl's virtual memory usage during testing.
if ( $number_of_files > 1 && $rOpts->{'file-size-order'} ) {
@ARGV =
map { $_->[0] }
sort { $a->[1] <=> $b->[1] }
map { [ $_, -e $_ ? -s $_ : 0 ] } @ARGV;
}
while ( my $input_file = shift @ARGV ) {
my $fileroot;
my @input_file_stat;
my $display_name;
#---------------------------------------------------------------
# prepare this input stream
#---------------------------------------------------------------
if ($source_stream) {
$fileroot = "perltidy";
$display_name = "<source_stream>";
# If the source is from an array or string, then .LOG output
# is only possible if a logfile stream is specified. This prevents
# unexpected perltidy.LOG files.
if ( !defined($logfile_stream) ) {
$logfile_stream = Perl::Tidy::DevNull->new();
# Likewise for .TEE and .DEBUG output
}
if ( !defined($teefile_stream) ) {
$teefile_stream = Perl::Tidy::DevNull->new();
}
if ( !defined($debugfile_stream) ) {
$debugfile_stream = Perl::Tidy::DevNull->new();
}
}
elsif ( $input_file eq '-' ) { # '-' indicates input from STDIN
$fileroot = "perltidy"; # root name to use for .ERR, .LOG, etc
$display_name = "<stdin>";
$in_place_modify = 0;
}
else {
$fileroot = $input_file;
$display_name = $input_file;
unless ( -e $input_file ) {
# file doesn't exist - check for a file glob
if ( $input_file =~ /([\?\*\[\{])/ ) {
# Windows shell may not remove quotes, so do it
my $input_file = $input_file;
if ( $input_file =~ /^\'(.+)\'$/ ) { $input_file = $1 }
if ( $input_file =~ /^\"(.+)\"$/ ) { $input_file = $1 }
my $pattern = fileglob_to_re($input_file);
##eval "/$pattern/";
if ( !$@ && opendir( DIR, './' ) ) {
my @files =
grep { /$pattern/ && !-d $_ } readdir(DIR);
closedir(DIR);
if (@files) {
unshift @ARGV, @files;
next;
}
}
}
Warn("skipping file: '$input_file': no matches found\n");
next;
}
unless ( -f $input_file ) {
Warn("skipping file: $input_file: not a regular file\n");
next;
}
# As a safety precaution, skip zero length files.
# If for example a source file got clobbered somehow,
# the old .tdy or .bak files might still exist so we
# shouldn't overwrite them with zero length files.
unless ( -s $input_file ) {
Warn("skipping file: $input_file: Zero size\n");
next;
}
unless ( ( -T $input_file ) || $rOpts->{'force-read-binary'} ) {
Warn(
"skipping file: $input_file: Non-text (override with -f)\n"
);
next;
}
# we should have a valid filename now
$fileroot = $input_file;
@input_file_stat = stat($input_file);
if ( $^O eq 'VMS' ) {
( $fileroot, $dot ) = check_vms_filename($fileroot);
}
# add option to change path here
if ( defined( $rOpts->{'output-path'} ) ) {
my ( $base, $old_path ) = fileparse($fileroot);
my $new_path = $rOpts->{'output-path'};
unless ( -d $new_path ) {
unless ( mkdir $new_path, 0777 ) {
Die("unable to create directory $new_path: $!\n");
}
}
my $path = $new_path;
$fileroot = catfile( $path, $base );
unless ($fileroot) {
Die(<<EOM);
------------------------------------------------------------------------
Problem combining $new_path and $base to make a filename; check -opath
------------------------------------------------------------------------
EOM
}
}
}
# Skip files with same extension as the output files because
# this can lead to a messy situation with files like
# script.tdy.tdy.tdy ... or worse problems ... when you
# rerun perltidy over and over with wildcard input.
if (
!$source_stream
&& ( $input_file =~ /$forbidden_file_extensions/
|| $input_file eq 'DIAGNOSTICS' )
)
{
Warn("skipping file: $input_file: wrong extension\n");
next;
}
# the 'source_object' supplies a method to read the input file
my $source_object = Perl::Tidy::LineSource->new(
input_file => $input_file,
rOpts => $rOpts,
rpending_logfile_message => $rpending_logfile_message,
);
next unless ($source_object);
my $max_iterations = $rOpts->{'iterations'};
my $do_convergence_test = $max_iterations > 1;
my $convergence_log_message;
my %saw_md5;
my $digest_input = 0;
my $buf = '';
while ( my $line = $source_object->get_line() ) {
$buf .= $line;
}
# Decode the input stream if necessary requested
my $encoding_in = "";
my $rOpts_character_encoding = $rOpts->{'character-encoding'};
my $encoding_log_message;
# Case 1. See if we already have an encoded string. In that
# case, we have to ignore any encoding flag.
if ( utf8::is_utf8($buf) ) {
$encoding_in = "utf8";
}
# Case 2. No input stream encoding requested. This is appropriate
# for single-byte encodings like ascii, latin-1, etc
elsif ( !$rOpts_character_encoding
|| $rOpts_character_encoding eq 'none' )
{
# nothing to do
}
# Case 3. guess input stream encoding if requested
elsif ( $rOpts_character_encoding =~ /^guess$/i ) {
# The guessing strategy is simple: use Encode::Guess to guess
# an encoding. If and only if the guess is utf8, try decoding and
# use it if successful. Otherwise, we proceed assuming the
# characters are encoded as single bytes (same as if 'none' had
# been specified as the encoding).
# In testing I have found that including additional guess 'suspect'
# encodings sometimes works but can sometimes lead to disaster by
# using an incorrect decoding. The user can always specify a
# specific input encoding.
my $buf_in = $buf;
my $decoder = guess_encoding( $buf_in, 'utf8' );
if ( ref($decoder) ) {
$encoding_in = $decoder->name;
if ( $encoding_in !~ /^(UTF-8|utf8)$/ ) {
$encoding_in = "";
$buf = $buf_in;
$encoding_log_message .= <<EOM;
Guessed encoding '$encoding_in' is not utf8; no encoding will be used
EOM
}
else {
eval { $buf = $decoder->decode($buf_in); };
if ($@) {
$encoding_log_message .= <<EOM;
Guessed encoding '$encoding_in' but decoding was unsuccessful; no encoding is used
EOM
# Note that a guess failed, but keep going
# This warning can eventually be removed
Warn(
"file: $input_file: bad guess to decode source as $encoding_in\n"
);
$encoding_in = "";
$buf = $buf_in;
}
else {
$encoding_log_message .= <<EOM;
Guessed encoding '$encoding_in' successfully decoded
EOM
}
}
}
}
# Case 4. Decode with a specific encoding
else {
$encoding_in = $rOpts_character_encoding;
eval {
$buf = Encode::decode( $encoding_in, $buf,
Encode::FB_CROAK | Encode::LEAVE_SRC );
};
if ($@) {
# Quit if we cannot decode by the requested encoding;
# Something is not right.
Warn(
"skipping file: $display_name: Unable to decode source as $encoding_in\n"
);
next;
}
else {
$encoding_log_message .= <<EOM;
Specified encoding '$encoding_in' successfully decoded
EOM
}
}
# Set the encoding to be used for all further i/o: If we have
# decoded the data with any format, then we must continue to
# read and write it as encoded data, and we will normalize these
# operations with utf8. If we have not decoded the data, then
# we must not treat it as encoded data.
my $is_encoded_data = $encoding_in ? 'utf8' : "";
# Define the function to determine the display width of character strings
my $length_function = sub { return length( $_[0] ) };
if ($is_encoded_data) {
# Delete any Byte Order Mark (BOM), which can cause trouble
$buf =~ s/^\x{FEFF}//;
# Try to load Unicode::GCString for defining text display width, if
# requested, when the first encoded file is encountered
if ( !defined($loaded_unicode_gcstring) ) {
eval { require Unicode::GCString };
$loaded_unicode_gcstring = !$@;
if ( $@ && $rOpts->{'use-unicode-gcstring'} ) {
Warn(<<EOM);
----------------------
Unable to load Unicode::GCString: $@
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;
};
}
}
# MD5 sum of input file is evaluated before any prefilter
if ( $rOpts->{'assert-tidy'} || $rOpts->{'assert-untidy'} ) {
$digest_input = $md5_hex->($buf);
}
# Prefilters and postfilters: The prefilter is a code reference
# that will be applied to the source before tidying, and the
# postfilter is a code reference to the result before outputting.
$buf = $prefilter->($buf) if $prefilter;
# starting MD5 sum for convergence test is evaluated after any prefilter
if ($do_convergence_test) {
my $digest = $md5_hex->($buf);
$saw_md5{$digest} = 0;
}
$source_object = Perl::Tidy::LineSource->new(
input_file => \$buf,
rOpts => $rOpts,
rpending_logfile_message => $rpending_logfile_message,
);
# register this file name with the Diagnostics package
$diagnostics_object->set_input_file($input_file)
if $diagnostics_object;
#---------------------------------------------------------------
# prepare the output stream
#---------------------------------------------------------------
my $output_file = undef;
my $actual_output_extension;
if ( $rOpts->{'outfile'} ) {
if ( $number_of_files <= 1 ) {
if ( $rOpts->{'standard-output'} ) {
my $msg = "You may not use -o and -st together";
$msg .= " (-pbp contains -st; see manual)" if ($saw_pbp);
Die("$msg\n");
}
elsif ($destination_stream) {
Die(
"You may not specify a destination array and -o together\n"
);
}
elsif ( defined( $rOpts->{'output-path'} ) ) {
Die("You may not specify -o and -opath together\n");
}
elsif ( defined( $rOpts->{'output-file-extension'} ) ) {
Die("You may not specify -o and -oext together\n");
}
$output_file = $rOpts->{outfile};
# make sure user gives a file name after -o
if ( $output_file =~ /^-/ ) {
Die("You must specify a valid filename after -o\n");
}
# do not overwrite input file with -o
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 $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 = '-';
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;
}
elsif ($source_stream) { # source but no destination goes to stdout
$output_file = '-';
}
elsif ( $input_file eq '-' ) {
$output_file = '-';
}
else {
if ($in_place_modify) {
$output_file = IO::File->new_tmpfile()
or Die("cannot open temp file for -b option: $!\n");
}
else {
$actual_output_extension = $output_extension;
$output_file = $fileroot . $output_extension;
}
}
my $fh_tee;
my $tee_file = $fileroot . $dot . "TEE";
if ($teefile_stream) { $tee_file = $teefile_stream }
if ( $rOpts->{'tee-pod'}
|| $rOpts->{'tee-block-comments'}
|| $rOpts->{'tee-side-comments'} )
{
( $fh_tee, my $tee_filename ) =
Perl::Tidy::streamhandle( $tee_file, 'w', $is_encoded_data );
if ( !$fh_tee ) {
Warn("couldn't open TEE file $tee_file: $!\n");
}
}
my $line_separator = $rOpts->{'output-line-ending'};
if ( $rOpts->{'preserve-line-endings'} ) {
$line_separator = find_input_line_ending($input_file);
}
$line_separator = "\n" unless defined($line_separator);
# the 'sink_object' knows how to write the output file
my ( $sink_object, $postfilter_buffer );
my $use_buffer =
$postfilter
|| $rOpts->{'assert-tidy'}
|| $rOpts->{'assert-untidy'};
$sink_object = Perl::Tidy::LineSink->new(
output_file => $use_buffer ? \$postfilter_buffer : $output_file,
line_separator => $line_separator,
rOpts => $rOpts,
rpending_logfile_message => $rpending_logfile_message,
is_encoded_data => $is_encoded_data,
);
#---------------------------------------------------------------
# initialize the error logger for this file
#---------------------------------------------------------------
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,
saw_extruce => $saw_extrude,
display_name => $display_name,
is_encoded_data => $is_encoded_data,
);
write_logfile_header(
$rOpts, $logger_object, $config_file,
$rraw_options, $Windows_type, $readable_options,
);
$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} );
}
#---------------------------------------------------------------
# initialize the debug object, if any
#---------------------------------------------------------------
my $debugger_object = undef;
if ( $rOpts->{DEBUG} ) {
my $debug_file = $fileroot . $dot . "DEBUG";
if ($debugfile_stream) { $debug_file = $debugfile_stream }
$debugger_object =
Perl::Tidy::Debugger->new( $debug_file, $is_encoded_data );
}
#---------------------------------------------------------------
# loop over iterations for one source stream
#---------------------------------------------------------------
# save objects to allow redirecting output during iterations
my $sink_object_final = $sink_object;
my $debugger_object_final = $debugger_object;
my $logger_object_final = $logger_object;
my $fh_tee_final = $fh_tee;
foreach my $iter ( 1 .. $max_iterations ) {
# send output stream to temp buffers until last iteration
my $sink_buffer;
if ( $iter < $max_iterations ) {
$sink_object = Perl::Tidy::LineSink->new(
output_file => \$sink_buffer,
line_separator => $line_separator,
rOpts => $rOpts,
rpending_logfile_message => $rpending_logfile_message,
is_encoded_data => $is_encoded_data,
);
}
else {
$sink_object = $sink_object_final;
}
# Save logger, debugger and tee output only on pass 1 because:
# (1) line number references must be to the starting
# source, not an intermediate result, and
# (2) we need to know if there are errors so we can stop the
# iterations early if necessary.
# (3) the tee option only works on first pass if comments are also
# being deleted.
if ( $iter > 1 ) {
$debugger_object = undef;
$logger_object = undef;
$fh_tee = undef;
}
#------------------------------------------------------------
# create a formatter for this file : html writer or
# pretty printer
#------------------------------------------------------------
# we have to delete any old formatter because, for safety,
# the formatter will check to see that there is only one.
$formatter = undef;
if ($user_formatter) {
$formatter = $user_formatter;
}
elsif ( $rOpts->{'format'} eq 'html' ) {
$formatter = Perl::Tidy::HtmlWriter->new(
input_file => $fileroot,
html_file => $output_file,
extension => $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 => $sink_object,
length_function => $length_function,
fh_tee => $fh_tee,
);
}
else {
Die("I don't know how to do -format=$rOpts->{'format'}\n");
}
unless ($formatter) {
Die("Unable to continue with $rOpts->{'format'} formatting\n");
}
#---------------------------------------------------------------
# create the tokenizer for this file
#---------------------------------------------------------------
$tokenizer = undef; # must destroy old tokenizer
$tokenizer = Perl::Tidy::Tokenizer->new(
source_object => $source_object,
logger_object => $logger_object,
debugger_object => $debugger_object,
diagnostics_object => $diagnostics_object,
tabsize => $tabsize,
starting_level => $rOpts->{'starting-indentation-level'},
indent_columns => $rOpts->{'indent-columns'},
look_for_hash_bang => $rOpts->{'look-for-hash-bang'},
look_for_autoloader => $rOpts->{'look-for-autoloader'},
look_for_selfloader => $rOpts->{'look-for-selfloader'},
trim_qw => $rOpts->{'trim-qw'},
extended_syntax => $rOpts->{'extended-syntax'},
continuation_indentation =>
$rOpts->{'continuation-indentation'},
outdent_labels => $rOpts->{'outdent-labels'},
);
#---------------------------------------------------------------
# now we can do it
#---------------------------------------------------------------
process_this_file( $tokenizer, $formatter );
#---------------------------------------------------------------
# close the input source and report errors
#---------------------------------------------------------------
$source_object->close_input_file();
# line source for next iteration (if any) comes from the current
# temporary output buffer
if ( $iter < $max_iterations ) {
$sink_object->close_output_file();
$source_object = Perl::Tidy::LineSource->new(
input_file => \$sink_buffer,
rOpts => $rOpts,
rpending_logfile_message => $rpending_logfile_message,
);
# stop iterations if errors or converged
my $stop_now = $tokenizer->report_tokenization_errors();
$stop_now ||= $tokenizer->get_unexpected_error_count();
if ($stop_now) {
$convergence_log_message = <<EOM;
Stopping iterations because of severe errors.
EOM
}
elsif ($do_convergence_test) {
my $digest = $md5_hex->($sink_buffer);
if ( !defined( $saw_md5{$digest} ) ) {
$saw_md5{$digest} = $iter;
}
else {
# Deja vu, stop iterating
$stop_now = 1;
my $iterm = $iter - 1;
if ( $saw_md5{$digest} != $iterm ) {
# Blinking (oscillating) between two stable
# end states. This has happened in the past
# but at present there are no known instances.
$convergence_log_message = <<EOM;
Blinking. Output for iteration $iter same as for $saw_md5{$digest}.
EOM
$diagnostics_object->write_diagnostics(
$convergence_log_message)
if $diagnostics_object;
# Uncomment to search for blinking states
# Warn( "$display_name: blinking; iter $iter same as for $saw_md5{$digest}\n" );
}
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;
}
}
} ## end if ($do_convergence_test)
if ($stop_now) {
# we are stopping the iterations early;
# copy the output stream to its final destination
$sink_object = $sink_object_final;
while ( my $line = $source_object->get_line() ) {
$sink_object->write_line($line);
}
$source_object->close_input_file();
last;
}
} ## end if ( $iter < $max_iterations)
} # end loop over iterations for one source file
# restore objects which have been temporarily undefined
# for second and higher iterations
$debugger_object = $debugger_object_final;
$logger_object = $logger_object_final;
$fh_tee = $fh_tee_final;
$logger_object->write_logfile_entry($convergence_log_message)
if $convergence_log_message;
#---------------------------------------------------------------
# Perform any postfilter operation
#---------------------------------------------------------------
if ($use_buffer) {
$sink_object->close_output_file();
$sink_object = Perl::Tidy::LineSink->new(
output_file => $output_file,
line_separator => $line_separator,
rOpts => $rOpts,
rpending_logfile_message => $rpending_logfile_message,
is_encoded_data => $is_encoded_data,
);
my $buf =
$postfilter
? $postfilter->($postfilter_buffer)
: $postfilter_buffer;
# Check if file changed if requested, but only after any postfilter
if ( $rOpts->{'assert-tidy'} ) {
my $digest_output = $md5_hex->($buf);
if ( $digest_output ne $digest_input ) {
$logger_object->warning(
"assertion failure: '--assert-tidy' is set but output differs from input\n"
);
}
}
if ( $rOpts->{'assert-untidy'} ) {
my $digest_output = $md5_hex->($buf);
if ( $digest_output eq $digest_input ) {
$logger_object->warning(
"assertion failure: '--assert-untidy' is set but output equals input\n"
);
}
}
$source_object = Perl::Tidy::LineSource->new(
input_file => \$buf,
rOpts => $rOpts,
rpending_logfile_message => $rpending_logfile_message,
);
while ( my $line = $source_object->get_line() ) {
$sink_object->write_line($line);
}
$source_object->close_input_file();
}
# Save names of the input and output files for syntax check
my $ifname = $input_file;
my $ofname = $output_file;
#---------------------------------------------------------------
# handle the -b option (backup and modify in-place)
#---------------------------------------------------------------
if ($in_place_modify) {
unless ( -f $input_file ) {
# oh, oh, no real file to backup ..
# shouldn't happen because of numerous preliminary checks
Die(
"problem with -b backing up input file '$input_file': not a file\n"
);
}
my $backup_name = $input_file . $backup_extension;
if ( -f $backup_name ) {
unlink($backup_name)
or Die(
"unable to remove previous '$backup_name' for -b option; check permissions: $!\n"
);
}
# backup the input file
# we use copy for symlinks, move for regular files
if ( -l $input_file ) {
File::Copy::copy( $input_file, $backup_name )
or Die("File::Copy failed trying to backup source: $!");
}
else {
rename( $input_file, $backup_name )
or Die(
"problem renaming $input_file to $backup_name for -b option: $!\n"
);
}
$ifname = $backup_name;
# copy the output to the original input file
# NOTE: it would be nice to just close $output_file and use
# File::Copy::copy here, but in this case $output_file is the
# handle of an open nameless temporary file so we would lose
# everything if we closed it.
seek( $output_file, 0, 0 )
or Die("unable to rewind a temporary file for -b option: $!\n");
my ( $fout, $iname ) =
Perl::Tidy::streamhandle( $input_file, 'w', $is_encoded_data );
if ( !$fout ) {
Die(
"problem re-opening $input_file for write for -b option; check file and directory permissions: $!\n"
);
}
my $line;
while ( $line = $output_file->getline() ) {
$fout->print($line);
}
$fout->close();
$output_file = $input_file;
$ofname = $input_file;
}
#---------------------------------------------------------------
# clean up and report errors
#---------------------------------------------------------------
$sink_object->close_output_file() if $sink_object;
$debugger_object->close_debug_file() if $debugger_object;
# set output file permissions
if ( $output_file && -f $output_file && !-l $output_file ) {
if (@input_file_stat) {
# Set file ownership and permissions
if ( $rOpts->{'format'} eq 'tidy' ) {
my ( $mode_i, $uid_i, $gid_i ) =
@input_file_stat[ 2, 4, 5 ];
my ( $uid_o, $gid_o ) = ( stat($output_file) )[ 4, 5 ];
my $input_file_permissions = $mode_i & oct(7777);
my $output_file_permissions = $input_file_permissions;
#rt128477: avoid inconsistent owner/group and suid/sgid
if ( $uid_i != $uid_o || $gid_i != $gid_o ) {
# try to change owner and group to match input file if
# in -b mode. Note: chown returns number of files
# successfully changed.
if ( $in_place_modify
&& chown( $uid_i, $gid_i, $output_file ) )
{
# owner/group successfully changed
}
else {
# owner or group differ: do not copy suid and sgid
$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"
);
}
}
}
# Make the output file for rw unless we are in -b mode.
# Explanation: perltidy does not unlink existing output
# files before writing to them, for safety. If a
# designated output file exists and is not writable,
# perltidy will halt. This can prevent a data loss if a
# user accidentally enters "perltidy infile -o
# important_ro_file", or "perltidy infile -st
# >important_ro_file". But it also means that perltidy can
# get locked out of rerunning unless it marks its own
# output files writable. The alternative, of always
# unlinking the designated output file, is less safe and
# not always possible, except in -b mode, where there is an
# assumption that a previous backup can be unlinked even if
# not writable.
if ( !$in_place_modify ) {
$output_file_permissions |= oct(600);
}
if ( !chmod( $output_file_permissions, $output_file ) ) {
# couldn't change file permissions
my $operm = sprintf "%04o", $output_file_permissions;
Warn(
"Unable to set permissions for output file '$output_file' to $operm\n"
);
}
}
# else use default permissions for html and any other format
}
}
#---------------------------------------------------------------
# Do syntax check if requested and possible
#---------------------------------------------------------------
my $infile_syntax_ok = 0; # -1 no 0=don't know 1 yes
if ( $logger_object
&& $rOpts->{'check-syntax'}
&& $ifname
&& $ofname )
{
$infile_syntax_ok =
check_syntax( $ifname, $ofname, $logger_object, $rOpts );
}
#---------------------------------------------------------------
# remove the original file for in-place modify as follows:
# $delete_backup=0 never
# $delete_backup=1 only if no errors
# $delete_backup>1 always : NOT ALLOWED, too risky, see above
#---------------------------------------------------------------
if ( $in_place_modify
&& $delete_backup
&& -f $ifname
&& ( $delete_backup > 1 || !$logger_object->{_warning_count} ) )
{
# As an added safety precaution, do not delete the source file
# if its size has dropped from positive to zero, since this
# could indicate a disaster of some kind, including a hardware
# failure. Actually, this could happen if you had a file of
# all comments (or pod) and deleted everything with -dac (-dap)
# for some reason.
if ( !-s $output_file && -s $ifname && $delete_backup == 1 ) {
Warn(
"output file '$output_file' missing or zero length; original '$ifname' not deleted\n"
);
}
else {
unlink($ifname)
or Die(
"unable to remove previous '$ifname' for -b option; check permissions: $!\n"
);
}
}
$logger_object->finish( $infile_syntax_ok, $formatter )
if $logger_object;
} # end of main loop to process all files
# Fix for RT #130297: return a true value if anything was written to the
# standard error output, even non-fatal warning messages, otherwise return
# false.
# These exit codes are returned:
# 0 = perltidy ran to completion with no errors
# 1 = perltidy could not run to completion due to errors
# 2 = perltidy ran to completion with error messages
# Note that if perltidy is run with multiple files, any single file with
# errors or warnings will write a line like
# '## Please see file testing.t.ERR'
# to standard output for each file with errors, so the flag will be true,
# even only some of the multiple files may have had errors.
NORMAL_EXIT:
my $ret = $Warn_count ? 2 : 0;
return $ret;
ERROR_EXIT:
return 1;
} # end of main program perltidy
sub get_stream_as_named_file {
# Return the name of a file containing a stream of data, creating
# a temporary file if necessary.
# Given:
# $stream - the name of a file or stream
# Returns:
# $fname = name of file if possible, or undef
# $if_tmpfile = true if temp file, undef if not temp file
#
# This routine is needed for passing actual files to Perl for
# a syntax check.
my ($stream) = @_;
my $is_tmpfile;
my $fname;
if ($stream) {
if ( ref($stream) ) {
my ( $fh_stream, $fh_name ) =
Perl::Tidy::streamhandle( $stream, 'r' );
if ($fh_stream) {
my ( $fout, $tmpnam ) = File::Temp::tempfile();
if ($fout) {
$fname = $tmpnam;
$is_tmpfile = 1;
binmode $fout;
while ( my $line = $fh_stream->getline() ) {
$fout->print($line);
}
$fout->close();
}
$fh_stream->close();
}
}
elsif ( $stream ne '-' && -f $stream ) {
$fname = $stream;
}
}
return ( $fname, $is_tmpfile );
}
sub fileglob_to_re {
# modified (corrected) from version in find2perl
my $x = shift;
$x =~ s#([./^\$()])#\\$1#g; # escape special characters
$x =~ s#\*#.*#g; # '*' -> '.*'
$x =~ s#\?#.#g; # '?' -> '.'
return "^$x\\z"; # match whole word
}
sub make_extension {
# Make a file extension, including any leading '.' if necessary
# The '.' may actually be an '_' under VMS
my ( $extension, $default, $dot ) = @_;
# Use the default if none specified
$extension = $default unless ($extension);
# Only extensions with these leading characters get a '.'
# This rule gives the user some freedom
if ( $extension =~ /^[a-zA-Z0-9]/ ) {
$extension = $dot . $extension;
}
return $extension;
}
sub write_logfile_header {
my (
$rOpts, $logger_object, $config_file,
$rraw_options, $Windows_type, $readable_options
) = @_;
$logger_object->write_logfile_entry(
"perltidy version $VERSION log file on a $^O system, OLD_PERL_VERSION=$]\n"
);
if ($Windows_type) {
$logger_object->write_logfile_entry("Windows type is $Windows_type\n");
}
my $options_string = join( ' ', @{$rraw_options} );
if ($config_file) {
$logger_object->write_logfile_entry(
"Found Configuration File >>> $config_file \n");
}
$logger_object->write_logfile_entry(
"Configuration and command line parameters for this run:\n");
$logger_object->write_logfile_entry("$options_string\n");
if ( $rOpts->{'DEBUG'} || $rOpts->{'show-options'} ) {
$rOpts->{'logfile'} = 1; # force logfile to be saved
$logger_object->write_logfile_entry(
"Final parameter set for this run\n");
$logger_object->write_logfile_entry(
"------------------------------------\n");
$logger_object->write_logfile_entry($readable_options);
$logger_object->write_logfile_entry(
"------------------------------------\n");
}
$logger_object->write_logfile_entry(
"To find error messages search for 'WARNING' with your editor\n");
return;
}
sub generate_options {
######################################################################
# Generate and return references to:
# @option_string - the list of options to be passed to Getopt::Long
# @defaults - the list of default options
# %expansion - a hash showing how all abbreviations are expanded
# %category - a hash giving the general category of each option
# %option_range - a hash giving the valid ranges of certain options
# Note: a few options are not documented in the man page and usage
# message. This is because these are experimental or debug options and
# may or may not be retained in future versions.
#
# Here are the undocumented flags as far as I know. Any of them
# may disappear at any time. They are mainly for fine-tuning
# and debugging.
#
# fll --> fuzzy-line-length # a trivial parameter which gets
# turned off for the extrude option
# which is mainly for debugging
# scl --> short-concatenation-item-length # helps break at '.'
# recombine # for debugging line breaks
# valign # for debugging vertical alignment
# I --> DIAGNOSTICS # for debugging [**DEACTIVATED**]
######################################################################
# here is a summary of the Getopt codes:
# <none> does not take an argument
# =s takes a mandatory string
# :s takes an optional string (DO NOT USE - filenames will get eaten up)
# =i takes a mandatory integer
# :i takes an optional integer (NOT RECOMMENDED - can cause trouble)
# ! 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
#
#---------------------------------------------------------------
# Define the option string passed to GetOptions.
#---------------------------------------------------------------
my @option_string = ();
my %expansion = ();
my %option_category = ();
my %option_range = ();
my $rexpansion = \%expansion;
# names of categories in manual
# leading integers will allow sorting
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',
);
# These options are parsed directly by perltidy:
# help h
# version v
# However, they are included in the option set so that they will
# be seen in the options dump.
# These long option names have no abbreviations or are treated specially
@option_string = qw(
html!
noprofile
no-profile
npro
recombine!
valign!
notidy
);
my $category = 13; # Debugging
foreach (@option_string) {
my $opt = $_; # must avoid changing the actual flag
$opt =~ s/!$//;
$option_category{$opt} = $category_name[$category];
}
$category = 11; # HTML
$option_category{html} = $category_name[$category];
# routine to install and check options
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];
}
}
};
# Install long option names which have a simple abbreviation.
# Options with code '!' get standard negation ('no' for long names,
# 'n' for abbreviations). Categories follow the manual.
###########################
$category = 0; # I/O_Control
###########################
$add_option->( 'backup-and-modify-in-place', 'b', '!' );
$add_option->( 'backup-file-extension', 'bext', '=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', '!' );
# options which are both toggle switches and values moved here
# to hide from tidyview (which does not show category 0 flags):
# -ole moved here from category 1
# -sil moved here from category 2
$add_option->( 'output-line-ending', 'ole', '=s' );
$add_option->( 'starting-indentation-level', 'sil', '=i' );
########################################
$category = 1; # Basic formatting options
########################################
$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->( 'sub-alias-list', 'sal', '=s' );
########################################
$category = 2; # Code indentation control
########################################
$add_option->( 'continuation-indentation', 'ci', '=i' );
$add_option->( 'line-up-parentheses', 'lp', '!' );
$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->( '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' );
########################################
$category = 3; # Whitespace control
########################################
$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-semicolons', 'dsm', '!' );
$add_option->( 'keyword-paren-inner-tightness', 'kpit', '=i' );
$add_option->( 'keyword-paren-inner-tightness-list', 'kpitl', '=s' );
$add_option->( 'logical-padding', 'lop', '!' );
$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->( 'space-prototype-paren', 'spp', '=i' );
########################################
$category = 4; # Comment controls
########################################
$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-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->( '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->( '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', '!' );
########################################
$category = 5; # Linebreak controls
########################################
$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-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->( '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->( '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-block-brace', 'sobb', '!' );
$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' );
########################################
$category = 6; # Controlling list formatting
########################################
$add_option->( 'break-at-old-comma-breakpoints', 'boc', '!' );
$add_option->( 'comma-arrow-breakpoints', 'cab', '=i' );
$add_option->( 'maximum-fields-per-table', 'mft', '=i' );
########################################
$category = 7; # Retaining or ignoring existing line breaks
########################################
$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->( 'ignore-old-breakpoints', 'iob', '!' );
########################################
$category = 8; # Blank line control
########################################
$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->( '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; # Other controls
########################################
$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', '!' );
########################################
$category = 13; # Debugging
########################################
## $add_option->( 'DIAGNOSTICS', 'I', '!' );
$add_option->( 'DEBUG', 'D', '!' );
$add_option->( 'dump-cuddled-block-list', 'dcbl', '!' );
$add_option->( 'dump-defaults', 'ddf', '!' );
$add_option->( 'dump-long-names', 'dln', '!' );
$add_option->( 'dump-options', 'dop', '!' );
$add_option->( 'dump-profile', 'dpro', '!' );
$add_option->( 'dump-short-names', 'dsn', '!' );
$add_option->( 'dump-token-types', 'dtt', '!' );
$add_option->( 'dump-want-left-space', 'dwls', '!' );
$add_option->( 'dump-want-right-space', 'dwrs', '!' );
$add_option->( 'fuzzy-line-length', 'fll', '!' );
$add_option->( 'help', 'h', '' );
$add_option->( 'short-concatenation-item-length', 'scl', '=i' );
$add_option->( 'show-options', 'opt', '!' );
$add_option->( 'timestamp', 'ts', '!' );
$add_option->( 'version', 'v', '' );
$add_option->( 'memoize', 'mem', '!' );
$add_option->( 'file-size-order', 'fso', '!' );
#---------------------------------------------------------------------
# The Perl::Tidy::HtmlWriter will add its own options to the string
Perl::Tidy::HtmlWriter->make_getopt_long_names( \@option_string );
########################################
# Set categories 10, 11, 12
########################################
# Based on their known order
$category = 12; # HTML properties
foreach my $opt (@option_string) {
my $long_name = $opt;
$long_name =~ s/(!|=.*|:.*)$//;
unless ( defined( $option_category{$long_name} ) ) {
if ( $long_name =~ /^html-linked/ ) {
$category = 10; # HTML options
}
elsif ( $long_name =~ /^pod2html/ ) {
$category = 11; # Pod2html
}
$option_category{$long_name} = $category_name[$category];
}
}
#---------------------------------------------------------------
# Assign valid ranges to certain options
#---------------------------------------------------------------
# In the future, these may be used to make preliminary checks
# hash keys are long names
# If key or value is undefined:
# strings may have any value
# integer ranges are >=0
# If value is defined:
# value is [qw(any valid words)] for strings
# value is [min, max] for integers
# if min is undefined, there is no lower limit
# if max is undefined, there is no upper limit
# Parameters not listed here have defaults
%option_range = (
'format' => [ 'tidy', 'html', 'user' ],
'output-line-ending' => [ 'dos', 'win', 'mac', 'unix' ],
'space-backslash-quote' => [ 0, 2 ],
'block-brace-tightness' => [ 0, 2 ],
'keyword-paren-inner-tightness' => [ 0, 2 ],
'brace-tightness' => [ 0, 2 ],
'paren-tightness' => [ 0, 2 ],
'square-bracket-tightness' => [ 0, 2 ],
'block-brace-vertical-tightness' => [ 0, 2 ],
'brace-vertical-tightness' => [ 0, 2 ],
'brace-vertical-tightness-closing' => [ 0, 2 ],
'paren-vertical-tightness' => [ 0, 2 ],
'paren-vertical-tightness-closing' => [ 0, 2 ],
'square-bracket-vertical-tightness' => [ 0, 2 ],
'square-bracket-vertical-tightness-closing' => [ 0, 2 ],
'vertical-tightness' => [ 0, 2 ],
'vertical-tightness-closing' => [ 0, 2 ],
'closing-brace-indentation' => [ 0, 3 ],
'closing-paren-indentation' => [ 0, 3 ],
'closing-square-bracket-indentation' => [ 0, 3 ],
'closing-token-indentation' => [ 0, 3 ],
'closing-side-comment-else-flag' => [ 0, 2 ],
'comma-arrow-breakpoints' => [ 0, 5 ],
'keyword-group-blanks-before' => [ 0, 2 ],
'keyword-group-blanks-after' => [ 0, 2 ],
'space-prototype-paren' => [ 0, 2 ],
);
# Note: we could actually allow negative ci if someone really wants it:
# $option_range{'continuation-indentation'} = [ undef, undef ];
#---------------------------------------------------------------
# Assign default values to the above options here, except
# for 'outfile' and 'help'.
# These settings should approximate the perlstyle(1) suggestions.
#---------------------------------------------------------------
my @defaults = qw(
add-newlines
add-semicolons
add-whitespace
blanks-before-blocks
blanks-before-comments
blank-lines-before-subs=1
blank-lines-before-packages=1
keyword-group-blanks-size=5
keyword-group-blanks-repeat-count=0
keyword-group-blanks-before=1
keyword-group-blanks-after=1
nokeyword-group-blanks-inside
nokeyword-group-blanks-delete
block-brace-tightness=0
block-brace-vertical-tightness=0
brace-tightness=1
brace-vertical-tightness-closing=0
brace-vertical-tightness=0
break-at-old-logical-breakpoints
break-at-old-ternary-breakpoints
break-at-old-attribute-breakpoints
break-at-old-keyword-breakpoints
comma-arrow-breakpoints=5
nocheck-syntax
character-encoding=guess
closing-side-comment-interval=6
closing-side-comment-maximum-text=20
closing-side-comment-else-flag=0
closing-side-comments-balanced
closing-paren-indentation=0
closing-brace-indentation=0
closing-square-bracket-indentation=0
continuation-indentation=2
cuddled-break-option=1
delete-old-newlines
delete-semicolons
extended-syntax
fuzzy-line-length
hanging-side-comments
indent-block-comments
indent-columns=4
iterations=1
keep-old-blank-lines=1
keyword-paren-inner-tightness=1
logical-padding
long-block-line-count=8
look-for-autoloader
look-for-selfloader
maximum-consecutive-blank-lines=1
maximum-fields-per-table=0
maximum-line-length=80
memoize
minimum-space-to-comment=4
nobrace-left-and-indent
nocuddled-else
nodelete-old-whitespace
nohtml
nologfile
noquiet
noshow-options
nostatic-side-comments
notabs
nowarning-output
one-line-block-semicolons=1
one-line-block-nesting=0
outdent-labels
outdent-long-quotes
outdent-long-comments
paren-tightness=1
paren-vertical-tightness-closing=0
paren-vertical-tightness=0
pass-version-line
noweld-nested-containers
recombine
nouse-unicode-gcstring
valign
short-concatenation-item-length=8
space-for-semicolon
space-backslash-quote=1
space-prototype-paren=1
square-bracket-tightness=1
square-bracket-vertical-tightness-closing=0
square-bracket-vertical-tightness=0
static-block-comments
timestamp
trim-qw
format=tidy
backup-file-extension=bak
format-skipping
default-tabsize=8
pod2html
html-table-of-contents
html-entities
);
push @defaults, "perl-syntax-check-flags=-c -T";
#---------------------------------------------------------------
# Define abbreviations which will be expanded into the above primitives.
# These may be defined recursively.
#---------------------------------------------------------------
%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)],
'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)],
# -cb is now a synonym for -ce
'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)],
'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)],
'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)],
# 'mangle' originally deleted pod and comments, but to keep it
# reversible, it no longer does. But if you really want to
# delete them, just use:
# -mangle -dac
# An interesting use for 'mangle' is to do this:
# perltidy -mangle myfile.pl -st | perltidy -o myfile.pl.new
# which will form as many one-line blocks as possible
'mangle' => [
qw(
check-syntax
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' originally deleted pod and comments, but to keep it
# reversible, it no longer does. But if you really want to
# delete them, just use
# extrude -dac
#
# An interesting use for 'extrude' is to do this:
# perltidy -extrude myfile.pl -st | perltidy -o myfile.pl.new
# which will break up all one-line blocks.
#
# Removed 'check-syntax' option, which is unsafe because it may execute
# code in BEGIN blocks. Example 'Moose/debugger-duck_type.t'.
'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
)
],
# this style tries to follow the GNU Coding Standards (which do
# not really apply to perl but which are followed by some perl
# programmers).
'gnu-style' => [
qw(
lp bl noll pt=2 bt=2 sbt=2 cpi=1 csbi=1 cbi=1
)
],
# Style suggested in Damian Conway's Perl Best Practices
'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=)
],
# Additional styles can be added here
);
Perl::Tidy::HtmlWriter->make_abbreviated_names( \%expansion );
# Uncomment next line to dump all expansions for debugging:
# dump_short_names(\%expansion);
return (
\@option_string, \@defaults, \%expansion,
\%option_category, \%option_range
);
} # end of generate_options
# Memoize process_command_line. Given same @ARGV passed in, return same
# values and same @ARGV back.
# This patch was supplied by Jonathan Swartz Nov 2012 and significantly speeds
# up masontidy (https://metacpan.org/module/masontidy)
my %process_command_line_cache;
sub process_command_line {
my @q = @_;
my (
$perltidyrc_stream, $is_Windows, $Windows_type,
$rpending_complaint, $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);
}
}
# (note the underscore here)
sub _process_command_line {
my (
$perltidyrc_stream, $is_Windows, $Windows_type,
$rpending_complaint, $dump_options_type
) = @_;
use Getopt::Long;
# Save any current Getopt::Long configuration
# and set to Getopt::Long defaults. Use eval to avoid
# breaking old versions of Perl without these routines.
# Previous configuration is reset at the exit of this routine.
my $glc;
eval { $glc = Getopt::Long::Configure() };
unless ($@) {
eval { Getopt::Long::ConfigDefaults() };
}
else { $glc = undef }
my (
$roption_string, $rdefaults, $rexpansion,
$roption_category, $roption_range
) = generate_options();
#---------------------------------------------------------------
# set the defaults by passing the above list through GetOptions
#---------------------------------------------------------------
my %Opts = ();
{
local @ARGV = ();
# do not load the defaults if we are just dumping perltidyrc
unless ( $dump_options_type eq '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 $word;
my @raw_options = ();
my $config_file = "";
my $saw_ignore_profile = 0;
my $saw_dump_profile = 0;
#---------------------------------------------------------------
# Take a first look at the command-line parameters. Do as many
# immediate dumps as possible, which can avoid confusion if the
# perltidyrc file has an error.
#---------------------------------------------------------------
foreach my $i (@ARGV) {
$i =~ s/^--/-/;
if ( $i =~ /^-(npro|noprofile|no-profile)$/ ) {
$saw_ignore_profile = 1;
}
# note: this must come before -pro and -profile, below:
elsif ( $i =~ /^-(dump-profile|dpro)$/ ) {
$saw_dump_profile = 1;
}
elsif ( $i =~ /^-(pro|profile)=(.+)/ ) {
if ($config_file) {
Warn(
"Only one -pro=filename allowed, using '$2' instead of '$config_file'\n"
);
}
$config_file = $2;
# resolve <dir>/.../<file>, meaning look upwards from directory
if ( defined($config_file) ) {
if ( my ( $start_dir, $search_file ) =
( $config_file =~ m{^(.*)\.\.\./(.*)$} ) )
{
$start_dir = '.' if !$start_dir;
$start_dir = Cwd::realpath($start_dir);
if ( my $found_file =
find_file_upwards( $start_dir, $search_file ) )
{
$config_file = $found_file;
}
}
}
unless ( -e $config_file ) {
Warn("cannot find file given with -pro=$config_file: $!\n");
$config_file = "";
}
}
elsif ( $i =~ /^-(pro|profile)=?$/ ) {
Die("usage: -pro=filename or --profile=filename, no spaces\n");
}
elsif ( $i =~ /^-(help|h|HELP|H|\?)$/ ) {
usage();
Exit(0);
}
elsif ( $i =~ /^-(version|v)$/ ) {
show_version();
Exit(0);
}
elsif ( $i =~ /^-(dump-defaults|ddf)$/ ) {
dump_defaults( @{$rdefaults} );
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);
}
}
if ( $saw_dump_profile && $saw_ignore_profile ) {
Warn("No profile to dump because of -npro\n");
Exit(1);
}
#---------------------------------------------------------------
# read any .perltidyrc configuration file
#---------------------------------------------------------------
unless ($saw_ignore_profile) {
# resolve possible conflict between $perltidyrc_stream passed
# as call parameter to perltidy and -pro=filename on command
# line.
if ($perltidyrc_stream) {
if ($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;
}
}
# look for a config file if we don't have one yet
my $rconfig_file_chatter;
${$rconfig_file_chatter} = "";
$config_file =
find_config_file( $is_Windows, $Windows_type, $rconfig_file_chatter,
$rpending_complaint )
unless $config_file;
# open any config file
my $fh_config;
if ($config_file) {
( $fh_config, $config_file ) =
Perl::Tidy::streamhandle( $config_file, 'r' );
unless ($fh_config) {
${$rconfig_file_chatter} .=
"# $config_file exists but cannot be opened\n";
}
}
if ($saw_dump_profile) {
dump_config_file( $fh_config, $config_file, $rconfig_file_chatter );
Exit(0);
}
if ($fh_config) {
my ( $rconfig_list, $death_message ) =
read_config_file( $fh_config, $config_file, $rexpansion );
Die($death_message) if ($death_message);
# process any .perltidyrc parameters right now so we can
# localize errors
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, -h for help'\n"
);
}
# Anything left in this local @ARGV is an error and must be
# invalid bare words from the configuration file. We cannot
# check this earlier because bare words may have been valid
# values for parameters. We had to wait for GetOptions to have
# a look at @ARGV.
if (@ARGV) {
my $count = @ARGV;
my $str = "\'" . pop(@ARGV) . "\'";
while ( my $param = pop(@ARGV) ) {
if ( length($str) < 70 ) {
$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
}
# Undo any options which cause premature exit. They are not
# appropriate for a config file, and it could be hard to
# diagnose the cause of the premature exit.
foreach (
qw{
dump-cuddled-block-list
dump-defaults
dump-long-names
dump-options
dump-profile
dump-short-names
dump-token-types
dump-want-left-space
dump-want-right-space
help
stylesheet
version
}
)
{
if ( defined( $Opts{$_} ) ) {
delete $Opts{$_};
Warn("ignoring --$_ in config file: $config_file\n");
}
}
}
}
}
#---------------------------------------------------------------
# now process the command line parameters
#---------------------------------------------------------------
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");
}
# reset Getopt::Long configuration back to its previous value
eval { Getopt::Long::Configure($glc) } if defined $glc;
return ( \%Opts, $config_file, \@raw_options, $roption_string,
$rexpansion, $roption_category, $roption_range );
} # end of _process_command_line
sub check_options {
my ( $rOpts, $is_Windows, $Windows_type, $rpending_complaint ) = @_;
#---------------------------------------------------------------
# check and handle any interactions among the basic options..
#---------------------------------------------------------------
# Since -vt, -vtc, and -cti are abbreviations, but under
# msdos, an unquoted input parameter like vtc=1 will be
# seen as 2 parameters, vtc and 1, so the abbreviations
# won't be seen. Therefore, we will catch them here if
# they get through.
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;
}
# In quiet mode, there is no log file and hence no way to report
# results of syntax check, so don't do it.
if ( $rOpts->{'quiet'} ) {
$rOpts->{'check-syntax'} = 0;
}
# can't check syntax if no output
if ( $rOpts->{'format'} ne 'tidy' ) {
$rOpts->{'check-syntax'} = 0;
}
# Never let Windows 9x/Me systems run syntax check -- this will prevent a
# wide variety of nasty problems on these systems, because they cannot
# reliably run backticks. Don't even think about changing this!
if ( $rOpts->{'check-syntax'}
&& $is_Windows
&& ( !$Windows_type || $Windows_type =~ /^(9|Me)/ ) )
{
$rOpts->{'check-syntax'} = 0;
}
###########################################################################
# Added Dec 2017: Deactivating check-syntax for all systems for safety
# because unexpected results can occur when code in BEGIN blocks is
# executed. This flag was included to help check for perltidy mistakes,
# and may still be useful for debugging. To activate for testing comment
# out the next three lines. Also fix sub 'do_check_syntax' in this file.
###########################################################################
else {
$rOpts->{'check-syntax'} = 0;
}
# It's really a bad idea to check syntax as root unless you wrote
# the script yourself. FIXME: not sure if this works with VMS
unless ($is_Windows) {
if ( $< == 0 && $rOpts->{'check-syntax'} ) {
$rOpts->{'check-syntax'} = 0;
${$rpending_complaint} .=
"Syntax check deactivated for safety; you shouldn't run this as root\n";
}
}
# check iteration count and quietly fix if necessary:
# - iterations option only applies to code beautification mode
# - the convergence check should stop most runs on iteration 2, and
# virtually all on iteration 3. But we'll allow up to 6.
if ( $rOpts->{'format'} ne 'tidy' ) {
$rOpts->{'iterations'} = 1;
}
elsif ( defined( $rOpts->{'iterations'} ) ) {
if ( $rOpts->{'iterations'} <= 0 ) { $rOpts->{'iterations'} = 1 }
elsif ( $rOpts->{'iterations'} > 6 ) { $rOpts->{'iterations'} = 6 }
}
else {
$rOpts->{'iterations'} = 1;
}
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;
}
}
};
# check for reasonable number of blank lines and fix to avoid problems
$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' );
# setting a non-negative logfile gap causes logfile to be saved
if ( defined( $rOpts->{'logfile-gap'} ) && $rOpts->{'logfile-gap'} >= 0 ) {
$rOpts->{'logfile'} = 1;
}
# set short-cut flag when only indentation is to be done.
# Note that the user may or may not have already set the
# indent-only flag.
if ( !$rOpts->{'add-whitespace'}
&& !$rOpts->{'delete-old-whitespace'}
&& !$rOpts->{'add-newlines'}
&& !$rOpts->{'delete-old-newlines'} )
{
$rOpts->{'indent-only'} = 1;
}
# -isbc implies -ibc
if ( $rOpts->{'indent-spaced-block-comments'} ) {
$rOpts->{'indent-block-comments'} = 1;
}
# -bli flag implies -bl
if ( $rOpts->{'brace-left-and-indent'} ) {
$rOpts->{'opening-brace-on-new-line'} = 1;
}
if ( $rOpts->{'opening-brace-always-on-right'}
&& $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;
}
# it simplifies things if -bl is 0 rather than undefined
if ( !defined( $rOpts->{'opening-brace-on-new-line'} ) ) {
$rOpts->{'opening-brace-on-new-line'} = 0;
}
# -sbl defaults to -bl if not defined
if ( !defined( $rOpts->{'opening-sub-brace-on-new-line'} ) ) {
$rOpts->{'opening-sub-brace-on-new-line'} =
$rOpts->{'opening-brace-on-new-line'};
}
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;
}
# entab leading whitespace has priority over the older 'tabs' option
if ( $rOpts->{'tabs'} ) { $rOpts->{'tabs'} = 0; }
}
# set a default tabsize to be used in guessing the starting indentation
# level if and only if this run does not use tabs and the old code does
# use tabs
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;
}
# Check and clean up any sub-alias-list
if ( $rOpts->{'sub-alias-list'} ) {
my $sub_alias_string = $rOpts->{'sub-alias-list'};
$sub_alias_string =~ s/,/ /g; # allow commas
$sub_alias_string =~ s/^\s+//;
$sub_alias_string =~ s/\s+$//;
my @sub_alias_list = split /\s+/, $sub_alias_string;
my @filtered_word_list = ('sub');
my %seen;
# include 'sub' for later convenience
$seen{sub}++;
foreach my $word (@sub_alias_list) {
if ($word) {
if ( $word !~ /^\w[\w\d]*$/ ) {
Warn("unexpected sub alias '$word' - ignoring\n");
}
if ( !$seen{$word} ) {
$seen{$word}++;
push @filtered_word_list, $word;
}
}
}
my $joined_words = join ' ', @filtered_word_list;
$rOpts->{'sub-alias-list'} = join ' ', @filtered_word_list;
}
# Define $tabsize, the number of spaces per tab for use in
# guessing the indentation of source lines with leading tabs.
# Assume same as for this run if tabs are used , otherwise assume
# a default value, typically 8
my $tabsize =
$rOpts->{'entab-leading-whitespace'}
? $rOpts->{'entab-leading-whitespace'}
: $rOpts->{'tabs'} ? $rOpts->{'indent-columns'}
: $rOpts->{'default-tabsize'};
return $tabsize;
}
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);
}
}
# This return is for Perl-Critic.
# We shouldn't get out of the while loop without a return
return;
}
sub expand_command_abbreviations {
# go through @ARGV and expand any abbreviations
my ( $rexpansion, $rraw_options, $config_file ) = @_;
# set a pass limit to prevent an infinite loop;
# 10 should be plenty, but it may be increased to allow deeply
# nested expansions.
my $max_passes = 10;
my @new_argv = ();
# keep looping until all expansions have been converted into actual
# dash parameters..
foreach my $pass_count ( 0 .. $max_passes ) {
my @new_argv = ();
my $abbrev_count = 0;
# loop over each item in @ARGV..
foreach my $word (@ARGV) {
# convert any leading 'no-' to just 'no'
if ( $word =~ /^(-[-]?no)-(.*)/ ) { $word = $1 . $2 }
# if it is a dash flag (instead of a file name)..
if ( $word =~ /^-[-]?([\w\-]+)(.*)/ ) {
my $abr = $1;
my $flags = $2;
# save the raw input for debug output in case of circular refs
if ( $pass_count == 0 ) {
push( @{$rraw_options}, $word );
}
# recombine abbreviation and flag, if necessary,
# to allow abbreviations with arguments such as '-vt=1'
if ( $rexpansion->{ $abr . $flags } ) {
$abr = $abr . $flags;
$flags = "";
}
# if we see this dash item in the expansion hash..
if ( $rexpansion->{$abr} ) {
$abbrev_count++;
# stuff all of the words that it expands to into the
# new arg list for the next pass
foreach my $abbrev ( @{ $rexpansion->{$abr} } ) {
next unless $abbrev; # for safety; shouldn't happen
push( @new_argv, '--' . $abbrev . $flags );
}
}
# not in expansion hash, must be actual long name
else {
push( @new_argv, $word );
}
}
# not a dash item, so just save it for the next pass
else {
push( @new_argv, $word );
}
} # end of this pass
# update parameter list @ARGV to the new one
@ARGV = @new_argv;
last unless ( $abbrev_count > 0 );
# make sure we are not in an infinite loop
if ( $pass_count == $max_passes ) {
local $" = ')(';
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 ($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
}
} # end of check for circular references
} # end of loop over all passes
return;
}
# Debug routine -- this will dump the expansion hash
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 {
# given a valid filename (the perltidy input file)
# create a modified filename and separator character
# suitable for VMS.
#
# Contributed by Michael Cartmell
#
my $filename = shift;
my ( $base, $path ) = fileparse($filename);
# remove explicit ; version
$base =~ s/;-?\d*$//
# remove explicit . version ie two dots in filename NB ^ escapes a dot
or $base =~ s/( # begin capture $1
(?:^|[^^])\. # match a dot not preceded by a caret
(?: # followed by nothing
| # or
.*[^^] # anything ending in a non caret
)
) # end capture $1
\.-?\d*$ # match . version number
/$1/x;
# normalise filename, if there are no unescaped dots then append one
$base .= '.' unless $base =~ /(?:^|[^^])\./;
# if we don't already have an extension then we just append the extension
my $separator = ( $base =~ /\.$/ ) ? "" : "_";
return ( $path . $base, $separator );
}
sub Win_OS_Type {
# TODO: are these more standard names?
# Win32s Win95 Win98 WinMe WinNT3.51 WinNT4 Win2000 WinXP/.Net Win2003
# Returns a string that determines what MS OS we are on.
# Returns win32s,95,98,Me,NT3.51,NT4,2000,XP/.Net,Win2003
# Returns blank string if not an MS system.
# Original code contributed by: Yves Orton
# We need to know this to decide where to look for config files
my $rpending_complaint = shift;
my $os = "";
return $os unless $^O =~ /win32|dos/i; # is it a MS box?
# Systems built from Perl source may not have Win32.pm
# But probably have Win32::GetOSVersion() anyway so the
# following line is not 'required':
# return $os unless eval('require Win32');
# Use the standard API call to determine the version
my ( $undef, $major, $minor, $build, $id );
eval { ( $undef, $major, $minor, $build, $id ) = Win32::GetOSVersion() };
#
# NAME ID MAJOR MINOR
# Windows NT 4 2 4 0
# Windows 2000 2 5 0
# Windows XP 2 5 1
# Windows Server 2003 2 5 2
return "win32s" unless $id; # If id==0 then its a win32s box.
$os = { # Magic numbers from MSDN
# documentation of GetOSVersion
1 => {
0 => "95",
10 => "98",
90 => "Me"
},
2 => {
0 => "2000", # or NT 4, see below
1 => "XP/.Net",
2 => "Win2003",
51 => "NT3.51"
}
}->{$id}->{$minor};
# If $os is undefined, the above code is out of date. Suggested updates
# are welcome.
unless ( defined $os ) {
$os = "";
# Deactivated this message 20180322 because it was needlessly
# causing some test scripts to fail. Need help from someone
# with expertise in Windows to decide what is possible with windows.
${$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
}
# Unfortunately the logic used for the various versions isn't so clever..
# so we have to handle an outside case.
return ( $os eq "2000" && $major != 5 ) ? "NT4" : $os;
}
sub is_unix {
return
( $^O !~ /win32|dos/i )
&& ( $^O ne 'VMS' )
&& ( $^O ne 'OS2' )
&& ( $^O ne 'MacOS' );
}
sub look_for_Windows {
# determine Windows sub-type and location of
# system-wide configuration files
my $rpending_complaint = shift;
my $is_Windows = ( $^O =~ /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 {
# look for a .perltidyrc configuration file
# For Windows also look for a file named perltidy.ini
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} .= " $^O\n";
}
# sub to check file existence and record all tests
my $exists_config_file = sub {
my $config_file = shift;
return 0 unless $config_file;
${$rconfig_file_chatter} .= "# Testing: $config_file\n";
return -f $config_file;
};
# Sub to search upward for config file
my $resolve_config_file = sub {
# resolve <dir>/.../<file>, meaning look upwards from directory
my $config_file = shift;
if ($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);
if ( my $found_file =
find_file_upwards( $start_dir, $search_file ) )
{
$config_file = $found_file;
${$rconfig_file_chatter} .= "# Found: $config_file\n";
}
}
}
return $config_file;
};
my $config_file;
# look in current directory first
$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);
}
# Default environment vars.
my @envs = qw(PERLTIDY HOME);
# Check the NT/2k/XP locations, first a local machine def, then a
# network def
push @envs, qw(USERPROFILE HOMESHARE) if $^O =~ /win32/i;
# Now go through the environment ...
foreach my $var (@envs) {
${$rconfig_file_chatter} .= "# Examining: \$ENV{$var}";
if ( defined( $ENV{$var} ) ) {
${$rconfig_file_chatter} .= " = $ENV{$var}\n";
# test ENV{ PERLTIDY } as file:
if ( $var eq 'PERLTIDY' ) {
$config_file = "$ENV{$var}";
$config_file = $resolve_config_file->($config_file);
return $config_file if $exists_config_file->($config_file);
}
# test ENV as directory:
$config_file = 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 = 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";
}
}
# then look for a system-wide definition
# where to look varies with OS
if ($is_Windows) {
if ($Windows_type) {
my ( $os, $system, $allusers ) =
Win_Config_Locs( $rpending_complaint, $Windows_type );
# Check All Users directory, if there is one.
# i.e. C:\Documents and Settings\User\perltidy.ini
if ($allusers) {
$config_file = catfile( $allusers, ".perltidyrc" );
return $config_file if $exists_config_file->($config_file);
$config_file = catfile( $allusers, "perltidy.ini" );
return $config_file if $exists_config_file->($config_file);
}
# Check system directory.
# retain old code in case someone has been able to create
# a file with a leading period.
$config_file = catfile( $system, ".perltidyrc" );
return $config_file if $exists_config_file->($config_file);
$config_file = catfile( $system, "perltidy.ini" );
return $config_file if $exists_config_file->($config_file);
}
}
# Place to add customization code for other systems
elsif ( $^O eq 'OS2' ) {
}
elsif ( $^O eq 'MacOS' ) {
}
elsif ( $^O eq 'VMS' ) {
}
# Assume some kind of Unix
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);
}
# Couldn't find a config file
return;
}
sub Win_Config_Locs {
# In scalar context returns the OS name (95 98 ME NT3.51 NT4 2000 XP),
# or undef if its not a win32 OS. In list context returns OS, System
# Directory, and All Users Directory. All Users will be empty on a
# 9x/Me box. Contributed by: Yves Orton.
# Original coding:
# my $rpending_complaint = shift;
# my $os = (@_) ? shift : Win_OS_Type();
my ( $rpending_complaint, $os ) = @_;
if ( !$os ) { $os = Win_OS_Type(); }
return unless $os;
my $system = "";
my $allusers = "";
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 {
# This currently would only happen on a win32s computer. I don't have
# one to test, so I am unsure how to proceed. Suggestions welcome!
${$rpending_complaint} .=
"I dont know a sensible place to look for config files on an $os system.\n";
return;
}
return wantarray ? ( $os, $system, $allusers ) : $os;
}
sub dump_config_file {
my ( $fh, $config_file, $rconfig_file_chatter ) = @_;
print STDOUT "$$rconfig_file_chatter";
if ($fh) {
print STDOUT "# Dump of file: '$config_file'\n";
while ( my $line = $fh->getline() ) { print STDOUT $line }
eval { $fh->close() };
}
else {
print STDOUT "# ...no config file found\n";
}
return;
}
sub read_config_file {
my ( $fh, $config_file, $rexpansion ) = @_;
my @config_list = ();
# file is bad if non-empty $death_message is returned
my $death_message = "";
my $name = undef;
my $line_no;
my $opening_brace_line;
while ( my $line = $fh->getline() ) {
$line_no++;
chomp $line;
( $line, $death_message ) =
strip_comment( $line, $config_file, $line_no );
last if ($death_message);
next unless $line;
$line =~ s/^\s*(.*?)\s*$/$1/; # trim both ends
next unless $line;
my $body = $line;
# Look for complete or partial abbreviation definition of the form
# name { body } or name { or name { body
# See rules in perltidy's perldoc page
# Section: Other Controls - Creating a new abbreviation
if ( $line =~ /^((\w+)\s*\{)(.*)?$/ ) {
my $oldname = $name;
( $name, $body ) = ( $2, $3 );
# Cannot start new abbreviation unless old abbreviation is complete
last if ($opening_brace_line);
$opening_brace_line = $line_no unless ( $body && $body =~ s/\}$// );
# handle a new alias definition
if ( ${$rexpansion}{$name} ) {
local $" = ')(';
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 $.\n";
last;
}
${$rexpansion}{$name} = [];
}
# leading opening braces not allowed
elsif ( $line =~ /^{/ ) {
$opening_brace_line = undef;
$death_message =
"Unexpected '{' at line $line_no in config file '$config_file'\n";
last;
}
# Look for abbreviation closing: body } or }
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;
}
}
# Now store any parameters
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) {
# remove leading dashes if this is an alias
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";
}
eval { $fh->close() };
return ( \@config_list, $death_message );
}
sub strip_comment {
# Strip any comment from a command line
my ( $instr, $config_file, $line_no ) = @_;
my $msg = "";
# check for full-line comment
if ( $instr =~ /^\s*#/ ) {
return ( "", $msg );
}
# nothing to do if no comments
if ( $instr !~ /#/ ) {
return ( $instr, $msg );
}
# handle case of no quotes
elsif ( $instr !~ /['"]/ ) {
# We now require a space before the # of a side comment
# this allows something like:
# -sbcp=#
# Otherwise, it would have to be quoted:
# -sbcp='#'
$instr =~ s/\s+\#.*$//;
return ( $instr, $msg );
}
# handle comments and quotes
my $outstr = "";
my $quote_char = "";
while (1) {
# looking for ending quote character
if ($quote_char) {
if ( $instr =~ /\G($quote_char)/gc ) {
$quote_char = "";
$outstr .= $1;
}
elsif ( $instr =~ /\G(.)/gc ) {
$outstr .= $1;
}
# error..we reached the end without seeing the ending quote char
else {
$msg = <<EOM;
Error reading file $config_file at line number $line_no.
Did not see ending quote character <$quote_char> in this text:
$instr
Please fix this line or use -npro to avoid reading this file
EOM
last;
}
}
# accumulating characters and looking for start of a quoted string
else {
if ( $instr =~ /\G([\"\'])/gc ) {
$outstr .= $1;
$quote_char = $1;
}
# Note: not yet enforcing the space-before-hash rule for side
# comments if the parameter is quoted.
elsif ( $instr =~ /\G#/gc ) {
last;
}
elsif ( $instr =~ /\G(.)/gc ) {
$outstr .= $1;
}
else {
last;
}
}
}
return ( $outstr, $msg );
}
sub parse_args {
# Parse a command string containing multiple string with possible
# quotes, into individual commands. It might look like this, for example:
#
# -wba=" + - " -some-thing -wbb='. && ||'
#
# There is no need, at present, to handle escaped quote characters.
# (They are not perltidy tokens, so needn't be in strings).
my ($body) = @_;
my @body_parts = ();
my $quote_char = "";
my $part = "";
my $msg = "";
while (1) {
# looking for ending quote character
if ($quote_char) {
if ( $body =~ /\G($quote_char)/gc ) {
$quote_char = "";
}
elsif ( $body =~ /\G(.)/gc ) {
$part .= $1;
}
# error..we reached the end without seeing the ending quote char
else {
if ( length($part) ) { push @body_parts, $part; }
$msg = <<EOM;
Did not see ending quote character <$quote_char> in this text:
$body
EOM
last;
}
}
# accumulating characters and looking for start of a quoted string
else {
if ( $body =~ /\G([\"\'])/gc ) {
$quote_char = $1;
}
elsif ( $body =~ /\G(\s+)/gc ) {
if ( length($part) ) { push @body_parts, $part; }
$part = "";
}
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_defaults {
my @defaults = @_;
print STDOUT "Default command line options:\n";
foreach my $line ( sort @defaults ) { print STDOUT "$line\n" }
return;
}
sub readable_options {
# return options for this run as a string which could be
# put in a perltidyrc file
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 = "";
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 = "";
if ($flag) {
if ( $flag =~ /^=/ ) {
if ( $value !~ /^\d+$/ ) { $value = '"' . $value . '"' }
$suffix = "=" . $value;
}
elsif ( $flag =~ /^!/ ) {
$prefix .= "no" unless ($value);
}
else {
# shouldn't happen
$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-2019, 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.
Complete documentation for perltidy can be found using 'man perltidy'
or on the internet at http://perltidy.sourceforge.net.
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
-syn run perl -c to check syntax (default under unix systems)
-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
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=40
-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",
or go to the perltidy home page at http://perltidy.sourceforge.net
EOF
return;
}
sub process_this_file {
my ( $tokenizer, $formatter ) = @_;
while ( my $line = $tokenizer->get_line() ) {
$formatter->write_line($line);
}
my $severe_error = $tokenizer->report_tokenization_errors();
eval { $formatter->finish_formatting($severe_error) };
return;
}
sub check_syntax {
# Use 'perl -c' to make sure that we did not create bad syntax
# This is a very good independent check for programming errors
#
# Given names of the input and output files, ($istream, $ostream),
# we do the following:
# - check syntax of the input file
# - if bad, all done (could be an incomplete code snippet)
# - if infile syntax ok, then check syntax of the output file;
# - if outfile syntax bad, issue warning; this implies a code bug!
# - set and return flag "infile_syntax_ok" : =-1 bad 0 unknown 1 good
my ( $istream, $ostream, $logger_object, $rOpts ) = @_;
my $infile_syntax_ok = 0;
my $line_of_dashes = '-' x 42 . "\n";
my $flags = $rOpts->{'perl-syntax-check-flags'};
# be sure we invoke perl with -c
# note: perl will accept repeated flags like '-c -c'. It is safest
# to append another -c than try to find an interior bundled c, as
# in -Tc, because such a 'c' might be in a quoted string, for example.
if ( $flags !~ /(^-c|\s+-c)/ ) { $flags .= " -c" }
# be sure we invoke perl with -x if requested
# same comments about repeated parameters applies
if ( $rOpts->{'look-for-hash-bang'} ) {
if ( $flags !~ /(^-x|\s+-x)/ ) { $flags .= " -x" }
}
# this shouldn't happen unless a temporary file couldn't be made
if ( $istream eq '-' ) {
$logger_object->write_logfile_entry(
"Cannot run perl -c on STDIN and STDOUT\n");
return $infile_syntax_ok;
}
$logger_object->write_logfile_entry(
"checking input file syntax with perl $flags\n");
# Not all operating systems/shells support redirection of the standard
# error output.
my $error_redirection = ( $^O eq 'VMS' ) ? "" : '2>&1';
my ( $istream_filename, $perl_output ) =
do_syntax_check( $istream, $flags, $error_redirection );
$logger_object->write_logfile_entry(
"Input stream passed to Perl as file $istream_filename\n");
$logger_object->write_logfile_entry($line_of_dashes);
$logger_object->write_logfile_entry("$perl_output\n");
if ( $perl_output =~ /syntax\s*OK/ ) {
$infile_syntax_ok = 1;
$logger_object->write_logfile_entry($line_of_dashes);
$logger_object->write_logfile_entry(
"checking output file syntax with perl $flags ...\n");
my ( $ostream_filename, $perl_output ) =
do_syntax_check( $ostream, $flags, $error_redirection );
$logger_object->write_logfile_entry(
"Output stream passed to Perl as file $ostream_filename\n");
$logger_object->write_logfile_entry($line_of_dashes);
$logger_object->write_logfile_entry("$perl_output\n");
unless ( $perl_output =~ /syntax\s*OK/ ) {
$logger_object->write_logfile_entry($line_of_dashes);
$logger_object->warning(
"The output file has a syntax error when tested with perl $flags $ostream !\n"
);
$logger_object->warning(
"This implies an error in perltidy; the file $ostream is bad\n"
);
$logger_object->report_definite_bug();
# the perl version number will be helpful for diagnosing the problem
$logger_object->write_logfile_entry( $^V . "\n" );
}
}
else {
# Only warn of perl -c syntax errors. Other messages,
# such as missing modules, are too common. They can be
# seen by running with perltidy -w
$logger_object->complain("A syntax check using perl $flags\n");
$logger_object->complain(
"for the output in file $istream_filename gives:\n");
$logger_object->complain($line_of_dashes);
$logger_object->complain("$perl_output\n");
$logger_object->complain($line_of_dashes);
$infile_syntax_ok = -1;
$logger_object->write_logfile_entry($line_of_dashes);
$logger_object->write_logfile_entry(
"The output file will not be checked because of input file problems\n"
);
}
return $infile_syntax_ok;
}
sub do_syntax_check {
# This should not be called; the syntax check is deactivated
Die("Unexpected call for syntax check-shouldn't happen\n");
return;
}
1;