autoconf-patches
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

optimize m4_defn, m4_popdef


From: Eric Blake
Subject: optimize m4_defn, m4_popdef
Date: Sat, 19 Jul 2008 13:37:37 -0600
User-agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.14) Gecko/20080421 Thunderbird/2.0.0.14 Mnenhy/0.7.5.666

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

In general, it is more efficient to directly invoke a builtin than it is
to write wrapper macros or even call m4_builtin([name]), because direct
invocation involves less text to parse and fewer lookups in m4's symbol
table.  Right now, we are wrapping m4_defn, m4_popdef, and m4_undefine in
order to cause a fatal exit in dereferencing undefined macros, when
compared with letting m4 1.4.x issue the warning for m4_dumpdef and
m4_indir.  The master branch of m4 has long issued warnings natively for
the three macros being wrapped, and I just added warnings on what will
become m4 1.6 to match:

http://lists.gnu.org/archive/html/m4-patches/2008-07/msg00004.html

Also in that message, I did some timing of two independent patches,
forerunners of this patch series: a) avoiding defining the wrapper, b)
substitute s/m4_builtin(\[\(defn\|popdef\|undefine\], /m4_\1(/.  In this
patch series, the first patch is a modification of a) that conditionally
uses the native version only if __m4_version__ exists, using that as the
key that the native version knows how to warn.  The second patch is a
modification of b) that introduces _m4_defn independent of whether m4_defn
is a wrapper or native call, so that I was able to make it work for even
1.4.x (unlike my claim in the m4-patches mail).

The third patch fixes an API hole - if we are going to use the native
m4_popdef, which supports multiple arguments, then we should do likewise
in our wrapper, so that someone writing a configure script with m4 1.6
doesn't accidentally introduce a bug when someone else reruns autoconf
with m4 1.4.x.  This doesn't quite work for all cases of m4_defn, but the
corner cases of m4_defn are rather unlikely to be triggered by normal
m4sugar clients.  It has no impact on m4 1.6+, but it unfortunately loses
a bit of the speed gains of the earlier two patches for m4 1.4.x, since
the wrappers now expands to more text; such is the price of fixing the API.

- --
Don't work too hard, make some time for fun as well!

Eric Blake             address@hidden
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.9 (Cygwin)
Comment: Public key at home.comcast.net/~ericblake/eblake.gpg
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org

iEYEARECAAYFAkiCQoEACgkQ84KuGfSFAYCVeQCgqu2M6q3vadA0zbYC0ougTN/U
kDYAmwej/UHOlmOjesDr3tfPG7Yav/oC
=6NOL
-----END PGP SIGNATURE-----
>From 434bdc105b409a017f572b1cf882466ba8a6a58c Mon Sep 17 00:00:00 2001
From: Eric Blake <address@hidden>
Date: Fri, 18 Jul 2008 12:05:43 -0600
Subject: [PATCH] Use warnings from m4 when available.

* lib/m4sugar/m4sugar.m4 (m4_defn, m4_popdef, m4_undefine): Don't
define slower wrapper if m4 will warn on our behalf; key off of
__m4_version__, added alongside the new warnings in m4 1.6.
* tests/m4sugar.at (m4@&address@hidden): New test.

Signed-off-by: Eric Blake <address@hidden>
---
 ChangeLog              |    8 ++++++++
 lib/m4sugar/m4sugar.m4 |   38 ++++++++++++++++++++++----------------
 tests/m4sugar.at       |   35 +++++++++++++++++++++++++++++++++++
 3 files changed, 65 insertions(+), 16 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index af9b4d9..d90117c 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+2008-07-19  Eric Blake  <address@hidden>
+
+       Use warnings from m4 when available.
+       * lib/m4sugar/m4sugar.m4 (m4_defn, m4_popdef, m4_undefine): Don't
+       define slower wrapper if m4 will warn on our behalf; key off of
+       __m4_version__, added alongside the new warnings in m4 1.6.
+       * tests/m4sugar.at (m4@&address@hidden): New test.
+
 2008-07-18  Eric Blake  <address@hidden>
 
        Add m4_joinall.
diff --git a/lib/m4sugar/m4sugar.m4 b/lib/m4sugar/m4sugar.m4
index eb4374e..b1e545e 100644
--- a/lib/m4sugar/m4sugar.m4
+++ b/lib/m4sugar/m4sugar.m4
@@ -151,7 +151,7 @@ m4_undefine([maketemp])],
 [m4_rename_m4([maketemp])
 m4_copy([m4_maketemp], [m4_mkstemp])])
 m4_rename([patsubst], [m4_bpatsubst])
-m4_undefine([popdef])
+m4_rename_m4([popdef])
 m4_rename_m4([pushdef])
 m4_rename([regexp], [m4_bregexp])
 m4_rename_m4([shift])
@@ -505,15 +505,17 @@ m4_define([m4_default],
 
 # m4_defn(NAME)
 # -------------
-# Like the original, except don't tolerate popping something which is
-# undefined, and only support one argument.
+# Like the original, except guarantee a warning when using something which is
+# undefined (unlike M4 1.4.x), and only support one argument.
 #
 # This macro is called frequently, so minimize the amount of additional
-# expansions by skipping m4_ifndef.
-m4_define([m4_defn],
+# expansions by skipping m4_ifndef.  Better yet, if __m4_version__ exists,
+# (added in M4 1.6), then let m4 do the job for us.
+m4_ifdef([__m4_version__], [],
+[m4_define([m4_defn],
 [m4_ifdef([$1], [],
          [m4_fatal([$0: undefined macro: $1])])]dnl
-[m4_builtin([defn], [$1])])
+[m4_builtin([defn], [$1])])])
 
 
 # _m4_dumpdefs_up(NAME)
@@ -546,15 +548,17 @@ _m4_dumpdefs_down([$1])])
 
 # m4_popdef(NAME)
 # ---------------
-# Like the original, except don't tolerate popping something which is
-# undefined, and only support one argument.
+# Like the original, except guarantee a warning when using something which is
+# undefined (unlike M4 1.4.x), and only support one argument.
 #
 # This macro is called frequently, so minimize the amount of additional
-# expansions by skipping m4_ifndef.
-m4_define([m4_popdef],
+# expansions by skipping m4_ifndef.  Better yet, if __m4_version__ exists,
+# (added in M4 1.6), then let m4 do the job for us.
+m4_ifdef([__m4_version__], [],
+[m4_define([m4_popdef],
 [m4_ifdef([$1], [],
          [m4_fatal([$0: undefined macro: $1])])]dnl
-[m4_builtin([popdef], [$1])])
+[m4_builtin([popdef], [$1])])])
 
 
 # m4_shiftn(N, ...)
@@ -603,15 +607,17 @@ m4_define([_m4_shift3],
 
 # m4_undefine(NAME)
 # -----------------
-# Like the original, except don't tolerate undefining something which is
-# undefined, and only support one argument.
+# Like the original, except guarantee a warning when using something which is
+# undefined (unlike M4 1.4.x), and only support one argument.
 #
 # This macro is called frequently, so minimize the amount of additional
-# expansions by skipping m4_ifndef.
-m4_define([m4_undefine],
+# expansions by skipping m4_ifndef.  Better yet, if __m4_version__ exists,
+# (added in M4 1.6), then let m4 do the job for us.
+m4_ifdef([__m4_version__], [],
+[m4_define([m4_undefine],
 [m4_ifdef([$1], [],
          [m4_fatal([$0: undefined macro: $1])])]dnl
-[m4_builtin([undefine], [$1])])
+[m4_builtin([undefine], [$1])])])
 
 # _m4_wrap(PRE, POST)
 # -------------------
diff --git a/tests/m4sugar.at b/tests/m4sugar.at
index b6a4cac..650f5dc 100644
--- a/tests/m4sugar.at
+++ b/tests/m4sugar.at
@@ -53,6 +53,41 @@ AT_CHECK_M4SUGAR([-o-],, [$2], [$3])
 # uses m4_split code.
 
 ## --------- ##
+## m4_defn.  ##
+## --------- ##
+
+AT_SETUP([m4@&address@hidden)
+
+AT_KEYWORDS([m4@&address@hidden m4@&address@hidden)
+
+# Ensure that m4sugar dies when dereferencing undefined macros, whether
+# this is provided by m4 natively or faked by wrappers in m4sugar.
+
+AT_DATA_M4SUGAR([script.4s],
+[[m4_defn([oops])
+]])
+
+AT_CHECK_M4SUGAR([-o-], 1, [], [stderr])
+AT_CHECK([grep 'm4@&address@hidden: undefined.*oops' stderr], [0], [ignore])
+
+AT_DATA_M4SUGAR([script.4s],
+[[m4_popdef([oops])
+]])
+
+AT_CHECK_M4SUGAR([-o-], 1, [], [stderr])
+AT_CHECK([grep 'm4@&address@hidden: undefined.*oops' stderr], [0], [ignore])
+
+AT_DATA_M4SUGAR([script.4s],
+[[m4_undefine([oops])
+]])
+
+AT_CHECK_M4SUGAR([-o-], 1, [], [stderr])
+AT_CHECK([grep 'm4@&address@hidden: undefined.*oops' stderr], [0], [ignore])
+
+AT_CLEANUP
+
+
+## --------- ##
 ## m4_warn.  ##
 ## --------- ##
 
-- 
1.5.6


>From 8c938c72f01272d23a5b7f110b8c0c0abbdf20f6 Mon Sep 17 00:00:00 2001
From: Eric Blake <address@hidden>
Date: Sat, 19 Jul 2008 10:53:10 -0600
Subject: [PATCH] Reduce overhead of m4_builtin([defn]).

* lib/m4sugar/m4sugar.m4 (_m4_defn, _m4_popdef, _m4_undefine): New
internal macros, which are slightly more efficient than
m4_builtin([defn]) and company.
(m4_defn, m4_popdef, m4_undefine, m4_warn, m4_ifset)
(_m4_dumpdefs_up, _m4_dumpdefs_down, _m4_wrap, m4_for)
(_m4_divert_n_stack, m4_divert_pop, m4_expansion_stack_push)
(m4_expansion_stack_dump, _m4_defun_pro, _m4_defun_epi)
(_m4_defun_epi_outer, _m4_require_call, m4_combine, m4_append)
(_m4_append_uniq, m4_append_uniq_w, _m4_text_wrap, m4_text_box)
(m4_version_prereq): Use them.

Signed-off-by: Eric Blake <address@hidden>
---
 ChangeLog              |   12 +++++
 lib/m4sugar/m4sugar.m4 |  122 +++++++++++++++++++++++++----------------------
 2 files changed, 77 insertions(+), 57 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index d90117c..974c025 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,17 @@
 2008-07-19  Eric Blake  <address@hidden>
 
+       Reduce overhead of m4_builtin([defn]).
+       * lib/m4sugar/m4sugar.m4 (_m4_defn, _m4_popdef, _m4_undefine): New
+       internal macros, which are slightly more efficient than
+       m4_builtin([defn]) and company.
+       (m4_defn, m4_popdef, m4_undefine, m4_warn, m4_ifset)
+       (_m4_dumpdefs_up, _m4_dumpdefs_down, _m4_wrap, m4_for)
+       (_m4_divert_n_stack, m4_divert_pop, m4_expansion_stack_push)
+       (m4_expansion_stack_dump, _m4_defun_pro, _m4_defun_epi)
+       (_m4_defun_epi_outer, _m4_require_call, m4_combine, m4_append)
+       (_m4_append_uniq, m4_append_uniq_w, _m4_text_wrap, m4_text_box)
+       (m4_version_prereq): Use them.
+
        Use warnings from m4 when available.
        * lib/m4sugar/m4sugar.m4 (m4_defn, m4_popdef, m4_undefine): Don't
        define slower wrapper if m4 will warn on our behalf; key off of
diff --git a/lib/m4sugar/m4sugar.m4 b/lib/m4sugar/m4sugar.m4
index b1e545e..347c123 100644
--- a/lib/m4sugar/m4sugar.m4
+++ b/lib/m4sugar/m4sugar.m4
@@ -234,7 +234,7 @@ m4_define([_m4_warn], [])
 m4_define([m4_warn],
 [_m4_warn([$1], [$2],
 m4_ifdef([m4_expansion_stack],
-        [m4_defn([m4_expansion_stack])
+        [_m4_defn([m4_expansion_stack])
 m4_location[: the top level]]))dnl
 ])
 
@@ -335,7 +335,7 @@ m4_define([m4_ifvaln],
 # expand IF-FALSE, otherwise IF-TRUE.
 m4_define([m4_ifset],
 [m4_ifdef([$1],
-         [m4_ifval(m4_defn([$1]), [$2], [$3])],
+         [m4_ifval(_m4_defn([$1]), [$2], [$3])],
          [$3])])
 
 
@@ -511,20 +511,26 @@ m4_define([m4_default],
 # 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.
+#
+# _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_ifdef([__m4_version__], [],
 [m4_define([m4_defn],
 [m4_ifdef([$1], [],
          [m4_fatal([$0: undefined macro: $1])])]dnl
-[m4_builtin([defn], [$1])])])
+[_m4_defn([$1])])])
 
 
 # _m4_dumpdefs_up(NAME)
 # ---------------------
 m4_define([_m4_dumpdefs_up],
 [m4_ifdef([$1],
-         [m4_pushdef([_m4_dumpdefs], m4_defn([$1]))dnl
+         [m4_pushdef([_m4_dumpdefs], _m4_defn([$1]))dnl
 m4_dumpdef([$1])dnl
-m4_popdef([$1])dnl
+_m4_popdef([$1])dnl
 _m4_dumpdefs_up([$1])])])
 
 
@@ -532,8 +538,8 @@ _m4_dumpdefs_up([$1])])])
 # -----------------------
 m4_define([_m4_dumpdefs_down],
 [m4_ifdef([_m4_dumpdefs],
-         [m4_pushdef([$1], m4_defn([_m4_dumpdefs]))dnl
-m4_popdef([_m4_dumpdefs])dnl
+         [m4_pushdef([$1], _m4_defn([_m4_dumpdefs]))dnl
+_m4_popdef([_m4_dumpdefs])dnl
 _m4_dumpdefs_down([$1])])])
 
 
@@ -554,11 +560,16 @@ _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.
+#
+# _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_ifdef([__m4_version__], [],
 [m4_define([m4_popdef],
 [m4_ifdef([$1], [],
          [m4_fatal([$0: undefined macro: $1])])]dnl
-[m4_builtin([popdef], [$1])])])
+[_m4_popdef([$1])])])
 
 
 # m4_shiftn(N, ...)
@@ -613,22 +624,26 @@ 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.
+#
+# _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_ifdef([__m4_version__], [],
 [m4_define([m4_undefine],
 [m4_ifdef([$1], [],
          [m4_fatal([$0: undefined macro: $1])])]dnl
-[m4_builtin([undefine], [$1])])])
+[_m4_undefine([$1])])])
 
 # _m4_wrap(PRE, POST)
 # -------------------
 # Helper macro for m4_wrap and m4_wrap_lifo.  Allows nested calls to
-# m4_wrap within wrapped text.
-# Skip m4_defn and m4_popdef for speed.
+# m4_wrap within wrapped text.  Use _m4_defn and _m4_popdef for speed.
 m4_define([_m4_wrap],
 [m4_ifdef([$0_text],
-         [m4_define([$0_text], [$1]m4_builtin([defn], [$0_text])[$2])],
-         [m4_builtin([m4wrap], [m4_unquote(m4_builtin([defn],
-  [$0_text])m4_builtin([popdef], [$0_text]))])m4_define([$0_text], [$1$2])])])
+         [m4_define([$0_text], [$1]_m4_defn([$0_text])[$2])],
+         [m4_builtin([m4wrap], [m4_unquote(
+  _m4_defn([$0_text])_m4_popdef([$0_text]))])m4_define([$0_text], [$1$2])])])
 
 # m4_wrap(TEXT)
 # -------------
@@ -799,21 +814,21 @@ m4_define([m4_unquote], [$*])
 # Expand EXPRESSION defining VARIABLE to FROM, FROM + 1, ..., TO with
 # increments of STEP.
 # Both limits are included, and bounds are checked for consistency.
-# The algorithm is robust to indirect VARIABLE names, and uses m4_builtin
-# to avoid some of the m4_defn overhead.
+# The algorithm is robust to indirect VARIABLE names, and uses _m4_defn
+# where possible for speed.
 m4_define([m4_for],
 [m4_pushdef([$1], m4_eval([$2]))dnl
-m4_cond([m4_eval(([$3]) > m4_builtin([defn], [$1]))], 1,
+m4_cond([m4_eval(([$3]) > _m4_defn([$1]))], 1,
 [m4_pushdef([_m4_step], m4_eval(m4_default([$4], 1)))dnl
 m4_assert(_m4_step > 0)dnl
-_m4_for([$1], m4_eval((([$3]) - m4_builtin([defn], [$1]))
-                     / _m4_step * _m4_step + m4_builtin([defn], [$1])),
+_m4_for([$1], m4_eval((([$3]) - _m4_defn([$1]))
+                     / _m4_step * _m4_step + _m4_defn([$1])),
        _m4_step, [$5])],
-       [m4_eval(([$3]) < m4_builtin([defn], [$1]))], 1,
+       [m4_eval(([$3]) < _m4_defn([$1]))], 1,
 [m4_pushdef([_m4_step], m4_eval(m4_default([$4], -1)))dnl
 m4_assert(_m4_step < 0)dnl
-_m4_for([$1], m4_eval((m4_builtin([defn], [$1]) - ([$3]))
-                     / -(_m4_step) * _m4_step + m4_builtin([defn], [$1])),
+_m4_for([$1], m4_eval((_m4_defn([$1]) - ([$3]))
+                     / -(_m4_step) * _m4_step + _m4_defn([$1])),
        _m4_step, [$5])],
        [m4_pushdef([_m4_step])dnl
 $5])[]dnl
@@ -1011,7 +1026,7 @@ m4_define([_m4_divert()],                0)
 # Print m4_divert_stack with newline prepended, if it's nonempty.
 m4_define([_m4_divert_n_stack],
 [m4_ifdef([m4_divert_stack], [
-m4_defn([m4_divert_stack])])])
+_m4_defn([m4_divert_stack])])])
 
 
 # m4_divert(DIVERSION-NAME)
@@ -1048,7 +1063,7 @@ m4_popdef([m4_divert_stack])dnl
 m4_popdef([_m4_divert_diversion])dnl
 m4_builtin([divert],
           m4_ifdef([_m4_divert_diversion],
-                   [_m4_divert(m4_defn([_m4_divert_diversion]))],
+                   [_m4_divert(_m4_defn([_m4_divert_diversion]))],
                    -1))dnl
 ])
 
@@ -1360,11 +1375,10 @@ m4_define([m4_undivert],
 
 # m4_expansion_stack_push(TEXT)
 # -----------------------------
-# Use m4_builtin to avoid m4_defn overhead.
 m4_define([m4_expansion_stack_push],
 [m4_pushdef([m4_expansion_stack],
            [$1]m4_ifdef([m4_expansion_stack], [
-m4_builtin([defn], [m4_expansion_stack])]))])
+_m4_defn([m4_expansion_stack])]))])
 
 
 # m4_expansion_stack_pop
@@ -1378,7 +1392,7 @@ m4_define([m4_expansion_stack_pop],
 # Dump the expansion stack.
 m4_define([m4_expansion_stack_dump],
 [m4_ifdef([m4_expansion_stack],
-         [m4_errprintn(m4_defn([m4_expansion_stack]))])dnl
+         [m4_errprintn(_m4_defn([m4_expansion_stack]))])dnl
 m4_errprintn(m4_location[: the top level])])
 
 
@@ -1409,7 +1423,7 @@ m4_define([_m4_divert(GROW)],       10000)
 # by avoiding dnl and m4_defn overhead.
 m4_define([_m4_defun_pro],
 m4_do([[m4_ifdef([m4_expansion_stack], [], [_m4_defun_pro_outer[]])]],
-      [[m4_expansion_stack_push(m4_builtin([defn],
+      [[m4_expansion_stack_push(_m4_defn(
          [m4_location($1)])[: $1 is expanded from...])]],
       [[m4_pushdef([_m4_expanding($1)])]]))
 
@@ -1424,15 +1438,13 @@ m4_define([_m4_defun_pro_outer],
 # This is called frequently, so minimize the number of macro invocations
 # by avoiding dnl and m4_popdef overhead.
 m4_define([_m4_defun_epi],
-m4_do([[m4_builtin([popdef], [_m4_expanding($1)])]],
+m4_do([[_m4_popdef([_m4_expanding($1)])]],
       [[m4_expansion_stack_pop()]],
       [[m4_ifdef([m4_expansion_stack], [], [_m4_defun_epi_outer[]])]],
       [[m4_provide([$1])]]))
 
 m4_define([_m4_defun_epi_outer],
-m4_do([[m4_builtin([undefine], [_m4_divert_dump])]],
-      [[m4_divert_pop([GROW])]],
-      [[m4_undivert([GROW])]]))
+[_m4_undefine([_m4_divert_dump])m4_divert_pop([GROW])m4_undivert([GROW])])
 
 
 # m4_defun(NAME, EXPANSION)
@@ -1550,7 +1562,7 @@ m4_provide_if([$1],
              [],
              [m4_warn([syntax],
                       [$1 is m4_require'd but not m4_defun'd])])]],
-      [[m4_divert(m4_builtin([defn], [_m4_divert_dump]))]],
+      [[m4_divert(_m4_defn([_m4_divert_dump]))]],
       [[m4_undivert(_m4_divert_grow)]],
       [[m4_divert_pop(_m4_divert_grow)]],
       [[m4_define([_m4_divert_grow], m4_incr(_m4_divert_grow))]]))
@@ -1872,20 +1884,19 @@ m4_define([_m4_joinall],
 #   => a-1, a-2, a-3, b-1, b-2, b-3, c-1, c-2, c-3
 #
 # In order to have the correct number of SEPARATORs, we use a temporary
-# variable that redefines itself after the first use.  We use m4_builtin
-# to avoid m4_defn overhead, but must use defn rather than overquoting
-# in case PREFIX or SUFFIX contains $1.  Likewise, we compute the m4_shift3
-# only once, rather than in each iteration of the outer m4_foreach.
+# variable that redefines itself after the first use.  We must use defn
+# rather than overquoting in case PREFIX or SUFFIX contains $1, but use
+# _m4_defn for speed.  Likewise, we compute the m4_shift3 only once,
+# rather than in each iteration of the outer m4_foreach.
 m4_define([m4_combine],
 [m4_if(m4_eval([$# > 3]), [1],
        [m4_pushdef([m4_Separator], [m4_define([m4_Separator],
-                                   m4_builtin([defn], [m4_echo]))])]]dnl
+                                   _m4_defn([m4_echo]))])]]dnl
 [[m4_foreach([m4_Prefix], [$2],
             [m4_foreach([m4_Suffix], ]m4_dquote(m4_dquote(m4_shift3($@)))[,
-                        [m4_Separator([$1])[]m4_builtin([defn],
-                                     [m4_Prefix])[$3]m4_builtin([defn],
+       [m4_Separator([$1])[]_m4_defn([m4_Prefix])[$3]_m4_defn(
                                                      [m4_Suffix])])])]]dnl
-[[m4_builtin([popdef], [m4_Separator])])])
+[[_m4_popdef([m4_Separator])])])
 
 
 # m4_append(MACRO-NAME, STRING, [SEPARATOR])
@@ -1942,10 +1953,9 @@ m4_define([m4_combine],
 # storage only occurs at the end of a macro, so the existing contents must
 # always be moved).
 #
-# Use m4_builtin to avoid overhead of m4_defn.
+# Use _m4_defn for speed.
 m4_define([m4_append],
-[m4_define([$1],
-          m4_ifdef([$1], [m4_builtin([defn], [$1])[$3]])[$2])])
+[m4_define([$1], m4_ifdef([$1], [_m4_defn([$1])[$3]])[$2])])
 
 
 # m4_append_uniq(MACRO-NAME, STRING, [SEPARATOR], [IF-UNIQ], [IF-DUP])
@@ -1964,7 +1974,7 @@ m4_define([m4_append_uniq],
                                [$0: `$2' contains `$3'])])])_$0($@)])
 m4_define([_m4_append_uniq],
 [m4_ifdef([$1],
-         [m4_if(m4_index([$3]m4_builtin([defn], [$1])[$3], [$3$2$3]), [-1],
+         [m4_if(m4_index([$3]_m4_defn([$1])[$3], [$3$2$3]), [-1],
                 [m4_append([$1], [$2], [$3])$4], [$5])],
          [m4_define([$1], [$2])$4])])
 
@@ -1973,10 +1983,10 @@ m4_define([_m4_append_uniq],
 # For each of the words in the whitespace separated list STRINGS, append
 # only the unique strings to the definition of MACRO-NAME.
 #
-# Avoid overhead of m4_defn by using m4_builtin.
+# Use _m4_defn for speed.
 m4_define([m4_append_uniq_w],
 [m4_foreach_w([m4_Word], [$2],
-             [_m4_append_uniq([$1], m4_builtin([defn], [m4_Word]), [ ])])])
+             [_m4_append_uniq([$1], _m4_defn([m4_Word]), [ ])])])
 
 
 # m4_text_wrap(STRING, [PREFIX], [FIRST-PREFIX], [WIDTH])
@@ -2022,7 +2032,7 @@ m4_define([m4_append_uniq_w],
 #
 # The algorithm uses a helper that uses $2 through $4 directly, rather than
 # using local variables, to avoid m4_defn overhead, or expansion swallowing
-# any $.  It also bypasses m4_popdef overhead with m4_builtin since no user
+# any $.  It also bypasses m4_popdef overhead with _m4_popdef since no user
 # macro expansion occurs in the meantime.  Also, the definition is written
 # with m4_do, to avoid time wasted on dnl during expansion (since this is
 # already a time-consuming macro).
@@ -2050,17 +2060,16 @@ dnl if not, insert the separator (usually a space)
 dnl either way, insert the word
 [[m4_foreach_w([m4_Word], [$1],
   [m4_define([m4_Cursor],
-            m4_eval(m4_Cursor + m4_qlen(m4_builtin([defn], [m4_Word]))
+            m4_eval(m4_Cursor + m4_qlen(_m4_defn([m4_Word]))
                     + 1))m4_if(m4_eval(m4_Cursor > ([$4])),
       [1], [m4_define([m4_Cursor],
-                     m4_eval(m4_Indent
-                             + m4_qlen(m4_builtin([defn], [m4_Word])) + 1))
+                     m4_eval(m4_Indent + m4_qlen(_m4_defn([m4_Word])) + 1))
 [$2]],
-      [m4_Separator[]])m4_builtin([defn], [m4_Word])])]],
+      [m4_Separator[]])_m4_defn([m4_Word])])]],
 dnl finally, clean up the local variabls
-[[m4_builtin([popdef], [m4_Separator])]],
-[[m4_builtin([popdef], [m4_Cursor])]],
-[[m4_builtin([popdef], [m4_Indent])]]))
+[[_m4_popdef([m4_Separator])]],
+[[_m4_popdef([m4_Cursor])]],
+[[_m4_popdef([m4_Indent])]]))
 
 
 # m4_text_box(MESSAGE, [FRAME-CHARACTER = `-'])
@@ -2076,8 +2085,7 @@ m4_define([m4_text_box],
                        [ ], m4_if([$2], [], [[-]], [[$2]])))dnl
 @%:@@%:@ m4_Border @%:@@%:@
 @%:@@%:@ $1 @%:@@%:@
address@hidden:@@%:@ m4_Border @%:@@%:@dnl
-m4_builtin([popdef], [m4_Border])dnl
address@hidden:@@%:@ m4_Border @%:@@%:@_m4_popdef([m4_Border])dnl
 ])
 
 
-- 
1.5.6


>From 36d8106f6dadede2d202cc1a71cb7dbbd7924fc9 Mon Sep 17 00:00:00 2001
From: Eric Blake <address@hidden>
Date: Fri, 18 Jul 2008 14:26:41 -0600
Subject: [PATCH] Support multiple arguments to m4_defn, m4_popdef, and 
m4_undefine.

* lib/m4sugar/m4sugar.m4 (m4_defn, m4_popdef, m4_undefine): Loop
through all variables, per POSIX and newer m4.
(_m4_text_wrap): Exploit the looping capabilities.
* tests/m4sugar.at (m4@&address@hidden): Test this.
* NEWS: Document it.
* doc/autoconf.texi (Redefined M4 Macros) <m4_defn, m4_popdef>
<m4_undefine>: Likewise.

Signed-off-by: Eric Blake <address@hidden>
---
 ChangeLog              |    9 +++++++++
 NEWS                   |    4 ++++
 doc/autoconf.texi      |   29 ++++++++++++++---------------
 lib/m4sugar/m4sugar.m4 |   20 +++++++++++---------
 tests/m4sugar.at       |   12 +++++++++---
 5 files changed, 47 insertions(+), 27 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 974c025..47c73b7 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,14 @@
 2008-07-19  Eric Blake  <address@hidden>
 
+       Support multiple arguments to m4_defn, m4_popdef, and m4_undefine.
+       * lib/m4sugar/m4sugar.m4 (m4_defn, m4_popdef, m4_undefine): Loop
+       through all variables, per POSIX and newer m4.
+       (_m4_text_wrap): Exploit the looping capabilities.
+       * tests/m4sugar.at (m4@&address@hidden): Test this.
+       * NEWS: Document it.
+       * doc/autoconf.texi (Redefined M4 Macros) <m4_defn, m4_popdef>
+       <m4_undefine>: Likewise.
+
        Reduce overhead of m4_builtin([defn]).
        * lib/m4sugar/m4sugar.m4 (_m4_defn, _m4_popdef, _m4_undefine): New
        internal macros, which are slightly more efficient than
diff --git a/NEWS b/NEWS
index d3fb23b..232ec86 100644
--- a/NEWS
+++ b/NEWS
@@ -22,6 +22,10 @@ GNU Autoconf NEWS - User visible changes.
 ** The following m4sugar macros are new:
    m4_joinall
 
+** The following m4sugar macros now accept multiple arguments, as is the
+   case with underlying m4:
+   m4_defn  m4_popdef  m4_undefine
+
 ** AT_KEYWORDS once again performs expansion on its argument, such that
    AT_KEYWORDS([m4_if([$1], [], [default])]) no longer complains about
    the possibly unexpanded m4_if [regression introduced in 2.62].
diff --git a/doc/autoconf.texi b/doc/autoconf.texi
index 4e8638d..efb6540 100644
--- a/doc/autoconf.texi
+++ b/doc/autoconf.texi
@@ -10323,12 +10323,14 @@ is kept for future versions of M4sugar, once 
@acronym{GNU} M4 2.0 is
 released and supports extended regular expression syntax.
 @end defmac
 
address@hidden m4_defn (@var{macro})
address@hidden m4_defn (@address@hidden)
 @msindex{defn}
-Unlike the M4 builtin, this macro fails if @var{macro} is not
-defined.  Also, while newer M4 can concatenate multiple definitions,
-this version currently only supports a single @var{macro}.  See
address@hidden
+This macro fails if @var{macro} is not defined, even when using older
+versions of M4 that did not warn.  See @code{m4_undefine}.
+Unfortunately, in order to support these older versions of M4, there are
+some situations involving unbalanced quotes where concatenating multiple
+macros together will work in newer M4 but not in m4sugar; use
+quadrigraphs to work around this.
 @end defmac
 
 @defmac m4_divert (@var{diversion})
@@ -10380,26 +10382,23 @@ and both have the secure semantics regardless of 
which macro the
 underlying M4 provides.
 @end defmac
 
address@hidden m4_popdef (@var{macro})
address@hidden m4_popdef (@address@hidden)
 @msindex{popdef}
-Unlike the M4 builtin, this macro fails if @var{macro} is not
-defined.  Also, while newer M4 can pop multiple definitions at once,
-this version currently only supports a single @var{macro}.  See
address@hidden
+This macro fails if @var{macro} is not defined, even when using older
+versions of M4 that did not warn.  See @code{m4_undefine}.
 @end defmac
 
address@hidden m4_undefine (@var{macro})
address@hidden m4_undefine (@address@hidden)
 @msindex{undefine}
-Unlike the M4 builtin, this macro fails if @var{macro} is not
-defined.  Also, while newer M4 can undefine multiple definitions at
-once, this version currently only supports a single @var{macro}.  Use
+This macro fails if @var{macro} is not defined, even when using older
+versions of M4 that did not warn.  Use
 
 @example
 m4_ifdef(address@hidden, [m4_undefine(address@hidden)])
 @end example
 
 @noindent
-to recover the behavior of the builtin.
+if you are not sure whether @var{macro} is defined.
 @end defmac
 
 @defmac m4_undivert (@var{diversion})
diff --git a/lib/m4sugar/m4sugar.m4 b/lib/m4sugar/m4sugar.m4
index 347c123..5ef7836 100644
--- a/lib/m4sugar/m4sugar.m4
+++ b/lib/m4sugar/m4sugar.m4
@@ -506,7 +506,11 @@ m4_define([m4_default],
 # m4_defn(NAME)
 # -------------
 # Like the original, except guarantee a warning when using something which is
-# undefined (unlike M4 1.4.x), and only support one argument.
+# undefined (unlike M4 1.4.x).  This replacement is not a full-featured
+# replacement: if any of the defined macros contain unbalanced quoting, but
+# when pasted together result in a well-quoted string, then only native m4
+# support is able to get it correct.  But that's where quadrigraphs come in
+# handy, if you really need unbalanced quotes inside your macros.
 #
 # This macro is called frequently, so minimize the amount of additional
 # expansions by skipping m4_ifndef.  Better yet, if __m4_version__ exists,
@@ -521,7 +525,7 @@ m4_ifdef([__m4_version__], [],
 [m4_define([m4_defn],
 [m4_ifdef([$1], [],
          [m4_fatal([$0: undefined macro: $1])])]dnl
-[_m4_defn([$1])])])
+[_m4_defn([$1])m4_if([$#], [1], [], [$0(m4_shift($@))])])])
 
 
 # _m4_dumpdefs_up(NAME)
@@ -555,7 +559,7 @@ _m4_dumpdefs_down([$1])])
 # m4_popdef(NAME)
 # ---------------
 # Like the original, except guarantee a warning when using something which is
-# undefined (unlike M4 1.4.x), and only support one argument.
+# undefined (unlike M4 1.4.x).
 #
 # This macro is called frequently, so minimize the amount of additional
 # expansions by skipping m4_ifndef.  Better yet, if __m4_version__ exists,
@@ -569,7 +573,7 @@ m4_ifdef([__m4_version__], [],
 [m4_define([m4_popdef],
 [m4_ifdef([$1], [],
          [m4_fatal([$0: undefined macro: $1])])]dnl
-[_m4_popdef([$1])])])
+[_m4_popdef([$1])m4_if([$#], [1], [], [$0(m4_shift($@))])])])
 
 
 # m4_shiftn(N, ...)
@@ -619,7 +623,7 @@ m4_define([_m4_shift3],
 # m4_undefine(NAME)
 # -----------------
 # Like the original, except guarantee a warning when using something which is
-# undefined (unlike M4 1.4.x), and only support one argument.
+# undefined (unlike M4 1.4.x).
 #
 # This macro is called frequently, so minimize the amount of additional
 # expansions by skipping m4_ifndef.  Better yet, if __m4_version__ exists,
@@ -633,7 +637,7 @@ m4_ifdef([__m4_version__], [],
 [m4_define([m4_undefine],
 [m4_ifdef([$1], [],
          [m4_fatal([$0: undefined macro: $1])])]dnl
-[_m4_undefine([$1])])])
+[_m4_undefine([$1])m4_if([$#], [1], [], [$0(m4_shift($@))])])])
 
 # _m4_wrap(PRE, POST)
 # -------------------
@@ -2067,9 +2071,7 @@ dnl either way, insert the word
 [$2]],
       [m4_Separator[]])_m4_defn([m4_Word])])]],
 dnl finally, clean up the local variabls
-[[_m4_popdef([m4_Separator])]],
-[[_m4_popdef([m4_Cursor])]],
-[[_m4_popdef([m4_Indent])]]))
+[[_m4_popdef([m4_Separator], [m4_Cursor], [m4_Indent])]]))
 
 
 # m4_text_box(MESSAGE, [FRAME-CHARACTER = `-'])
diff --git a/tests/m4sugar.at b/tests/m4sugar.at
index 650f5dc..9dd953a 100644
--- a/tests/m4sugar.at
+++ b/tests/m4sugar.at
@@ -64,24 +64,30 @@ AT_KEYWORDS([m4@&address@hidden m4@&address@hidden)
 # this is provided by m4 natively or faked by wrappers in m4sugar.
 
 AT_DATA_M4SUGAR([script.4s],
-[[m4_defn([oops])
+[[m4_define([good])
+m4_defn([good], [oops])
 ]])
 
 AT_CHECK_M4SUGAR([-o-], 1, [], [stderr])
+AT_CHECK([grep good stderr], [1])
 AT_CHECK([grep 'm4@&address@hidden: undefined.*oops' stderr], [0], [ignore])
 
 AT_DATA_M4SUGAR([script.4s],
-[[m4_popdef([oops])
+[[m4_define([good])
+m4_popdef([good], [oops])
 ]])
 
 AT_CHECK_M4SUGAR([-o-], 1, [], [stderr])
+AT_CHECK([grep good stderr], [1])
 AT_CHECK([grep 'm4@&address@hidden: undefined.*oops' stderr], [0], [ignore])
 
 AT_DATA_M4SUGAR([script.4s],
-[[m4_undefine([oops])
+[[m4_define([good])
+m4_undefine([good], [oops])
 ]])
 
 AT_CHECK_M4SUGAR([-o-], 1, [], [stderr])
+AT_CHECK([grep good stderr], [1])
 AT_CHECK([grep 'm4@&address@hidden: undefined.*oops' stderr], [0], [ignore])
 
 AT_CLEANUP
-- 
1.5.6


reply via email to

[Prev in Thread] Current Thread [Next in Thread]