[Top][All Lists]
[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
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- optimize m4_defn, m4_popdef,
Eric Blake <=