From: Eric Blake Date: Fri, 24 Oct 2008 03:17:25 +0000 (-0600) Subject: Improve m4_copy. X-Git-Tag: v2.63b~203 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=2922868b72bb0847d5df79dfc95fd93a2049cf42;p=thirdparty%2Fautoconf.git Improve m4_copy. * lib/m4sugar/m4sugar.m4 (m4_copy): Add second implementation for public use. (_m4_copy): New macro, which preserves pushdef stacks. (_m4_defun_pro_outer): Bypass it, for speed. (m4_init): Bypass new implementation, since it breaks on m4_defn. * bin/autoupdate.in (handle_autoconf_macros): Likewise. * lib/autoconf/general.m4 (AC_PREREQ): Undefine before redefining, now that m4_copy checks this. * doc/autoconf.texi (Redefined M4 Macros) : Document this, as well as m4_rename. * lib/autoconf/autoconf.m4 (m4_copy): Temporarily redefine when renaming builtins. * NEWS: Likewise. * tests/m4sugar.at (m4@&t@_defn): Enhance test. Signed-off-by: Eric Blake --- diff --git a/ChangeLog b/ChangeLog index 0a835899..f8361b79 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,21 @@ +2008-10-24 Eric Blake + + Improve m4_copy. + * lib/m4sugar/m4sugar.m4 (m4_copy): Add second implementation for + public use. + (_m4_copy): New macro, which preserves pushdef stacks. + (_m4_defun_pro_outer): Bypass it, for speed. + (m4_init): Bypass new implementation, since it breaks on m4_defn. + * bin/autoupdate.in (handle_autoconf_macros): Likewise. + * lib/autoconf/general.m4 (AC_PREREQ): Undefine before redefining, + now that m4_copy checks this. + * doc/autoconf.texi (Redefined M4 Macros) : Document + this, as well as m4_rename. + * lib/autoconf/autoconf.m4 (m4_copy): Temporarily redefine when + renaming builtins, since it breaks on m4_ifdef. + * NEWS: Likewise. + * tests/m4sugar.at (m4@&t@_defn): Enhance test. + 2008-10-24 Eric Blake AC_FUNC_GETGROUPS: Revert regression. diff --git a/NEWS b/NEWS index 8b682b84..496fac71 100644 --- a/NEWS +++ b/NEWS @@ -12,10 +12,13 @@ GNU Autoconf NEWS - User visible changes. ** Configure scripts now use shell functions. -** The following m4sugar macros are new: +** The following documented m4sugar macros are new: m4_curry m4_default_quoted m4_map_args m4_map_args_pair m4_set_map +** The following m4sugar macros are documented now: + m4_copy m4_rename + ** The following documented m4sh macros are new: AS_LINENO_PREPARE AS_ME_PREPARE AS_VAR_APPEND AS_VAR_COPY diff --git a/bin/autoupdate.in b/bin/autoupdate.in index d23048a1..c9235596 100644 --- a/bin/autoupdate.in +++ b/bin/autoupdate.in @@ -271,7 +271,8 @@ foreach my $file (@ARGV) define([_au__include], defn([include])) define([_au___undefine], defn([undefine])) define([_au__undefine], [_au__ifdef([$1], [_au___undefine([$1])])]) - define([_au__save], [m4_ifdef([$1], [m4_copy([$1], [_au_$1])])]) + define([_au__save], [m4_ifdef([$1], + [m4_define([_au_$1], _m4_defn([$1]))])]) define([_au__restore], [_au_m4_ifdef([_au_$1], [_au_m4_define([$1], _au__defn([_au_$1]))])]) diff --git a/doc/autoconf.texi b/doc/autoconf.texi index 71f507f1..85093229 100644 --- a/doc/autoconf.texi +++ b/doc/autoconf.texi @@ -10363,6 +10363,25 @@ is kept for future versions of M4sugar, once @acronym{GNU} M4 2.0 is released and supports extended regular expression syntax. @end defmac +@defmac m4_copy (@var{source}, @var{dest}) +@defmacx m4_rename (@var{source}, @var{dest}) +@msindex{copy} +@msindex{rename} +These macros aren't directly builtins, but are closely related to +@code{m4_pushdef} and @code{m4_defn}. They both ensures that @var{dest} +is undefined, then proceed to copy the entire pushdef stack of +definitions of @var{source}. @code{m4_copy} preserves the source, while +@code{m4_rename} undefines the original macro name. + +Note that attempting to invoke a renamed macro might not work, since the +macro may have a dependence on helper macros accessed via composition of +@samp{$0} but that were not also renamed; likewise, other macros may +have a hard-coded dependence on @var{source} and could break if +@var{source} has been deleted. On the other hand, it is always safe to +rename a macro to temporarily move it out of the way, then rename it +back later to restore original semantics. +@end defmac + @defmac m4_defn (@var{macro}@dots{}) @msindex{defn} This macro fails if @var{macro} is not defined, even when using older diff --git a/lib/autoconf/autoconf.m4 b/lib/autoconf/autoconf.m4 index c8029595..0a838a6e 100644 --- a/lib/autoconf/autoconf.m4 +++ b/lib/autoconf/autoconf.m4 @@ -1,7 +1,7 @@ # This file is part of Autoconf. -*- Autoconf -*- # Driver that loads the Autoconf macro files. # -# Copyright (C) 1994, 1999, 2000, 2001, 2002, 2006 Free Software +# Copyright (C) 1994, 1999, 2000, 2001, 2002, 2006, 2008 Free Software # Foundation, Inc. # # This program is free software: you can redistribute it and/or modify @@ -76,6 +76,14 @@ m4_include([autoconf/oldnames.m4]) # names too. But users may still depend upon these, so reestablish # them. +# In order to copy pushdef stacks, m4_copy temporarily destroys the +# current pushdef stack. But these builtins are so primitive that: +# 1. they should not have more than one pushdef definition +# 2. undefining the pushdef stack to copy breaks m4_copy +# Hence, we temporarily restore a simpler m4_copy. + +m4_pushdef([m4_copy], [m4_define([$2], m4_defn([$1]))]) + m4_copy_unm4([m4_builtin]) m4_copy_unm4([m4_changequote]) m4_copy_unm4([m4_decr]) @@ -104,6 +112,8 @@ m4_copy_unm4([m4_translit]) m4_copy_unm4([m4_undefine]) m4_copy_unm4([m4_undivert]) +m4_popdef([m4_copy]) + # Yet some people have started to use m4_patsubst and m4_regexp. m4_define([m4_patsubst], [m4_expand_once([m4_warn([syntax], diff --git a/lib/autoconf/general.m4 b/lib/autoconf/general.m4 index 158391cd..4f13b58e 100644 --- a/lib/autoconf/general.m4 +++ b/lib/autoconf/general.m4 @@ -317,6 +317,7 @@ AU_DEFUN([AC_PREREQ], # AC_PREREQ(VERSION) # ------------------ # Complain and exit if the Autoconf version is less than VERSION. +m4_undefine([AC_PREREQ]) m4_copy([m4_version_prereq], [AC_PREREQ]) diff --git a/lib/m4sugar/m4sugar.m4 b/lib/m4sugar/m4sugar.m4 index ee8ee63e..d0fe9ade 100644 --- a/lib/m4sugar/m4sugar.m4 +++ b/lib/m4sugar/m4sugar.m4 @@ -91,6 +91,10 @@ m4_undefine([undefine]) # Nevertheless, one huge difference is the handling of `$0'. If `from' # uses `$0', then with 1, `to''s `$0' is `to', while it is `from' in 2. # The user would certainly prefer to see `to'. +# +# This definition is in effect during m4sugar initialization, when +# there are no pushdef stacks; later on, we redefine it to something +# more powerful for all other clients to use. m4_define([m4_copy], [m4_define([$2], m4_defn([$1]))]) @@ -166,6 +170,28 @@ m4_rename_m4([traceon]) m4_rename_m4([translit]) m4_undefine([undivert]) +# _m4_defn(ARG) +# ---------------- +# _m4_defn is for internal use only - it bypasses the wrapper, so it +# must only be used on one argument at a time, and only on macros +# known to be defined. Make sure this still works if the user renames +# m4_defn but not _m4_defn. +m4_copy([m4_defn], [_m4_defn]) + +# _m4_popdef(ARG...) +# ------------------ +# _m4_popdef is for internal use only - it bypasses the wrapper, so it +# must only be used on macros known to be defined. Make sure this +# still works if the user renames m4_popdef but not _m4_popdef. +m4_copy([m4_popdef], [_m4_popdef]) + +# _m4_undefine(ARG...) +# -------------------- +# _m4_undefine is for internal use only - it bypasses the wrapper, so +# it must only be used on macros known to be defined. Make sure this +# still works if the user renames m4_undefine but not _m4_undefine. +m4_copy([m4_undefine], [_m4_undefine]) + ## ------------------- ## ## 2. Error messages. ## @@ -501,6 +527,28 @@ m4_define([_m4_bpatsubsts], m4_shift3($@))])]) +# m4_copy(SRC, DST) +# ----------------- +# Define the pushdef stack DST as a copy of the pushdef stack SRC; +# give an error if DST is already defined. This is particularly nice +# for copying self-modifying pushdef stacks, where the top definition +# includes one-shot initialization that is later popped to the normal +# definition. +# +# The recursive worker destructively swaps the order of a stack. We +# use a temporary stack, and swap directions twice, using the third +# argument to restore the original stack. +# +# Some macros simply can't be renamed with this method: namely, +# anything involved in the implementation of _m4_copy. +m4_define([m4_copy], +[m4_ifdef([$2], [m4_fatal([$0: won't overwrite defined macro: $2])], + [_$0([$1], [m4_tmp])_$0([m4_tmp], [$2], + [m4_pushdef([$1], _m4_defn([m4_tmp]))])])]) +m4_define([_m4_copy], +[m4_ifdef([$1], [m4_pushdef([$2], _m4_defn([$1]))$3[]_m4_popdef([$1])$0($@)])]) + + # m4_define_default(MACRO, VALUE) # ------------------------------- # If MACRO is undefined, set it to VALUE. @@ -547,12 +595,6 @@ m4_define([m4_default_quoted], # This macro is called frequently, so minimize the amount of additional # expansions by skipping m4_ifndef. Better yet, if __m4_version__ exists, # (added in M4 1.6), then let m4 do the job for us (see m4_init). -# -# _m4_defn is for internal use only - it bypasses the wrapper, so it -# must only be used on one argument at a time, and only on macros -# known to be defined. Make sure this still works if the user renames -# m4_defn but not _m4_defn. -m4_copy([m4_defn], [_m4_defn]) m4_define([m4_defn], [m4_if([$#], [0], [[$0]], [$#], [1], [m4_ifdef([$1], [_m4_defn([$1])], @@ -596,11 +638,6 @@ _m4_dumpdefs_down([$1])]) # This macro is called frequently, so minimize the amount of additional # expansions by skipping m4_ifndef. Better yet, if __m4_version__ exists, # (added in M4 1.6), then let m4 do the job for us (see m4_init). -# -# _m4_popdef is for internal use only - it bypasses the wrapper, so it -# must only be used on macros known to be defined. Make sure this -# still works if the user renames m4_popdef but not _m4_popdef. -m4_copy([m4_popdef], [_m4_popdef]) m4_define([m4_popdef], [m4_if([$#], [0], [[$0]], [$#], [1], [m4_ifdef([$1], [_m4_popdef([$1])], @@ -662,11 +699,6 @@ m4_define([_m4_shift3], # This macro is called frequently, so minimize the amount of additional # expansions by skipping m4_ifndef. Better yet, if __m4_version__ exists, # (added in M4 1.6), then let m4 do the job for us (see m4_init). -# -# _m4_undefine is for internal use only - it bypasses the wrapper, so -# it must only be used on macros known to be defined. Make sure this -# still works if the user renames m4_undefine but not _m4_undefine. -m4_copy([m4_undefine], [_m4_undefine]) m4_define([m4_undefine], [m4_if([$#], [0], [[$0]], [$#], [1], [m4_ifdef([$1], [_m4_undefine([$1])], @@ -1578,7 +1610,8 @@ m4_do([[m4_ifdef([m4_expansion_stack], [], [_m4_defun_pro_outer[]])]], [[m4_pushdef([_m4_expanding($1)])]])) m4_define([_m4_defun_pro_outer], -[m4_copy([_m4_divert_diversion], [_m4_divert_dump])m4_divert_push([GROW])]) +[m4_define([_m4_divert_dump], + m4_defn([_m4_divert_diversion]))m4_divert_push([GROW])]) # _m4_defun_epi(MACRO-NAME) # ------------------------- @@ -2838,12 +2871,13 @@ m4_pattern_forbid([^dnl$]) # But if it is missing, we assume we are being run by M4 1.4.x, that # $@ recursion is quadratic, and that we need foreach-based # replacement macros. Use the raw builtin to avoid tripping up -# include tracing. +# include tracing. Meanwhile, avoid m4_copy, since it temporarily +# undefines m4_defn. m4_ifdef([__m4_version__], [m4_debugmode([+d]) -m4_copy([_m4_defn], [m4_defn]) -m4_copy([_m4_popdef], [m4_popdef]) -m4_copy([_m4_undefine], [m4_undefine])], +m4_define([m4_defn], _m4_defn([m4_defn])) +m4_define([m4_popdef], _m4_defn([m4_popdef])) +m4_define([m4_undefine], _m4_defn([m4_undefine]))], [m4_builtin([include], [m4sugar/foreach.m4])]) # _m4_divert_diversion should be defined: diff --git a/tests/m4sugar.at b/tests/m4sugar.at index f34bca36..deb6f8ca 100644 --- a/tests/m4sugar.at +++ b/tests/m4sugar.at @@ -43,7 +43,7 @@ AT_CHECK_M4SUGAR([-o-],, [$2], [$3]) AT_SETUP([m4@&t@_defn]) -AT_KEYWORDS([m4@&t@_popdef m4@&t@_undefine]) +AT_KEYWORDS([m4@&t@_popdef m4@&t@_undefine m4@&t@_copy m4@&t@_rename]) # Ensure that m4sugar dies when dereferencing undefined macros, whether # this is provided by m4 natively or faked by wrappers in m4sugar. @@ -75,6 +75,25 @@ AT_CHECK_M4SUGAR([-o-], 1, [], [stderr]) AT_CHECK([grep good stderr], [1]) AT_CHECK([grep 'm4@&t@_undefine: undefined.*oops' stderr], [0], [ignore]) +# Check that pushdef stacks can be renamed. +AT_CHECK_M4SUGAR_TEXT([[m4_pushdef([a], [1])dnl +m4_pushdef([a], [2])dnl +a b c +m4_rename([a], [b])dnl +a b c +m4_copy([b], [c])dnl +a b c +m4_popdef([b], [c])dnl +a b c +m4_popdef([b], [c])dnl +a b c +]], [[2 b c +a 2 c +a 2 2 +a 1 1 +a b c +]]) + AT_CLEANUP