diff options
Diffstat (limited to 'lib/Autom4te')
-rw-r--r-- | lib/Autom4te/C4che.pm | 242 | ||||
-rw-r--r-- | lib/Autom4te/ChannelDefs.pm | 390 | ||||
-rw-r--r-- | lib/Autom4te/Channels.pm | 836 | ||||
-rw-r--r-- | lib/Autom4te/Configure_ac.pm | 127 | ||||
-rw-r--r-- | lib/Autom4te/FileUtils.pm | 452 | ||||
-rw-r--r-- | lib/Autom4te/General.pm | 426 | ||||
-rw-r--r-- | lib/Autom4te/Getopt.pm | 115 | ||||
-rw-r--r-- | lib/Autom4te/Makefile.am | 37 | ||||
-rw-r--r-- | lib/Autom4te/Makefile.in | 454 | ||||
-rw-r--r-- | lib/Autom4te/Request.pm | 114 | ||||
-rw-r--r-- | lib/Autom4te/XFile.pm | 319 |
11 files changed, 3512 insertions, 0 deletions
diff --git a/lib/Autom4te/C4che.pm b/lib/Autom4te/C4che.pm new file mode 100644 index 0000000..b91a5e8 --- /dev/null +++ b/lib/Autom4te/C4che.pm @@ -0,0 +1,242 @@ +# autoconf -- create `configure' using m4 macros +# Copyright (C) 2003, 2006, 2009-2012 Free Software Foundation, Inc. + +# 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 3 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, see <http://www.gnu.org/licenses/>. + +package Autom4te::C4che; + +=head1 NAME + +Autom4te::C4che - a single m4 run request + +=head1 SYNOPSIS + + use Autom4te::C4che; + +=head1 DESCRIPTION + +This Perl module handles the cache of M4 runs used by autom4te. + +=cut + +use Data::Dumper; +use Autom4te::Request; +use Carp; +use strict; + +=over 4 + +=item @request + +List of requests. + +We cannot declare it "my" as the loading, performed via "do", would +refer to another scope, and @request would not be updated. It used to +work with "my" vars, and I do not know whether the current behavior +(5.6) is wanted or not. + +=cut + +use vars qw(@request); + +=item C<$req = Autom4te::C4che-E<gt>retrieve (%attr)> + +Find a request with the same path and input. + +=cut + +sub retrieve($%) +{ + my ($self, %attr) = @_; + + foreach (@request) + { + # Same path. + next + if join ("\n", @{$_->path}) ne join ("\n", @{$attr{path}}); + + # Same inputs. + next + if join ("\n", @{$_->input}) ne join ("\n", @{$attr{input}}); + + # Found it. + return $_; + } + + return undef; +} + +=item C<$req = Autom4te::C4che-E<gt>register (%attr)> + +Create and register a request for these path and input. + +=cut + +# $REQUEST-OBJ +# register ($SELF, %ATTR) +# ----------------------- +# NEW should not be called directly. +# Private. +sub register ($%) +{ + my ($self, %attr) = @_; + + # path and input are the only ID for a request object. + my $obj = new Autom4te::Request ('path' => $attr{path}, + 'input' => $attr{input}); + push @request, $obj; + + # Assign an id for cache file. + $obj->id ("$#request"); + + return $obj; +} + + +=item C<$req = Autom4te::C4che-E<gt>request (%request)> + +Get (retrieve or create) a request for the path C<$request{path}> and +the input C<$request{input}>. + +=cut + +# $REQUEST-OBJ +# request($SELF, %REQUEST) +# ------------------------ +sub request ($%) +{ + my ($self, %request) = @_; + + my $req = + Autom4te::C4che->retrieve (%request) + || Autom4te::C4che->register (%request); + + # If there are new traces to produce, then we are not valid. + foreach (@{$request{'macro'}}) + { + if (! exists ${$req->macro}{$_}) + { + ${$req->macro}{$_} = 1; + $req->valid (0); + } + } + + # It would be great to have $REQ check that it is up to date wrt + # its dependencies, but that requires getting traces (to fetch the + # included files), which is out of the scope of Request (currently?). + + return $req; +} + + +=item C<$string = Autom4te::C4che-E<gt>marshall ()> + +Serialize all the current requests. + +=cut + + +# marshall($SELF) +# --------------- +sub marshall ($) +{ + my ($caller) = @_; + my $res = ''; + + my $marshall = Data::Dumper->new ([\@request], [qw (*request)]); + $marshall->Indent(2)->Terse(0); + $res = $marshall->Dump . "\n"; + + return $res; +} + + +=item C<Autom4te::C4che-E<gt>save ($file)> + +Save the cache in the C<$file> file object. + +=cut + +# SAVE ($FILE) +# ------------ +sub save ($$) +{ + my ($self, $file) = @_; + + confess "cannot save a single request\n" + if ref ($self); + + $file->seek (0, 0); + $file->truncate (0); + print $file + "# This file was generated.\n", + "# It contains the lists of macros which have been traced.\n", + "# It can be safely removed.\n", + "\n", + $self->marshall; +} + + +=item C<Autom4te::C4che-E<gt>load ($file)> + +Load the cache from the C<$file> file object. + +=cut + +# LOAD ($FILE) +# ------------ +sub load ($$) +{ + my ($self, $file) = @_; + my $fname = $file->name; + + confess "cannot load a single request\n" + if ref ($self); + + my $contents = join "", $file->getlines; + + eval $contents; + + confess "cannot eval $fname: $@\n" if $@; +} + + +=head1 SEE ALSO + +L<Autom4te::Request> + +=head1 HISTORY + +Written by Akim Demaille E<lt>F<akim@freefriends.org>E<gt>. + +=cut + +1; # for require + +### Setup "GNU" style for perl-mode and cperl-mode. +## Local Variables: +## perl-indent-level: 2 +## perl-continued-statement-offset: 2 +## perl-continued-brace-offset: 0 +## perl-brace-offset: 0 +## perl-brace-imaginary-offset: 0 +## perl-label-offset: -2 +## cperl-indent-level: 2 +## cperl-brace-offset: 0 +## cperl-continued-brace-offset: 0 +## cperl-label-offset: -2 +## cperl-extra-newline-before-brace: t +## cperl-merge-trailing-else: nil +## cperl-continued-statement-offset: 2 +## End: diff --git a/lib/Autom4te/ChannelDefs.pm b/lib/Autom4te/ChannelDefs.pm new file mode 100644 index 0000000..0d5b5c4 --- /dev/null +++ b/lib/Autom4te/ChannelDefs.pm @@ -0,0 +1,390 @@ +# Copyright (C) 2002-2003, 2006, 2008-2012 Free Software Foundation, +# Inc. + +# 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 3 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, see <http://www.gnu.org/licenses/>. + +package Autom4te::ChannelDefs; + +use Autom4te::Channels; + +=head1 NAME + +Autom4te::ChannelDefs - channel definitions for Automake and helper functions + +=head1 SYNOPSIS + + use Autom4te::ChannelDefs; + + print Autom4te::ChannelDefs::usage (), "\n"; + prog_error ($MESSAGE, [%OPTIONS]); + error ($WHERE, $MESSAGE, [%OPTIONS]); + error ($MESSAGE); + fatal ($WHERE, $MESSAGE, [%OPTIONS]); + fatal ($MESSAGE); + verb ($MESSAGE, [%OPTIONS]); + switch_warning ($CATEGORY); + parse_WARNINGS (); + parse_warnings ($OPTION, @ARGUMENT); + Autom4te::ChannelDefs::set_strictness ($STRICTNESS_NAME); + +=head1 DESCRIPTION + +This package defines channels that can be used in Automake to +output diagnostics and other messages (via C<msg()>). It also defines +some helper function to enable or disable these channels, and some +shorthand function to output on specific channels. + +=cut + +use 5.006; +use strict; +use Exporter; + +use vars qw (@ISA @EXPORT); + +@ISA = qw (Exporter); +@EXPORT = qw (&prog_error &error &fatal &verb + &switch_warning &parse_WARNINGS &parse_warnings); + +=head2 CHANNELS + +The following channels can be used as the first argument of +C<Autom4te::Channel::msg>. For some of them we list a shorthand +function that makes the code more readable. + +=over 4 + +=item C<fatal> + +Fatal errors. Use C<&fatal> to send messages over this channel. + +=item C<error> + +Common errors. Use C<&error> to send messages over this channel. + +=item C<error-gnu> + +Errors related to GNU Standards. + +=item C<error-gnu/warn> + +Errors related to GNU Standards that should be warnings in "foreign" mode. + +=item C<error-gnits> + +Errors related to GNITS Standards (silent by default). + +=item C<automake> + +Internal errors. Use C<&prog_error> to send messages over this channel. + +=item C<cross> + +Constructs compromising the cross-compilation of the package. + +=item C<gnu> + +Warnings related to GNU Coding Standards. + +=item C<obsolete> + +Warnings about obsolete features (silent by default). + +=item C<override> + +Warnings about user redefinitions of Automake rules or +variables (silent by default). + +=item C<portability> + +Warnings about non-portable constructs. + +=item C<syntax> + +Warnings about weird syntax, unused variables, typos ... + +=item C<unsupported> + +Warnings about unsupported (or mis-supported) features. + +=item C<verb> + +Messages output in C<--verbose> mode. Use C<&verb> to send such messages. + +=item C<note> + +Informative messages. + +=back + +=cut + +# Initialize our list of error/warning channels. +# Do not forget to update &usage and the manual +# if you add or change a warning channel. + +register_channel 'fatal', type => 'fatal', ordered => 0; +register_channel 'error', type => 'error'; +register_channel 'error-gnu', type => 'error'; +register_channel 'error-gnu/warn', type => 'error'; +register_channel 'error-gnits', type => 'error', silent => 1; +register_channel 'automake', type => 'fatal', backtrace => 1, + header => ("####################\n" . + "## Internal Error ##\n" . + "####################\n"), + footer => "\nPlease contact <bug-automake\@gnu.org>.", + ordered => 0; + +register_channel 'cross', type => 'warning', silent => 1; +register_channel 'gnu', type => 'warning'; +register_channel 'obsolete', type => 'warning', silent => 1; +register_channel 'override', type => 'warning', silent => 1; +register_channel 'portability', type => 'warning', silent => 1; +register_channel 'syntax', type => 'warning'; +register_channel 'unsupported', type => 'warning'; + +register_channel 'verb', type => 'debug', silent => 1, ordered => 0; +register_channel 'note', type => 'debug', silent => 0; + +=head2 FUNCTIONS + +=over 4 + +=item C<usage ()> + +Return the warning category descriptions. + +=cut + +sub usage () +{ + return "Warning categories include: + `cross' cross compilation issues + `gnu' GNU coding standards (default in gnu and gnits modes) + `obsolete' obsolete features or constructions + `override' user redefinitions of Automake rules or variables + `portability' portability issues (default in gnu and gnits modes) + `syntax' dubious syntactic constructs (default) + `unsupported' unsupported or incomplete features (default) + `all' all the warnings + `no-CATEGORY' turn off warnings in CATEGORY + `none' turn off all the warnings + `error' treat warnings as errors"; +} + +=item C<prog_error ($MESSAGE, [%OPTIONS])> + +Signal a programming error (on channel C<automake>), +display C<$MESSAGE>, and exit 1. + +=cut + +sub prog_error ($;%) +{ + my ($msg, %opts) = @_; + msg 'automake', '', $msg, %opts; +} + +=item C<error ($WHERE, $MESSAGE, [%OPTIONS])> + +=item C<error ($MESSAGE)> + +Uncategorized errors. + +=cut + +sub error ($;$%) +{ + my ($where, $msg, %opts) = @_; + msg ('error', $where, $msg, %opts); +} + +=item C<fatal ($WHERE, $MESSAGE, [%OPTIONS])> + +=item C<fatal ($MESSAGE)> + +Fatal errors. + +=cut + +sub fatal ($;$%) +{ + my ($where, $msg, %opts) = @_; + msg ('fatal', $where, $msg, %opts); +} + +=item C<verb ($MESSAGE, [%OPTIONS])> + +C<--verbose> messages. + +=cut + +sub verb ($;%) +{ + my ($msg, %opts) = @_; + msg 'verb', '', $msg, %opts; +} + +=item C<switch_warning ($CATEGORY)> + +If C<$CATEGORY> is C<mumble>, turn on channel C<mumble>. +If it is C<no-mumble>, turn C<mumble> off. +Else handle C<all> and C<none> for completeness. + +=cut + +sub switch_warning ($) +{ + my ($cat) = @_; + my $has_no = 0; + + if ($cat =~ /^no-(.*)$/) + { + $cat = $1; + $has_no = 1; + } + + if ($cat eq 'all') + { + setup_channel_type 'warning', silent => $has_no; + } + elsif ($cat eq 'none') + { + setup_channel_type 'warning', silent => ! $has_no; + } + elsif ($cat eq 'error') + { + $warnings_are_errors = ! $has_no; + # Set exit code if Perl warns about something + # (like uninitialized variables). + $SIG{"__WARN__"} = + $has_no ? 'DEFAULT' : sub { print STDERR @_; $exit_code = 1; }; + } + elsif (channel_type ($cat) eq 'warning') + { + setup_channel $cat, silent => $has_no; + } + else + { + return 1; + } + return 0; +} + +=item C<parse_WARNINGS ()> + +Parse the WARNINGS environment variable. + +=cut + +sub parse_WARNINGS () +{ + if (exists $ENV{'WARNINGS'}) + { + # Ignore unknown categories. This is required because WARNINGS + # should be honored by many tools. + switch_warning $_ foreach (split (',', $ENV{'WARNINGS'})); + } +} + +=item C<parse_warnings ($OPTION, @ARGUMENT)> + +Parse the argument of C<--warning=CATEGORY> or C<-WCATEGORY>. + +C<$OPTIONS> is C<"--warning"> or C<"-W">, C<@ARGUMENT> is a list of +C<CATEGORY>. + +This can be used as an argument to C<Getopt>. + +=cut + +sub parse_warnings ($@) +{ + my ($opt, @categories) = @_; + + foreach my $cat (map { split ',' } @categories) + { + msg 'unsupported', "unknown warning category `$cat'" + if switch_warning $cat; + } +} + +=item C<set_strictness ($STRICTNESS_NAME)> + +Configure channels for strictness C<$STRICTNESS_NAME>. + +=cut + +sub set_strictness ($) +{ + my ($name) = @_; + + if ($name eq 'gnu') + { + setup_channel 'error-gnu', silent => 0; + setup_channel 'error-gnu/warn', silent => 0, type => 'error'; + setup_channel 'error-gnits', silent => 1; + setup_channel 'portability', silent => 0; + setup_channel 'gnu', silent => 0; + } + elsif ($name eq 'gnits') + { + setup_channel 'error-gnu', silent => 0; + setup_channel 'error-gnu/warn', silent => 0, type => 'error'; + setup_channel 'error-gnits', silent => 0; + setup_channel 'portability', silent => 0; + setup_channel 'gnu', silent => 0; + } + elsif ($name eq 'foreign') + { + setup_channel 'error-gnu', silent => 1; + setup_channel 'error-gnu/warn', silent => 0, type => 'warning'; + setup_channel 'error-gnits', silent => 1; + setup_channel 'portability', silent => 1; + setup_channel 'gnu', silent => 1; + } + else + { + prog_error "level `$name' not recognized\n"; + } +} + +=back + +=head1 SEE ALSO + +L<Autom4te::Channels> + +=head1 HISTORY + +Written by Alexandre Duret-Lutz E<lt>F<adl@gnu.org>E<gt>. + +=cut + +### Setup "GNU" style for perl-mode and cperl-mode. +## Local Variables: +## perl-indent-level: 2 +## perl-continued-statement-offset: 2 +## perl-continued-brace-offset: 0 +## perl-brace-offset: 0 +## perl-brace-imaginary-offset: 0 +## perl-label-offset: -2 +## cperl-indent-level: 2 +## cperl-brace-offset: 0 +## cperl-continued-brace-offset: 0 +## cperl-label-offset: -2 +## cperl-extra-newline-before-brace: t +## cperl-merge-trailing-else: nil +## cperl-continued-statement-offset: 2 +## End: diff --git a/lib/Autom4te/Channels.pm b/lib/Autom4te/Channels.pm new file mode 100644 index 0000000..1f0fc1e --- /dev/null +++ b/lib/Autom4te/Channels.pm @@ -0,0 +1,836 @@ +# Copyright (C) 2002-2012 Free Software Foundation, Inc. + +# 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, 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, see <http://www.gnu.org/licenses/>. + +############################################################### +# The main copy of this file is in Automake's git repository. # +# Updates should be sent to automake-patches@gnu.org. # +############################################################### + +package Autom4te::Channels; + +=head1 NAME + +Autom4te::Channels - support functions for error and warning management + +=head1 SYNOPSIS + + use Autom4te::Channels; + + # Register a channel to output warnings about unused variables. + register_channel 'unused', type => 'warning'; + + # Register a channel for system errors. + register_channel 'system', type => 'error', exit_code => 4; + + # Output a message on channel 'unused'. + msg 'unused', "$file:$line", "unused variable '$var'"; + + # Make the 'unused' channel silent. + setup_channel 'unused', silent => 1; + + # Turn on all channels of type 'warning'. + setup_channel_type 'warning', silent => 0; + + # Redirect all channels to push messages on a Thread::Queue using + # the specified serialization key. + setup_channel_queue $queue, $key; + + # Output a message pending in a Thread::Queue. + pop_channel_queue $queue; + + # Treat all warnings as errors. + $warnings_are_errors = 1; + + # Exit with the greatest exit code encountered so far. + exit $exit_code; + +=head1 DESCRIPTION + +This perl module provides support functions for handling diagnostic +channels in programs. Channels can be registered to convey fatal, +error, warning, or debug messages. Each channel has various options +(e.g. is the channel silent, should duplicate messages be removed, +etc.) that can also be overridden on a per-message basis. + +=cut + +use 5.006; +use strict; +use Exporter; +use Carp; +use File::Basename; + +use vars qw (@ISA @EXPORT %channels $me); + +@ISA = qw (Exporter); +@EXPORT = qw ($exit_code $warnings_are_errors + &reset_local_duplicates &reset_global_duplicates + ®ister_channel &msg &exists_channel &channel_type + &setup_channel &setup_channel_type + &dup_channel_setup &drop_channel_setup + &buffer_messages &flush_messages + &setup_channel_queue &pop_channel_queue + US_GLOBAL US_LOCAL + UP_NONE UP_TEXT UP_LOC_TEXT); + +$me = basename $0; + +=head2 Global Variables + +=over 4 + +=item C<$exit_code> + +The greatest exit code seen so far. C<$exit_code> is updated from +the C<exit_code> options of C<fatal> and C<error> channels. + +=cut + +use vars qw ($exit_code); +$exit_code = 0; + +=item C<$warnings_are_errors> + +Set this variable to 1 if warning messages should be treated as +errors (i.e. if they should update C<$exit_code>). + +=cut + +use vars qw ($warnings_are_errors); +$warnings_are_errors = 0; + +=back + +=head2 Constants + +=over 4 + +=item C<UP_NONE>, C<UP_TEXT>, C<UP_LOC_TEXT> + +Possible values for the C<uniq_part> options. This selects the part +of the message that should be considered when filtering out duplicates. +If C<UP_LOC_TEXT> is used, the location and the explanation message +are used for filtering. If C<UP_TEXT> is used, only the explanation +message is used (so the same message will be filtered out if it appears +at different locations). C<UP_NONE> means that duplicate messages +should be output. + +=cut + +use constant UP_NONE => 0; +use constant UP_TEXT => 1; +use constant UP_LOC_TEXT => 2; + +=item C<US_LOCAL>, C<US_GLOBAL> + +Possible values for the C<uniq_scope> options. +Use C<US_GLOBAL> for error messages that should be printed only +once during the execution of the program, C<US_LOCAL> for message that +should be printed only once per file. (Actually, C<Channels> does not +do this now when files are changed, it relies on you calling +C<reset_local_duplicates> when this happens.) + +=cut + +# possible values for uniq_scope +use constant US_LOCAL => 0; +use constant US_GLOBAL => 1; + +=back + +=head2 Options + +Channels accept the options described below. These options can be +passed as a hash to the C<register_channel>, C<setup_channel>, and C<msg> +functions. The possible keys, with their default value are: + +=over + +=item C<type =E<gt> 'warning'> + +The type of the channel. One of C<'debug'>, C<'warning'>, C<'error'>, or +C<'fatal'>. Fatal messages abort the program when they are output. +Error messages update the exit status. Debug and warning messages are +harmless, except that warnings are treated as errors if +C<$warnings_are_errors> is set. + +=item C<exit_code =E<gt> 1> + +The value to update C<$exit_code> with when a fatal or error message +is emitted. C<$exit_code> is also updated for warnings output +when C<$warnings_are_errors> is set. + +=item C<file =E<gt> \*STDERR> + +The file where the error should be output. + +=item C<silent =E<gt> 0> + +Whether the channel should be silent. Use this do disable a +category of warning, for instance. + +=item C<ordered =E<gt> 1> + +Whether, with multi-threaded execution, the message should be queued +for ordered output. + +=item C<uniq_part =E<gt> UP_LOC_TEXT> + +The part of the message subject to duplicate filtering. See the +documentation for the C<UP_NONE>, C<UP_TEXT>, and C<UP_LOC_TEXT> +constants above. + +C<uniq_part> can also be set to an arbitrary string that will be used +instead of the message when considering duplicates. + +=item C<uniq_scope =E<gt> US_LOCAL> + +The scope of duplicate filtering. See the documentation for the +C<US_LOCAL>, and C<US_GLOBAL> constants above. + +=item C<header =E<gt> ''> + +A string to prepend to each message emitted through this channel. +With partial messages, only the first part will have C<header> +prepended. + +=item C<footer =E<gt> ''> + +A string to append to each message emitted through this channel. +With partial messages, only the final part will have C<footer> +appended. + +=item C<backtrace =E<gt> 0> + +Die with a stack backtrace after displaying the message. + +=item C<partial =E<gt> 0> + +When set, indicates a partial message that should +be output along with the next message with C<partial> unset. +Several partial messages can be stacked this way. + +Duplicate filtering will apply to the I<global> message resulting from +all I<partial> messages, using the options from the last (non-partial) +message. Linking associated messages is the main reason to use this +option. + +For instance the following messages + + msg 'channel', 'foo:2', 'redefinition of A ...'; + msg 'channel', 'foo:1', '... A previously defined here'; + msg 'channel', 'foo:3', 'redefinition of A ...'; + msg 'channel', 'foo:1', '... A previously defined here'; + +will result in + + foo:2: redefinition of A ... + foo:1: ... A previously defined here + foo:3: redefinition of A ... + +where the duplicate "I<... A previously defined here>" has been +filtered out. + +Linking these messages using C<partial> as follows will prevent the +fourth message to disappear. + + msg 'channel', 'foo:2', 'redefinition of A ...', partial => 1; + msg 'channel', 'foo:1', '... A previously defined here'; + msg 'channel', 'foo:3', 'redefinition of A ...', partial => 1; + msg 'channel', 'foo:1', '... A previously defined here'; + +Note that because the stack of C<partial> messages is printed with the +first non-C<partial> message, most options of C<partial> messages will +be ignored. + +=back + +=cut + +use vars qw (%_default_options %_global_duplicate_messages + %_local_duplicate_messages); + +# Default options for a channel. +%_default_options = + ( + type => 'warning', + exit_code => 1, + file => \*STDERR, + silent => 0, + ordered => 1, + queue => 0, + queue_key => undef, + uniq_scope => US_LOCAL, + uniq_part => UP_LOC_TEXT, + header => '', + footer => '', + backtrace => 0, + partial => 0, + ); + +# Filled with output messages as keys, to detect duplicates. +# The value associated with each key is the number of occurrences +# filtered out. +%_local_duplicate_messages = (); +%_global_duplicate_messages = (); + +sub _reset_duplicates (\%) +{ + my ($ref) = @_; + my $dup = 0; + foreach my $k (keys %$ref) + { + $dup += $ref->{$k}; + } + %$ref = (); + return $dup; +} + + +=head2 Functions + +=over 4 + +=item C<reset_local_duplicates ()> + +Reset local duplicate messages (see C<US_LOCAL>), and +return the number of messages that have been filtered out. + +=cut + +sub reset_local_duplicates () +{ + return _reset_duplicates %_local_duplicate_messages; +} + +=item C<reset_global_duplicates ()> + +Reset local duplicate messages (see C<US_GLOBAL>), and +return the number of messages that have been filtered out. + +=cut + +sub reset_global_duplicates () +{ + return _reset_duplicates %_global_duplicate_messages; +} + +sub _merge_options (\%%) +{ + my ($hash, %options) = @_; + local $_; + + foreach (keys %options) + { + if (exists $hash->{$_}) + { + $hash->{$_} = $options{$_} + } + else + { + confess "unknown option '$_'"; + } + } + if ($hash->{'ordered'}) + { + confess "fatal messages cannot be ordered" + if $hash->{'type'} eq 'fatal'; + confess "backtrace cannot be output on ordered messages" + if $hash->{'backtrace'}; + } +} + +=item C<register_channel ($name, [%options])> + +Declare channel C<$name>, and override the default options +with those listed in C<%options>. + +=cut + +sub register_channel ($;%) +{ + my ($name, %options) = @_; + my %channel_opts = %_default_options; + _merge_options %channel_opts, %options; + $channels{$name} = \%channel_opts; +} + +=item C<exists_channel ($name)> + +Returns true iff channel C<$name> has been registered. + +=cut + +sub exists_channel ($) +{ + my ($name) = @_; + return exists $channels{$name}; +} + +=item C<channel_type ($name)> + +Returns the type of channel C<$name> if it has been registered. +Returns the empty string otherwise. + +=cut + +sub channel_type ($) +{ + my ($name) = @_; + return $channels{$name}{'type'} if exists_channel $name; + return ''; +} + +# _format_sub_message ($LEADER, $MESSAGE) +# --------------------------------------- +# Split $MESSAGE at new lines and add $LEADER to each line. +sub _format_sub_message ($$) +{ + my ($leader, $message) = @_; + return $leader . join ("\n" . $leader, split ("\n", $message)) . "\n"; +} + +# Store partial messages here. (See the 'partial' option.) +use vars qw ($partial); +$partial = ''; + +# _format_message ($LOCATION, $MESSAGE, %OPTIONS) +# ----------------------------------------------- +# Format the message. Return a string ready to print. +sub _format_message ($$%) +{ + my ($location, $message, %opts) = @_; + my $msg = ($partial eq '' ? $opts{'header'} : '') . $message + . ($opts{'partial'} ? '' : $opts{'footer'}); + if (ref $location) + { + # If $LOCATION is a reference, assume it's an instance of the + # Autom4te::Location class and display contexts. + my $loc = $location->get || $me; + $msg = _format_sub_message ("$loc: ", $msg); + for my $pair ($location->get_contexts) + { + $msg .= _format_sub_message ($pair->[0] . ": ", $pair->[1]); + } + } + else + { + $location ||= $me; + $msg = _format_sub_message ("$location: ", $msg); + } + return $msg; +} + +# _enqueue ($QUEUE, $KEY, $UNIQ_SCOPE, $TO_FILTER, $MSG, $FILE) +# ------------------------------------------------------------- +# Push message on a queue, to be processed by another thread. +sub _enqueue ($$$$$$) +{ + my ($queue, $key, $uniq_scope, $to_filter, $msg, $file) = @_; + $queue->enqueue ($key, $msg, $to_filter, $uniq_scope); + confess "message queuing works only for STDERR" + if $file ne \*STDERR; +} + +# _dequeue ($QUEUE) +# ----------------- +# Pop a message from a queue, and print, similarly to how +# _print_message would do it. Return 0 if the queue is +# empty. Note that the key has already been dequeued. +sub _dequeue ($) +{ + my ($queue) = @_; + my $msg = $queue->dequeue || return 0; + my $to_filter = $queue->dequeue; + my $uniq_scope = $queue->dequeue; + my $file = \*STDERR; + + if ($to_filter ne '') + { + # Do we want local or global uniqueness? + my $dups; + if ($uniq_scope == US_LOCAL) + { + $dups = \%_local_duplicate_messages; + } + elsif ($uniq_scope == US_GLOBAL) + { + $dups = \%_global_duplicate_messages; + } + else + { + confess "unknown value for uniq_scope: " . $uniq_scope; + } + + # Update the hash of messages. + if (exists $dups->{$to_filter}) + { + ++$dups->{$to_filter}; + return 1; + } + else + { + $dups->{$to_filter} = 0; + } + } + print $file $msg; + return 1; +} + + +# _print_message ($LOCATION, $MESSAGE, %OPTIONS) +# ---------------------------------------------- +# Format the message, check duplicates, and print it. +sub _print_message ($$%) +{ + my ($location, $message, %opts) = @_; + + return 0 if ($opts{'silent'}); + + my $msg = _format_message ($location, $message, %opts); + if ($opts{'partial'}) + { + # Incomplete message. Store, don't print. + $partial .= $msg; + return; + } + else + { + # Prefix with any partial message send so far. + $msg = $partial . $msg; + $partial = ''; + } + + msg ('note', '', 'warnings are treated as errors', uniq_scope => US_GLOBAL) + if ($opts{'type'} eq 'warning' && $warnings_are_errors); + + # Check for duplicate message if requested. + my $to_filter; + if ($opts{'uniq_part'} ne UP_NONE) + { + # Which part of the error should we match? + if ($opts{'uniq_part'} eq UP_TEXT) + { + $to_filter = $message; + } + elsif ($opts{'uniq_part'} eq UP_LOC_TEXT) + { + $to_filter = $msg; + } + else + { + $to_filter = $opts{'uniq_part'}; + } + + # Do we want local or global uniqueness? + my $dups; + if ($opts{'uniq_scope'} == US_LOCAL) + { + $dups = \%_local_duplicate_messages; + } + elsif ($opts{'uniq_scope'} == US_GLOBAL) + { + $dups = \%_global_duplicate_messages; + } + else + { + confess "unknown value for uniq_scope: " . $opts{'uniq_scope'}; + } + + # Update the hash of messages. + if (exists $dups->{$to_filter}) + { + ++$dups->{$to_filter}; + return 0; + } + else + { + $dups->{$to_filter} = 0; + } + } + my $file = $opts{'file'}; + if ($opts{'ordered'} && $opts{'queue'}) + { + _enqueue ($opts{'queue'}, $opts{'queue_key'}, $opts{'uniq_scope'}, + $to_filter, $msg, $file); + } + else + { + print $file $msg; + } + return 1; +} + +=item C<msg ($channel, $location, $message, [%options])> + +Emit a message on C<$channel>, overriding some options of the channel with +those specified in C<%options>. Obviously C<$channel> must have been +registered with C<register_channel>. + +C<$message> is the text of the message, and C<$location> is a location +associated to the message. + +For instance to complain about some unused variable C<mumble> +declared at line 10 in F<foo.c>, one could do: + + msg 'unused', 'foo.c:10', "unused variable 'mumble'"; + +If channel C<unused> is not silent (and if this message is not a duplicate), +the following would be output: + + foo.c:10: unused variable 'mumble' + +C<$location> can also be an instance of C<Autom4te::Location>. In this +case, the stack of contexts will be displayed in addition. + +If C<$message> contains newline characters, C<$location> is prepended +to each line. For instance, + + msg 'error', 'somewhere', "1st line\n2nd line"; + +becomes + + somewhere: 1st line + somewhere: 2nd line + +If C<$location> is an empty string, it is replaced by the name of the +program. Actually, if you don't use C<%options>, you can even +elide the empty C<$location>. Thus + + msg 'fatal', '', 'fatal error'; + msg 'fatal', 'fatal error'; + +both print + + progname: fatal error + +=cut + + +use vars qw (@backlog %buffering); + +# See buffer_messages() and flush_messages() below. +%buffering = (); # The map of channel types to buffer. +@backlog = (); # The buffer of messages. + +sub msg ($$;$%) +{ + my ($channel, $location, $message, %options) = @_; + + if (! defined $message) + { + $message = $location; + $location = ''; + } + + confess "unknown channel $channel" unless exists $channels{$channel}; + + my %opts = %{$channels{$channel}}; + _merge_options (%opts, %options); + + if (exists $buffering{$opts{'type'}}) + { + push @backlog, [$channel, $location->clone, $message, %options]; + return; + } + + # Print the message if needed. + if (_print_message ($location, $message, %opts)) + { + # Adjust exit status. + if ($opts{'type'} eq 'error' + || $opts{'type'} eq 'fatal' + || ($opts{'type'} eq 'warning' && $warnings_are_errors)) + { + my $es = $opts{'exit_code'}; + $exit_code = $es if $es > $exit_code; + } + + # Die on fatal messages. + confess if $opts{'backtrace'}; + if ($opts{'type'} eq 'fatal') + { + # flush messages explicitly here, needed in worker threads. + STDERR->flush; + exit $exit_code; + } + } +} + + +=item C<setup_channel ($channel, %options)> + +Override the options of C<$channel> with those specified by C<%options>. + +=cut + +sub setup_channel ($%) +{ + my ($name, %opts) = @_; + confess "unknown channel $name" unless exists $channels{$name}; + _merge_options %{$channels{$name}}, %opts; +} + +=item C<setup_channel_type ($type, %options)> + +Override the options of any channel of type C<$type> +with those specified by C<%options>. + +=cut + +sub setup_channel_type ($%) +{ + my ($type, %opts) = @_; + foreach my $channel (keys %channels) + { + setup_channel $channel, %opts + if $channels{$channel}{'type'} eq $type; + } +} + +=item C<dup_channel_setup ()>, C<drop_channel_setup ()> + +Sometimes it is necessary to make temporary modifications to channels. +For instance one may want to disable a warning while processing a +particular file, and then restore the initial setup. These two +functions make it easy: C<dup_channel_setup ()> saves a copy of the +current configuration for later restoration by +C<drop_channel_setup ()>. + +You can think of this as a stack of configurations whose first entry +is the active one. C<dup_channel_setup ()> duplicates the first +entry, while C<drop_channel_setup ()> just deletes it. + +=cut + +use vars qw (@_saved_channels @_saved_werrors); +@_saved_channels = (); +@_saved_werrors = (); + +sub dup_channel_setup () +{ + my %channels_copy; + foreach my $k1 (keys %channels) + { + $channels_copy{$k1} = {%{$channels{$k1}}}; + } + push @_saved_channels, \%channels_copy; + push @_saved_werrors, $warnings_are_errors; +} + +sub drop_channel_setup () +{ + my $saved = pop @_saved_channels; + %channels = %$saved; + $warnings_are_errors = pop @_saved_werrors; +} + +=item C<buffer_messages (@types)>, C<flush_messages ()> + +By default, when C<msg> is called, messages are processed immediately. + +Sometimes it is necessary to delay the output of messages. +For instance you might want to make diagnostics before +channels have been completely configured. + +After C<buffer_messages(@types)> has been called, messages sent with +C<msg> to a channel whose type is listed in C<@types> will be stored in a +list for later processing. + +This backlog of messages is processed when C<flush_messages> is +called, with the current channel options (not the options in effect, +at the time of C<msg>). So for instance, if some channel was silenced +in the meantime, messages to this channel will not be printed. + +C<flush_messages> cancels the effect of C<buffer_messages>. Following +calls to C<msg> are processed immediately as usual. + +=cut + +sub buffer_messages (@) +{ + foreach my $type (@_) + { + $buffering{$type} = 1; + } +} + +sub flush_messages () +{ + %buffering = (); + foreach my $args (@backlog) + { + &msg (@$args); + } + @backlog = (); +} + +=item C<setup_channel_queue ($queue, $key)> + +Set the queue to fill for each channel that is ordered, +and the key to use for serialization. + +=cut +sub setup_channel_queue ($$) +{ + my ($queue, $key) = @_; + foreach my $channel (keys %channels) + { + setup_channel $channel, queue => $queue, queue_key => $key + if $channels{$channel}{'ordered'}; + } +} + +=item C<pop_channel_queue ($queue)> + +pop a message off the $queue; the key has already been popped. + +=cut +sub pop_channel_queue ($) +{ + my ($queue) = @_; + return _dequeue ($queue); +} + +=back + +=head1 SEE ALSO + +L<Autom4te::Location> + +=head1 HISTORY + +Written by Alexandre Duret-Lutz E<lt>F<adl@gnu.org>E<gt>. + +=cut + +1; + +### Setup "GNU" style for perl-mode and cperl-mode. +## Local Variables: +## perl-indent-level: 2 +## perl-continued-statement-offset: 2 +## perl-continued-brace-offset: 0 +## perl-brace-offset: 0 +## perl-brace-imaginary-offset: 0 +## perl-label-offset: -2 +## cperl-indent-level: 2 +## cperl-brace-offset: 0 +## cperl-continued-brace-offset: 0 +## cperl-label-offset: -2 +## cperl-extra-newline-before-brace: t +## cperl-merge-trailing-else: nil +## cperl-continued-statement-offset: 2 +## End: diff --git a/lib/Autom4te/Configure_ac.pm b/lib/Autom4te/Configure_ac.pm new file mode 100644 index 0000000..924b23c --- /dev/null +++ b/lib/Autom4te/Configure_ac.pm @@ -0,0 +1,127 @@ +# Copyright (C) 2003-2012 Free Software Foundation, Inc. + +# 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, 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, see <http://www.gnu.org/licenses/>. + +############################################################### +# The main copy of this file is in Automake's git repository. # +# Updates should be sent to automake-patches@gnu.org. # +############################################################### + +package Autom4te::Configure_ac; + +use 5.006; +use strict; +use Exporter; +use Autom4te::Channels; +use Autom4te::ChannelDefs; + +use vars qw (@ISA @EXPORT); + +@ISA = qw (Exporter); +@EXPORT = qw (&find_configure_ac &require_configure_ac); + +=head1 NAME + +Autom4te::Configure_ac - Locate configure.ac or configure.in. + +=head1 SYNOPSIS + + use Autom4te::Configure_ac; + + # Try to locate configure.in or configure.ac in the current + # directory. It may be absent. Complain if both files exist. + my $file_name = find_configure_ac; + + # Likewise, but bomb out if the file does not exist. + my $file_name = require_configure_ac; + + # Likewise, but in $dir. + my $file_name = find_configure_ac ($dir); + my $file_name = require_configure_ac ($dir); + +=over 4 + +=back + +=head2 Functions + +=over 4 + +=item C<$configure_ac = find_configure_ac ([$directory])> + +Find a F<configure.ac> or F<configure.in> file in C<$directory>, +defaulting to the current directory. Complain if both files are present. +Return the name of the file found, or the former if neither is present. + +=cut + +sub find_configure_ac (;@) +{ + my ($directory) = @_; + $directory ||= '.'; + my $configure_ac = + File::Spec->canonpath (File::Spec->catfile ($directory, 'configure.ac')); + my $configure_in = + File::Spec->canonpath (File::Spec->catfile ($directory, 'configure.in')); + + if (-f $configure_ac) + { + if (-f $configure_in) + { + msg ('unsupported', + "'$configure_ac' and '$configure_in' both present.\n" + . "proceeding with '$configure_ac'"); + } + return $configure_ac + } + elsif (-f $configure_in) + { + return $configure_in; + } + return $configure_ac; +} + + +=item C<$configure_ac = require_configure_ac ([$directory])> + +Like C<find_configure_ac>, but fail if neither is present. + +=cut + +sub require_configure_ac (;$) +{ + my $res = find_configure_ac (@_); + fatal "'configure.ac' or 'configure.in' is required" + unless -f $res; + return $res +} + +1; + +### Setup "GNU" style for perl-mode and cperl-mode. +## Local Variables: +## perl-indent-level: 2 +## perl-continued-statement-offset: 2 +## perl-continued-brace-offset: 0 +## perl-brace-offset: 0 +## perl-brace-imaginary-offset: 0 +## perl-label-offset: -2 +## cperl-indent-level: 2 +## cperl-brace-offset: 0 +## cperl-continued-brace-offset: 0 +## cperl-label-offset: -2 +## cperl-extra-newline-before-brace: t +## cperl-merge-trailing-else: nil +## cperl-continued-statement-offset: 2 +## End: diff --git a/lib/Autom4te/FileUtils.pm b/lib/Autom4te/FileUtils.pm new file mode 100644 index 0000000..30bbdb9 --- /dev/null +++ b/lib/Autom4te/FileUtils.pm @@ -0,0 +1,452 @@ +# Copyright (C) 2003-2012 Free Software Foundation, Inc. + +# 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, 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, see <http://www.gnu.org/licenses/>. + +############################################################### +# The main copy of this file is in Automake's git repository. # +# Updates should be sent to automake-patches@gnu.org. # +############################################################### + +package Autom4te::FileUtils; + +=head1 NAME + +Autom4te::FileUtils - handling files + +=head1 SYNOPSIS + + use Autom4te::FileUtils + +=head1 DESCRIPTION + +This perl module provides various general purpose file handling functions. + +=cut + +use 5.006; +use strict; +use Exporter; +use File::stat; +use IO::File; +use Autom4te::Channels; +use Autom4te::ChannelDefs; + +use vars qw (@ISA @EXPORT); + +@ISA = qw (Exporter); +@EXPORT = qw (&open_quote &contents + &find_file &mtime + &update_file &up_to_date_p + &xsystem &xsystem_hint &xqx + &dir_has_case_matching_file &reset_dir_cache + &set_dir_cache_file); + + +=item C<open_quote ($file_name)> + +Quote C<$file_name> for open. + +=cut + +# $FILE_NAME +# open_quote ($FILE_NAME) +# ----------------------- +# If the string $S is a well-behaved file name, simply return it. +# If it starts with white space, prepend './', if it ends with +# white space, add '\0'. Return the new string. +sub open_quote($) +{ + my ($s) = @_; + if ($s =~ m/^\s/) + { + $s = "./$s"; + } + if ($s =~ m/\s$/) + { + $s = "$s\0"; + } + return $s; +} + +=item C<find_file ($file_name, @include)> + +Return the first path for a C<$file_name> in the C<include>s. + +We match exactly the behavior of GNU M4: first look in the current +directory (which includes the case of absolute file names), and then, +if the file name is not absolute, look in C<@include>. + +If the file is flagged as optional (ends with C<?>), then return undef +if absent, otherwise exit with error. + +=cut + +# $FILE_NAME +# find_file ($FILE_NAME, @INCLUDE) +# -------------------------------- +sub find_file ($@) +{ + use File::Spec; + + my ($file_name, @include) = @_; + my $optional = 0; + + $optional = 1 + if $file_name =~ s/\?$//; + + return File::Spec->canonpath ($file_name) + if -e $file_name; + + if (!File::Spec->file_name_is_absolute ($file_name)) + { + foreach my $path (@include) + { + return File::Spec->canonpath (File::Spec->catfile ($path, $file_name)) + if -e File::Spec->catfile ($path, $file_name) + } + } + + fatal "$file_name: no such file or directory" + unless $optional; + return undef; +} + +=item C<mtime ($file)> + +Return the mtime of C<$file>. Missing files, or C<-> standing for +C<STDIN> or C<STDOUT> are "obsolete", i.e., as old as possible. + +=cut + +# $MTIME +# MTIME ($FILE) +# ------------- +sub mtime ($) +{ + my ($file) = @_; + + return 0 + if $file eq '-' || ! -f $file; + + my $stat = stat ($file) + or fatal "cannot stat $file: $!"; + + return $stat->mtime; +} + + +=item C<update_file ($from, $to, [$force])> + +Rename C<$from> as C<$to>, preserving C<$to> timestamp if it has not +changed, unless C<$force> is true (defaults to false). Recognize +C<$to> = C<-> standing for C<STDIN>. C<$from> is always +removed/renamed. + +=cut + +# &update_file ($FROM, $TO; $FORCE) +# --------------------------------- +sub update_file ($$;$) +{ + my ($from, $to, $force) = @_; + $force = 0 + unless defined $force; + my $SIMPLE_BACKUP_SUFFIX = $ENV{'SIMPLE_BACKUP_SUFFIX'} || '~'; + use File::Compare; + use File::Copy; + + if ($to eq '-') + { + my $in = new IO::File ("< " . open_quote ($from)); + my $out = new IO::File (">-"); + while ($_ = $in->getline) + { + print $out $_; + } + $in->close; + unlink ($from) || fatal "cannot remove $from: $!"; + return; + } + + if (!$force && -f "$to" && compare ("$from", "$to") == 0) + { + # File didn't change, so don't update its mod time. + msg 'note', "'$to' is unchanged"; + unlink ($from) + or fatal "cannot remove $from: $!"; + return + } + + if (-f "$to") + { + # Back up and install the new one. + move ("$to", "$to$SIMPLE_BACKUP_SUFFIX") + or fatal "cannot backup $to: $!"; + move ("$from", "$to") + or fatal "cannot rename $from as $to: $!"; + msg 'note', "'$to' is updated"; + } + else + { + move ("$from", "$to") + or fatal "cannot rename $from as $to: $!"; + msg 'note', "'$to' is created"; + } +} + + +=item C<up_to_date_p ($file, @dep)> + +Is C<$file> more recent than C<@dep>? + +=cut + +# $BOOLEAN +# &up_to_date_p ($FILE, @DEP) +# --------------------------- +sub up_to_date_p ($@) +{ + my ($file, @dep) = @_; + my $mtime = mtime ($file); + + foreach my $dep (@dep) + { + if ($mtime < mtime ($dep)) + { + verb "up_to_date ($file): outdated: $dep"; + return 0; + } + } + + verb "up_to_date ($file): up to date"; + return 1; +} + + +=item C<handle_exec_errors ($command, [$expected_exit_code = 0], [$hint])> + +Display an error message for C<$command>, based on the content of +C<$?> and C<$!>. Be quiet if the command exited normally +with C<$expected_exit_code>. If C<$hint> is given, display that as well +if the command failed to run at all. + +=cut + +sub handle_exec_errors ($;$$) +{ + my ($command, $expected, $hint) = @_; + $expected = 0 unless defined $expected; + if (defined $hint) + { + $hint = "\n" . $hint; + } + else + { + $hint = ''; + } + + $command = (split (' ', $command))[0]; + if ($!) + { + fatal "failed to run $command: $!" . $hint; + } + else + { + use POSIX qw (WIFEXITED WEXITSTATUS WIFSIGNALED WTERMSIG); + + if (WIFEXITED ($?)) + { + my $status = WEXITSTATUS ($?); + # Propagate exit codes. + fatal ('', + "$command failed with exit status: $status", + exit_code => $status) + unless $status == $expected; + } + elsif (WIFSIGNALED ($?)) + { + my $signal = WTERMSIG ($?); + fatal "$command terminated by signal: $signal"; + } + else + { + fatal "$command exited abnormally"; + } + } +} + +=item C<xqx ($command)> + +Same as C<qx> (but in scalar context), but fails on errors. + +=cut + +# xqx ($COMMAND) +# -------------- +sub xqx ($) +{ + my ($command) = @_; + + verb "running: $command"; + + $! = 0; + my $res = `$command`; + handle_exec_errors $command + if $?; + + return $res; +} + + +=item C<xsystem (@argv)> + +Same as C<system>, but fails on errors, and reports the C<@argv> +in verbose mode. + +=cut + +sub xsystem (@) +{ + my (@command) = @_; + + verb "running: @command"; + + $! = 0; + handle_exec_errors "@command" + if system @command; +} + + +=item C<xsystem_hint ($msg, @argv)> + +Same as C<xsystem>, but allows to pass a hint that will be displayed +in case the command failed to run at all. + +=cut + +sub xsystem_hint (@) +{ + my ($hint, @command) = @_; + + verb "running: @command"; + + $! = 0; + handle_exec_errors "@command", 0, $hint + if system @command; +} + + +=item C<contents ($file_name)> + +Return the contents of C<$file_name>. + +=cut + +# contents ($FILE_NAME) +# --------------------- +sub contents ($) +{ + my ($file) = @_; + verb "reading $file"; + local $/; # Turn on slurp-mode. + my $f = new Autom4te::XFile "< " . open_quote ($file); + my $contents = $f->getline; + $f->close; + return $contents; +} + + +=item C<dir_has_case_matching_file ($DIRNAME, $FILE_NAME)> + +Return true iff $DIR contains a file name that matches $FILE_NAME case +insensitively. + +We need to be cautious on case-insensitive case-preserving file +systems (e.g. Mac OS X's HFS+). On such systems C<-f 'Foo'> and C<-f +'foO'> answer the same thing. Hence if a package distributes its own +F<CHANGELOG> file, but has no F<ChangeLog> file, automake would still +try to distribute F<ChangeLog> (because it thinks it exists) in +addition to F<CHANGELOG>, although it is impossible for these two +files to be in the same directory (the two file names designate the +same file). + +=cut + +use vars '%_directory_cache'; +sub dir_has_case_matching_file ($$) +{ + # Note that print File::Spec->case_tolerant returns 0 even on MacOS + # X (with Perl v5.8.1-RC3 at least), so do not try to shortcut this + # function using that. + + my ($dirname, $file_name) = @_; + return 0 unless -f "$dirname/$file_name"; + + # The file appears to exist, however it might be a mirage if the + # system is case insensitive. Let's browse the directory and check + # whether the file is really in. We maintain a cache of directories + # so Automake doesn't spend all its time reading the same directory + # again and again. + if (!exists $_directory_cache{$dirname}) + { + error "failed to open directory '$dirname'" + unless opendir (DIR, $dirname); + $_directory_cache{$dirname} = { map { $_ => 1 } readdir (DIR) }; + closedir (DIR); + } + return exists $_directory_cache{$dirname}{$file_name}; +} + +=item C<reset_dir_cache ($dirname)> + +Clear C<dir_has_case_matching_file>'s cache for C<$dirname>. + +=cut + +sub reset_dir_cache ($) +{ + delete $_directory_cache{$_[0]}; +} + +=item C<set_dir_cache_file ($dirname, $file_name)> + +State that C<$dirname> contains C<$file_name> now. + +=cut + +sub set_dir_cache_file ($$) +{ + my ($dirname, $file_name) = @_; + $_directory_cache{$dirname}{$file_name} = 1 + if exists $_directory_cache{$dirname}; +} + +1; # for require + +### Setup "GNU" style for perl-mode and cperl-mode. +## Local Variables: +## perl-indent-level: 2 +## perl-continued-statement-offset: 2 +## perl-continued-brace-offset: 0 +## perl-brace-offset: 0 +## perl-brace-imaginary-offset: 0 +## perl-label-offset: -2 +## cperl-indent-level: 2 +## cperl-brace-offset: 0 +## cperl-continued-brace-offset: 0 +## cperl-label-offset: -2 +## cperl-extra-newline-before-brace: t +## cperl-merge-trailing-else: nil +## cperl-continued-statement-offset: 2 +## End: diff --git a/lib/Autom4te/General.pm b/lib/Autom4te/General.pm new file mode 100644 index 0000000..ef1e987 --- /dev/null +++ b/lib/Autom4te/General.pm @@ -0,0 +1,426 @@ +# autoconf -- create `configure' using m4 macros +# Copyright (C) 2001-2004, 2006-2007, 2009-2012 Free Software +# Foundation, Inc. + +# 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 3 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, see <http://www.gnu.org/licenses/>. + +package Autom4te::General; + +=head1 NAME + +Autom4te::General - general support functions for Autoconf + +=head1 SYNOPSIS + + use Autom4te::General + +=head1 DESCRIPTION + +This perl module provides various general purpose support functions +used in several executables of the Autoconf package. + +=cut + +use 5.006; +use Exporter; +use Autom4te::ChannelDefs; +use Autom4te::Channels; +use Autom4te::Getopt (); +use File::Basename; +use File::Path (); +use File::stat; +use IO::File; +use Carp; +use strict; + +use vars qw (@ISA @EXPORT); + +@ISA = qw (Exporter); + +# Variables we define and export. +my @export_vars = + qw ($debug $force $help $me $tmp $verbose $version); + +# Functions we define and export. +my @export_subs = + qw (&debug + &getopt &shell_quote &mktmpdir + &uniq); + +# Functions we forward (coming from modules we use). +my @export_forward_subs = + qw (&basename &dirname &fileparse); + +@EXPORT = (@export_vars, @export_subs, @export_forward_subs); + + +# Variable we share with the main package. Be sure to have a single +# copy of them: using `my' together with multiple inclusion of this +# package would introduce several copies. + +=head2 Global Variables + +=over 4 + +=item C<$debug> + +Set this variable to 1 if debug messages should be enabled. Debug +messages are meant for developers only, or when tracking down an +incorrect execution. + +=cut + +use vars qw ($debug); +$debug = 0; + +=item C<$force> + +Set this variable to 1 to recreate all the files, or to consider all +the output files are obsolete. + +=cut + +use vars qw ($force); +$force = undef; + +=item C<$help> + +Set to the help message associated with the option C<--help>. + +=cut + +use vars qw ($help); +$help = undef; + +=item C<$me> + +The name of this application, for diagnostic messages. + +=cut + +use vars qw ($me); +$me = basename ($0); + +=item C<$tmp> + +The name of the temporary directory created by C<mktmpdir>. Left +C<undef> otherwise. + +=cut + +# Our tmp dir. +use vars qw ($tmp); +$tmp = undef; + +=item C<$verbose> + +Enable verbosity messages. These messages are meant for ordinary +users, and typically make explicit the steps being performed. + +=cut + +use vars qw ($verbose); +$verbose = 0; + +=item C<$version> + +Set to the version message associated to the option C<--version>. + +=cut + +use vars qw ($version); +$version = undef; + +=back + +=cut + + + +## ----- ## +## END. ## +## ----- ## + +=head2 Functions + +=over 4 + +=item C<END> + +Filter Perl's exit codes, delete any temporary directory (unless +C<$debug>), and exit nonzero whenever closing C<STDOUT> fails. + +=cut + +# END +# --- +sub END +{ + # $? contains the exit status we will return. + # It was set using one of the following ways: + # + # 1) normal termination + # this sets $? = 0 + # 2) calling `exit (n)' + # this sets $? = n + # 3) calling die or friends (croak, confess...): + # a) when $! is non-0 + # this set $? = $! + # b) when $! is 0 but $? is not + # this sets $? = ($? >> 8) (i.e., the exit code of the + # last program executed) + # c) when both $! and $? are 0 + # this sets $? = 255 + # + # Cases 1), 2), and 3b) are fine, but we prefer $? = 1 for 3a) and 3c). + my $status = $?; + $status = 1 if ($! && $! == $?) || $? == 255; + # (Note that we cannot safely distinguish calls to `exit (n)' + # from calls to die when `$! = n'. It's not big deal because + # we only call `exit (0)' or `exit (1)'.) + + if (!$debug && defined $tmp && -d $tmp) + { + local $SIG{__WARN__} = sub { $status = 1; warn $_[0] }; + File::Path::rmtree $tmp; + } + + # This is required if the code might send any output to stdout + # E.g., even --version or --help. So it's best to do it unconditionally. + if (! close STDOUT) + { + print STDERR "$me: closing standard output: $!\n"; + $? = 1; + return; + } + + $? = $status; +} + + +## ----------- ## +## Functions. ## +## ----------- ## + + +=item C<debug (@message)> + +If the debug mode is enabled (C<$debug> and C<$verbose>), report the +C<@message> on C<STDERR>, signed with the name of the program. + +=cut + +# &debug(@MESSAGE) +# ---------------- +# Messages displayed only if $DEBUG and $VERBOSE. +sub debug (@) +{ + print STDERR "$me: ", @_, "\n" + if $verbose && $debug; +} + + +=item C<getopt (%option)> + +Wrapper around C<Autom4te::Getopt::parse_options>. In addition to +the user C<option>s, support C<-h>/C<--help>, C<-V>/C<--version>, +C<-v>/C<--verbose>, C<-d>/C<--debug>, C<-f>/C<--force>. Conform to +the GNU Coding Standards for error messages. + +=cut + +# getopt (%OPTION) +# ---------------- +# Handle the %OPTION, plus all the common options. +sub getopt (%) +{ + my (%option) = @_; + %option = ("h|help" => sub { print $help; exit 0 }, + "V|version" => sub { print $version; exit 0 }, + + "v|verbose" => sub { ++$verbose }, + "d|debug" => sub { ++$debug }, + 'f|force' => \$force, + + # User options last, so that they have precedence. + %option); + Autom4te::Getopt::parse_options (%option); + + setup_channel 'note', silent => !$verbose; + setup_channel 'verb', silent => !$verbose; +} + + +=item C<shell_quote ($file_name)> + +Quote C<$file_name> for the shell. + +=cut + +# $FILE_NAME +# shell_quote ($FILE_NAME) +# ------------------------ +# If the string $S is a well-behaved file name, simply return it. +# If it contains white space, quotes, etc., quote it, and return +# the new string. +sub shell_quote($) +{ + my ($s) = @_; + if ($s =~ m![^\w+/.,-]!) + { + # Convert each single quote to '\'' + $s =~ s/\'/\'\\\'\'/g; + # Then single quote the string. + $s = "'$s'"; + } + return $s; +} + +=item C<mktmpdir ($signature)> + +Create a temporary directory which name is based on C<$signature>. +Store its name in C<$tmp>. C<END> is in charge of removing it, unless +C<$debug>. + +=cut + +# mktmpdir ($SIGNATURE) +# --------------------- +sub mktmpdir ($) +{ + my ($signature) = @_; + my $TMPDIR = $ENV{'TMPDIR'} || '/tmp'; + my $quoted_tmpdir = shell_quote ($TMPDIR); + + # If mktemp supports dirs, use it. + $tmp = `(umask 077 && + mktemp -d $quoted_tmpdir/"${signature}XXXXXX") 2>/dev/null`; + chomp $tmp; + + if (!$tmp || ! -d $tmp) + { + $tmp = "$TMPDIR/$signature" . int (rand 10000) . ".$$"; + mkdir $tmp, 0700 + or croak "$me: cannot create $tmp: $!\n"; + } + + print STDERR "$me:$$: working in $tmp\n" + if $debug; +} + + +=item C<uniq (@list)> + +Return C<@list> with no duplicates, keeping only the first +occurrences. + +=cut + +# @RES +# uniq (@LIST) +# ------------ +sub uniq (@) +{ + my @res = (); + my %seen = (); + foreach my $item (@_) + { + if (! exists $seen{$item}) + { + $seen{$item} = 1; + push (@res, $item); + } + } + return wantarray ? @res : "@res"; +} + + +=item C<handle_exec_errors ($command)> + +Display an error message for C<$command>, based on the content of +C<$?> and C<$!>. + +=cut + + +# handle_exec_errors ($COMMAND) +# ----------------------------- +sub handle_exec_errors ($) +{ + my ($command) = @_; + + $command = (split (' ', $command))[0]; + if ($!) + { + error "failed to run $command: $!"; + } + else + { + use POSIX qw (WIFEXITED WEXITSTATUS WIFSIGNALED WTERMSIG); + + if (WIFEXITED ($?)) + { + my $status = WEXITSTATUS ($?); + # WIFEXITED and WEXITSTATUS can alter $!, reset it so that + # error() actually propagates the command's exit status, not $!. + $! = 0; + error "$command failed with exit status: $status"; + } + elsif (WIFSIGNALED ($?)) + { + my $signal = WTERMSIG ($?); + # In this case we prefer to exit with status 1. + $! = 1; + error "$command terminated by signal: $signal"; + } + else + { + error "$command exited abnormally"; + } + } +} + +=back + +=head1 SEE ALSO + +L<Autom4te::XFile> + +=head1 HISTORY + +Written by Alexandre Duret-Lutz E<lt>F<adl@gnu.org>E<gt> and Akim +Demaille E<lt>F<akim@freefriends.org>E<gt>. + +=cut + + + +1; # for require + +### Setup "GNU" style for perl-mode and cperl-mode. +## Local Variables: +## perl-indent-level: 2 +## perl-continued-statement-offset: 2 +## perl-continued-brace-offset: 0 +## perl-brace-offset: 0 +## perl-brace-imaginary-offset: 0 +## perl-label-offset: -2 +## cperl-indent-level: 2 +## cperl-brace-offset: 0 +## cperl-continued-brace-offset: 0 +## cperl-label-offset: -2 +## cperl-extra-newline-before-brace: t +## cperl-merge-trailing-else: nil +## cperl-continued-statement-offset: 2 +## End: diff --git a/lib/Autom4te/Getopt.pm b/lib/Autom4te/Getopt.pm new file mode 100644 index 0000000..d73c5ef --- /dev/null +++ b/lib/Autom4te/Getopt.pm @@ -0,0 +1,115 @@ +# Copyright (C) 2012 Free Software Foundation, Inc. + +# 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 3 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, see <http://www.gnu.org/licenses/>. + +package Autom4te::Getopt; + +=head1 NAME + +Autom4te::Getopt - GCS conforming parser for command line options + +=head1 SYNOPSIS + + use Autom4te::Getopt; + +=head1 DESCRIPTION + +Export a function C<parse_options>, performing parsing of command +line options in conformance to the GNU Coding standards. + +=cut + +use 5.006; +use strict; +use warnings FATAL => 'all'; +use Exporter (); +use Getopt::Long (); +use Autom4te::ChannelDefs qw/fatal/; +use Carp qw/croak confess/; + +use vars qw (@ISA @EXPORT); +@ISA = qw (Exporter); +@EXPORT= qw/getopt/; + +=item C<parse_options (%option)> + +Wrapper around C<Getopt::Long>, trying to conform to the GNU +Coding Standards for error messages. + +=cut + +sub parse_options (%) +{ + my %option = @_; + + Getopt::Long::Configure ("bundling", "pass_through"); + # Unrecognized options are passed through, so GetOption can only fail + # due to internal errors or misuse of options specification. + Getopt::Long::GetOptions (%option) + or confess "error in options specification (likely)"; + + if (@ARGV && $ARGV[0] =~ /^-./) + { + my %argopts; + for my $k (keys %option) + { + if ($k =~ /(.*)=s$/) + { + map { $argopts{(length ($_) == 1) + ? "-$_" : "--$_" } = 1; } (split (/\|/, $1)); + } + } + if ($ARGV[0] eq '--') + { + shift @ARGV; + } + elsif (exists $argopts{$ARGV[0]}) + { + fatal ("option '$ARGV[0]' requires an argument\n" + . "Try '$0 --help' for more information."); + } + else + { + fatal ("unrecognized option '$ARGV[0]'.\n" + . "Try '$0 --help' for more information."); + } + } +} + +=back + +=head1 SEE ALSO + +L<Getopt::Long> + +=cut + +1; # for require + +### Setup "GNU" style for perl-mode and cperl-mode. +## Local Variables: +## perl-indent-level: 2 +## perl-continued-statement-offset: 2 +## perl-continued-brace-offset: 0 +## perl-brace-offset: 0 +## perl-brace-imaginary-offset: 0 +## perl-label-offset: -2 +## cperl-indent-level: 2 +## cperl-brace-offset: 0 +## cperl-continued-brace-offset: 0 +## cperl-label-offset: -2 +## cperl-extra-newline-before-brace: t +## cperl-merge-trailing-else: nil +## cperl-continued-statement-offset: 2 +## End: diff --git a/lib/Autom4te/Makefile.am b/lib/Autom4te/Makefile.am new file mode 100644 index 0000000..5d9bdac --- /dev/null +++ b/lib/Autom4te/Makefile.am @@ -0,0 +1,37 @@ +## Process this file with automake to create Makefile.in + +# Copyright (C) 2001, 2003, 2009-2012 Free Software Foundation, Inc. + +# 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 3 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, see <http://www.gnu.org/licenses/>. + +perllibdir = $(pkgdatadir)/Autom4te +dist_perllib_DATA = \ + C4che.pm \ + ChannelDefs.pm \ + Channels.pm \ + Configure_ac.pm \ + FileUtils.pm \ + General.pm \ + Getopt.pm \ + Request.pm \ + XFile.pm + + +## --------------- ## +## Building TAGS. ## +## --------------- ## + +TAGS_FILES = $(dist_perllib_DATA) + +ETAGS_ARGS = --lang=perl diff --git a/lib/Autom4te/Makefile.in b/lib/Autom4te/Makefile.in new file mode 100644 index 0000000..280af35 --- /dev/null +++ b/lib/Autom4te/Makefile.in @@ -0,0 +1,454 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +# Copyright (C) 2001, 2003, 2009-2012 Free Software Foundation, Inc. + +# 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 3 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, see <http://www.gnu.org/licenses/>. + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = lib/Autom4te +DIST_COMMON = $(dist_perllib_DATA) $(srcdir)/Makefile.am \ + $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/autobuild.m4 \ + $(top_srcdir)/m4/m4.m4 $(top_srcdir)/m4/make-case.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +SOURCES = +DIST_SOURCES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__installdirs = "$(DESTDIR)$(perllibdir)" +DATA = $(dist_perllib_DATA) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EMACS = @EMACS@ +EMACSLOADPATH = @EMACSLOADPATH@ +EXPR = @EXPR@ +GREP = @GREP@ +HELP2MAN = @HELP2MAN@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LTLIBOBJS = @LTLIBOBJS@ +M4 = @M4@ +M4_DEBUGFILE = @M4_DEBUGFILE@ +M4_GNU = @M4_GNU@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PERL = @PERL@ +PERL_FLOCK = @PERL_FLOCK@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +TEST_EMACS = @TEST_EMACS@ +VERSION = @VERSION@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_cv_dir_trailing_space = @ac_cv_dir_trailing_space@ +ac_cv_sh_n_works = @ac_cv_sh_n_works@ +ac_cv_unsupported_fs_chars = @ac_cv_unsupported_fs_chars@ +am__leading_dot = @am__leading_dot@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +lispdir = @lispdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +perllibdir = $(pkgdatadir)/Autom4te +dist_perllib_DATA = \ + C4che.pm \ + ChannelDefs.pm \ + Channels.pm \ + Configure_ac.pm \ + FileUtils.pm \ + General.pm \ + Getopt.pm \ + Request.pm \ + XFile.pm + +TAGS_FILES = $(dist_perllib_DATA) +ETAGS_ARGS = --lang=perl +all: all-am + +.SUFFIXES: +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu lib/Autom4te/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu lib/Autom4te/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): +install-dist_perllibDATA: $(dist_perllib_DATA) + @$(NORMAL_INSTALL) + test -z "$(perllibdir)" || $(MKDIR_P) "$(DESTDIR)$(perllibdir)" + @list='$(dist_perllib_DATA)'; test -n "$(perllibdir)" || list=; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(perllibdir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(perllibdir)" || exit $$?; \ + done + +uninstall-dist_perllibDATA: + @$(NORMAL_UNINSTALL) + @list='$(dist_perllib_DATA)'; test -n "$(perllibdir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + test -n "$$files" || exit 0; \ + echo " ( cd '$(DESTDIR)$(perllibdir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(perllibdir)" && rm -f $$files + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(DATA) +installdirs: + for dir in "$(DESTDIR)$(perllibdir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-generic distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: install-dist_perllibDATA + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-generic + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-dist_perllibDATA + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + ctags distclean distclean-generic distclean-tags distdir dvi \ + dvi-am html html-am info info-am install install-am \ + install-data install-data-am install-dist_perllibDATA \ + install-dvi install-dvi-am install-exec install-exec-am \ + install-html install-html-am install-info install-info-am \ + install-man install-pdf install-pdf-am install-ps \ + install-ps-am install-strip installcheck installcheck-am \ + installdirs maintainer-clean maintainer-clean-generic \ + mostlyclean mostlyclean-generic pdf pdf-am ps ps-am tags \ + uninstall uninstall-am uninstall-dist_perllibDATA + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/lib/Autom4te/Request.pm b/lib/Autom4te/Request.pm new file mode 100644 index 0000000..c3cd050 --- /dev/null +++ b/lib/Autom4te/Request.pm @@ -0,0 +1,114 @@ +# autoconf -- create `configure' using m4 macros +# Copyright (C) 2001-2003, 2009-2012 Free Software Foundation, Inc. + +# 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 3 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, see <http://www.gnu.org/licenses/>. + +package Autom4te::Request; + +=head1 NAME + +Autom4te::Request - a single m4 run request + +=head1 SYNOPSIS + + use Autom4te::Request; + +=head1 DESCRIPTION + +This perl module provides various general purpose support functions +used in several executables of the Autoconf and Automake packages. + +=cut + +use strict; +use Class::Struct; +use Carp; +use Data::Dumper; + +struct + ( + # The key of the cache files. + 'id' => "\$", + # True iff %MACRO contains all the macros we want to trace. + 'valid' => "\$", + # The include path. + 'path' => '@', + # The set of input files. + 'input' => '@', + # The set of macros currently traced. + 'macro' => '%', + ); + + +# Serialize a request or all the current requests. +sub marshall($) +{ + my ($caller) = @_; + my $res = ''; + + # CALLER is an object: instance method. + my $marshall = Data::Dumper->new ([$caller]); + $marshall->Indent(2)->Terse(0); + $res = $marshall->Dump . "\n"; + + return $res; +} + + +# includes_p ($SELF, @MACRO) +# -------------------------- +# Does this request covers all the @MACRO. +sub includes_p +{ + my ($self, @macro) = @_; + + foreach (@macro) + { + return 0 + if ! exists ${$self->macro}{$_}; + } + return 1; +} + + +=head1 SEE ALSO + +L<Autom4te::C4che> + +=head1 HISTORY + +Written by Akim Demaille E<lt>F<akim@freefriends.org>E<gt>. + +=cut + + + +1; # for require + +### Setup "GNU" style for perl-mode and cperl-mode. +## Local Variables: +## perl-indent-level: 2 +## perl-continued-statement-offset: 2 +## perl-continued-brace-offset: 0 +## perl-brace-offset: 0 +## perl-brace-imaginary-offset: 0 +## perl-label-offset: -2 +## cperl-indent-level: 2 +## cperl-brace-offset: 0 +## cperl-continued-brace-offset: 0 +## cperl-label-offset: -2 +## cperl-extra-newline-before-brace: t +## cperl-merge-trailing-else: nil +## cperl-continued-statement-offset: 2 +## End: diff --git a/lib/Autom4te/XFile.pm b/lib/Autom4te/XFile.pm new file mode 100644 index 0000000..28d5bc6 --- /dev/null +++ b/lib/Autom4te/XFile.pm @@ -0,0 +1,319 @@ +# Copyright (C) 2001-2012 Free Software Foundation, Inc. + +# 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, 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, see <http://www.gnu.org/licenses/>. + +# Written by Akim Demaille <akim@freefriends.org>. + +############################################################### +# The main copy of this file is in Automake's git repository. # +# Updates should be sent to automake-patches@gnu.org. # +############################################################### + +package Autom4te::XFile; + +=head1 NAME + +Autom4te::XFile - supply object methods for filehandles with error handling + +=head1 SYNOPSIS + + use Autom4te::XFile; + + $fh = new Autom4te::XFile; + $fh->open ("< file"); + # No need to check $FH: we died if open failed. + print <$fh>; + $fh->close; + # No need to check the return value of close: we died if it failed. + + $fh = new Autom4te::XFile "> file"; + # No need to check $FH: we died if new failed. + print $fh "bar\n"; + $fh->close; + + $fh = new Autom4te::XFile "file", "r"; + # No need to check $FH: we died if new failed. + defined $fh + print <$fh>; + undef $fh; # automatically closes the file and checks for errors. + + $fh = new Autom4te::XFile "file", O_WRONLY | O_APPEND; + # No need to check $FH: we died if new failed. + print $fh "corge\n"; + + $pos = $fh->getpos; + $fh->setpos ($pos); + + undef $fh; # automatically closes the file and checks for errors. + + autoflush STDOUT 1; + +=head1 DESCRIPTION + +C<Autom4te::XFile> inherits from C<IO::File>. It provides the method +C<name> returning the file name. It provides dying versions of the +methods C<close>, C<lock> (corresponding to C<flock>), C<new>, +C<open>, C<seek>, and C<truncate>. It also overrides the C<getline> +and C<getlines> methods to translate C<\r\n> to C<\n>. + +=cut + +use 5.006; +use strict; +use vars qw($VERSION @EXPORT @EXPORT_OK $AUTOLOAD @ISA); +use Carp; +use Errno; +use IO::File; +use File::Basename; +use Autom4te::ChannelDefs; +use Autom4te::Channels qw(msg); +use Autom4te::FileUtils; + +require Exporter; +require DynaLoader; + +@ISA = qw(IO::File Exporter DynaLoader); + +$VERSION = "1.2"; + +@EXPORT = @IO::File::EXPORT; + +eval { + # Make all Fcntl O_XXX and LOCK_XXX constants available for importing + require Fcntl; + my @O = grep /^(LOCK|O)_/, @Fcntl::EXPORT, @Fcntl::EXPORT_OK; + Fcntl->import (@O); # first we import what we want to export + push (@EXPORT, @O); +}; + +=head2 Methods + +=over + +=item C<$fh = new Autom4te::XFile ([$expr, ...]> + +Constructor a new XFile object. Additional arguments +are passed to C<open>, if any. + +=cut + +sub new +{ + my $type = shift; + my $class = ref $type || $type || "Autom4te::XFile"; + my $fh = $class->SUPER::new (); + if (@_) + { + $fh->open (@_); + } + $fh; +} + +=item C<$fh-E<gt>open ([$file, ...])> + +Open a file, passing C<$file> and further arguments to C<IO::File::open>. +Die if opening fails. Store the name of the file. Use binmode for writing. + +=cut + +sub open +{ + my $fh = shift; + my ($file) = @_; + + # WARNING: Gross hack: $FH is a typeglob: use its hash slot to store + # the 'name' of the file we are opening. See the example with + # io_socket_timeout in IO::Socket for more, and read Graham's + # comment in IO::Handle. + ${*$fh}{'autom4te_xfile_file'} = "$file"; + + if (!$fh->SUPER::open (@_)) + { + fatal "cannot open $file: $!"; + } + + # In case we're running under MSWindows, don't write with CRLF. + # (This circumvents a bug in at least Cygwin bash where the shell + # parsing fails on lines ending with the continuation character '\' + # and CRLF). + binmode $fh if $file =~ /^\s*>/; +} + +=item C<$fh-E<gt>close> + +Close the file, handling errors. + +=cut + +sub close +{ + my $fh = shift; + if (!$fh->SUPER::close (@_)) + { + my $file = $fh->name; + Autom4te::FileUtils::handle_exec_errors $file + unless $!; + fatal "cannot close $file: $!"; + } +} + +=item C<$line = $fh-E<gt>getline> + +Read and return a line from the file. Ensure C<\r\n> is translated to +C<\n> on input files. + +=cut + +# Some native Windows/perl installations fail to translate \r\n to \n on +# input so we do that here. +sub getline +{ + local $_ = $_[0]->SUPER::getline; + # Perform a _global_ replacement: $_ may can contains many lines + # in slurp mode ($/ = undef). + s/\015\012/\n/gs if defined $_; + return $_; +} + +=item C<@lines = $fh-E<gt>getlines> + +Slurp lines from the files. + +=cut + +sub getlines +{ + my @res = (); + my $line; + push @res, $line while $line = $_[0]->getline; + return @res; +} + +=item C<$name = $fh-E<gt>name> + +Return the name of the file. + +=cut + +sub name +{ + my $fh = shift; + return ${*$fh}{'autom4te_xfile_file'}; +} + +=item C<$fh-E<gt>lock> + +Lock the file using C<flock>. If locking fails for reasons other than +C<flock> being unsupported, then error out if C<$ENV{'MAKEFLAGS'}> indicates +that we are spawned from a parallel C<make>. + +=cut + +sub lock +{ + my ($fh, $mode) = @_; + # Cannot use @_ here. + + # Unless explicitly configured otherwise, Perl implements its 'flock' with the + # first of flock(2), fcntl(2), or lockf(3) that works. These can fail on + # NFS-backed files, with ENOLCK (GNU/Linux) or EOPNOTSUPP (FreeBSD); we + # usually ignore these errors. If $ENV{MAKEFLAGS} suggests that a parallel + # invocation of 'make' has invoked the tool we serve, report all locking + # failures and abort. + # + # On Unicos, flock(2) and fcntl(2) over NFS hang indefinitely when 'lockd' is + # not running. NetBSD NFS clients silently grant all locks. We do not + # attempt to defend against these dangers. + # + # -j is for parallel BSD make, -P is for parallel HP-UX make. + if (!flock ($fh, $mode)) + { + my $make_j = (exists $ENV{'MAKEFLAGS'} + && " -$ENV{'MAKEFLAGS'}" =~ / (-[BdeikrRsSw]*[jP]|--[jP]|---?jobs)/); + my $note = "\nforgo \"make -j\" or use a file system that supports locks"; + my $file = $fh->name; + + msg ($make_j ? 'fatal' : 'unsupported', + "cannot lock $file with mode $mode: $!" . ($make_j ? $note : "")) + if $make_j || !($!{ENOLCK} || $!{EOPNOTSUPP}); + } +} + +=item C<$fh-E<gt>seek ($position, [$whence])> + +Seek file to C<$position>. Die if seeking fails. + +=cut + +sub seek +{ + my $fh = shift; + # Cannot use @_ here. + if (!seek ($fh, $_[0], $_[1])) + { + my $file = $fh->name; + fatal "cannot rewind $file with @_: $!"; + } +} + +=item C<$fh-E<gt>truncate ($len)> + +Truncate the file to length C<$len>. Die on failure. + +=cut + +sub truncate +{ + my ($fh, $len) = @_; + if (!truncate ($fh, $len)) + { + my $file = $fh->name; + fatal "cannot truncate $file at $len: $!"; + } +} + +=back + +=head1 SEE ALSO + +L<perlfunc>, +L<perlop/"I/O Operators">, +L<IO::File> +L<IO::Handle> +L<IO::Seekable> + +=head1 HISTORY + +Derived from IO::File.pm by Akim Demaille E<lt>F<akim@freefriends.org>E<gt>. + +=cut + +1; + +### Setup "GNU" style for perl-mode and cperl-mode. +## Local Variables: +## perl-indent-level: 2 +## perl-continued-statement-offset: 2 +## perl-continued-brace-offset: 0 +## perl-brace-offset: 0 +## perl-brace-imaginary-offset: 0 +## perl-label-offset: -2 +## cperl-indent-level: 2 +## cperl-brace-offset: 0 +## cperl-continued-brace-offset: 0 +## cperl-label-offset: -2 +## cperl-extra-newline-before-brace: t +## cperl-merge-trailing-else: nil +## cperl-continued-statement-offset: 2 +## End: |