Blame bin/autoupdate.in

Packit 47b4ca
#! @PERL@ -w
Packit 47b4ca
# -*- perl -*-
Packit 47b4ca
# @configure_input@
Packit 47b4ca
Packit 47b4ca
# autoupdate - modernize an Autoconf file.
Packit 47b4ca
# Copyright (C) 1994, 1999-2012 Free Software Foundation, Inc.
Packit 47b4ca
Packit 47b4ca
# This program is free software: you can redistribute it and/or modify
Packit 47b4ca
# it under the terms of the GNU General Public License as published by
Packit 47b4ca
# the Free Software Foundation, either version 3 of the License, or
Packit 47b4ca
# (at your option) any later version.
Packit 47b4ca
Packit 47b4ca
# This program is distributed in the hope that it will be useful,
Packit 47b4ca
# but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 47b4ca
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit 47b4ca
# GNU General Public License for more details.
Packit 47b4ca
Packit 47b4ca
# You should have received a copy of the GNU General Public License
Packit 47b4ca
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
Packit 47b4ca
Packit 47b4ca
# Originally written by David MacKenzie <djm@gnu.ai.mit.edu>.
Packit 47b4ca
# Rewritten by Akim Demaille <akim@freefriends.org>.
Packit 47b4ca
Packit 47b4ca
eval 'case $# in 0) exec @PERL@ -S "$0";; *) exec @PERL@ -S "$0" "$@";; esac'
Packit 47b4ca
    if 0;
Packit 47b4ca
Packit 47b4ca
BEGIN
Packit 47b4ca
{
Packit 47b4ca
  my $pkgdatadir = $ENV{'autom4te_perllibdir'} || '@pkgdatadir@';
Packit 47b4ca
  unshift @INC, $pkgdatadir;
Packit 47b4ca
Packit 47b4ca
  # Override SHELL.  On DJGPP SHELL may not be set to a shell
Packit 47b4ca
  # that can handle redirection and quote arguments correctly,
Packit 47b4ca
  # e.g.: COMMAND.COM.  For DJGPP always use the shell that configure
Packit 47b4ca
  # has detected.
Packit 47b4ca
  $ENV{'SHELL'} = '@SHELL@' if ($^O eq 'dos');
Packit 47b4ca
}
Packit 47b4ca
Packit 47b4ca
use Autom4te::ChannelDefs;
Packit 47b4ca
use Autom4te::Channels;
Packit 47b4ca
use Autom4te::Configure_ac;
Packit 47b4ca
use Autom4te::FileUtils;
Packit 47b4ca
use Autom4te::General;
Packit 47b4ca
use Autom4te::XFile;
Packit 47b4ca
use File::Basename;
Packit 47b4ca
use strict;
Packit 47b4ca
Packit 47b4ca
# Lib files.
Packit 47b4ca
my $autom4te = $ENV{'AUTOM4TE'} || '@bindir@/@autom4te-name@';
Packit 47b4ca
my $autoconf = "$autom4te --language=autoconf";
Packit 47b4ca
# We need to find m4sugar.
Packit 47b4ca
my @prepend_include;
Packit 47b4ca
my @include = ('@pkgdatadir@');
Packit 47b4ca
my $force = 0;
Packit 47b4ca
# m4.
Packit 47b4ca
my $m4 = $ENV{"M4"} || '@M4@';
Packit 47b4ca
Packit 47b4ca
Packit 47b4ca
# $HELP
Packit 47b4ca
# -----
Packit 47b4ca
$help = "Usage: $0 [OPTION]... [TEMPLATE-FILE]...
Packit 47b4ca
Packit 47b4ca
Update each TEMPLATE-FILE if given, or `configure.ac' if present,
Packit 47b4ca
or else `configure.in', to the syntax of the current version of
Packit 47b4ca
Autoconf.  The original files are backed up.
Packit 47b4ca
Packit 47b4ca
Operation modes:
Packit 47b4ca
  -h, --help                 print this help, then exit
Packit 47b4ca
  -V, --version              print version number, then exit
Packit 47b4ca
  -v, --verbose              verbosely report processing
Packit 47b4ca
  -d, --debug                don't remove temporary files
Packit 47b4ca
  -f, --force                consider all files obsolete
Packit 47b4ca
Packit 47b4ca
Library directories:
Packit 47b4ca
  -B, --prepend-include=DIR  prepend directory DIR to search path
Packit 47b4ca
  -I, --include=DIR          append directory DIR to search path
Packit 47b4ca
Packit 47b4ca
Report bugs to <bug-autoconf\@gnu.org>.
Packit 47b4ca
GNU Autoconf home page: <http://www.gnu.org/software/autoconf/>.
Packit 47b4ca
General help using GNU software: <http://www.gnu.org/gethelp/>.
Packit 47b4ca
";
Packit 47b4ca
Packit 47b4ca
# $VERSION
Packit 47b4ca
# --------
Packit 47b4ca
$version = "autoupdate (@PACKAGE_NAME@) @VERSION@
Packit 47b4ca
Copyright (C) @RELEASE_YEAR@ Free Software Foundation, Inc.
Packit 47b4ca
License GPLv3+/Autoconf: GNU GPL version 3 or later
Packit 47b4ca
<http://gnu.org/licenses/gpl.html>, <http://gnu.org/licenses/exceptions.html>
Packit 47b4ca
This is free software: you are free to change and redistribute it.
Packit 47b4ca
There is NO WARRANTY, to the extent permitted by law.
Packit 47b4ca
Packit 47b4ca
Written by David J. MacKenzie and Akim Demaille.
Packit 47b4ca
";
Packit 47b4ca
Packit 47b4ca
## ---------- ##
Packit 47b4ca
## Routines.  ##
Packit 47b4ca
## ---------- ##
Packit 47b4ca
Packit 47b4ca
Packit 47b4ca
# parse_args ()
Packit 47b4ca
# -------------
Packit 47b4ca
# Process any command line arguments.
Packit 47b4ca
sub parse_args ()
Packit 47b4ca
{
Packit 47b4ca
  my $srcdir;
Packit 47b4ca
Packit 47b4ca
  getopt ('I|include=s'         => \@include,
Packit 47b4ca
	  'B|prepend-include=s' => \@prepend_include,
Packit 47b4ca
	  'f|force'             => \$force);
Packit 47b4ca
Packit 47b4ca
  if (! @ARGV)
Packit 47b4ca
    {
Packit 47b4ca
      my $configure_ac = require_configure_ac;
Packit 47b4ca
      push @ARGV, $configure_ac;
Packit 47b4ca
    }
Packit 47b4ca
}
Packit 47b4ca
Packit 47b4ca
Packit 47b4ca
Packit 47b4ca
# ----------------- #
Packit 47b4ca
# Autoconf macros.  #
Packit 47b4ca
# ----------------- #
Packit 47b4ca
Packit 47b4ca
my (%ac_macros, %au_macros, %m4_builtins);
Packit 47b4ca
Packit 47b4ca
# HANDLE_AUTOCONF_MACROS ()
Packit 47b4ca
# -------------------------
Packit 47b4ca
# @M4_BUILTINS -- M4 builtins and a useful comment.
Packit 47b4ca
sub handle_autoconf_macros ()
Packit 47b4ca
{
Packit 47b4ca
  # Get the builtins.
Packit 47b4ca
  xsystem ("echo dumpdef | $m4 2>" . shell_quote ("$tmp/m4.defs") . " >/dev/null");
Packit 47b4ca
  my $m4_defs = new Autom4te::XFile "< " . open_quote ("$tmp/m4.defs");
Packit 47b4ca
  while ($_ = $m4_defs->getline)
Packit 47b4ca
    {
Packit 47b4ca
      $m4_builtins{$1} = 1
Packit 47b4ca
	if /^(\w+):/;
Packit 47b4ca
    }
Packit 47b4ca
  $m4_defs->close;
Packit 47b4ca
Packit 47b4ca
  my $macros = new Autom4te::XFile ("$autoconf"
Packit 47b4ca
				    . " --trace AU_DEFINE:'AU:\$f:\$1'"
Packit 47b4ca
				    . " --trace define:'AC:\$f:\$1'"
Packit 47b4ca
				    . " --melt /dev/null |");
Packit 47b4ca
  while ($_ = $macros->getline)
Packit 47b4ca
    {
Packit 47b4ca
      chomp;
Packit 47b4ca
      my ($domain, $file, $macro) = /^(AC|AU):(.*):([^:]*)$/ or next;
Packit 47b4ca
      if ($domain eq "AU")
Packit 47b4ca
	{
Packit 47b4ca
	  $au_macros{$macro} = 1;
Packit 47b4ca
	}
Packit 47b4ca
      elsif ($file =~ /(^|\/)m4sugar\/(m4sugar|version)\.m4$/)
Packit 47b4ca
	{
Packit 47b4ca
	  # Add the m4sugar macros to m4_builtins.
Packit 47b4ca
	  $m4_builtins{$macro} = 1;
Packit 47b4ca
	}
Packit 47b4ca
      else
Packit 47b4ca
	{
Packit 47b4ca
	  # Autoconf, aclocal, and m4sh macros.
Packit 47b4ca
	  $ac_macros{$macro} = 1;
Packit 47b4ca
	}
Packit 47b4ca
    }
Packit 47b4ca
  $macros->close;
Packit 47b4ca
Packit 47b4ca
Packit 47b4ca
  # Don't keep AU macros in @AC_MACROS.
Packit 47b4ca
  delete $ac_macros{$_}
Packit 47b4ca
    foreach (keys %au_macros);
Packit 47b4ca
  # Don't keep M4sugar macros which are redefined by Autoconf,
Packit 47b4ca
  # such as `builtin', `changequote' etc.  See autoconf/autoconf.m4.
Packit 47b4ca
  delete $ac_macros{$_}
Packit 47b4ca
    foreach (keys %m4_builtins);
Packit 47b4ca
  error "no current Autoconf macros found"
Packit 47b4ca
    unless keys %ac_macros;
Packit 47b4ca
  error "no obsolete Autoconf macros found"
Packit 47b4ca
    unless keys %au_macros;
Packit 47b4ca
Packit 47b4ca
  if ($debug)
Packit 47b4ca
    {
Packit 47b4ca
      print STDERR "Current Autoconf macros:\n";
Packit 47b4ca
      print STDERR join (' ', sort keys %ac_macros) . "\n\n";
Packit 47b4ca
      print STDERR "Obsolete Autoconf macros:\n";
Packit 47b4ca
      print STDERR join (' ', sort keys %au_macros) . "\n\n";
Packit 47b4ca
    }
Packit 47b4ca
Packit 47b4ca
  # ac.m4 -- autoquoting definitions of the AC macros (M4sugar excluded).
Packit 47b4ca
  # unac.m4 -- undefine the AC macros.
Packit 47b4ca
  my $ac_m4 = new Autom4te::XFile "> " . open_quote ("$tmp/ac.m4");
Packit 47b4ca
  print $ac_m4 "# ac.m4 -- autoquoting definitions of the AC macros.\n";
Packit 47b4ca
  my $unac_m4 = new Autom4te::XFile "> " . open_quote ("$tmp/unac.m4");
Packit 47b4ca
  print $unac_m4 "# unac.m4 -- undefine the AC macros.\n";
Packit 47b4ca
  foreach (sort keys %ac_macros)
Packit 47b4ca
    {
Packit 47b4ca
      print $ac_m4   "_au_m4_define([$_], [m4_if(\$#, 0, [[\$0]], [[\$0(\$\@)]])])\n";
Packit 47b4ca
      print $unac_m4 "_au_m4_undefine([$_])\n";
Packit 47b4ca
    }
Packit 47b4ca
Packit 47b4ca
  # m4save.m4 -- save the m4 builtins.
Packit 47b4ca
  # unm4.m4 -- disable the m4 builtins.
Packit 47b4ca
  # m4.m4 -- enable the m4 builtins.
Packit 47b4ca
  my $m4save_m4 = new Autom4te::XFile "> " . open_quote ("$tmp/m4save.m4");
Packit 47b4ca
  print $m4save_m4 "# m4save.m4 -- save the m4 builtins.\n";
Packit 47b4ca
  my $unm4_m4 = new Autom4te::XFile "> " . open_quote ("$tmp/unm4.m4");
Packit 47b4ca
  print $unm4_m4 "# unm4.m4 -- disable the m4 builtins.\n";
Packit 47b4ca
  my $m4_m4 = new Autom4te::XFile "> " . open_quote ("$tmp/m4.m4");
Packit 47b4ca
  print $m4_m4 "# m4.m4 -- enable the m4 builtins.\n";
Packit 47b4ca
  foreach (sort keys %m4_builtins)
Packit 47b4ca
    {
Packit 47b4ca
      print $m4save_m4 "_au__save([$_])\n";
Packit 47b4ca
      print $unm4_m4   "_au__undefine([$_])\n";
Packit 47b4ca
      print $m4_m4     "_au__restore([$_])\n";
Packit 47b4ca
    }
Packit 47b4ca
}
Packit 47b4ca
Packit 47b4ca
Packit 47b4ca
## -------------- ##
Packit 47b4ca
## Main program.  ##
Packit 47b4ca
## -------------- ##
Packit 47b4ca
Packit 47b4ca
parse_args;
Packit 47b4ca
$autoconf .= " --debug" if $debug;
Packit 47b4ca
$autoconf .= " --force" if $force;
Packit 47b4ca
$autoconf .= " --verbose" if $verbose;
Packit 47b4ca
$autoconf .= join (' --include=', '', map { shell_quote ($_) } @include);
Packit 47b4ca
$autoconf .= join (' --prepend-include=', '', map { shell_quote ($_) } @prepend_include);
Packit 47b4ca
Packit 47b4ca
mktmpdir ('au');
Packit 47b4ca
handle_autoconf_macros;
Packit 47b4ca
Packit 47b4ca
# $au_changequote -- enable the quote `[', `]' right before any AU macro.
Packit 47b4ca
my $au_changequote =
Packit 47b4ca
  's/\b(' . join ('|', keys %au_macros) . ')\b/_au_m4_changequote([,])$1/g';
Packit 47b4ca
Packit 47b4ca
# au.m4 -- definitions the AU macros.
Packit 47b4ca
xsystem ("$autoconf --trace AU_DEFINE:'_au_defun(\@<:\@\$1\@:>\@,
Packit 47b4ca
\@<:\@\$2\@:>\@)' --melt /dev/null "
Packit 47b4ca
	. ">" . shell_quote ("$tmp/au.m4"));
Packit 47b4ca
Packit 47b4ca
Packit 47b4ca
Packit 47b4ca
## ------------------- ##
Packit 47b4ca
## Process the files.  ##
Packit 47b4ca
## ------------------- ##
Packit 47b4ca
Packit 47b4ca
foreach my $file (@ARGV)
Packit 47b4ca
  {
Packit 47b4ca
    # We need an actual file.
Packit 47b4ca
    if ($file eq '-')
Packit 47b4ca
      {
Packit 47b4ca
	$file = "$tmp/stdin";
Packit 47b4ca
	system "cat >" . shell_quote ($file);
Packit 47b4ca
      }
Packit 47b4ca
    elsif (! -r "$file")
Packit 47b4ca
      {
Packit 47b4ca
	die "$me: $file: No such file or directory";
Packit 47b4ca
      }
Packit 47b4ca
Packit 47b4ca
    # input.m4 -- m4 program to produce the updated file.
Packit 47b4ca
    # Load the values, the dispatcher, neutralize m4, and the prepared
Packit 47b4ca
    # input file.
Packit 47b4ca
    my $input_m4 = <<\EOF;
Packit 47b4ca
      divert(-1)                                            -*- Autoconf -*-
Packit 47b4ca
      changequote([,])
Packit 47b4ca
Packit 47b4ca
      # Define our special macros:
Packit 47b4ca
      define([_au__defn], defn([defn]))
Packit 47b4ca
      define([_au__divert], defn([divert]))
Packit 47b4ca
      define([_au__ifdef], defn([ifdef]))
Packit 47b4ca
      define([_au__include], defn([include]))
Packit 47b4ca
      define([_au___undefine], defn([undefine]))
Packit 47b4ca
      define([_au__undefine], [_au__ifdef([$1], [_au___undefine([$1])])])
Packit 47b4ca
      define([_au__save], [m4_ifdef([$1],
Packit 47b4ca
	[m4_define([_au_$1], _m4_defn([$1]))])])
Packit 47b4ca
      define([_au__restore],
Packit 47b4ca
	[_au_m4_ifdef([_au_$1],
Packit 47b4ca
	  [_au_m4_define([$1], _au__defn([_au_$1]))])])
Packit 47b4ca
Packit 47b4ca
      # Set up m4sugar.
Packit 47b4ca
      include(m4sugar/m4sugar.m4)
Packit 47b4ca
Packit 47b4ca
      # Redefine __file__ to make warnings nicer; $file is replaced below.
Packit 47b4ca
      m4_define([__file__], [$file])
Packit 47b4ca
Packit 47b4ca
      # Redefine m4_location to fix the line number.
Packit 47b4ca
      m4_define([m4_location], [__file__:m4_eval(__line__ - _au__first_line)])
Packit 47b4ca
Packit 47b4ca
      # Move all the builtins into the `_au_' pseudo namespace
Packit 47b4ca
      m4_include([m4save.m4])
Packit 47b4ca
Packit 47b4ca
      # _au_defun(NAME, BODY)
Packit 47b4ca
      # ---------------------
Packit 47b4ca
      # Define NAME to BODY, plus AU activation/deactivation.
Packit 47b4ca
      _au_m4_define([_au_defun],
Packit 47b4ca
      [_au_m4_define([$1],
Packit 47b4ca
      [_au_enable()dnl
Packit 47b4ca
      $2[]dnl
Packit 47b4ca
      _au_disable()])])
Packit 47b4ca
Packit 47b4ca
      # Import the definition of the obsolete macros.
Packit 47b4ca
      _au__include([au.m4])
Packit 47b4ca
Packit 47b4ca
Packit 47b4ca
      ## ------------------------ ##
Packit 47b4ca
      ## _au_enable/_au_disable.  ##
Packit 47b4ca
      ## ------------------------ ##
Packit 47b4ca
Packit 47b4ca
      # They work by pair: each time an AU macro is activated, it runs
Packit 47b4ca
      # _au_enable, and at its end its runs _au_disable (see _au_defun
Packit 47b4ca
      # above).  AU macros might use AU macros, which should
Packit 47b4ca
      # enable/disable only for the outer AU macros.
Packit 47b4ca
      #
Packit 47b4ca
      # `_au_enabled' is used to this end, determining whether we really
Packit 47b4ca
      # enable/disable.
Packit 47b4ca
Packit 47b4ca
Packit 47b4ca
      # __au_enable
Packit 47b4ca
      # -----------
Packit 47b4ca
      # Reenable the builtins, m4sugar, and the autoquoting AC macros.
Packit 47b4ca
      _au_m4_define([__au_enable],
Packit 47b4ca
      [_au__divert(-1)
Packit 47b4ca
      # Enable special characters.
Packit 47b4ca
      _au_m4_changecom([#])
Packit 47b4ca
Packit 47b4ca
      _au__include([m4.m4])
Packit 47b4ca
      _au__include([ac.m4])
Packit 47b4ca
Packit 47b4ca
      _au__divert(0)])
Packit 47b4ca
Packit 47b4ca
      # _au_enable
Packit 47b4ca
      # ----------
Packit 47b4ca
      # Called at the beginning of all the obsolete macros.  If this is the
Packit 47b4ca
      # outermost level, call __au_enable.
Packit 47b4ca
      _au_m4_define([_au_enable],
Packit 47b4ca
      [_au_m4_ifdef([_au_enabled],
Packit 47b4ca
		 [],
Packit 47b4ca
		 [__au_enable()])_au_dnl
Packit 47b4ca
      _au_m4_pushdef([_au_enabled])])
Packit 47b4ca
Packit 47b4ca
Packit 47b4ca
      # __au_disable
Packit 47b4ca
      # ------------
Packit 47b4ca
      # Disable the AC autoquoting macros, m4sugar, and m4.
Packit 47b4ca
      _au_m4_define([__au_disable],
Packit 47b4ca
      [_au__divert(-1)
Packit 47b4ca
      _au__include([unac.m4])
Packit 47b4ca
      _au__include([unm4.m4])
Packit 47b4ca
Packit 47b4ca
      # Disable special characters.
Packit 47b4ca
      _au_m4_changequote()
Packit 47b4ca
      _au_m4_changecom()
Packit 47b4ca
Packit 47b4ca
      _au__divert(0)])
Packit 47b4ca
Packit 47b4ca
      # _au_disable
Packit 47b4ca
      # -----------
Packit 47b4ca
      # Called at the end of all the obsolete macros.  If we are at the
Packit 47b4ca
      # outermost level, call __au_disable.
Packit 47b4ca
      _au_m4_define([_au_disable],
Packit 47b4ca
      [_au_m4_popdef([_au_enabled])_au_dnl
Packit 47b4ca
      _au_m4_ifdef([_au_enabled],
Packit 47b4ca
		[],
Packit 47b4ca
		[__au_disable()])])
Packit 47b4ca
Packit 47b4ca
Packit 47b4ca
      ## ------------------------------- ##
Packit 47b4ca
      ## Disable, and process the file.  ##
Packit 47b4ca
      ## ------------------------------- ##
Packit 47b4ca
      # The AC autoquoting macros are not loaded yet, hence invoking
Packit 47b4ca
      # `_au_disable' would be wrong.
Packit 47b4ca
      _au__include([unm4.m4])
Packit 47b4ca
Packit 47b4ca
      # Disable special characters, and set the first line number.
Packit 47b4ca
      _au_m4_changequote()
Packit 47b4ca
      _au_m4_changecom()
Packit 47b4ca
Packit 47b4ca
      _au_m4_define(_au__first_line, _au___line__)_au__divert(0)_au_dnl
Packit 47b4ca
EOF
Packit 47b4ca
Packit 47b4ca
    $input_m4 =~ s/^      //mg;
Packit 47b4ca
    $input_m4 =~ s/\$file/$file/g;
Packit 47b4ca
Packit 47b4ca
    # prepared input -- input, but reenables the quote before each AU macro.
Packit 47b4ca
    open INPUT_M4, "> " . open_quote ("$tmp/input.m4")
Packit 47b4ca
       or error "cannot open: $!";
Packit 47b4ca
    open FILE, "< " . open_quote ($file)
Packit 47b4ca
       or error "cannot open: $!";
Packit 47b4ca
    print INPUT_M4 "$input_m4";
Packit 47b4ca
    while (<FILE>)
Packit 47b4ca
       {
Packit 47b4ca
	 eval $au_changequote;
Packit 47b4ca
	 print INPUT_M4;
Packit 47b4ca
       }
Packit 47b4ca
    close FILE
Packit 47b4ca
       or error "cannot close $file: $!";
Packit 47b4ca
    close INPUT_M4
Packit 47b4ca
       or error "cannot close $tmp/input.m4: $!";
Packit 47b4ca
Packit 47b4ca
    # Now ask m4 to perform the update.
Packit 47b4ca
    xsystem ("$m4 --include=" . shell_quote ($tmp)
Packit 47b4ca
	     . join (' --include=', '', map { shell_quote ($_) } reverse (@prepend_include))
Packit 47b4ca
	     . join (' --include=', '', map { shell_quote ($_) } @include)
Packit 47b4ca
	     . " " . shell_quote ("$tmp/input.m4") . " > " . shell_quote ("$tmp/updated"));
Packit 47b4ca
    update_file ("$tmp/updated",
Packit 47b4ca
		 "$file" eq "$tmp/stdin" ? '-' : "$file");
Packit 47b4ca
  }
Packit 47b4ca
exit 0;
Packit 47b4ca
Packit 47b4ca
Packit 47b4ca
#		  ## ---------------------------- ##
Packit 47b4ca
#		  ## How `autoupdate' functions.  ##
Packit 47b4ca
#		  ## ---------------------------- ##
Packit 47b4ca
#
Packit 47b4ca
# The task of `autoupdate' is not trivial: the biggest difficulty being
Packit 47b4ca
# that you must limit the changes to the parts that really need to be
Packit 47b4ca
# updated.  Finding a satisfying implementation proved to be quite hard,
Packit 47b4ca
# as this is the fifth implementation of `autoupdate'.
Packit 47b4ca
#
Packit 47b4ca
# Below, we will use a simple example of an obsolete macro:
Packit 47b4ca
#
Packit 47b4ca
#     AU_DEFUN([OLD], [NEW([$1, $2], m4_eval([$1 + $2]))])
Packit 47b4ca
#     AC_DEFUN([NEW], [echo "sum($1) = $2"])
Packit 47b4ca
#
Packit 47b4ca
# the input file contains
Packit 47b4ca
#
Packit 47b4ca
#     dnl The Unbelievable Truth
Packit 47b4ca
#     OLD(1, 2)
Packit 47b4ca
#     NEW([0, 0], [0])
Packit 47b4ca
#
Packit 47b4ca
# Of course the expected output is
Packit 47b4ca
#
Packit 47b4ca
#     dnl The Unbelievable Truth
Packit 47b4ca
#     NEW([1, 2], [3])
Packit 47b4ca
#     NEW([0, 0], [0])
Packit 47b4ca
#
Packit 47b4ca
#
Packit 47b4ca
# # First implementation: sed
Packit 47b4ca
# # =========================
Packit 47b4ca
#
Packit 47b4ca
# The first implementation was only able to change the name of obsolete
Packit 47b4ca
# macros.
Packit 47b4ca
#
Packit 47b4ca
# The file `acoldnames.m4' defined the old names based on the new names.
Packit 47b4ca
# It was simple then to produce a sed script such as:
Packit 47b4ca
#
Packit 47b4ca
#     s/OLD/NEW/g
Packit 47b4ca
#
Packit 47b4ca
# Updating merely consisted in running this script on the file to
Packit 47b4ca
# update.
Packit 47b4ca
#
Packit 47b4ca
# This scheme suffers from an obvious limitation: that `autoupdate' was
Packit 47b4ca
# unable to cope with new macros that just swap some of its arguments
Packit 47b4ca
# compared to the old macro.  Fortunately, that was enough to upgrade
Packit 47b4ca
# from Autoconf 1 to Autoconf 2.  (But I have no idea whether the
Packit 47b4ca
# changes in Autoconf 2 were precisely limited by this constraint.)
Packit 47b4ca
#
Packit 47b4ca
#
Packit 47b4ca
# # Second implementation: hooks
Packit 47b4ca
# # ============================
Packit 47b4ca
#
Packit 47b4ca
# The version 2.15 of Autoconf brought a vast number of changes compared
Packit 47b4ca
# to 2.13, so a solution was needed.  One could think of extending the
Packit 47b4ca
# `sed' scripts with specialized code for complex macros.  However, this
Packit 47b4ca
# approach is of course full of flaws:
Packit 47b4ca
#
Packit 47b4ca
# a. the Autoconf maintainers have to write these snippets, which we
Packit 47b4ca
#    just don't want to,
Packit 47b4ca
#
Packit 47b4ca
# b. I really don't think you'll ever manage to handle the quoting of
Packit 47b4ca
#    m4 with a sed script.
Packit 47b4ca
#
Packit 47b4ca
# To satisfy a., let's remark that the code which implements the old
Packit 47b4ca
# features in term of the new feature is exactly the code which should
Packit 47b4ca
# replace the old code.
Packit 47b4ca
#
Packit 47b4ca
# To answer point b, as usual in the history of Autoconf, the answer, at
Packit 47b4ca
# least on the paper, is simple: m4 is the best tool to parse m4, so
Packit 47b4ca
# let's use m4.
Packit 47b4ca
#
Packit 47b4ca
# Therefore the specification is:
Packit 47b4ca
#
Packit 47b4ca
#     I want to be able to tell Autoconf, well, m4, that the macro I
Packit 47b4ca
#     am currently defining is an obsolete macro (so that the user is
Packit 47b4ca
#     warned), and its code is the code to use when running autoconf,
Packit 47b4ca
#     but that the very same code has to be used when running
Packit 47b4ca
#     autoupdate.  To summarize, the interface I want is
Packit 47b4ca
#     `AU_DEFUN(OLD-NAME, NEW-CODE)'.
Packit 47b4ca
#
Packit 47b4ca
#
Packit 47b4ca
# Now for the technical details.
Packit 47b4ca
#
Packit 47b4ca
# When running autoconf, except for the warning, AU_DEFUN is basically
Packit 47b4ca
# AC_DEFUN.
Packit 47b4ca
#
Packit 47b4ca
# When running autoupdate, we want *only* OLD-NAMEs to be expanded.
Packit 47b4ca
# This obviously means that acgeneral.m4 and acspecific.m4 must not be
Packit 47b4ca
# loaded.  Nonetheless, because we want to use a rich set of m4
Packit 47b4ca
# features, m4sugar.m4 is needed.  Please note that the fact that
Packit 47b4ca
# Autoconf's macros are not loaded is positive on two points:
Packit 47b4ca
#
Packit 47b4ca
# - we do get an updated `configure.ac', not a `configure'!
Packit 47b4ca
#
Packit 47b4ca
# - the old macros are replaced by *calls* to the new-macros, not the
Packit 47b4ca
#   body of the new macros, since their body is not defined!!!
Packit 47b4ca
#   (Whoa, that's really beautiful!).
Packit 47b4ca
#
Packit 47b4ca
# Additionally we need to disable the quotes when reading the input for
Packit 47b4ca
# two reasons: first because otherwise `m4' will swallow the quotes of
Packit 47b4ca
# other macros:
Packit 47b4ca
#
Packit 47b4ca
#     NEW([1, 2], 3)
Packit 47b4ca
#     => NEW(1, 2, 3)
Packit 47b4ca
#
Packit 47b4ca
# and second, because we want to update the macro calls which are
Packit 47b4ca
# quoted, i.e., we want
Packit 47b4ca
#
Packit 47b4ca
#     FOO([OLD(1, 2)])
Packit 47b4ca
#     => FOO([NEW([1, 2], [3])])
Packit 47b4ca
#
Packit 47b4ca
# If we don't disable the quotes, only the macros called at the top
Packit 47b4ca
# level would be updated.
Packit 47b4ca
#
Packit 47b4ca
# So, let's disable the quotes.
Packit 47b4ca
#
Packit 47b4ca
# Well, not quite: m4sugar.m4 still needs to use quotes for some macros.
Packit 47b4ca
# Well, in this case, when running in autoupdate code, each macro first
Packit 47b4ca
# reestablishes the quotes, expands itself, and disables the quotes.
Packit 47b4ca
#
Packit 47b4ca
# Thinking a bit more, you realize that in fact, people may use `define',
Packit 47b4ca
# `ifelse' etc. in their files, and you certainly don't want to process
Packit 47b4ca
# them.  Another example is `dnl': you don't want to remove the
Packit 47b4ca
# comments.  You then realize you don't want exactly to import m4sugar:
Packit 47b4ca
# you want to specify when it is enabled (macros active), and disabled.
Packit 47b4ca
# m4sugar provides m4_disable/m4_enable to this end.
Packit 47b4ca
#
Packit 47b4ca
# You're getting close to it.  Now remains one task: how to handle
Packit 47b4ca
# twofold definitions?
Packit 47b4ca
#
Packit 47b4ca
# Remember that the same AU_DEFUN must be understood in two different
Packit 47b4ca
# ways, the AC way, and the AU way.
Packit 47b4ca
#
Packit 47b4ca
# One first solution is to check whether acgeneral.m4 was loaded.  But
Packit 47b4ca
# that's definitely not cute.  Another is simply to install `hooks',
Packit 47b4ca
# that is to say, to keep in some place m4 knows, late `define' to be
Packit 47b4ca
# triggered *only* in AU mode.
Packit 47b4ca
#
Packit 47b4ca
# You first think of designing AU_DEFUN like this:
Packit 47b4ca
#
Packit 47b4ca
# 1. AC_DEFUN(OLD-NAME,
Packit 47b4ca
#	      [Warn the user OLD-NAME is obsolete.
Packit 47b4ca
#	       NEW-CODE])
Packit 47b4ca
#
Packit 47b4ca
# 2. Store for late AU binding([define(OLD_NAME,
Packit 47b4ca
#				[Reestablish the quotes.
Packit 47b4ca
#				 NEW-CODE
Packit 47b4ca
#				 Disable the quotes.])])
Packit 47b4ca
#
Packit 47b4ca
# but this will not work: NEW-CODE probably uses $1, $2 etc. and these
Packit 47b4ca
# guys will be replaced with the argument of `Store for late AU binding'
Packit 47b4ca
# when you call it.
Packit 47b4ca
#
Packit 47b4ca
# I don't think there is a means to avoid this using this technology
Packit 47b4ca
# (remember that $1 etc. are *always* expanded in m4).  You may also try
Packit 47b4ca
# to replace them with $[1] to preserve them for a later evaluation, but
Packit 47b4ca
# if `Store for late AU binding' is properly written, it will remain
Packit 47b4ca
# quoted till the end...
Packit 47b4ca
#
Packit 47b4ca
# You have to change technology.  Since the problem is that `$1'
Packit 47b4ca
# etc. should be `consumed' right away, one solution is to define now a
Packit 47b4ca
# second macro, `AU_OLD-NAME', and to install a hook than binds OLD-NAME
Packit 47b4ca
# to AU_OLD-NAME.  Then, autoupdate.m4 just need to run the hooks.  By
Packit 47b4ca
# the way, the same method was used in autoheader.
Packit 47b4ca
#
Packit 47b4ca
#
Packit 47b4ca
# # Third implementation: m4 namespaces by m4sugar
Packit 47b4ca
# # ==============================================
Packit 47b4ca
#
Packit 47b4ca
# Actually, this implementation was just a clean up of the previous
Packit 47b4ca
# implementation: instead of defining hooks by hand, m4sugar was equipped
Packit 47b4ca
# with `namespaces'.  What are they?
Packit 47b4ca
#
Packit 47b4ca
# Sometimes we want to disable some *set* of macros, and restore them
Packit 47b4ca
# later.  We provide support for this via namespaces.
Packit 47b4ca
#
Packit 47b4ca
# There are basically three characters playing this scene: defining a
Packit 47b4ca
# macro in a namespace, disabling a namespace, and restoring a namespace
Packit 47b4ca
# (i.e., all the definitions it holds).
Packit 47b4ca
#
Packit 47b4ca
# Technically, to define a MACRO in NAMESPACE means to define the macro
Packit 47b4ca
# named `NAMESPACE::MACRO' to the VALUE.  At the same time, we append
Packit 47b4ca
# `undefine(NAME)' in the macro named `m4_disable(NAMESPACE)', and
Packit 47b4ca
# similarly a binding of NAME to the value of `NAMESPACE::MACRO' in
Packit 47b4ca
# `m4_enable(NAMESPACE)'.  These mechanisms allow to bind the macro of
Packit 47b4ca
# NAMESPACE and to unbind them at will.
Packit 47b4ca
#
Packit 47b4ca
# Of course this implementation is really inefficient: m4 has to grow
Packit 47b4ca
# strings which can become quickly huge, which slows it significantly.
Packit 47b4ca
#
Packit 47b4ca
# In particular one should avoid as much as possible to use `define' for
Packit 47b4ca
# temporaries.  Now that `define' has quite a complex meaning, it is an
Packit 47b4ca
# expensive operations that should be limited to macros.  Use
Packit 47b4ca
# `m4_define' for temporaries.
Packit 47b4ca
#
Packit 47b4ca
# Private copies of the macros we used in entering / exiting the m4sugar
Packit 47b4ca
# namespace.  It is much more convenient than fighting with the renamed
Packit 47b4ca
# version of define etc.
Packit 47b4ca
#
Packit 47b4ca
#
Packit 47b4ca
#
Packit 47b4ca
# Those two implementations suffered from serious problems:
Packit 47b4ca
#
Packit 47b4ca
# - namespaces were really expensive, and incurred a major performance
Packit 47b4ca
#   loss on `autoconf' itself, not only `autoupdate'.  One solution
Packit 47b4ca
#   would have been the limit the use of namespaces to `autoupdate', but
Packit 47b4ca
#   that's again some complications on m4sugar, which really doesn't need
Packit 47b4ca
#   this.  So we wanted to get rid of the namespaces.
Packit 47b4ca
#
Packit 47b4ca
# - since the quotes were disabled, autoupdate was sometimes making
Packit 47b4ca
#   wrong guesses, for instance on:
Packit 47b4ca
#
Packit 47b4ca
#     foo([1, 2])
Packit 47b4ca
#
Packit 47b4ca
#   m4 saw 2 arguments: `[1'and `2]'.  A simple solution, somewhat
Packit 47b4ca
#   fragile, is to reestablish the quotes right before all the obsolete
Packit 47b4ca
#   macros, i.e., to use sed so that the previous text becomes
Packit 47b4ca
#
Packit 47b4ca
#     changequote([, ])foo([1, 2])
Packit 47b4ca
#
Packit 47b4ca
#   To this end, one wants to trace the definition of obsolete macros.
Packit 47b4ca
#
Packit 47b4ca
# It was there that the limitations of the namespace approach became
Packit 47b4ca
# painful: because it was a complex machinery playing a lot with the
Packit 47b4ca
# builtins of m4 (hence, quite fragile), tracing was almost impossible.
Packit 47b4ca
#
Packit 47b4ca
#
Packit 47b4ca
# So this approach was dropped.
Packit 47b4ca
#
Packit 47b4ca
#
Packit 47b4ca
# # The fourth implementation: two steps
Packit 47b4ca
# # ====================================
Packit 47b4ca
#
Packit 47b4ca
# If you drop the uses of namespaces, you no longer can compute the
Packit 47b4ca
# updated value, and replace the old call with it simultaneously.
Packit 47b4ca
#
Packit 47b4ca
# Obviously you will use m4 to compute the updated values, but you may
Packit 47b4ca
# use some other tool to achieve the replacement.  Personally, I trust
Packit 47b4ca
# nobody but m4 to parse m4, so below, m4 will perform the two tasks.
Packit 47b4ca
#
Packit 47b4ca
# How can m4 be used to replace *some* macros calls with newer values.
Packit 47b4ca
# Well, that's dead simple: m4 should learn the definitions of obsolete
Packit 47b4ca
# macros, forget its builtins, disable the quotes, and then run on the
Packit 47b4ca
# input file, which amounts to doing this:
Packit 47b4ca
#
Packit 47b4ca
#     divert(-1)dnl
Packit 47b4ca
#     changequote([, ])
Packit 47b4ca
#     define([OLD], [NEW([$1, $2], m4_eval([$1 + $2]))changequote()])
Packit 47b4ca
#     undefine([dnl])
Packit 47b4ca
#     undefine([m4_eval])
Packit 47b4ca
#     # Some more undefines...
Packit 47b4ca
#     changequote()
Packit 47b4ca
#     divert(0)dnl
Packit 47b4ca
#     dnl The Unbelievable Truth
Packit 47b4ca
#     changequote([, ])OLD(1, 2)
Packit 47b4ca
#     NEW([0, 0],
Packit 47b4ca
#	  0)
Packit 47b4ca
#
Packit 47b4ca
# which will result in
Packit 47b4ca
#
Packit 47b4ca
#     dnl The Unbelievable Truth
Packit 47b4ca
#     NEW(1, 2, m4_eval(1 + 2))
Packit 47b4ca
#     NEW([0, 0],
Packit 47b4ca
#	  0)
Packit 47b4ca
#
Packit 47b4ca
# Grpmh.  Two problems.  A minor problem: it would have been much better
Packit 47b4ca
# to have the `m4_eval' computed, and a major problem: you lost the
Packit 47b4ca
# quotation in the result.
Packit 47b4ca
#
Packit 47b4ca
# Let's address the big problem first.  One solution is to define any
Packit 47b4ca
# modern macro to rewrite its calls with the proper quotation, thanks to
Packit 47b4ca
# `$@'.  Again, tracing the `define's makes it possible to know which
Packit 47b4ca
# are these macros, so you input is:
Packit 47b4ca
#
Packit 47b4ca
#     divert(-1)dnl
Packit 47b4ca
#     changequote([, ])
Packit 47b4ca
#     define([OLD], [NEW([$1, $2], m4_eval([$1 + $2]))changequote()])
Packit 47b4ca
#     define([NEW], [[NEW($@)]changequote()])
Packit 47b4ca
#     undefine([dnl])
Packit 47b4ca
#     undefine([m4_eval])
Packit 47b4ca
#     # Some more undefines...
Packit 47b4ca
#     changequote()
Packit 47b4ca
#     divert(0)dnl
Packit 47b4ca
#     dnl The Unbelievable Truth
Packit 47b4ca
#     changequote([, ])OLD(1, 2)
Packit 47b4ca
#     changequote([, ])NEW([0, 0],
Packit 47b4ca
#	  0)
Packit 47b4ca
#
Packit 47b4ca
# which results in
Packit 47b4ca
#
Packit 47b4ca
#     dnl The Unbelievable Truth
Packit 47b4ca
#     NEW([1, 2],[m4_eval(1 + 2)])
Packit 47b4ca
#     NEW([0, 0],[0])
Packit 47b4ca
#
Packit 47b4ca
# Our problem is solved, i.e., the first call to `NEW' is properly
Packit 47b4ca
# quoted, but introduced another problem: we changed the layout of the
Packit 47b4ca
# second calls, which can be a drama in the case of huge macro calls
Packit 47b4ca
# (think of `AC_TRY_RUN' for instance).  This example didn't show it,
Packit 47b4ca
# but we also introduced parens to macros which did not have some:
Packit 47b4ca
#
Packit 47b4ca
#     AC_INIT
Packit 47b4ca
#     => AC_INIT()
Packit 47b4ca
#
Packit 47b4ca
# No big deal for the semantics (unless the macro depends upon $#, which
Packit 47b4ca
# is bad), but the users would not be happy.
Packit 47b4ca
#
Packit 47b4ca
# Additionally, we introduced quotes that were not there before, which is
Packit 47b4ca
# OK in most cases, but could change the semantics of the file.
Packit 47b4ca
#
Packit 47b4ca
# Cruel dilemma: we do want the auto-quoting definition of `NEW' when
Packit 47b4ca
# evaluating `OLD', but we don't when we evaluate the second `NEW'.
Packit 47b4ca
# Back to namespaces?
Packit 47b4ca
#
Packit 47b4ca
# No.
Packit 47b4ca
#
Packit 47b4ca
#
Packit 47b4ca
# # Second step: replacement
Packit 47b4ca
# # ------------------------
Packit 47b4ca
#
Packit 47b4ca
# No, as announced above, we will work in two steps: in a first step we
Packit 47b4ca
# compute the updated values, and in a second step we replace them.  Our
Packit 47b4ca
# goal is something like this:
Packit 47b4ca
#
Packit 47b4ca
#     divert(-1)dnl
Packit 47b4ca
#     changequote([, ])
Packit 47b4ca
#     define([OLD], [NEW([1, 2], [3])changequote()])
Packit 47b4ca
#     undefine([dnl])
Packit 47b4ca
#     undefine([m4_eval])
Packit 47b4ca
#     # Some more undefines...
Packit 47b4ca
#     changequote()
Packit 47b4ca
#     divert(0)dnl
Packit 47b4ca
#     dnl The Unbelievable Truth
Packit 47b4ca
#     changequote([, ])OLD(1, 2)
Packit 47b4ca
#     NEW([0, 0],
Packit 47b4ca
#	  0)
Packit 47b4ca
#
Packit 47b4ca
# i.e., the new value of `OLD' is precomputed using the auto-quoting
Packit 47b4ca
# definition of `NEW' and the m4 builtins.  We'll see how afterwards,
Packit 47b4ca
# let's finish with the replacement.
Packit 47b4ca
#
Packit 47b4ca
# Of course the solution above is wrong: if there were other calls to
Packit 47b4ca
# `OLD' with different values, we would smash them to the same value.
Packit 47b4ca
# But it is quite easy to generalize the scheme above:
Packit 47b4ca
#
Packit 47b4ca
#     divert(-1)dnl
Packit 47b4ca
#     changequote([, ])
Packit 47b4ca
#     define([OLD([1],[2])], [NEW([1, 2], [3])])
Packit 47b4ca
#     define([OLD], [defn([OLD($@)])changequote()])
Packit 47b4ca
#     undefine([dnl])
Packit 47b4ca
#     undefine([m4_eval])
Packit 47b4ca
#     # Some more undefines...
Packit 47b4ca
#     changequote()
Packit 47b4ca
#     divert(0)dnl
Packit 47b4ca
#     dnl The Unbelievable Truth
Packit 47b4ca
#     changequote([, ])OLD(1, 2)
Packit 47b4ca
#     NEW([0, 0],
Packit 47b4ca
#	  0)
Packit 47b4ca
#
Packit 47b4ca
# i.e., for each call to obsolete macros, we build an array `call =>
Packit 47b4ca
# value', and use a macro to dispatch these values.  This results in:
Packit 47b4ca
#
Packit 47b4ca
#     dnl The Unbelievable Truth
Packit 47b4ca
#     NEW([1, 2], [3])
Packit 47b4ca
#     NEW([0, 0],
Packit 47b4ca
#	  0)
Packit 47b4ca
#
Packit 47b4ca
# In French, we say `Youpi !', which you might roughly translate as
Packit 47b4ca
# `Yippee!'.
Packit 47b4ca
#
Packit 47b4ca
#
Packit 47b4ca
# # First step: computation
Packit 47b4ca
# # -----------------------
Packit 47b4ca
#
Packit 47b4ca
# Let's study the anatomy of the file, and name its sections:
Packit 47b4ca
#
Packit 47b4ca
# prologue
Packit 47b4ca
#     divert(-1)dnl
Packit 47b4ca
#     changequote([, ])
Packit 47b4ca
# values
Packit 47b4ca
#     define([OLD([1],[2])], [NEW([1, 2], [3])])
Packit 47b4ca
# dispatcher
Packit 47b4ca
#     define([OLD], [defn([OLD($@)])changequote()])
Packit 47b4ca
# disabler
Packit 47b4ca
#     undefine([dnl])
Packit 47b4ca
#     undefine([m4_eval])
Packit 47b4ca
#     # Some more undefines...
Packit 47b4ca
#     changequote()
Packit 47b4ca
#     divert(0)dnl
Packit 47b4ca
# input
Packit 47b4ca
#     dnl The Unbelievable Truth
Packit 47b4ca
#     changequote([, ])OLD(1, 2)
Packit 47b4ca
#     NEW([0, 0],
Packit 47b4ca
#	  0)
Packit 47b4ca
#
Packit 47b4ca
#
Packit 47b4ca
# # Computing the `values' section
Packit 47b4ca
# # ..............................
Packit 47b4ca
#
Packit 47b4ca
# First we need to get the list of all the AU macro uses.  To this end,
Packit 47b4ca
# first get the list of all the AU macros names by tracing `AU_DEFUN' in
Packit 47b4ca
# the initialization of autoconf.  This list is computed in the file
Packit 47b4ca
# `au.txt' below.
Packit 47b4ca
#
Packit 47b4ca
# Then use this list to trace all the AU macro uses in the input.  The
Packit 47b4ca
# goal is obtain in the case of our example:
Packit 47b4ca
#
Packit 47b4ca
#     [define([OLD([1],[2])],]@<<@OLD([1],[2])@>>@[)]
Packit 47b4ca
#
Packit 47b4ca
# This is the file `values.in' below.
Packit 47b4ca
#
Packit 47b4ca
# We want to evaluate this with only the builtins (in fact m4sugar), the
Packit 47b4ca
# auto-quoting definitions of the new macros (`new.m4'), and the
Packit 47b4ca
# definition of the old macros (`old.m4').  Computing these last two
Packit 47b4ca
# files is easy: it's just a matter of using the right `--trace' option.
Packit 47b4ca
#
Packit 47b4ca
# So the content of `values.in' is:
Packit 47b4ca
#
Packit 47b4ca
#     include($autoconf_dir/m4sugar.m4)
Packit 47b4ca
#     m4_include(new.m4)
Packit 47b4ca
#     m4_include(old.m4)
Packit 47b4ca
#     divert(0)dnl
Packit 47b4ca
#     [define([OLD([1],[2])],]@<<@OLD([1],[2])@>>@[)]
Packit 47b4ca
#
Packit 47b4ca
# We run m4 on it, which yields:
Packit 47b4ca
#
Packit 47b4ca
#     define([OLD([1],[2])],@<<@NEW([1, 2], [3])@>>@)
Packit 47b4ca
#
Packit 47b4ca
# Transform `@<<@' and `@>>@' into quotes and we get
Packit 47b4ca
#
Packit 47b4ca
#     define([OLD([1],[2])],[NEW([1, 2], [3])])
Packit 47b4ca
#
Packit 47b4ca
# This is `values.m4'.
Packit 47b4ca
#
Packit 47b4ca
#
Packit 47b4ca
# # Computing the `dispatcher' section
Packit 47b4ca
# # ..................................
Packit 47b4ca
#
Packit 47b4ca
# The `prologue', and the `disabler' are simple and need no commenting.
Packit 47b4ca
#
Packit 47b4ca
# To compute the `dispatcher' (`dispatch.m4'), again, it is a simple
Packit 47b4ca
# matter of using the right `--trace'.
Packit 47b4ca
#
Packit 47b4ca
# Finally, the input is not exactly the input file, rather it is the
Packit 47b4ca
# input file with the added `changequote'.  To this end, we build
Packit 47b4ca
# `quote.sed'.
Packit 47b4ca
#
Packit 47b4ca
#
Packit 47b4ca
# # Putting it all together
Packit 47b4ca
# # .......................
Packit 47b4ca
#
Packit 47b4ca
# We build the file `input.m4' which contains:
Packit 47b4ca
#
Packit 47b4ca
#     divert(-1)dnl
Packit 47b4ca
#     changequote([, ])
Packit 47b4ca
#     include(values.m4)
Packit 47b4ca
#     include(dispatch.m4)
Packit 47b4ca
#     undefine([dnl])
Packit 47b4ca
#     undefine([eval])
Packit 47b4ca
#     # Some more undefines...
Packit 47b4ca
#     changequote()
Packit 47b4ca
#     divert(0)dnl
Packit 47b4ca
#     dnl The Unbelievable Truth
Packit 47b4ca
#     changequote([, ])OLD(1, 2)
Packit 47b4ca
#     NEW([0, 0],
Packit 47b4ca
#	  0)
Packit 47b4ca
#
Packit 47b4ca
# And we just run m4 on it.  Et voila`, Monsieur !  Mais oui, mais oui.
Packit 47b4ca
#
Packit 47b4ca
# Well, there are a few additional technicalities.  For instance, we
Packit 47b4ca
# rely on `changequote', `ifelse' and `defn', but we don't want to
Packit 47b4ca
# interpret the changequotes of the user, so we simply use another name:
Packit 47b4ca
# `_au_changequote' etc.
Packit 47b4ca
#
Packit 47b4ca
#
Packit 47b4ca
# # Failure of the fourth approach
Packit 47b4ca
# # ------------------------------
Packit 47b4ca
#
Packit 47b4ca
# This approach is heavily based on traces, but then there is an obvious
Packit 47b4ca
# problem: non expanded code will never be seen.  In particular, the body
Packit 47b4ca
# of a `define' definition is not seen, so on the input
Packit 47b4ca
#
Packit 47b4ca
#	  define([idem], [OLD(0, [$1])])
Packit 47b4ca
#
Packit 47b4ca
# autoupdate would never see the `OLD', and wouldn't have updated it.
Packit 47b4ca
# Worse yet, if `idem(0)' was used later, then autoupdate sees that
Packit 47b4ca
# `OLD' is used, computes the result for `OLD(0, 0)' and sets up a
Packit 47b4ca
# dispatcher for `OLD'.  Since there was no computed value for `OLD(0,
Packit 47b4ca
# [$1])', the dispatcher would have replaced with... nothing, leading
Packit 47b4ca
# to
Packit 47b4ca
#
Packit 47b4ca
#	  define([idem], [])
Packit 47b4ca
#
Packit 47b4ca
# With some more thinking, you see that the two step approach is wrong,
Packit 47b4ca
# the namespace approach was much saner.
Packit 47b4ca
#
Packit 47b4ca
# But you learned a lot, in particular you realized that using traces
Packit 47b4ca
# can make it possible to simulate namespaces!
Packit 47b4ca
#
Packit 47b4ca
#
Packit 47b4ca
#
Packit 47b4ca
# # The fifth implementation: m4 namespaces by files
Packit 47b4ca
# # ================================================
Packit 47b4ca
#
Packit 47b4ca
# The fourth implementation demonstrated something unsurprising: you
Packit 47b4ca
# cannot precompute, i.e., the namespace approach was the right one.
Packit 47b4ca
# Still, we no longer want them, they're too expensive.  Let's have a
Packit 47b4ca
# look at the way it worked.
Packit 47b4ca
#
Packit 47b4ca
# When updating
Packit 47b4ca
#
Packit 47b4ca
#     dnl The Unbelievable Truth
Packit 47b4ca
#     OLD(1, 2)
Packit 47b4ca
#     NEW([0, 0], [0])
Packit 47b4ca
#
Packit 47b4ca
# you evaluate `input.m4':
Packit 47b4ca
#
Packit 47b4ca
#     divert(-1)
Packit 47b4ca
#     changequote([, ])
Packit 47b4ca
#     define([OLD],
Packit 47b4ca
#     [m4_enable()NEW([$1, $2], m4_eval([$1 + $2]))m4_disable()])
Packit 47b4ca
#     ...
Packit 47b4ca
#     m4_disable()
Packit 47b4ca
#     dnl The Unbelievable Truth
Packit 47b4ca
#     OLD(1, 2)
Packit 47b4ca
#     NEW([0, 0], [0])
Packit 47b4ca
#
Packit 47b4ca
# where `m4_disable' undefines the m4 and m4sugar, and disables the quotes
Packit 47b4ca
# and comments:
Packit 47b4ca
#
Packit 47b4ca
#     define([m4_disable],
Packit 47b4ca
#     [undefine([__file__])
Packit 47b4ca
#     ...
Packit 47b4ca
#     changecom(#)
Packit 47b4ca
#     changequote()])
Packit 47b4ca
#
Packit 47b4ca
# `m4_enable' does the converse: reestablish quotes and comments
Packit 47b4ca
# --easy--, reestablish m4sugar --easy: just load `m4sugar.m4' again-- and
Packit 47b4ca
# reenable the builtins.  This later task requires that you first save
Packit 47b4ca
# the builtins.  And BTW, the definition above of `m4_disable' cannot
Packit 47b4ca
# work: you undefined `changequote' before using it!  So you need to use
Packit 47b4ca
# your privates copies of the builtins.  Let's introduce three files for
Packit 47b4ca
# this:
Packit 47b4ca
#
Packit 47b4ca
#  `m4save.m4'
Packit 47b4ca
#    moves the m4 builtins into the `_au_' pseudo namespace,
Packit 47b4ca
#  `unm4.m4'
Packit 47b4ca
#    undefines the builtins,
Packit 47b4ca
#  `m4.m4'
Packit 47b4ca
#    restores them.
Packit 47b4ca
#
Packit 47b4ca
# So `input.m4' is:
Packit 47b4ca
#
Packit 47b4ca
#     divert(-1)
Packit 47b4ca
#     changequote([, ])
Packit 47b4ca
#
Packit 47b4ca
#     include([m4save.m4])
Packit 47b4ca
#
Packit 47b4ca
#     # Import AU.
Packit 47b4ca
#     define([OLD],
Packit 47b4ca
#     [m4_enable()NEW([$1, $2], m4_eval([$1 + $2]))m4_disable()])
Packit 47b4ca
#
Packit 47b4ca
#     define([_au_enable],
Packit 47b4ca
#     [_au_changecom([#])
Packit 47b4ca
#     _au_include([m4.m4])
Packit 47b4ca
#     _au_include(m4sugar.m4)])
Packit 47b4ca
#
Packit 47b4ca
#     define([_au_disable],
Packit 47b4ca
#     [# Disable m4sugar.
Packit 47b4ca
#     # Disable the m4 builtins.
Packit 47b4ca
#     _au_include([unm4.m4])
Packit 47b4ca
#     # 1. Disable special characters.
Packit 47b4ca
#     _au_changequote()
Packit 47b4ca
#     _au_changecom()])
Packit 47b4ca
#
Packit 47b4ca
#     m4_disable()
Packit 47b4ca
#     dnl The Unbelievable Truth
Packit 47b4ca
#     OLD(1, 2)
Packit 47b4ca
#     NEW([0, 0], [0])
Packit 47b4ca
#
Packit 47b4ca
# Based on what we learned in the fourth implementation we know that we
Packit 47b4ca
# have to enable the quotes *before* any AU macro, and we know we need
Packit 47b4ca
# to build autoquoting versions of the AC macros.  But the autoquoting
Packit 47b4ca
# AC definitions must be disabled in the rest of the file, and enabled
Packit 47b4ca
# inside AU macros.
Packit 47b4ca
#
Packit 47b4ca
# Using `autoconf --trace' it is easy to build the files
Packit 47b4ca
#
Packit 47b4ca
#   `ac.m4'
Packit 47b4ca
#     define the autoquoting AC fake macros
Packit 47b4ca
#   `disable.m4'
Packit 47b4ca
#     undefine the m4sugar and AC autoquoting macros.
Packit 47b4ca
#   `au.m4'
Packit 47b4ca
#     definitions of the AU macros (such as `OLD' above).
Packit 47b4ca
#
Packit 47b4ca
# Now, `input.m4' is:
Packit 47b4ca
#
Packit 47b4ca
#     divert(-1)
Packit 47b4ca
#     changequote([, ])
Packit 47b4ca
#
Packit 47b4ca
#     include([m4save.m4])
Packit 47b4ca
#     # Import AU.
Packit 47b4ca
#     include([au.m4])
Packit 47b4ca
#
Packit 47b4ca
#     define([_au_enable],
Packit 47b4ca
#     [_au_changecom([#])
Packit 47b4ca
#     _au_include([m4.m4])
Packit 47b4ca
#     _au_include(m4sugar.m4)
Packit 47b4ca
#     _au_include(ac.m4)])
Packit 47b4ca
#
Packit 47b4ca
#     define([_au_disable],
Packit 47b4ca
#     [_au_include([disable.m4])
Packit 47b4ca
#     _au_include([unm4.m4])
Packit 47b4ca
#     # 1. Disable special characters.
Packit 47b4ca
#     _au_changequote()
Packit 47b4ca
#     _au_changecom()])
Packit 47b4ca
#
Packit 47b4ca
#     m4_disable()
Packit 47b4ca
#     dnl The Unbelievable Truth
Packit 47b4ca
#     _au_changequote([, ])OLD(1, 2)
Packit 47b4ca
#     NEW([0, 0], [0])
Packit 47b4ca
#
Packit 47b4ca
# Finally, version V is ready.
Packit 47b4ca
#
Packit 47b4ca
# Well... almost.
Packit 47b4ca
#
Packit 47b4ca
# There is a slight problem that remains: if an AU macro OUTER includes
Packit 47b4ca
# an AU macro INNER, then _au_enable will be run when entering OUTER
Packit 47b4ca
# and when entering INNER (not good, but not too bad yet).  But when
Packit 47b4ca
# getting out of INNER, _au_disable will disable everything while we
Packit 47b4ca
# were still in OUTER.  Badaboom.
Packit 47b4ca
#
Packit 47b4ca
# Therefore _au_enable and _au_disable have to be written to work by
Packit 47b4ca
# pairs: each _au_enable pushdef's _au_enabled, and each _au_disable
Packit 47b4ca
# popdef's _au_enabled.  And of course _au_enable and _au_disable are
Packit 47b4ca
# effective when _au_enabled is *not* defined.
Packit 47b4ca
#
Packit 47b4ca
# Finally, version V' is ready.  And there is much rejoicing.  (And I
Packit 47b4ca
# have free time again.  I think.  Yeah, right.)
Packit 47b4ca
Packit 47b4ca
### Setup "GNU" style for perl-mode and cperl-mode.
Packit 47b4ca
## Local Variables:
Packit 47b4ca
## perl-indent-level: 2
Packit 47b4ca
## perl-continued-statement-offset: 2
Packit 47b4ca
## perl-continued-brace-offset: 0
Packit 47b4ca
## perl-brace-offset: 0
Packit 47b4ca
## perl-brace-imaginary-offset: 0
Packit 47b4ca
## perl-label-offset: -2
Packit 47b4ca
## cperl-indent-level: 2
Packit 47b4ca
## cperl-brace-offset: 0
Packit 47b4ca
## cperl-continued-brace-offset: 0
Packit 47b4ca
## cperl-label-offset: -2
Packit 47b4ca
## cperl-extra-newline-before-brace: t
Packit 47b4ca
## cperl-merge-trailing-else: nil
Packit 47b4ca
## cperl-continued-statement-offset: 2
Packit 47b4ca
## End: