1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319
|
#!/usr/bin/perl -w
use strict;
# This program reads .perltidyrc files and writes them back out
# into a standard format (but comments will be lost).
#
# It also demonstrates how to use the perltidy 'options-dump' and related call
# parameters to read a .perltidyrc file, convert to long names, put it in a
# hash, and write back to standard output in sorted order. Requires
# Perl::Tidy.
#
# Steve Hancock, June 2006
#
my $usage = <<EOM;
usage:
perltidyrc_dump.pl [-d -s -q -h] [ filename ]
filename is the name of a .perltidyrc config file to dump, or
if no filename is given, find and dump the system default .perltidyrc.
-d delete options which are the same as Perl::Tidy defaults
(default is to keep them)
-s write short parameter names
(default is long names with short name in side comment)
-q quiet: no comments
-h help
EOM
use Getopt::Std;
my %my_opts;
my $cmdline = $0 . " " . join " ", @ARGV;
getopts( 'hdsq', \%my_opts ) or die "$usage";
if ( $my_opts{h} ) { die "$usage" }
if ( @ARGV > 1 ) { die "$usage" }
my $config_file = $ARGV[0];
my (
$error_message, $rOpts, $rGetopt_flags,
$rsections, $rabbreviations, $rOpts_default,
$rabbreviations_default,
) = read_perltidyrc($config_file);
# always check the error message first
if ($error_message) {
die "$error_message\n";
}
# make a list of perltidyrc options which are same as default
my %equals_default;
foreach my $long_name ( keys %{$rOpts} ) {
my $val = $rOpts->{$long_name};
if ( defined( $rOpts_default->{$long_name} ) ) {
my $val2 = $rOpts_default->{$long_name};
if ( defined($val2) && defined($val) ) {
$equals_default{$long_name} = ( $val2 eq $val );
}
}
}
# Optional: minimize the perltidyrc file length by deleting long_names
# in $rOpts which are also in $rOpts_default and have the same value.
# This would be useful if a perltidyrc file has been constructed from a
# full parameter dump, for example.
if ( $my_opts{d} ) {
foreach my $long_name ( keys %{$rOpts} ) {
delete $rOpts->{$long_name} if $equals_default{$long_name};
}
}
# find user-defined abbreviations
my %abbreviations_user;
foreach my $key ( keys %$rabbreviations ) {
unless ( $rabbreviations_default->{$key} ) {
$abbreviations_user{$key} = $rabbreviations->{$key};
}
}
# dump the options, if any
if ( %$rOpts || %abbreviations_user ) {
dump_options( $cmdline, \%my_opts, $rOpts, $rGetopt_flags, $rsections,
$rabbreviations, \%equals_default, \%abbreviations_user );
}
else {
if ($config_file) {
print STDERR <<EOM;
No configuration parameters seen in file: $config_file
EOM
}
else {
print STDERR <<EOM;
No .perltidyrc file found, use perltidy -dpro to see locations checked.
EOM
}
}
sub dump_options {
# write the options back out as a valid .perltidyrc file
# This version writes long names by sections
my ( $cmdline, $rmy_opts, $rOpts, $rGetopt_flags, $rsections,
$rabbreviations, $requals_default, $rabbreviations_user )
= @_;
# $rOpts is a reference to the hash returned by Getopt::Long
# $rGetopt_flags are the flags passed to Getopt::Long
# $rsections is a hash giving manual section {long_name}
# build a hash giving section->long_name->parameter_value
# so that we can write parameters by section
my %section_and_name;
my $rsection_name_value = \%section_and_name;
my %saw_section;
foreach my $long_name ( keys %{$rOpts} ) {
my $section = $rsections->{$long_name};
$section = "UNKNOWN" unless ($section); # shouldn't happen
# build a hash giving section->long_name->parameter_value
$rsection_name_value->{$section}->{$long_name} = $rOpts->{$long_name};
# remember what sections are in this hash
$saw_section{$section}++;
}
# build a table for long_name->short_name abbreviations
my %short_name;
foreach my $abbrev ( keys %{$rabbreviations} ) {
foreach my $abbrev ( sort keys %$rabbreviations ) {
my @list = @{ $$rabbreviations{$abbrev} };
# an abbreviation may expand into one or more other words,
# but only those that expand to a single word (which must be
# one of the long names) are the short names that we want
# here.
next unless @list == 1;
my $long_name = $list[0];
$short_name{$long_name} = $abbrev;
}
}
unless ( $rmy_opts->{q} ) {
my $date = localtime();
print "# perltidy configuration file created $date\n";
print "# using: $cmdline\n";
}
# loop to write section-by-section
foreach my $section ( sort keys %saw_section ) {
unless ( $rmy_opts->{q} ) {
print "\n";
# remove leading section number, which is there
# for sorting, i.e.,
# 1. Basic formatting options -> Basic formatting options
my $trimmed_section = $section;
$trimmed_section =~ s/^\d+\. //;
print "# $trimmed_section\n";
}
# loop over all long names for this section
my $rname_value = $rsection_name_value->{$section};
foreach my $long_name ( sort keys %{$rname_value} ) {
# pull out getopt flag and actual parameter value
my $flag = $rGetopt_flags->{$long_name};
my $value = $rname_value->{$long_name};
# turn this it back into a parameter
my $prefix = '--';
my $short_prefix = '-';
my $suffix = "";
if ($flag) {
if ( $flag =~ /^=/ ) {
if ( $value !~ /^\d+$/ ) { $value = '"' . $value . '"' }
$suffix = "=" . $value;
}
elsif ( $flag =~ /^!/ ) {
$prefix .= "no" unless ($value);
$short_prefix .= "n" unless ($value);
}
elsif ( $flag =~ /^:/ ) {
if ( $value !~ /^\d+$/ ) { $value = '"' . $value . '"' }
$suffix = "=" . $value;
}
else {
# shouldn't happen
print
"# ERROR in dump_options: unrecognized flag $flag for $long_name\n";
}
}
# print the long version of the parameter
# with the short version as a side comment
my $short_name = $short_name{$long_name};
my $short_option = $short_prefix . $short_name . $suffix;
my $long_option = $prefix . $long_name . $suffix;
my $note = $requals_default->{$long_name} ? " [=default]" : "";
if ( $rmy_opts->{s} ) {
print $short_option. "\n";
}
else {
my $side_comment = "";
unless ( $rmy_opts->{q} ) {
my $spaces = 40 - length($long_option);
$spaces = 2 if ( $spaces < 2 );
$side_comment =
' ' x $spaces . '# ' . $short_option . $note;
}
print $long_option . $side_comment . "\n";
}
}
}
if ( %{$rabbreviations_user} ) {
unless ( $rmy_opts->{q} ) {
print "\n";
print "# Abbreviations\n";
}
foreach my $key ( keys %$rabbreviations_user ) {
my @vals = @{ $rabbreviations_user->{$key} };
print $key. ' {' . join( ' ', @vals ) . '}' . "\n";
}
}
}
sub read_perltidyrc {
# Example routine to have Perl::Tidy read and validate perltidyrc
# file, and return related flags and abbreviations.
#
# input parameter -
# $config_file is the name of a .perltidyrc file we want to read
# or a reference to a string or array containing the .perltidyrc file
# if not defined, Perl::Tidy will try to find the user's .perltidyrc
# output parameters -
# $error_message will be blank unless an error occurs
# $rOpts - reference to the hash of options in the .perlticyrc
# NOTE:
# Perl::Tidy will croak or die on certain severe errors
my ($config_file) = @_;
my $error_message = "";
my %Opts; # any options found will be put here
# the module must be installed for this to work
eval "use Perl::Tidy";
if ($@) {
$error_message = "Perl::Tidy not installed\n";
return ( $error_message, \%Opts );
}
# be sure this version supports this
my $version = $Perl::Tidy::VERSION;
if ( $version < 20060528 ) {
$error_message = "perltidy version $version cannot read options\n";
return ( $error_message, \%Opts );
}
my $stderr = ""; # try to capture error messages
my $argv = ""; # do not let perltidy see our @ARGV
# we are going to make two calls to perltidy...
# first with an empty .perltidyrc to get the default parameters
my $empty_file = ""; # this will be our .perltidyrc file
my %Opts_default; # this will receive the default options hash
my %abbreviations_default;
my $err = Perl::Tidy::perltidy(
perltidyrc => \$empty_file,
dump_options => \%Opts_default,
dump_options_type => 'full', # 'full' gives everything
dump_abbreviations => \%abbreviations_default,
stderr => \$stderr,
argv => \$argv,
);
if ($err) {
die "Error calling perltidy\n";
}
# now we call with a .perltidyrc file to get its parameters
my %Getopt_flags;
my %sections;
my %abbreviations;
Perl::Tidy::perltidy(
perltidyrc => $config_file,
dump_options => \%Opts,
dump_options_type => 'perltidyrc', # default is 'perltidyrc'
dump_getopt_flags => \%Getopt_flags,
dump_options_category => \%sections,
dump_abbreviations => \%abbreviations,
stderr => \$stderr,
argv => \$argv,
);
# try to capture any errors generated by perltidy call
# but for severe errors it will typically croak
$error_message .= $stderr;
# debug: show how everything is stored by printing it out
my $DEBUG = 0;
if ($DEBUG) {
print "---Getopt Parameters---\n";
foreach my $key ( sort keys %Getopt_flags ) {
print "$key$Getopt_flags{$key}\n";
}
print "---Manual Sections---\n";
foreach my $key ( sort keys %sections ) {
print "$key -> $sections{$key}\n";
}
print "---Abbreviations---\n";
foreach my $key ( sort keys %abbreviations ) {
my @names = @{ $abbreviations{$key} };
print "$key -> {@names}\n";
unless ( $abbreviations_default{$key} ) {
print "NOTE: $key is user defined\n";
}
}
}
return ( $error_message, \%Opts, \%Getopt_flags, \%sections,
\%abbreviations, \%Opts_default, \%abbreviations_default, );
}
|