From 3d672eb1ef8572ac257652cab0ab416bd32be024 Mon Sep 17 00:00:00 2001 From: Matthias Paulmier Date: Wed, 6 Jun 2018 15:46:24 +0200 Subject: lib: fix Automake::Variable Some methods added to this module were not working properly because they depend on others which stayed in automake.in * ConfVars.pm: Added this module to put the methods in question. * CondStack.pm: Module that takes care of the conditional stack. * Utils.pm: Added some needed utility functions for the above to run properly. * File.pm: Methods that looks at files' content. * local.mk: Added the new modules. --- bin/automake.in | 320 +--------------------------------------------- lib/Automake/CondStack.pm | 150 ++++++++++++++++++++++ lib/Automake/ConfVars.pm | 71 ++++++++++ lib/Automake/File.pm | 247 +++++++++++++++++++++++++++++++++++ lib/Automake/Utils.pm | 189 ++++++++++++++++++++++++++- lib/Automake/Variable.pm | 35 +---- lib/Automake/local.mk | 4 + 7 files changed, 663 insertions(+), 353 deletions(-) create mode 100644 lib/Automake/CondStack.pm create mode 100644 lib/Automake/ConfVars.pm create mode 100644 lib/Automake/File.pm diff --git a/bin/automake.in b/bin/automake.in index fb9779882..18a6fbf3e 100755 --- a/bin/automake.in +++ b/bin/automake.in @@ -57,6 +57,7 @@ use Automake::Channels; use Automake::ChannelDefs; use Automake::Configure_ac; use Automake::FileUtils; +use Automake::File; use Automake::Location; use Automake::Condition qw/TRUE FALSE/; use Automake::DisjConditions; @@ -68,6 +69,8 @@ use Automake::RuleDef; use Automake::Wrap 'makefile_wrap'; use Automake::Language; use Automake::Utils; +use Automake::CondStack; +use Automake::ConfVars; use File::Basename; use File::Spec; use Carp; @@ -5528,132 +5531,6 @@ sub pretty_print_rule ################################################################ -## -------------------------------- ## -## Handling the conditional stack. ## -## -------------------------------- ## - - -# $STRING -# make_conditional_string ($NEGATE, $COND) -# ---------------------------------------- -sub make_conditional_string -{ - my ($negate, $cond) = @_; - $cond = "${cond}_TRUE" - unless $cond =~ /^TRUE|FALSE$/; - $cond = Automake::Condition::conditional_negate ($cond) - if $negate; - return $cond; -} - - -my %_am_macro_for_cond = - ( - AMDEP => "one of the compiler tests\n" - . " AC_PROG_CC, AC_PROG_CXX, AC_PROG_OBJC, AC_PROG_OBJCXX,\n" - . " AM_PROG_AS, AM_PROG_GCJ, AM_PROG_UPC", - am__fastdepCC => 'AC_PROG_CC', - am__fastdepCCAS => 'AM_PROG_AS', - am__fastdepCXX => 'AC_PROG_CXX', - am__fastdepGCJ => 'AM_PROG_GCJ', - am__fastdepOBJC => 'AC_PROG_OBJC', - am__fastdepOBJCXX => 'AC_PROG_OBJCXX', - am__fastdepUPC => 'AM_PROG_UPC' - ); - -# $COND -# cond_stack_if ($NEGATE, $COND, $WHERE) -# -------------------------------------- -sub cond_stack_if -{ - my ($negate, $cond, $where) = @_; - - if (! $configure_cond{$cond} && $cond !~ /^TRUE|FALSE$/) - { - my $text = "$cond does not appear in AM_CONDITIONAL"; - my $scope = US_LOCAL; - if (exists $_am_macro_for_cond{$cond}) - { - my $mac = $_am_macro_for_cond{$cond}; - $text .= "\n The usual way to define '$cond' is to add "; - $text .= ($mac =~ / /) ? $mac : "'$mac'"; - $text .= "\n to '$configure_ac' and run 'aclocal' and 'autoconf' again"; - # These warnings appear in Automake files (depend2.am), - # so there is no need to display them more than once: - $scope = US_GLOBAL; - } - error $where, $text, uniq_scope => $scope; - } - - push (@cond_stack, make_conditional_string ($negate, $cond)); - - return new Automake::Condition (@cond_stack); -} - - -# $COND -# cond_stack_else ($NEGATE, $COND, $WHERE) -# ---------------------------------------- -sub cond_stack_else -{ - my ($negate, $cond, $where) = @_; - - if (! @cond_stack) - { - error $where, "else without if"; - return FALSE; - } - - $cond_stack[$#cond_stack] = - Automake::Condition::conditional_negate ($cond_stack[$#cond_stack]); - - # If $COND is given, check against it. - if (defined $cond) - { - $cond = make_conditional_string ($negate, $cond); - - error ($where, "else reminder ($negate$cond) incompatible with " - . "current conditional: $cond_stack[$#cond_stack]") - if $cond_stack[$#cond_stack] ne $cond; - } - - return new Automake::Condition (@cond_stack); -} - - -# $COND -# cond_stack_endif ($NEGATE, $COND, $WHERE) -# ----------------------------------------- -sub cond_stack_endif -{ - my ($negate, $cond, $where) = @_; - my $old_cond; - - if (! @cond_stack) - { - error $where, "endif without if"; - return TRUE; - } - - # If $COND is given, check against it. - if (defined $cond) - { - $cond = make_conditional_string ($negate, $cond); - - error ($where, "endif reminder ($negate$cond) incompatible with " - . "current conditional: $cond_stack[$#cond_stack]") - if $cond_stack[$#cond_stack] ne $cond; - } - - pop @cond_stack; - - return new Automake::Condition (@cond_stack); -} - - - - - ## ------------------------ ## ## Handling the variables. ## ## ------------------------ ## @@ -6111,197 +5988,6 @@ sub read_main_am_file ################################################################ -# $STRING -# flatten ($ORIGINAL_STRING) -# -------------------------- -sub flatten -{ - $_ = shift; - - s/\\\n//somg; - s/\s+/ /g; - s/^ //; - s/ $//; - - return $_; -} - - -# transform_token ($TOKEN, \%PAIRS, $KEY) -# --------------------------------------- -# Return the value associated to $KEY in %PAIRS, as used on $TOKEN -# (which should be ?KEY? or any of the special %% requests).. -sub transform_token ($\%$) -{ - my ($token, $transform, $key) = @_; - my $res = $transform->{$key}; - prog_error "Unknown key '$key' in '$token'" unless defined $res; - return $res; -} - - -# transform ($TOKEN, \%PAIRS) -# --------------------------- -# If ($TOKEN, $VAL) is in %PAIRS: -# - replaces %KEY% with $VAL, -# - enables/disables ?KEY? and ?!KEY?, -# - replaces %?KEY% with TRUE or FALSE. -sub transform ($\%) -{ - my ($token, $transform) = @_; - - # %KEY%. - # Must be before the following pattern to exclude the case - # when there is neither IFTRUE nor IFFALSE. - if ($token =~ /^%([\w\-]+)%$/) - { - return transform_token ($token, %$transform, $1); - } - # %?KEY%. - elsif ($token =~ /^%\?([\w\-]+)%$/) - { - return transform_token ($token, %$transform, $1) ? 'TRUE' : 'FALSE'; - } - # ?KEY? and ?!KEY?. - elsif ($token =~ /^ \? (!?) ([\w\-]+) \? $/x) - { - my $neg = ($1 eq '!') ? 1 : 0; - my $val = transform_token ($token, %$transform, $2); - return (!!$val == $neg) ? '##%' : ''; - } - else - { - prog_error "Unknown request format: $token"; - } -} - -# $TEXT -# preprocess_file ($MAKEFILE, [%TRANSFORM]) -# ----------------------------------------- -# Load a $MAKEFILE, apply the %TRANSFORM, and return the result. -# No extra parsing or post-processing is done (i.e., recognition of -# rules declaration or of make variables definitions). -sub preprocess_file -{ - my ($file, %transform) = @_; - - # Complete %transform with global options. - # Note that %transform goes last, so it overrides global options. - %transform = ( 'MAINTAINER-MODE' - => $seen_maint_mode ? subst ('MAINTAINER_MODE_TRUE') : '', - - 'XZ' => !! option 'dist-xz', - 'LZIP' => !! option 'dist-lzip', - 'BZIP2' => !! option 'dist-bzip2', - 'COMPRESS' => !! option 'dist-tarZ', - 'GZIP' => ! option 'no-dist-gzip', - 'SHAR' => !! option 'dist-shar', - 'ZIP' => !! option 'dist-zip', - - 'INSTALL-INFO' => ! option 'no-installinfo', - 'INSTALL-MAN' => ! option 'no-installman', - 'CK-NEWS' => !! option 'check-news', - - 'SUBDIRS' => !! var ('SUBDIRS'), - 'TOPDIR_P' => $relative_dir eq '.', - - 'BUILD' => ($seen_canonical >= AC_CANONICAL_BUILD), - 'HOST' => ($seen_canonical >= AC_CANONICAL_HOST), - 'TARGET' => ($seen_canonical >= AC_CANONICAL_TARGET), - - 'LIBTOOL' => !! var ('LIBTOOL'), - 'NONLIBTOOL' => 1, - %transform); - - if (! defined ($_ = $am_file_cache{$file})) - { - verb "reading $file"; - # Swallow the whole file. - my $fc_file = new Automake::XFile "< $file"; - my $saved_dollar_slash = $/; - undef $/; - $_ = $fc_file->getline; - $/ = $saved_dollar_slash; - $fc_file->close; - # Remove ##-comments. - # Besides we don't need more than two consecutive new-lines. - s/(?:$IGNORE_PATTERN|(?<=\n\n)\n+)//gom; - # Remember the contents of the just-read file. - $am_file_cache{$file} = $_; - } - - # Substitute Automake template tokens. - s/(?: % \?? [\w\-]+ % - | \? !? [\w\-]+ \? - )/transform($&, %transform)/gex; - # transform() may have added some ##%-comments to strip. - # (we use '##%' instead of '##' so we can distinguish ##%##%##% from - # ####### and do not remove the latter.) - s/^[ \t]*(?:##%)+.*\n//gm; - - return $_; -} - - -# @PARAGRAPHS -# make_paragraphs ($MAKEFILE, [%TRANSFORM]) -# ----------------------------------------- -# Load a $MAKEFILE, apply the %TRANSFORM, and return it as a list of -# paragraphs. -sub make_paragraphs -{ - my ($file, %transform) = @_; - $transform{FIRST} = !$transformed_files{$file}; - $transformed_files{$file} = 1; - - my @lines = split /(?. + +package Automake::CondStack; + +use 5.006; +use strict; + +use Exporter; +use Automake::Condition qw (TRUE FALSE); +use Automake::Global; +use Automake::Channels; +use Automake::ChannelDefs; + +use vars qw (@ISA @EXPORT); + +@ISA = qw (Exporter); +@EXPORT = qw (cond_stack_if cond_stack_else cond_stack_endif); + +my %_am_macro_for_cond = + ( + AMDEP => "one of the compiler tests\n" + . " AC_PROG_CC, AC_PROG_CXX, AC_PROG_OBJC, AC_PROG_OBJCXX,\n" + . " AM_PROG_AS, AM_PROG_GCJ, AM_PROG_UPC", + am__fastdepCC => 'AC_PROG_CC', + am__fastdepCCAS => 'AM_PROG_AS', + am__fastdepCXX => 'AC_PROG_CXX', + am__fastdepGCJ => 'AM_PROG_GCJ', + am__fastdepOBJC => 'AC_PROG_OBJC', + am__fastdepOBJCXX => 'AC_PROG_OBJCXX', + am__fastdepUPC => 'AM_PROG_UPC' + ); + + +# $STRING +# _make_conditional_string ($NEGATE, $COND) +# ---------------------------------------- +sub _make_conditional_string +{ + my ($negate, $cond) = @_; + $cond = "${cond}_TRUE" + unless $cond =~ /^TRUE|FALSE$/; + $cond = Automake::Condition::conditional_negate ($cond) + if $negate; + return $cond; +} + + +# $COND +# cond_stack_if ($NEGATE, $COND, $WHERE) +# -------------------------------------- +sub cond_stack_if +{ + my ($negate, $cond, $where) = @_; + + if (! $configure_cond{$cond} && $cond !~ /^TRUE|FALSE$/) + { + my $text = "$cond does not appear in AM_CONDITIONAL"; + my $scope = US_LOCAL; + if (exists $_am_macro_for_cond{$cond}) + { + my $mac = $_am_macro_for_cond{$cond}; + $text .= "\n The usual way to define '$cond' is to add "; + $text .= ($mac =~ / /) ? $mac : "'$mac'"; + $text .= "\n to '$configure_ac' and run 'aclocal' and 'autoconf' again"; + # These warnings appear in Automake files (depend2.am), + # so there is no need to display them more than once: + $scope = US_GLOBAL; + } + error $where, $text, uniq_scope => $scope; + } + + push (@cond_stack, _make_conditional_string ($negate, $cond)); + + return new Automake::Condition (@cond_stack); +} + + +# $COND +# cond_stack_else ($NEGATE, $COND, $WHERE) +# ---------------------------------------- +sub cond_stack_else +{ + my ($negate, $cond, $where) = @_; + + if (! @cond_stack) + { + error $where, "else without if"; + return FALSE; + } + + $cond_stack[$#cond_stack] = + Automake::Condition::conditional_negate ($cond_stack[$#cond_stack]); + + # If $COND is given, check against it. + if (defined $cond) + { + $cond = _make_conditional_string ($negate, $cond); + + error ($where, "else reminder ($negate$cond) incompatible with " + . "current conditional: $cond_stack[$#cond_stack]") + if $cond_stack[$#cond_stack] ne $cond; + } + + return new Automake::Condition (@cond_stack); +} + + +# $COND +# cond_stack_endif ($NEGATE, $COND, $WHERE) +# ----------------------------------------- +sub cond_stack_endif +{ + my ($negate, $cond, $where) = @_; + my $old_cond; + + if (! @cond_stack) + { + error $where, "endif without if"; + return TRUE; + } + + # If $COND is given, check against it. + if (defined $cond) + { + $cond = _make_conditional_string ($negate, $cond); + + error ($where, "endif reminder ($negate$cond) incompatible with " + . "current conditional: $cond_stack[$#cond_stack]") + if $cond_stack[$#cond_stack] ne $cond; + } + + pop @cond_stack; + + return new Automake::Condition (@cond_stack); +} + +1; diff --git a/lib/Automake/ConfVars.pm b/lib/Automake/ConfVars.pm new file mode 100644 index 000000000..8d7f362b0 --- /dev/null +++ b/lib/Automake/ConfVars.pm @@ -0,0 +1,71 @@ +# Copyright (C) 2018 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 . + +# Like define_variable, but define a variable to be the configure +# substitution by the same name. + +package Automake::ConfVars; + +use 5.006; +use strict; + +use Exporter; +use Automake::ChannelDefs; +use Automake::Channels; +use Automake::Condition qw (TRUE FALSE); +use Automake::Config; +use Automake::File; +use Automake::Global; +use Automake::Location; +use Automake::Utils; +use Automake::VarDef; +use Automake::Variable; + +use vars qw (@ISA @EXPORT); + +@ISA = qw (Exporter); +@EXPORT = qw (define_standard_variables); + + +sub _define_configure_variable ($) +{ + my ($var) = @_; + # Some variables we do not want to output. For instance it + # would be a bad idea to output `U = @U@` when `@U@` can be + # substituted as `\`. + my $pretty = exists $ignored_configure_vars{$var} ? VAR_SILENT : VAR_ASIS; + Automake::Variable::define ($var, VAR_CONFIGURE, '', TRUE, subst ($var), + '', $configure_vars{$var}, $pretty); +} + + +# A helper for read_main_am_file which initializes configure variables +# and variables from header-vars.am. +sub define_standard_variables () +{ + my $saved_output_vars = $output_vars; + my ($comments, undef, $rules) = + file_contents_internal (1, "$libdir/am/header-vars.am", + new Automake::Location); + + foreach my $var (sort keys %configure_vars) + { + _define_configure_variable ($var); + } + + $output_vars .= $comments . $rules; +} + +1; diff --git a/lib/Automake/File.pm b/lib/Automake/File.pm new file mode 100644 index 000000000..77cc062e0 --- /dev/null +++ b/lib/Automake/File.pm @@ -0,0 +1,247 @@ +# Copyright (C) 2018 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 . + +package Automake::File; + +use 5.006; +use strict; + +use Exporter; +use Automake::ChannelDefs; +use Automake::Channels; +use Automake::Condition qw (TRUE FALSE); +use Automake::CondStack; +use Automake::Config; +use Automake::Global; +use Automake::Location; +use Automake::Rule; +use Automake::RuleDef; +use Automake::Utils; +use Automake::VarDef; +use Automake::Variable; + +use vars qw (@ISA @EXPORT); + +@ISA = qw (Exporter); +@EXPORT = qw (file_contents_internal file_contents); + +# ($COMMENT, $VARIABLES, $RULES) +# file_contents_internal ($IS_AM, $FILE, $WHERE, [%TRANSFORM]) +# ------------------------------------------------------------ +# Return contents of a file from $libdir/am, automatically skipping +# macros or rules which are already known. $IS_AM iff the caller is +# reading an Automake file (as opposed to the user's Makefile.am). +sub file_contents_internal +{ + my ($is_am, $file, $where, %transform) = @_; + + $where->set ($file); + + my $result_vars = ''; + my $result_rules = ''; + my $comment = ''; + my $spacing = ''; + + # The following flags are used to track rules spanning across + # multiple paragraphs. + my $is_rule = 0; # 1 if we are processing a rule. + my $discard_rule = 0; # 1 if the current rule should not be output. + + # We save the conditional stack on entry, and then check to make + # sure it is the same on exit. This lets us conditionally include + # other files. + my @saved_cond_stack = @cond_stack; + my $cond = new Automake::Condition (@cond_stack); + + foreach (make_paragraphs ($file, %transform)) + { + # FIXME: no line number available. + $where->set ($file); + + # Sanity checks. + error $where, "blank line following trailing backslash:\n$_" + if /\\$/; + error $where, "comment following trailing backslash:\n$_" + if /\\#/; + + if (/^$/) + { + $is_rule = 0; + # Stick empty line before the incoming macro or rule. + $spacing = "\n"; + } + elsif (/$COMMENT_PATTERN/mso) + { + $is_rule = 0; + # Stick comments before the incoming macro or rule. + $comment = "$_\n"; + } + + # Handle inclusion of other files. + elsif (/$INCLUDE_PATTERN/o) + { + if ($cond != FALSE) + { + my $file = ($is_am ? "$libdir/am/" : '') . $1; + $where->push_context ("'$file' included from here"); + # N-ary '.=' fails. + my ($com, $vars, $rules) + = file_contents_internal ($is_am, $file, $where, %transform); + $where->pop_context; + $comment .= $com; + $result_vars .= $vars; + $result_rules .= $rules; + } + } + + # Handling the conditionals. + elsif (/$IF_PATTERN/o) + { + $cond = cond_stack_if ($1, $2, $file); + } + elsif (/$ELSE_PATTERN/o) + { + $cond = cond_stack_else ($1, $2, $file); + } + elsif (/$ENDIF_PATTERN/o) + { + $cond = cond_stack_endif ($1, $2, $file); + } + + # Handling rules. + elsif (/$RULE_PATTERN/mso) + { + $is_rule = 1; + $discard_rule = 0; + # Separate relationship from optional actions: the first + # `new-line tab" not preceded by backslash (continuation + # line). + my $paragraph = $_; + /^(.*?)(?:(?subst_string/gme; + $result_rules .= "$spacing$comment$condparagraph\n"; + } + if (scalar @undefined_conds == 0) + { + # Remember to discard next paragraphs + # if they belong to this rule. + # (but see also FIXME: #2 above.) + $discard_rule = 1; + } + $comment = $spacing = ''; + last; + } + } + } + + elsif (/$ASSIGNMENT_PATTERN/mso) + { + my ($var, $type, $val) = ($1, $2, $3); + error $where, "variable '$var' with trailing backslash" + if /\\$/; + + $is_rule = 0; + + Automake::Variable::define ($var, + $is_am ? VAR_AUTOMAKE : VAR_MAKEFILE, + $type, $cond, $val, $comment, $where, + VAR_ASIS) + if $cond != FALSE; + + $comment = $spacing = ''; + } + else + { + # This isn't an error; it is probably some tokens which + # configure is supposed to replace, such as '@SET-MAKE@', + # or some part of a rule cut by an if/endif. + if (! $cond->false && ! ($is_rule && $discard_rule)) + { + s/^/$cond->subst_string/gme; + $result_rules .= "$spacing$comment$_\n"; + } + $comment = $spacing = ''; + } + } + + error ($where, @cond_stack ? + "unterminated conditionals: @cond_stack" : + "too many conditionals closed in include file") + if "@saved_cond_stack" ne "@cond_stack"; + + return ($comment, $result_vars, $result_rules); +} + + +# $CONTENTS +# file_contents ($BASENAME, $WHERE, [%TRANSFORM]) +# ----------------------------------------------- +# Return contents of a file from $libdir/am, automatically skipping +# macros or rules which are already known. +sub file_contents +{ + my ($basename, $where, %transform) = @_; + my ($comments, $variables, $rules) = + file_contents_internal (1, "$libdir/am/$basename.am", $where, + %transform); + return "$comments$variables$rules"; +} + +1; diff --git a/lib/Automake/Utils.pm b/lib/Automake/Utils.pm index 832b74e05..aafb911cd 100644 --- a/lib/Automake/Utils.pm +++ b/lib/Automake/Utils.pm @@ -18,15 +18,19 @@ package Automake::Utils; use 5.006; use strict; use Exporter; -use Automake::Rule; use Automake::Global; use Automake::Location; -use Automake::Condition; +use Automake::Options; +use Automake::XFile; +use Automake::ChannelDefs; +use Automake::Variable; +use Automake::Rule; use vars qw (@ISA @EXPORT); @ISA = qw (Exporter); -@EXPORT = qw (var_SUFFIXES_trigger locate_aux_dir subst); +@EXPORT = qw (var_SUFFIXES_trigger locate_aux_dir subst + make_paragraphs flatten); # var_SUFFIXES_trigger ($TYPE, $VALUE) # ------------------------------------ @@ -80,4 +84,183 @@ sub subst ($) return '@' . $text . '@'; } + +# transform_token ($TOKEN, \%PAIRS, $KEY) +# --------------------------------------- +# Return the value associated to $KEY in %PAIRS, as used on $TOKEN +# (which should be ?KEY? or any of the special %% requests).. +sub transform_token ($\%$) +{ + my ($token, $transform, $key) = @_; + my $res = $transform->{$key}; + prog_error "Unknown key '$key' in '$token'" unless defined $res; + return $res; +} + + +# transform ($TOKEN, \%PAIRS) +# --------------------------- +# If ($TOKEN, $VAL) is in %PAIRS: +# - replaces %KEY% with $VAL, +# - enables/disables ?KEY? and ?!KEY?, +# - replaces %?KEY% with TRUE or FALSE. +sub transform ($\%) +{ + my ($token, $transform) = @_; + + # %KEY%. + # Must be before the following pattern to exclude the case + # when there is neither IFTRUE nor IFFALSE. + if ($token =~ /^%([\w\-]+)%$/) + { + return transform_token ($token, %$transform, $1); + } + # %?KEY%. + elsif ($token =~ /^%\?([\w\-]+)%$/) + { + return transform_token ($token, %$transform, $1) ? 'TRUE' : 'FALSE'; + } + # ?KEY? and ?!KEY?. + elsif ($token =~ /^ \? (!?) ([\w\-]+) \? $/x) + { + my $neg = ($1 eq '!') ? 1 : 0; + my $val = transform_token ($token, %$transform, $2); + return (!!$val == $neg) ? '##%' : ''; + } + else + { + prog_error "Unknown request format: $token"; + } +} + + +# $TEXT +# preprocess_file ($MAKEFILE, [%TRANSFORM]) +# ----------------------------------------- +# Load a $MAKEFILE, apply the %TRANSFORM, and return the result. +# No extra parsing or post-processing is done (i.e., recognition of +# rules declaration or of make variables definitions). +sub preprocess_file +{ + my ($file, %transform) = @_; + + # Complete %transform with global options. + # Note that %transform goes last, so it overrides global options. + %transform = ( 'MAINTAINER-MODE' + => $seen_maint_mode ? subst ('MAINTAINER_MODE_TRUE') : '', + + 'XZ' => !! option 'dist-xz', + 'LZIP' => !! option 'dist-lzip', + 'BZIP2' => !! option 'dist-bzip2', + 'COMPRESS' => !! option 'dist-tarZ', + 'GZIP' => ! option 'no-dist-gzip', + 'SHAR' => !! option 'dist-shar', + 'ZIP' => !! option 'dist-zip', + + 'INSTALL-INFO' => ! option 'no-installinfo', + 'INSTALL-MAN' => ! option 'no-installman', + 'CK-NEWS' => !! option 'check-news', + + 'SUBDIRS' => !! Automake::Variable::var ('SUBDIRS'), + 'TOPDIR_P' => $relative_dir eq '.', + + 'BUILD' => ($seen_canonical >= AC_CANONICAL_BUILD), + 'HOST' => ($seen_canonical >= AC_CANONICAL_HOST), + 'TARGET' => ($seen_canonical >= AC_CANONICAL_TARGET), + + 'LIBTOOL' => !! Automake::Variable::var ('LIBTOOL'), + 'NONLIBTOOL' => 1, + %transform); + + if (! defined ($_ = $am_file_cache{$file})) + { + verb "reading $file"; + # Swallow the whole file. + my $fc_file = new Automake::XFile "< $file"; + my $saved_dollar_slash = $/; + undef $/; + $_ = $fc_file->getline; + $/ = $saved_dollar_slash; + $fc_file->close; + # Remove ##-comments. + # Besides we don't need more than two consecutive new-lines. + s/(?:$IGNORE_PATTERN|(?<=\n\n)\n+)//gom; + # Remember the contents of the just-read file. + $am_file_cache{$file} = $_; + } + + # Substitute Automake template tokens. + s/(?: % \?? [\w\-]+ % + | \? !? [\w\-]+ \? + )/transform($&, %transform)/gex; + # transform() may have added some ##%-comments to strip. + # (we use '##%' instead of '##' so we can distinguish ##%##%##% from + # ####### and do not remove the latter.) + s/^[ \t]*(?:##%)+.*\n//gm; + + return $_; +} + + +# @PARAGRAPHS +# make_paragraphs ($MAKEFILE, [%TRANSFORM]) +# ----------------------------------------- +# Load a $MAKEFILE, apply the %TRANSFORM, and return it as a list of +# paragraphs. +sub make_paragraphs +{ + my ($file, %transform) = @_; + $transform{FIRST} = !$transformed_files{$file}; + $transformed_files{$file} = 1; + + my @lines = split /(?