bison-patches
[Top][All Lists]
Advanced

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

final m4sugar sync


From: Eric Blake
Subject: final m4sugar sync
Date: Fri, 15 Aug 2008 18:26:48 +0000 (UTC)
User-agent: Loom/3.14 (http://gmane.org/)

Here's the final two patches to make bison use autoconf's m4sugar.  The first 
patch ports m4_map, which was the only macro with subtle semantic changes in 
autoconf 2.62 that broke bison; the issue has since been resolved in autoconf 
(will become 2.63).  It also includes a couple of speedups for m4 1.4.x, where:
  m4_if([$#$1],[1],[],...$@)
is practically twice as fast as:
  m4_if(address@hidden,[[]],[],...$@)
for any non-empty address@hidden

The second patch pulls in autoconf's linear algorithms for m4 1.4.x, but those 
algorithms pessimize the future m4 1.6.  Therefore, m4_init() now makes a 
runtime decision as to whether to use the alternate algorithms in 
m4sugar/foreach.m4, and in order to include that file, m4 needs the -I option.  
With this patch in place, you might want to try playing with the tuning 
parameters in tests/torture.at, perhaps going with larger values.  For example, 
the 'Big horizontal' test had a comment about GNU m4 needing an inordinate 
amount of time and memory, which is probably no longer the case (in my limited 
testing of that parameter I saw that doubling the limit still resulted in a 
quadratic growth of execution time, but it seems like that test was previously 
suffering from cubic or worse based on the comment).

The second patch is huge (and probably mangled by gmane); it may be easier to 
read online:
http://repo.or.cz/w/bison/ericb.git?a=shortlog;h=refs/heads/m4sugar

or pull manually:

$ git fetch git://repo.or.cz/bison/ericb.git m4sugar

From: Eric Blake <address@hidden>
Date: Fri, 15 Aug 2008 10:59:32 -0600
Subject: [PATCH] Partial m4sugar merge from autoconf: m4_map.

* data/m4sugar/m4sugar.m4 (m4_fst): Delete.
(m4_map, m4_map_sep, _m4_map): Rewrite more efficiently.
(m4_apply, _m4_apply, m4_mapall, m4_mapall_sep): New macros.
* data/java.m4 (b4_token_enums): Use more efficient short-circuit
for empty list.
* data/c.m4 (b4_token_defines, b4_token_enums, b4_c_ansi_formals):
Likewise.
(b4_parse_param_for): Avoid m4_fst, now that autoconf no longer
declares it.

Signed-off-by: Eric Blake <address@hidden>
---
 ChangeLog               |   13 ++++++
 data/c.m4               |   11 ++---
 data/java.m4            |    2 +-
 data/m4sugar/m4sugar.m4 |  103 ++++++++++++++++++++++++++++++++++++----------
 4 files changed, 99 insertions(+), 30 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index dd85885..ffdc2b7 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,16 @@
+2008-08-15  Eric Blake  <address@hidden>
+
+       Partial m4sugar merge from autoconf: m4_map.
+       * data/m4sugar/m4sugar.m4 (m4_fst): Delete.
+       (m4_map, m4_map_sep, _m4_map): Rewrite more efficiently.
+       (m4_apply, _m4_apply, m4_mapall, m4_mapall_sep): New macros.
+       * data/java.m4 (b4_token_enums): Use more efficient short-circuit
+       for empty list.
+       * data/c.m4 (b4_token_defines, b4_token_enums, b4_c_ansi_formals):
+       Likewise.
+       (b4_parse_param_for): Avoid m4_fst, now that autoconf no longer
+       declares it.
+
 2008-08-07  Joel E. Denny  <address@hidden>
 
        Keep .version and PACKAGE_VERSION in sync.
diff --git a/data/c.m4 b/data/c.m4
index ced2b1e..5d74e86 100644
--- a/data/c.m4
+++ b/data/c.m4
@@ -90,7 +90,7 @@ b4_parse_param)
 # the formal name to FORMAL, and evaluating the BODY.
 m4_define([b4_parse_param_for],
 [m4_foreach([$1_$2], m4_defn([b4_parse_param]),
-[m4_pushdef([$1], m4_fst($1_$2))dnl
+[m4_pushdef([$1], m4_unquote(m4_car($1_$2)))dnl
 m4_pushdef([$2], m4_shift($1_$2))dnl
 $3[]dnl
 m4_popdef([$2])dnl
@@ -160,7 +160,7 @@ m4_define([b4_token_define],
 # -------------------------------------------------------
 # Output the definition of the tokens (if there are) as #defines.
 m4_define([b4_token_defines],
-[m4_if(address@hidden, [[]], [],
+[m4_if([$#$1], [1], [],
 [/* Tokens.  */
 m4_map([b4_token_define], address@hidden)])
 ])
@@ -177,7 +177,7 @@ m4_define([b4_token_enum],
 # -----------------------------------------------------
 # Output the definition of the tokens (if there are) as enums.
 m4_define([b4_token_enums],
-[m4_if(address@hidden, [[]], [],
+[m4_if([$#$1], [1], [],
 [/* Tokens.  */
 #ifndef YYTOKENTYPE
 # define YYTOKENTYPE
@@ -248,9 +248,8 @@ $1 (b4_c_ansi_formals(m4_shift2($@)))[]dnl
 # --------------------------------------
 # Output the arguments ANSI-C definition.
 m4_define([b4_c_ansi_formals],
-[m4_case(address@hidden,
-        [],   [void],
-        [[]], [void],
+[m4_if([$#], [0], [void],
+       [$#$1], [1], [void],
               [m4_map_sep([b4_c_ansi_formal], [, ], address@hidden)])])
 
 m4_define([b4_c_ansi_formal],
diff --git a/data/java.m4 b/data/java.m4
index 1387694..9ee581a 100644
--- a/data/java.m4
+++ b/data/java.m4
@@ -106,7 +106,7 @@ m4_define([b4_token_enum],
 # -----------------------------------------------------
 # Output the definition of the tokens (if there are) as enums.
 m4_define([b4_token_enums],
-[m4_if(address@hidden, [[]], [],
+[m4_if([$#$1], [1], [],
 [/* Tokens.  */
 m4_map([b4_token_enum], address@hidden)])
 ])
diff --git a/data/m4sugar/m4sugar.m4 b/data/m4sugar/m4sugar.m4
index 97b38a4..be39096 100644
--- a/data/m4sugar/m4sugar.m4
+++ b/data/m4sugar/m4sugar.m4
@@ -403,29 +403,6 @@ m4_define([m4_cdr],
        [m4_dquote(m4_shift($@))])])
 
 
-# m4_map(MACRO, LIST)
-# -------------------
-# Invoke MACRO($1), MACRO($2) etc. where $1, $2... are the elements
-# of LIST (which can be lists themselves, for multiple arguments MACROs).
-m4_define([m4_fst], [$1])
-m4_define([m4_map],
-[m4_if([$2], [[]], [],
-       [_m4_map([$1], [$2])])])
-m4_define([_m4_map],
-[m4_ifval([$2],
-         [$1(m4_fst($2))[]_m4_map([$1], m4_cdr($2))])])
-
-
-# m4_map_sep(MACRO, SEPARATOR, LIST)
-# ----------------------------------
-# Invoke MACRO($1), SEPARATOR, MACRO($2), ..., MACRO($N) where $1, $2... $N
-# are the elements of LIST (which can be lists themselves, for multiple
-# arguments MACROs).
-m4_define([m4_map_sep],
-[m4_if([$3], [[]], [],
-       [$1(m4_fst($3))[]_m4_map([$2[]$1], m4_cdr($3))])])
-
-
 ## ---------------------------------------- ##
 ## 6. Enhanced version of some primitives.  ##
 ## ---------------------------------------- ##
@@ -647,6 +624,27 @@ m4_define([m4_wrap],
 m4_define([m4_wrap_lifo],
 [_m4_wrap([$1[]])])
 
+## ------------------------- ##
+## 7. Quoting manipulation.  ##
+## ------------------------- ##
+
+
+# m4_apply(MACRO, LIST)
+# ---------------------
+# Invoke MACRO, with arguments provided from the quoted list of
+# comma-separated quoted arguments.  If LIST is empty, invoke MACRO
+# without arguments.  The expansion will not be concatenated with
+# subsequent text.
+m4_define([m4_apply],
+[m4_if([$2], [], [$1], [$1($2)])[]])
+
+# _m4_apply(MACRO, LIST)
+# ----------------------
+# Like m4_apply, except do nothing if LIST is empty.
+m4_define([_m4_apply],
+[m4_if([$2], [], [], [$1($2)[]])])
+
+
 ## -------------------------- ##
 ## 8. Implementing m4 loops.  ##
 ## -------------------------- ##
@@ -801,6 +799,65 @@ m4_define([m4_foreach_w],
 [m4_foreach([$1], m4_split(m4_normalize([$2])), [$3])])
 
 
+# m4_map(MACRO, LIST)
+# m4_mapall(MACRO, LIST)
+# ----------------------
+# Invoke MACRO($1), MACRO($2) etc. where $1, $2... are the elements of
+# LIST.  $1, $2... must in turn be lists, appropriate for m4_apply.
+# If LIST contains an empty sublist, m4_map skips the expansion of
+# MACRO, while m4_mapall expands MACRO with no arguments.
+#
+# Since LIST may be quite large, we want to minimize how often it
+# appears in the expansion.  Rather than use m4_car/m4_cdr iteration,
+# we unbox the list, ignore the second argument, and use m4_shift2 to
+# detect the end of recursion.  The mismatch in () is intentional; see
+# _m4_map.  For m4_map, an empty list behaves like an empty sublist
+# and gets ignored; for m4_mapall, we must special-case the empty
+# list.
+m4_define([m4_map],
+[_m4_map([_m4_apply([$1]], [], $2)])
+
+m4_define([m4_mapall],
+[m4_if([$2], [], [],
+       [_m4_map([m4_apply([$1]], [], $2)])])
+
+
+# m4_map_sep(MACRO, SEPARATOR, LIST)
+# m4_mapall_sep(MACRO, SEPARATOR, LIST)
+# -------------------------------------
+# Invoke MACRO($1), SEPARATOR, MACRO($2), ..., MACRO($N) where $1,
+# $2... $N are the elements of LIST, and are in turn lists appropriate
+# for m4_apply.  SEPARATOR is expanded, in order to allow the creation
+# of a list of arguments by using a single-quoted comma as the
+# separator.  For each empty sublist, m4_map_sep skips the expansion
+# of MACRO and SEPARATOR, while m4_mapall_sep expands MACRO with no
+# arguments.
+#
+# For m4_mapall_sep, merely expand the first iteration without the
+# separator, then include separator as part of subsequent recursion.
+# For m4_map_sep, things are trickier - we don't know if the first
+# list element is an empty sublist, so we must define a self-modifying
+# helper macro and use that as the separator instead.
+m4_define([m4_map_sep],
+[m4_pushdef([m4_Sep], [m4_define([m4_Sep], m4_defn([m4_unquote]))])]dnl
+[_m4_map([_m4_apply([m4_Sep([$2])[]$1]], [], $3)m4_popdef([m4_Sep])])
+
+m4_define([m4_mapall_sep],
+[m4_if([$3], [], [],
+       [m4_apply([$1], m4_car($3))_m4_map([m4_apply([$2[]$1]], $3)])])
+
+# _m4_map(PREFIX, IGNORED, SUBLIST, ...)
+# --------------------------------------
+# Common implementation for all four m4_map variants.  The mismatch in
+# the number of () is intentional.  PREFIX must supply a form of
+# m4_apply, the open `(', and the MACRO to be applied.  Each iteration
+# then appends `,', the current SUBLIST and the closing `)', then
+# recurses to the next SUBLIST.  IGNORED is an aid to ending recursion
+# efficiently.
+m4_define([_m4_map],
+[m4_if([$#], [2], [],
+       [$1, [$3])$0([$1], m4_shift2($@))])])
+
 
 ## --------------------------- ##
 ## 9. More diversion support.  ##
-- 
1.5.6.4


>From d67c52e8527291fd7d4dcc78c364b3dba84a2f14 Mon Sep 17 00:00:00 2001
From: Eric Blake <address@hidden>
Date: Fri, 15 Aug 2008 11:46:20 -0600
Subject: [PATCH] Remaining m4sugar merge from autoconf.

* data/m4sugar/m4sugar.m4: Copy entire file from autoconf.
* data/m4sugar/foreach.m4: New file, copied from autoconf.
* data/Makefile.am (dist_m4sugar_DATA): Distribute it.
* src/output.c (output_skeleton): Tell m4 how to find it.

Signed-off-by: Eric Blake <address@hidden>
---
 ChangeLog               |    6 +
 data/Makefile.am        |    2 +-
 data/m4sugar/foreach.m4 |  396 ++++++++++++++
 data/m4sugar/m4sugar.m4 | 1363 +++++++++++++++++++++++++++++++++++++----------
 src/output.c            |    4 +-
 5 files changed, 1489 insertions(+), 282 deletions(-)
 create mode 100644 data/m4sugar/foreach.m4

diff --git a/ChangeLog b/ChangeLog
index ffdc2b7..15ae566 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,11 @@
 2008-08-15  Eric Blake  <address@hidden>
 
+       Remaining m4sugar merge from autoconf.
+       * data/m4sugar/m4sugar.m4: Copy entire file from autoconf.
+       * data/m4sugar/foreach.m4: New file, copied from autoconf.
+       * data/Makefile.am (dist_m4sugar_DATA): Distribute it.
+       * src/output.c (output_skeleton): Tell m4 how to find it.
+
        Partial m4sugar merge from autoconf: m4_map.
        * data/m4sugar/m4sugar.m4 (m4_fst): Delete.
        (m4_map, m4_map_sep, _m4_map): Rewrite more efficiently.
diff --git a/data/Makefile.am b/data/Makefile.am
index a2e4a1b..ce15dac 100644
--- a/data/Makefile.am
+++ b/data/Makefile.am
@@ -19,7 +19,7 @@ dist_pkgdata_DATA = README bison.m4 \
    java-skel.m4 java.m4 lalr1.java
 
 m4sugardir = $(pkgdatadir)/m4sugar
-dist_m4sugar_DATA = m4sugar/m4sugar.m4
+dist_m4sugar_DATA = m4sugar/m4sugar.m4 m4sugar/foreach.m4
 
 xsltdir = $(pkgdatadir)/xslt
 dist_xslt_DATA =                               \
diff --git a/data/m4sugar/foreach.m4 b/data/m4sugar/foreach.m4
new file mode 100644
index 0000000..e54e30e
--- /dev/null
+++ b/data/m4sugar/foreach.m4
@@ -0,0 +1,396 @@
+#                                                  -*- Autoconf -*-
+# This file is part of Autoconf.
+# foreach-based replacements for recursive functions.
+# Speeds up GNU M4 1.4.x by avoiding quadratic $@ recursion, but penalizes
+# GNU M4 1.6 by requiring more memory and macro expansions.
+#
+# Copyright (C) 2008 Free Software Foundation, Inc.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# As a special exception, the Free Software Foundation gives unlimited
+# permission to copy, distribute and modify the configure scripts that
+# are the output of Autoconf.  You need not follow the terms of the GNU
+# General Public License when using or distributing such scripts, even
+# though portions of the text of Autoconf appear in them.  The GNU
+# General Public License (GPL) does govern all other use of the material
+# that constitutes the Autoconf program.
+#
+# Certain portions of the Autoconf source text are designed to be copied
+# (in certain cases, depending on the input) into the output of
+# Autoconf.  We call these the "data" portions.  The rest of the Autoconf
+# source text consists of comments plus executable code that decides which
+# of the data portions to output in any given case.  We call these
+# comments and executable code the "non-data" portions.  Autoconf never
+# copies any of the non-data portions into its output.
+#
+# This special exception to the GPL applies to versions of Autoconf
+# released by the Free Software Foundation.  When you make and
+# distribute a modified version of Autoconf, you may extend this special
+# exception to the GPL to apply to your modified version as well, *unless*
+# your modified version has the potential to copy into its output some
+# of the text that was the non-data portion of the version that you started
+# with.  (In other words, unless your change moves or copies text from
+# the non-data portions to the data portions.)  If your modification has
+# such potential, you must delete any notice of this special exception
+# to the GPL from your modified version.
+#
+# Written by Eric Blake.
+#
+
+# In M4 1.4.x, every byte of $@ is rescanned.  This means that an
+# algorithm on n arguments that recurses with one less argument each
+# iteration will scan n * (n + 1) / 2 arguments, for O(n^2) time.  In
+# M4 1.6, this was fixed so that $@ is only scanned once, then
+# back-references are made to information stored about the scan.
+# Thus, n iterations need only scan n arguments, for O(n) time.
+# Additionally, in M4 1.4.x, recursive algorithms did not clean up
+# memory very well, requiring O(n^2) memory rather than O(n) for n
+# iterations.
+#
+# This file is designed to overcome the quadratic nature of $@
+# recursion by writing a variant of m4_foreach that uses m4_for rather
+# than $@ recursion to operate on the list.  This involves more macro
+# expansions, but avoids the need to rescan a quadratic number of
+# arguments, making these replacements very attractive for M4 1.4.x.
+# On the other hand, in any version of M4, expanding additional macros
+# costs additional time; therefore, in M4 1.6, where $@ recursion uses
+# fewer macros, these replacements actually pessimize performance.
+# Additionally, the use of $10 to mean the tenth argument violates
+# POSIX; although all versions of m4 1.4.x support this meaning, a
+# future m4 version may switch to take it as the first argument
+# concatenated with a literal 0, so the implementations in this file
+# are not future-proof.  Thus, this file is conditionally included as
+# part of m4_init(), only when it is detected that M4 probably has
+# quadratic behavior (ie. it lacks the macro __m4_version__).
+
+# m4_foreach(VARIABLE, LIST, EXPRESSION)
+# --------------------------------------
+# Expand EXPRESSION assigning each value of the LIST to VARIABLE.
+# LIST should have the form `item_1, item_2, ..., item_n', i.e. the
+# whole list must *quoted*.  Quote members too if you don't want them
+# to be expanded.
+#
+# This version minimizes the number of times that $@ is evaluated by
+# using m4_for to generate a boilerplate into VARIABLE then passing $@
+# to that temporary macro.  Thus, the recursion is done in m4_for
+# without reparsing any user input, and is not quadratic.  For an idea
+# of how this works, note that m4_foreach(i,[1,2],[i]) defines i to be
+#   m4_define([$1],[$3])$2[]m4_define([$1],[$4])$2[]m4_popdef([i])
+# then calls i([i],[i],[1],[2]).
+m4_define([m4_foreach],
+[m4_if([$2], [], [], [_$0([$1], [$3], $2)])])
+
+m4_define([_m4_foreach],
+[m4_define([$1], m4_pushdef([$1])_m4_for([$1], [3], [$#], [1],
+    [$0_([1], [2], _m4_defn([$1]))])[m4_popdef([$1])])m4_indir([$1], $@)])
+
+m4_define([_m4_foreach_],
+[[m4_define([$$1], [$$3])$$2[]]])
+
+# m4_case(SWITCH, VAL1, IF-VAL1, VAL2, IF-VAL2, ..., DEFAULT)
+# -----------------------------------------------------------
+# Find the first VAL that SWITCH matches, and expand the corresponding
+# IF-VAL.  If there are no matches, expand DEFAULT.
+#
+# Use m4_for to create a temporary macro in terms of a boilerplate
+# m4_if with final cleanup.  If $# is even, we have DEFAULT; if it is
+# odd, then rounding the last $# up in the temporary macro is
+# harmless.  For example, both m4_case(1,2,3,4,5) and
+# m4_case(1,2,3,4,5,6) result in the intermediate _m4_case being
+#   m4_if([$1],[$2],[$3],[$1],[$4],[$5],_m4_popdef([_m4_case])[$6])
+m4_define([m4_case],
+[m4_if(m4_eval([$# <= 2]), [1], [$2],
+[m4_pushdef([_$0], [m4_if(]m4_for([_m4_count], [2], m4_decr([$#]), [2],
+     [_$0_([1], _m4_count, m4_incr(_m4_count))])[_m4_popdef(
+        [_$0])]m4_dquote($m4_eval([($# + 1) & ~1]))[)])_$0($@)])])
+
+m4_define([_m4_case_],
+[[[$$1],[$$2],[$$3],]])
+
+# m4_bmatch(SWITCH, RE1, VAL1, RE2, VAL2, ..., DEFAULT)
+# -----------------------------------------------------
+# m4 equivalent of
+#
+# if (SWITCH =~ RE1)
+#   VAL1;
+# elif (SWITCH =~ RE2)
+#   VAL2;
+# elif ...
+#   ...
+# else
+#   DEFAULT
+#
+# We build the temporary macro _m4_b:
+#   m4_define([_m4_b], _m4_defn([_m4_bmatch]))_m4_b([$1], [$2], [$3])...
+#   _m4_b([$1], [$m-1], [$m])_m4_b([], [], [$m+1]_m4_popdef([_m4_b]))
+# then invoke m4_unquote(_m4_b($@)), for concatenation with later text.
+m4_define([m4_bmatch],
+[m4_if([$#], 0, [m4_fatal([$0: too few arguments: $#])],
+       [$#], 1, [m4_fatal([$0: too few arguments: $#: $1])],
+       [$#], 2, [$2],
+       [m4_define([_m4_b], m4_pushdef([_m4_b])[m4_define([_m4_b],
+  _m4_defn([_$0]))]_m4_for([_m4_b], [3], m4_eval([($# + 1) / 2 * 2 - 1]),
+  [2], [_$0_([1], m4_decr(_m4_b), _m4_b)])[_m4_b([], [],]m4_dquote(
+  [$]m4_incr(_m4_b))[_m4_popdef([_m4_b]))])m4_unquote(_m4_b($@))])])
+
+m4_define([_m4_bmatch],
+[m4_if(m4_bregexp([$1], [$2]), [-1], [], [[$3]m4_define([$0])])])
+
+m4_define([_m4_bmatch_],
+[[_m4_b([$$1], [$$2], [$$3])]])
+
+
+# m4_cond(TEST1, VAL1, IF-VAL1, TEST2, VAL2, IF-VAL2, ..., [DEFAULT])
+# -------------------------------------------------------------------
+# Similar to m4_if, except that each TEST is expanded when encountered.
+# If the expansion of TESTn matches the string VALn, the result is IF-VALn.
+# The result is DEFAULT if no tests passed.  This macro allows
+# short-circuiting of expensive tests, where it pays to arrange quick
+# filter tests to run first.
+#
+# m4_cond already guarantees either 3*n or 3*n + 1 arguments, 1 <= n.
+# We only have to speed up _m4_cond, by building the temporary _m4_c:
+#   m4_define([_m4_c], _m4_defn([m4_unquote]))_m4_c([m4_if(($1), [($2)],
+#   [[$3]m4_define([_m4_c])])])_m4_c([m4_if(($4), [($5)],
+#   [[$6]m4_define([_m4_c])])])..._m4_c([m4_if(($m-2), [($m-1)],
+#   [[$m]m4_define([_m4_c])])])_m4_c([[$m+1]]_m4_popdef([_m4_c]))
+# We invoke m4_unquote(_m4_c($@)), for concatenation with later text.
+m4_define([_m4_cond],
+[m4_define([_m4_c], m4_pushdef([_m4_c])[m4_define([_m4_c],
+  _m4_defn([m4_unquote]))]_m4_for([_m4_c], [2], m4_eval([$# / 3 * 3 - 1]), [3],
+  [$0_(m4_decr(_m4_c), _m4_c, m4_incr(_m4_c))])[_m4_c(]m4_dquote(m4_dquote(
+  [$]m4_eval([$# / 3 * 3 + 1])))[_m4_popdef([_m4_c]))])m4_unquote(_m4_c($@))])
+
+m4_define([_m4_cond_],
+[[_m4_c([m4_if(($$1), [($$2)], [[$$3]m4_define([_m4_c])])])]])
+
+# m4_bpatsubsts(STRING, RE1, SUBST1, RE2, SUBST2, ...)
+# ----------------------------------------------------
+# m4 equivalent of
+#
+#   $_ = STRING;
+#   s/RE1/SUBST1/g;
+#   s/RE2/SUBST2/g;
+#   ...
+#
+# m4_bpatsubsts already validated an odd number of arguments; we only
+# need to speed up _m4_bpatsubsts.  To avoid nesting, we build the
+# temporary _m4_p:
+#   m4_define([_m4_p], [$1])m4_define([_m4_p],
+#   m4_bpatsubst(m4_dquote(_m4_defn([_m4_p])), [$2], [$3]))m4_define([_m4_p],
+#   m4_bpatsubst(m4_dquote(_m4_defn([_m4_p])), [$4], [$5]))m4_define
([_m4_p],...
+#   m4_bpatsubst(m4_dquote(_m4_defn([_m4_p])), [$m-1], [$m]))m4_unquote(
+#   _m4_defn([_m4_p])_m4_popdef([_m4_p]))
+m4_define([_m4_bpatsubsts],
+[m4_define([_m4_p], m4_pushdef([_m4_p])[m4_define([_m4_p],
+  ]m4_dquote([$]1)[)]_m4_for([_m4_p], [3], [$#], [2], [$0_(m4_decr(_m4_p),
+  _m4_p)])[m4_unquote(_m4_defn([_m4_p])_m4_popdef([_m4_p]))])_m4_p($@)])
+
+m4_define([_m4_bpatsubsts_],
+[[m4_define([_m4_p],
+m4_bpatsubst(m4_dquote(_m4_defn([_m4_p])), [$$1], [$$2]))]])
+
+# m4_shiftn(N, ...)
+# -----------------
+# Returns ... shifted N times.  Useful for recursive "varargs" constructs.
+#
+# m4_shiftn already validated arguments; we only need to speed up
+# _m4_shiftn.  If N is 3, then we build the temporary _m4_s, defined as
+#   ,[$5],[$6],...,[$m]_m4_popdef([_m4_s])
+# before calling m4_shift(_m4_s($@)).
+m4_define([_m4_shiftn],
+[m4_define([_m4_s],
+          m4_pushdef([_m4_s])_m4_for([_m4_s], m4_eval([$1 + 2]), [$#], [1],
+  [[,]m4_dquote([$]_m4_s)])[_m4_popdef([_m4_s])])m4_shift(_m4_s($@))])
+
+# m4_do(STRING, ...)
+# ------------------
+# This macro invokes all its arguments (in sequence, of course).  It is
+# useful for making your macros more structured and readable by dropping
+# unnecessary dnl's and have the macros indented properly.
+#
+# Here, we use the temporary macro _m4_do, defined as
+#   $1[]$2[]...[]$n[]_m4_popdef([_m4_do])
+m4_define([m4_do],
+[m4_if([$#], [0], [],
+       [m4_define([_$0], m4_pushdef([_$0])_m4_for([_$0], [1], [$#], [1],
+                 [$_$0[[]]])[_m4_popdef([_$0])])_$0($@)])])
+
+# m4_dquote_elt(ARGS)
+# -------------------
+# Return ARGS as an unquoted list of double-quoted arguments.
+#
+# m4_foreach to the rescue.  It's easier to shift off the leading comma.
+m4_define([m4_dquote_elt],
+[m4_shift(m4_foreach([_m4_elt], address@hidden, 
[,m4_dquote(_m4_defn([_m4_elt]))]))])
+
+# m4_reverse(ARGS)
+# ----------------
+# Output ARGS in reverse order.
+#
+# Invoke _m4_r($@) with the temporary _m4_r built as
+#   [$m], [$m-1], ..., [$2], [$1]_m4_popdef([_m4_r])
+m4_define([m4_reverse],
+[m4_if([$#], [0], [], [$#], [1], [[$1]],
+[m4_define([_m4_r], m4_dquote([$$#])m4_pushdef([_m4_r])_m4_for([_m4_r],
+      m4_decr([$#]), [1], [-1],
+    [[, ]m4_dquote([$]_m4_r)])[_m4_popdef([_m4_r])])_m4_r($@)])])
+
+
+# m4_map(MACRO, LIST)
+# -------------------
+# Invoke MACRO($1), MACRO($2) etc. where $1, $2... are the elements
+# of LIST.  $1, $2... must in turn be lists, appropriate for m4_apply.
+#
+# m4_map/m4_map_sep only execute once; the speedup comes in fixing
+# _m4_map.  The mismatch in () is intentional, since $1 supplies the
+# opening `(' (but it sure looks odd!).  Build the temporary _m4_m:
+#   $1, [$3])$1, [$4])...$1, [$m])_m4_popdef([_m4_m])
+m4_define([_m4_map],
+[m4_if([$#], [2], [],
+       [m4_define([_m4_m], m4_pushdef([_m4_m])_m4_for([_m4_m], [3], [$#], [1],
+   [$0_([1], _m4_m)])[_m4_popdef([_m4_m])])_m4_m($@)])])
+
+m4_define([_m4_map_],
+[[$$1, [$$2])]])
+
+# m4_transform(EXPRESSION, ARG...)
+# --------------------------------
+# Expand EXPRESSION([ARG]) for each argument.  More efficient than
+# m4_foreach([var], [ARG...], [EXPRESSION(m4_defn([var]))])
+#
+# Invoke the temporary macro _m4_transform, defined as:
+#   $1([$2])[]$1([$3])[]...$1([$m])[]_m4_popdef([_m4_transform])
+m4_define([m4_transform],
+[m4_if([$#], [0], [m4_fatal([$0: too few arguments: $#])],
+       [$#], [1], [],
+       [m4_define([_$0], m4_pushdef([_$0])_m4_for([_$0], [2], [$#], [1],
+   [_$0_([1], _$0)])[_m4_popdef([_$0])])_$0($@)])])
+
+m4_define([_m4_transform_],
+[[$$1([$$2])[]]])
+
+# m4_transform_pair(EXPRESSION, [END-EXPR = EXPRESSION], ARG...)
+# --------------------------------------------------------------
+# Perform a pairwise grouping of consecutive ARGs, by expanding
+# EXPRESSION([ARG1], [ARG2]).  If there are an odd number of ARGs, the
+# final argument is expanded with END-EXPR([ARGn]).
+#
+# Build the temporary macro _m4_transform_pair, with the $2([$m+1])
+# only output if $# is odd:
+#   $1([$3], [$4])[]$1([$5], [$6])[]...$1([$m-1],
+#   [$m])[]m4_default([$2], [$1])([$m+1])[]_m4_popdef([_m4_transform_pair])
+m4_define([m4_transform_pair],
+[m4_if([$#], [0], [m4_fatal([$0: too few arguments: $#])],
+       [$#], [1], [m4_fatal([$0: too few arguments: $#: $1])],
+       [$#], [2], [],
+       [$#], [3], [m4_default([$2], [$1])([$3])[]],
+       [m4_define([_$0], m4_pushdef([_$0])_m4_for([_$0], [3],
+   m4_eval([$# / 2 * 2 - 1]), [2], [_$0_([1], _$0, m4_incr(_$0))])_$0_end(
+   [1], [2], [$#])[_m4_popdef([_$0])])_$0($@)])])
+
+m4_define([_m4_transform_pair_],
+[[$$1([$$2], [$$3])[]]])
+
+m4_define([_m4_transform_pair_end],
+[m4_if(m4_eval([$3 & 1]), [1], [[m4_default([$$2], [$$1])([$$3])[]]])])
+
+# m4_join(SEP, ARG1, ARG2...)
+# ---------------------------
+# Produce ARG1SEPARG2...SEPARGn.  Avoid back-to-back SEP when a given ARG
+# is the empty string.  No expansion is performed on SEP or ARGs.
+#
+# Use a self-modifying separator, since we don't know how many
+# arguments might be skipped before a separator is first printed, but
+# be careful if the separator contains $.  m4_foreach to the rescue.
+m4_define([m4_join],
+[m4_pushdef([_m4_sep], [m4_define([_m4_sep], _m4_defn([m4_echo]))])]dnl
+[m4_foreach([_m4_arg], [m4_shift($@)],
+           [m4_ifset([_m4_arg], [_m4_sep([$1])_m4_defn([_m4_arg])])])]dnl
+[_m4_popdef([_m4_sep])])
+
+# m4_joinall(SEP, ARG1, ARG2...)
+# ------------------------------
+# Produce ARG1SEPARG2...SEPARGn.  An empty ARG results in back-to-back SEP.
+# No expansion is performed on SEP or ARGs.
+#
+# A bit easier than m4_join.  m4_foreach to the rescue.
+m4_define([m4_joinall],
+[[$2]m4_if(m4_eval([$# <= 2]), [1], [],
+          [m4_foreach([_m4_arg], [m4_shift2($@)],
+                      [[$1]_m4_defn([_m4_arg])])])])
+
+# m4_list_cmp(A, B)
+# -----------------
+# Compare the two lists of integer expressions A and B.
+#
+# First, insert padding so that both lists are the same length; the
+# trailing +0 is necessary to handle a missing list.  Next, create a
+# temporary macro to perform pairwise comparisons until an inequality
+# is found.  For example, m4_list_cmp([1], [1,2]) creates _m4_cmp as
+#   m4_if(m4_eval([($1) != ($3)]), [1], [m4_cmp([$1], [$3])],
+#         m4_eval([($2) != ($4)]), [1], [m4_cmp([$2], [$4])],
+#         [0]_m4_popdef([_m4_cmp], [_m4_size]))
+# then calls _m4_cmp([1+0], [0], [1], [2+0])
+m4_define([m4_list_cmp],
+[m4_if([$1], [$2], 0,
+  [m4_pushdef([_m4_size])_$0($1+0_m4_list_pad(m4_count($1), m4_count($2)),
+                            $2+0_m4_list_pad(m4_count($2), m4_count($1)))])])
+
+m4_define([_m4_list_pad],
+[m4_if(m4_eval($1 < $2), [1],
+       [_m4_for([_m4_size], m4_incr([$1]), [$2], [1], [,0])])])
+
+m4_define([_m4_list_cmp],
+[m4_define([_m4_size], m4_eval([$# >> 1]))]dnl
+[m4_define([_m4_cmp], m4_pushdef([_m4_cmp])[m4_if(]_m4_for([_m4_cmp],
+   [1], _m4_size, [1], [$0_(_m4_cmp, m4_eval(_m4_cmp + _m4_size))])[
+      [0]_m4_popdef([_m4_cmp], [_m4_size]))])_m4_cmp($@)])
+
+m4_define([_m4_list_cmp_],
+[[m4_eval([($$1) != ($$2)]), [1], [m4_cmp([$$1], [$$2])],
+]])
+
+# m4_max(EXPR, ...)
+# m4_min(EXPR, ...)
+# -----------------
+# Return the decimal value of the maximum (or minimum) in a series of
+# integer expressions.
+#
+# m4_foreach to the rescue; we only need to replace _m4_minmax.  Here,
+# we need a temporary macro to track the best answer so far, so that
+# the foreach expression is tractable.
+m4_define([_m4_minmax],
+[m4_pushdef([_m4_best], m4_eval([$2]))m4_foreach([_m4_arg], [m4_shift2($@)],
+    [m4_define([_m4_best], $1(_m4_best, _m4_defn([_m4_arg])))])]dnl
+[_m4_best[]_m4_popdef([_m4_best])])
+
+# m4_set_add_all(SET, VALUE...)
+# -----------------------------
+# Add each VALUE into SET.  This is O(n) in the number of VALUEs, and
+# can be faster than calling m4_set_add for each VALUE.
+#
+# m4_foreach to the rescue.  If no deletions have occurred, then avoid
+# the speed penalty of m4_set_add.
+m4_define([m4_set_add_all],
+[m4_if([$#], [0], [], [$#], [1], [],
+       [m4_define([_m4_set_size($1)], m4_eval(m4_set_size([$1])
+         + m4_len(m4_foreach([_m4_arg], [m4_shift($@)],
+    m4_ifdef([_m4_set_cleanup($1)],
+            [[m4_set_add([$1], _m4_defn([_m4_arg]))]],
+            [[m4_ifdef([_m4_set([$1],]_m4_defn([_m4_arg])[)], [],
+                       [m4_define([_m4_set([$1],]_m4_defn([_m4_arg])[)],
+                                  [1])m4_pushdef([_m4_set([$1])],
+       _m4_defn([_m4_arg]))-])]])))))])])
diff --git a/data/m4sugar/m4sugar.m4 b/data/m4sugar/m4sugar.m4
index be39096..b9ccd5b 100644
--- a/data/m4sugar/m4sugar.m4
+++ b/data/m4sugar/m4sugar.m4
@@ -149,7 +149,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])
@@ -232,7 +232,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
 ])
 
@@ -333,7 +333,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])])
 
 
@@ -402,6 +402,60 @@ m4_define([m4_cdr],
        [$#], 1, [],
        [m4_dquote(m4_shift($@))])])
 
+# _m4_cdr(LIST)
+# -------------
+# Like m4_cdr, except include a leading comma unless only one element
+# remains.  Why?  Because comparing a large list against [] is more
+# expensive in expansion time than comparing the number of arguments; so
+# _m4_cdr can be used to reduce the number of arguments when it is time
+# to end recursion.
+m4_define([_m4_cdr],
+[m4_if([$#], 1, [],
+       [, m4_dquote(m4_shift($@))])])
+
+
+
+# m4_cond(TEST1, VAL1, IF-VAL1, TEST2, VAL2, IF-VAL2, ..., [DEFAULT])
+# -------------------------------------------------------------------
+# Similar to m4_if, except that each TEST is expanded when encountered.
+# If the expansion of TESTn matches the string VALn, the result is IF-VALn.
+# The result is DEFAULT if no tests passed.  This macro allows
+# short-circuiting of expensive tests, where it pays to arrange quick
+# filter tests to run first.
+#
+# For an example, consider a previous implementation of _AS_QUOTE_IFELSE:
+#
+#    m4_if(m4_index([$1], [\]), [-1], [$2],
+#          m4_eval(m4_index([$1], [\\]) >= 0), [1], [$2],
+#          m4_eval(m4_index([$1], [\$]) >= 0), [1], [$2],
+#          m4_eval(m4_index([$1], [\`]) >= 0), [1], [$3],
+#          m4_eval(m4_index([$1], [\"]) >= 0), [1], [$3],
+#          [$2])
+#
+# Here, m4_index is computed 5 times, and m4_eval 4, even if $1 contains
+# no backslash.  It is more efficient to do:
+#
+#    m4_cond([m4_index([$1], [\])], [-1], [$2],
+#            [m4_eval(m4_index([$1], [\\]) >= 0)], [1], [$2],
+#            [m4_eval(m4_index([$1], [\$]) >= 0)], [1], [$2],
+#            [m4_eval(m4_index([$1], [\`]) >= 0)], [1], [$3],
+#            [m4_eval(m4_index([$1], [\"]) >= 0)], [1], [$3],
+#            [$2])
+#
+# In the common case of $1 with no backslash, only one m4_index expansion
+# occurs, and m4_eval is avoided altogether.
+m4_define([m4_cond],
+[m4_if([$#], [0], [m4_fatal([$0: cannot be called without arguments])],
+       [$#], [1], [$1],
+       m4_eval([$# % 3]), [2], [m4_fatal([$0: missing an argument])],
+       [_$0($@)])])
+
+m4_define([_m4_cond],
+[m4_if(($1), [($2)], [$3],
+       [$#], [3], [],
+       [$#], [4], [$4],
+       [$0(m4_shift3($@))])])
+
 
 ## ---------------------------------------- ##
 ## 6. Enhanced version of some primitives.  ##
@@ -437,17 +491,6 @@ m4_define([_m4_bpatsubsts],
           m4_shift3($@))])])
 
 
-# m4_do(STRING, ...)
-# ------------------
-# This macro invokes all its arguments (in sequence, of course).  It is
-# useful for making your macros more structured and readable by dropping
-# unnecessary dnl's and have the macros indented properly.
-m4_define([m4_do],
-[m4_if($#, 0, [],
-       $#, 1, [$1],
-       [$1[]m4_do(m4_shift($@))])])
-
-
 # m4_define_default(MACRO, VALUE)
 # -------------------------------
 # If MACRO is undefined, set it to VALUE.
@@ -458,27 +501,46 @@ m4_define([m4_define_default],
 # m4_default(EXP1, EXP2)
 # ----------------------
 # Returns EXP1 if non empty, otherwise EXP2.
+#
+# This macro is called on hot paths, so inline the contents of m4_ifval,
+# for one less round of expansion.
 m4_define([m4_default],
-[m4_ifval([$1], [$1], [$2])])
+[m4_if([$1], [], [$2], [$1])])
 
 
 # m4_defn(NAME)
 # -------------
-# Unlike to the original, don't tolerate popping something which is
-# undefined.
-m4_define([m4_defn],
-[m4_ifndef([$1],
-          [m4_fatal([$0: undefined macro: $1])])dnl
-m4_builtin([defn], $@)])
+# Like the original, except guarantee a warning when using something which is
+# 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,
+# (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_if([$#], [0], [[$0]],
+       [$#], [1], [m4_ifdef([$1], [_m4_defn([$1])],
+                           [m4_fatal([$0: undefined macro: $1])])],
+       [m4_foreach([_m4_macro], address@hidden, 
[$0(_m4_defn([_m4_macro]))])])])])
 
 
 # _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])])])
 
 
@@ -486,8 +548,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])])])
 
 
@@ -502,37 +564,23 @@ _m4_dumpdefs_down([$1])])
 
 # m4_popdef(NAME)
 # ---------------
-# Unlike to the original, don't tolerate popping something which is
-# undefined.
-m4_define([m4_popdef],
-[m4_ifndef([$1],
-          [m4_fatal([$0: undefined macro: $1])])dnl
-m4_builtin([popdef], $@)])
-
-
-# m4_quote(ARGS)
-# --------------
-# Return ARGS as a single arguments.
+# Like the original, except guarantee a warning when using something which is
+# undefined (unlike M4 1.4.x).
 #
-# It is important to realize the difference between `m4_quote(exp)' and
-# `[exp]': in the first case you obtain the quoted *result* of the
-# expansion of EXP, while in the latter you just obtain the string
-# `exp'.
-m4_define([m4_quote],  [[$*]])
-m4_define([m4_dquote],  address@hidden)
-
-
-# m4_noquote(STRING)
-# ------------------
-# Return the result of ignoring all quotes in STRING and invoking the
-# macros it contains.  Amongst other things, this is useful for enabling
-# macro invocations inside strings with [] blocks (for instance regexps
-# and help-strings).  On the other hand, since all quotes are disabled,
-# any macro expanded during this time that relies on nested [] quoting
-# will likely crash and burn.  This macro is seldom useful; consider
-# m4_unquote or m4_expand instead.
-m4_define([m4_noquote],
-[m4_changequote(-=<{,}>=-)$1-=<{}>=-m4_changequote([,])])
+# 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_if([$#], [0], [[$0]],
+       [$#], [1], [m4_ifdef([$1], [_m4_popdef([$1])],
+                           [m4_fatal([$0: undefined macro: $1])])],
+       [m4_foreach([_m4_macro], address@hidden, 
[$0(_m4_defn([_m4_macro]))])])])])
 
 
 # m4_shiftn(N, ...)
@@ -581,32 +629,33 @@ m4_define([_m4_shift3],
 
 # m4_undefine(NAME)
 # -----------------
-# Unlike to the original, don't tolerate undefining something which is
-# undefined.
-m4_define([m4_undefine],
-[m4_ifndef([$1],
-          [m4_fatal([$0: undefined macro: $1])])dnl
-m4_builtin([undefine], $@)])
-
-
-# m4_unquote(ARGS)
-# ----------------
-# Remove one layer of quotes from each ARG, performing one level of
-# expansion.  For one argument, m4_unquote([arg]) is more efficient than
-# m4_do([arg]), but for multiple arguments, the difference is that
-# m4_unquote separates arguments with commas while m4_do concatenates.
-m4_define([m4_unquote], [$*])
+# Like the original, except guarantee a warning when using something which is
+# 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,
+# (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_if([$#], [0], [[$0]],
+       [$#], [1], [m4_ifdef([$1], [_m4_undefine([$1])],
+                           [m4_fatal([$0: undefined macro: $1])])],
+       [m4_foreach([_m4_macro], address@hidden, 
[$0(_m4_defn([_m4_macro]))])])])])
 
 # _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)
 # -------------
@@ -645,6 +694,146 @@ m4_define([_m4_apply],
 [m4_if([$2], [], [], [$1($2)[]])])
 
 
+# m4_count(ARGS)
+# --------------
+# Return a count of how many ARGS are present.
+m4_define([m4_count], [$#])
+
+
+# m4_do(STRING, ...)
+# ------------------
+# This macro invokes all its arguments (in sequence, of course).  It is
+# useful for making your macros more structured and readable by dropping
+# unnecessary dnl's and have the macros indented properly.  No concatenation
+# occurs after a STRING; use m4_unquote(m4_join(,STRING)) for that.
+m4_define([m4_do],
+[m4_if([$#], 0, [],
+       [$#], 1, [$1[]],
+       [$1[]$0(m4_shift($@))])])
+
+
+# m4_dquote(ARGS)
+# ---------------
+# Return ARGS as a quoted list of quoted arguments.
+m4_define([m4_dquote],  address@hidden)
+
+
+# m4_dquote_elt(ARGS)
+# -------------------
+# Return ARGS as an unquoted list of double-quoted arguments.
+m4_define([m4_dquote_elt],
+[m4_if([$#], [0], [],
+       [$#], [1], [[[$1]]],
+       [[[$1]],$0(m4_shift($@))])])
+
+
+# m4_echo(ARGS)
+# -------------
+# Return the ARGS, with the same level of quoting.  Whitespace after
+# unquoted commas are consumed.
+m4_define([m4_echo], address@hidden)
+
+
+# m4_expand(ARG)
+# --------------
+# Return the expansion of ARG as a single string.  Unlike m4_quote($1), this
+# correctly preserves whitespace following single-quoted commas that appeared
+# within ARG.
+#
+#   m4_define([active], [ACT, IVE])
+#   m4_define([active2], [[ACT, IVE]])
+#   m4_quote(active, active2)
+#   => ACT,IVE,ACT, IVE
+#   m4_expand([active, active2])
+#   => ACT, IVE, ACT, IVE
+#
+# Unfortunately, due to limitations in m4, ARG must expand to something
+# with balanced quotes (use quadrigraphs to get around this).  The input
+# is not likely to have unbalanced -=<{(/)}>=- quotes, and it is possible
+# to have unbalanced (), provided it was specified with proper [] quotes.
+#
+# Exploit that extra () will group unquoted commas and the following
+# whitespace, then convert () to [].  m4_bpatsubst can't handle newlines
+# inside $1, and m4_substr strips quoting.  So we (ab)use m4_changequote.
+m4_define([m4_expand], [_$0(-=<{($1)}>=-)])
+m4_define([_m4_expand],
+[m4_changequote([-=<{(], [)}>=-])$1m4_changequote([, ])])
+
+
+# m4_ignore(ARGS)
+# ---------------
+# Expands to nothing.  Useful for conditionally ignoring an arbitrary
+# number of arguments (see _m4_list_cmp for an example).
+m4_define([m4_ignore])
+
+
+# m4_make_list(ARGS)
+# ------------------
+# Similar to m4_dquote, this creates a quoted list of quoted ARGS.  This
+# version is less efficient than m4_dquote, but separates each argument
+# with a comma and newline, rather than just comma, for readability.
+# When developing an m4sugar algorithm, you could temporarily use
+#   m4_pushdef([m4_dquote],m4_defn([m4_make_list]))
+# around your code to make debugging easier.
+m4_define([m4_make_list], [m4_join([,
+], m4_dquote_elt($@))])
+
+
+# m4_noquote(STRING)
+# ------------------
+# Return the result of ignoring all quotes in STRING and invoking the
+# macros it contains.  Amongst other things, this is useful for enabling
+# macro invocations inside strings with [] blocks (for instance regexps
+# and help-strings).  On the other hand, since all quotes are disabled,
+# any macro expanded during this time that relies on nested [] quoting
+# will likely crash and burn.  This macro is seldom useful; consider
+# m4_unquote or m4_expand instead.
+m4_define([m4_noquote],
+[m4_changequote([-=<{(],[)}>=-])$1-=<{()}>=-m4_changequote([,])])
+
+
+# m4_quote(ARGS)
+# --------------
+# Return ARGS as a single argument.  Any whitespace after unquoted commas
+# is stripped.  There is always output, even when there were no arguments.
+#
+# It is important to realize the difference between `m4_quote(exp)' and
+# `[exp]': in the first case you obtain the quoted *result* of the
+# expansion of EXP, while in the latter you just obtain the string
+# `exp'.
+m4_define([m4_quote],  [[$*]])
+
+
+# _m4_quote(ARGS)
+# ---------------
+# Like m4_quote, except that when there are no arguments, there is no
+# output.  For conditional scenarios (such as passing _m4_quote as the
+# macro name in m4_mapall), this feature can be used to distinguish between
+# one argument of the empty string vs. no arguments.  However, in the
+# normal case with arguments present, this is less efficient than m4_quote.
+m4_define([_m4_quote],
+[m4_if([$#], [0], [], [[$*]])])
+
+
+# m4_reverse(ARGS)
+# ----------------
+# Output ARGS in reverse order.
+m4_define([m4_reverse],
+[m4_if([$#], [0], [], [$#], [1], [[$1]],
+       [$0(m4_shift($@)), [$1]])])
+
+
+# m4_unquote(ARGS)
+# ----------------
+# Remove one layer of quotes from each ARG, performing one level of
+# expansion.  For one argument, m4_unquote([arg]) is more efficient than
+# m4_do([arg]), but for multiple arguments, the difference is that
+# m4_unquote separates arguments with commas while m4_do concatenates.
+# Follow this macro with [] if concatenation with subsequent text is
+# undesired.
+m4_define([m4_unquote], [$*])
+
+
 ## -------------------------- ##
 ## 8. Implementing m4 loops.  ##
 ## -------------------------- ##
@@ -653,26 +842,36 @@ m4_define([_m4_apply],
 # m4_for(VARIABLE, FIRST, LAST, [STEP = +/-1], EXPRESSION)
 # --------------------------------------------------------
 # Expand EXPRESSION defining VARIABLE to FROM, FROM + 1, ..., TO with
-# increments of STEP.
-# Both limits are included, and bounds are checked for consistency.
+# increments of STEP.  Both limits are included, and bounds are
+# checked for consistency.  The algorithm is robust to indirect
+# VARIABLE names.  Changing VARIABLE inside EXPRESSION will not impact
+# the number of iterations.
+#
+# Uses _m4_defn for speed, and avoid dnl in the macro body.
 m4_define([m4_for],
-[m4_case(m4_sign(m4_eval($3 - $2)),
-        1, [m4_assert(m4_sign(m4_default($4, 1)) == 1)],
-       -1, [m4_assert(m4_sign(m4_default($4, -1)) == -1)])dnl
-m4_pushdef([$1], [$2])dnl
-m4_if(m4_eval([$3 > $2]), 1,
-      [_m4_for([$1], [$3], m4_default([$4], 1), [$5])],
-      [_m4_for([$1], [$3], m4_default([$4], -1), [$5])])dnl
-m4_popdef([$1])])
-
-
-# _m4_for(VARIABLE, FIRST, LAST, STEP, EXPRESSION)
+[m4_pushdef([$1], m4_eval([$2]))]dnl
+[m4_cond([m4_eval(([$3]) > ([$2]))], 1,
+          [m4_pushdef([_m4_step], m4_eval(m4_default([$4],
+             1)))m4_assert(_m4_step > 0)_$0([$1], _m4_defn([$1]),
+  m4_eval((([$3]) - ([$2])) / _m4_step * _m4_step + ([$2])),
+  _m4_step, [$5])],
+        [m4_eval(([$3]) < ([$2]))], 1,
+          [m4_pushdef([_m4_step], m4_eval(m4_default([$4],
+             -1)))m4_assert(_m4_step < 0)_$0([$1], _m4_defn([$1]),
+  m4_eval((([$2]) - ([$3])) / -(_m4_step) * _m4_step + ([$2])),
+  _m4_step, [$5])],
+        [m4_pushdef([_m4_step])$5])[]]dnl
+[m4_popdef([_m4_step], [$1])])
+
+
+# _m4_for(VARIABLE, COUNT, LAST, STEP, EXPRESSION)
 # ------------------------------------------------
-# Core of the loop, no consistency checks.
+# Core of the loop, no consistency checks, all arguments are plain
+# numbers.  Define VARIABLE to COUNT, expand EXPRESSION, then alter
+# COUNT by STEP and iterate if COUNT is not LAST.
 m4_define([_m4_for],
-[$4[]dnl
-m4_if($1, [$2], [],
-      [m4_define([$1], m4_eval($1+[$3]))_m4_for([$1], [$2], [$3], [$4])])])
+[m4_define([$1], [$2])$5[]m4_if([$2], [$3], [],
+      [$0([$1], m4_eval([$2 + $4]), [$3], [$4], [$5])])])
 
 
 # Implementing `foreach' loops in m4 is much more tricky than it may
@@ -775,13 +974,21 @@ m4_if($1, [$2], [],
 #
 #      | m4_foreach(Var, [[[active]], [[active]]], [-Var-])
 #     => -active--active-
+#
+# This macro is called frequently, so avoid extra expansions such as
+# m4_ifval and dnl.  Also, since $2 might be quite large, try to use it
+# as little as possible in _m4_foreach; each extra use requires that much
+# more memory for expansion.  So, rather than directly compare $2 against
+# [] and use m4_car/m4_cdr for recursion, we instead unbox the list (which
+# requires swapping the argument order in the helper), insert an ignored
+# third argument, and use m4_shift3 to detect when recursion is complete.
 m4_define([m4_foreach],
-[m4_pushdef([$1])_m4_foreach($@)m4_popdef([$1])])
+[m4_if([$2], [], [],
+       [m4_pushdef([$1])_$0([$1], [$3], [], $2)m4_popdef([$1])])])
 
 m4_define([_m4_foreach],
-[m4_ifval([$2],
-         [m4_define([$1], m4_car($2))$3[]dnl
-_m4_foreach([$1], m4_cdr($2), [$3])])])
+[m4_if([$#], [3], [],
+       [m4_define([$1], [$4])$2[]$0([$1], [$2], m4_shift3($@))])])
 
 
 # m4_foreach_w(VARIABLE, LIST, EXPRESSION)
@@ -796,7 +1003,7 @@ _m4_foreach([$1], m4_cdr($2), [$3])])])
 #    => -active--b--active-end
 #
 m4_define([m4_foreach_w],
-[m4_foreach([$1], m4_split(m4_normalize([$2])), [$3])])
+[m4_foreach([$1], m4_split(m4_normalize([$2]), [ ]), [$3])])
 
 
 # m4_map(MACRO, LIST)
@@ -839,7 +1046,7 @@ m4_define([m4_mapall],
 # list element is an empty sublist, so we must define a self-modifying
 # helper macro and use that as the separator instead.
 m4_define([m4_map_sep],
-[m4_pushdef([m4_Sep], [m4_define([m4_Sep], m4_defn([m4_unquote]))])]dnl
+[m4_pushdef([m4_Sep], [m4_define([m4_Sep], _m4_defn([m4_unquote]))])]dnl
 [_m4_map([_m4_apply([m4_Sep([$2])[]$1]], [], $3)m4_popdef([m4_Sep])])
 
 m4_define([m4_mapall_sep],
@@ -858,6 +1065,37 @@ m4_define([_m4_map],
 [m4_if([$#], [2], [],
        [$1, [$3])$0([$1], m4_shift2($@))])])
 
+# m4_transform(EXPRESSION, ARG...)
+# --------------------------------
+# Expand EXPRESSION([ARG]) for each argument.  More efficient than
+# m4_foreach([var], [ARG...], [EXPRESSION(m4_defn([var]))])
+m4_define([m4_transform],
+[m4_if([$#], [0], [m4_fatal([$0: too few arguments: $#])],
+       [$#], [1], [],
+       [$#], [2], [$1([$2])[]],
+       [$1([$2])[]$0([$1], m4_shift2($@))])])
+
+
+# m4_transform_pair(EXPRESSION, [END-EXPR = EXPRESSION], ARG...)
+# --------------------------------------------------------------
+# Perform a pairwise grouping of consecutive ARGs, by expanding
+# EXPRESSION([ARG1], [ARG2]).  If there are an odd number of ARGs, the
+# final argument is expanded with END-EXPR([ARGn]).
+#
+# For example:
+#   m4_define([show], [($*)m4_newline])dnl
+#   m4_transform_pair([show], [], [a], [b], [c], [d], [e])dnl
+#   => (a,b)
+#   => (c,d)
+#   => (e)
+m4_define([m4_transform_pair],
+[m4_if([$#], [0], [m4_fatal([$0: too few arguments: $#])],
+       [$#], [1], [m4_fatal([$0: too few arguments: $#: $1])],
+       [$#], [2], [],
+       [$#], [3], [m4_default([$2], [$1])([$3])[]],
+       [$#], [4], [$1([$3], [$4])[]],
+       [$1([$3], [$4])[]$0([$1], [$2], m4_shift(m4_shift3($@)))])])
+
 
 ## --------------------------- ##
 ## 9. More diversion support.  ##
@@ -876,32 +1114,33 @@ m4_define([_m4_divert],
 # KILL is only used to suppress output.
 m4_define([_m4_divert(KILL)],           -1)
 
+# The empty diversion name is a synonym for 0.
+m4_define([_m4_divert()],                0)
+
 
 # _m4_divert_n_stack
 # ------------------
 # 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)
 # -------------------------
 # Change the diversion stream to DIVERSION-NAME.
 m4_define([m4_divert],
-[m4_define([m4_divert_stack], m4_location[: $0: $1]_m4_divert_n_stack)dnl
-m4_builtin([divert], _m4_divert([$1]))dnl
-])
+[m4_define([m4_divert_stack], m4_location[: $0: $1]_m4_divert_n_stack)]dnl
+[m4_builtin([divert], _m4_divert([$1]))])
 
 
 # m4_divert_push(DIVERSION-NAME)
 # ------------------------------
 # Change the diversion stream to DIVERSION-NAME, while stacking old values.
 m4_define([m4_divert_push],
-[m4_pushdef([m4_divert_stack], m4_location[: $0: $1]_m4_divert_n_stack)dnl
-m4_pushdef([_m4_divert_diversion], [$1])dnl
-m4_builtin([divert], _m4_divert([$1]))dnl
-])
+[m4_pushdef([m4_divert_stack], m4_location[: $0: $1]_m4_divert_n_stack)]dnl
+[m4_pushdef([_m4_divert_diversion], [$1])]dnl
+[m4_builtin([divert], _m4_divert([$1]))])
 
 
 # m4_divert_pop([DIVERSION-NAME])
@@ -911,17 +1150,15 @@ m4_builtin([divert], _m4_divert([$1]))dnl
 # When we pop the last value from the stack, we divert to -1.
 m4_define([m4_divert_pop],
 [m4_ifndef([_m4_divert_diversion],
-          [m4_fatal([too many m4_divert_pop])])dnl
-m4_if([$1], [], [],
-      [$1], m4_defn([_m4_divert_diversion]), [],
-      [m4_fatal([$0($1): diversion mismatch: ]_m4_divert_n_stack)])dnl
-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]))],
-                   -1))dnl
-])
+          [m4_fatal([too many m4_divert_pop])])]dnl
+[m4_if([$1], [], [],
+       [$1], _m4_defn([_m4_divert_diversion]), [],
+       [m4_fatal([$0($1): diversion mismatch: ]_m4_divert_n_stack)])]dnl
+[_m4_popdef([m4_divert_stack], [_m4_divert_diversion])]dnl
+[m4_builtin([divert],
+           m4_ifdef([_m4_divert_diversion],
+                    [_m4_divert(_m4_defn([_m4_divert_diversion]))],
+                    -1))])
 
 
 # m4_divert_text(DIVERSION-NAME, CONTENT)
@@ -929,10 +1166,8 @@ m4_builtin([divert],
 # Output CONTENT into DIVERSION-NAME (which may be a number actually).
 # An end of line is appended for free to CONTENT.
 m4_define([m4_divert_text],
-[m4_divert_push([$1])dnl
-$2
-m4_divert_pop([$1])dnl
-])
+[m4_divert_push([$1])$2
+m4_divert_pop([$1])])
 
 
 # m4_divert_once(DIVERSION-NAME, CONTENT)
@@ -1234,7 +1469,7 @@ m4_define([m4_undivert],
 m4_define([m4_expansion_stack_push],
 [m4_pushdef([m4_expansion_stack],
            [$1]m4_ifdef([m4_expansion_stack], [
-m4_defn([m4_expansion_stack])]))])
+_m4_defn([m4_expansion_stack])]))])
 
 
 # m4_expansion_stack_pop
@@ -1248,7 +1483,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])])
 
 
@@ -1274,33 +1509,33 @@ m4_define([_m4_divert(GROW)],       10000)
 # _m4_defun_pro(MACRO-NAME)
 # -------------------------
 # The prologue for Autoconf macros.
+#
+# This is called frequently, so minimize the number of macro invocations
+# by avoiding dnl and m4_defn overhead.
 m4_define([_m4_defun_pro],
-[m4_ifndef([m4_expansion_stack], [_m4_defun_pro_outer[]])dnl
-m4_expansion_stack_push(m4_defn([m4_location($1)])[: $1 is expanded from...])
dnl
-m4_pushdef([_m4_expanding($1)])dnl
-])
+m4_do([[m4_ifdef([m4_expansion_stack], [], [_m4_defun_pro_outer[]])]],
+      [[m4_expansion_stack_push(_m4_defn(
+         [m4_location($1)])[: $1 is expanded from...])]],
+      [[m4_pushdef([_m4_expanding($1)])]]))
 
 m4_define([_m4_defun_pro_outer],
-[m4_copy([_m4_divert_diversion], [_m4_divert_dump])dnl
-m4_divert_push([GROW])dnl
-])
+[m4_copy([_m4_divert_diversion], [_m4_divert_dump])m4_divert_push([GROW])])
 
 # _m4_defun_epi(MACRO-NAME)
 # -------------------------
 # The Epilogue for Autoconf macros.  MACRO-NAME only helps tracing
 # the PRO/EPI pairs.
+#
+# This is called frequently, so minimize the number of macro invocations
+# by avoiding dnl and m4_popdef overhead.
 m4_define([_m4_defun_epi],
-[m4_popdef([_m4_expanding($1)])dnl
-m4_expansion_stack_pop()dnl
-m4_ifndef([m4_expansion_stack], [_m4_defun_epi_outer[]])dnl
-m4_provide([$1])dnl
-])
+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_undefine([_m4_divert_dump])dnl
-m4_divert_pop([GROW])dnl
-m4_undivert([GROW])dnl
-])
+[_m4_undefine([_m4_divert_dump])m4_divert_pop([GROW])m4_undivert([GROW])])
 
 
 # m4_defun(NAME, EXPANSION)
@@ -1390,33 +1625,38 @@ m4_define([m4_before],
 #   such as `C' should dispatch the call to `AC_LANG_COMPILER(C)'.  But this
 #   `extension' prevents `AC_LANG_COMPILER' from having actual arguments that
 #   it passes to `AC_LANG_COMPILER(C)'.
+#
+# This is called frequently, so minimize the number of macro invocations
+# by avoiding dnl and other overhead on the common path.
 m4_define([m4_require],
-[m4_ifdef([_m4_expanding($1)],
-        [m4_fatal([$0: circular dependency of $1])])dnl
-m4_ifndef([_m4_divert_dump],
-         [m4_fatal([$0($1): cannot be used outside of an m4_defun'd macro])])
dnl
-m4_provide_if([$1],
-             [],
-             [_m4_require_call([$1], [$2])])dnl
-])
-
-
-# _m4_require_call(BODY-TO-EXPAND)
-# --------------------------------
+m4_do([[m4_ifdef([_m4_expanding($1)],
+                [m4_fatal([$0: circular dependency of $1])])]],
+      [[m4_ifdef([_m4_divert_dump], [],
+                [m4_fatal([$0($1): cannot be used outside of an ]dnl
+m4_bmatch([$0], [^AC_], [[AC_DEFUN]], [[m4_defun]])['d macro])])]],
+      [[m4_provide_if([$1],
+                     [],
+                     [_m4_require_call([$1], [$2])])]]))
+
+
+# _m4_require_call(NAME-TO-CHECK, [BODY-TO-EXPAND = NAME-TO-CHECK])
+# -----------------------------------------------------------------
 # If m4_require decides to expand the body, it calls this macro.
+#
+# This is called frequently, so minimize the number of macro invocations
+# by avoiding dnl and other overhead on the common path.
 m4_define([_m4_require_call],
-[m4_define([_m4_divert_grow], m4_decr(_m4_divert_grow))dnl
-m4_divert_push(_m4_divert_grow)dnl
-m4_default([$2], [$1])
+m4_do([[m4_define([_m4_divert_grow], m4_decr(_m4_divert_grow))]],
+      [[m4_divert_push(_m4_divert_grow)]],
+      [[m4_default([$2], [$1])
 m4_provide_if([$1],
              [],
              [m4_warn([syntax],
-                      [$1 is m4_require'd but not m4_defun'd])])dnl
-m4_divert(m4_defn([_m4_divert_dump]))dnl
-m4_undivert(_m4_divert_grow)dnl
-m4_divert_pop(_m4_divert_grow)dnl
-m4_define([_m4_divert_grow], m4_incr(_m4_divert_grow))dnl
-])
+                      [$1 is m4_require'd but not m4_defun'd])])]],
+      [[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))]]))
 
 
 # _m4_divert_grow
@@ -1474,7 +1714,16 @@ m4_defn([m4_cr_LETTERS])dnl
 m4_define([m4_cr_digits], [0123456789])
 
 
-# m4_cr_symbols1 & m4_cr_symbols2
+# m4_cr_alnum
+# -----------
+m4_define([m4_cr_alnum],
+m4_defn([m4_cr_Letters])dnl
+m4_defn([m4_cr_digits])dnl
+)
+
+
+# m4_cr_symbols1
+# m4_cr_symbols2
 # -------------------------------
 m4_define([m4_cr_symbols1],
 m4_defn([m4_cr_Letters])dnl
@@ -1485,6 +1734,59 @@ m4_defn([m4_cr_symbols1])dnl
 m4_defn([m4_cr_digits])dnl
 )
 
+# m4_cr_all
+# ---------
+# The character range representing everything, with `-' as the last
+# character, since it is special to m4_translit.  Use with care, because
+# it contains characters special to M4 (fortunately, both ASCII and EBCDIC
+# have [] in order, so m4_defn([m4_cr_all]) remains a valid string).  It
+# also contains characters special to terminals, so it should never be
+# displayed in an error message.  Also, attempts to map [ and ] to other
+# characters via m4_translit must deal with the fact that m4_translit does
+# not add quotes to the output.
+#
+# It is mainly useful in generating inverted character range maps, for use
+# in places where m4_translit is faster than an equivalent m4_bpatsubst;
+# the regex `[^a-z]' is equivalent to:
+#  m4_translit(m4_dquote(m4_defn([m4_cr_all])), [a-z])
+m4_define([m4_cr_all],
+m4_translit(m4_dquote(m4_format(m4_dquote(m4_for(
+  ,1,255,,[[%c]]))m4_for([i],1,255,,[,i]))), [-])-)
+
+
+# _m4_define_cr_not(CATEGORY)
+# ---------------------------
+# Define m4_cr_not_CATEGORY as the inverse of m4_cr_CATEGORY.
+m4_define([_m4_define_cr_not],
+[m4_define([m4_cr_not_$1],
+          m4_translit(m4_dquote(m4_defn([m4_cr_all])),
+                      m4_defn([m4_cr_$1])))])
+
+
+# m4_cr_not_letters
+# m4_cr_not_LETTERS
+# m4_cr_not_Letters
+# m4_cr_not_digits
+# m4_cr_not_alnum
+# m4_cr_not_symbols1
+# m4_cr_not_symbols2
+# ------------------
+# Inverse character sets
+_m4_define_cr_not([letters])
+_m4_define_cr_not([LETTERS])
+_m4_define_cr_not([Letters])
+_m4_define_cr_not([digits])
+_m4_define_cr_not([alnum])
+_m4_define_cr_not([symbols1])
+_m4_define_cr_not([symbols2])
+
+
+# m4_newline
+# ----------
+# Expands to a newline.  Exists for formatting reasons.
+m4_define([m4_newline], [
+])
+
 
 # m4_re_escape(STRING)
 # --------------------
@@ -1516,11 +1818,15 @@ m4_defn([m4_re_string])dnl
 # m4_tolower(STRING)
 # m4_toupper(STRING)
 # ------------------
-# These macros lowercase and uppercase strings.
+# These macros convert STRING to lowercase or uppercase.
+#
+# Rather than expand the m4_defn each time, we inline them up front.
 m4_define([m4_tolower],
-[m4_translit([$1], m4_defn([m4_cr_LETTERS]), m4_defn([m4_cr_letters]))])
+[m4_translit([$1], ]m4_dquote(m4_defn([m4_cr_LETTERS]))[,
+                  ]m4_dquote(m4_defn([m4_cr_letters]))[)])
 m4_define([m4_toupper],
-[m4_translit([$1], m4_defn([m4_cr_letters]), m4_defn([m4_cr_LETTERS]))])
+[m4_translit([$1], ]m4_dquote(m4_defn([m4_cr_letters]))[,
+                  ]m4_dquote(m4_defn([m4_cr_LETTERS]))[)])
 
 
 # m4_split(STRING, [REGEXP])
@@ -1536,28 +1842,32 @@ m4_define([m4_toupper],
 #
 # Pay attention to the m4_changequotes.  When m4 reads the definition of
 # m4_split, it still has quotes set to [ and ].  Luckily, these are matched
-# in the macro body, so the definition is stored correctly.
+# in the macro body, so the definition is stored correctly.  Use the same
+# alternate quotes as m4_noquote; it must be unlikely to appear in $1.
 #
 # Also, notice that $1 is quoted twice, since we want the result to
 # be quoted.  Then you should understand that the argument of
-# patsubst is ``STRING'' (i.e., with additional `` and '').
+# patsubst is -=<{(STRING)}>=- (i.e., with additional -=<{( and )}>=-).
 #
 # This macro is safe on active symbols, i.e.:
 #   m4_define(active, ACTIVE)
 #   m4_split([active active ])end
 #   => [active], [active], []end
-
+#
+# Optimize on regex of ` ' (space), since m4_foreach_w already guarantees
+# that the list contains single space separators, and a common case is
+# splitting a single-element list.  This macro is called frequently,
+# so avoid unnecessary dnl inside the definition.
 m4_define([m4_split],
-[m4_ifval([$1], [_m4_split($@)])])
+[m4_if([$1], [], [],
+       [$2], [ ], [m4_if(m4_index([$1], [ ]), [-1], [[[$1]]], [_$0($@)])],
+       [$2], [], [_$0([$1], [[  ]+])],
+       [_$0($@)])])
 
 m4_define([_m4_split],
-[m4_changequote(``, '')dnl
-[dnl Can't use m4_default here instead of m4_if, because m4_default uses
-dnl [ and ] as quotes.
-m4_bpatsubst(````$1'''',
-            m4_if(``$2'',, ``[  ]+'', ``$2''),
-            ``], ['')]dnl
-m4_changequote([, ])])
+[m4_changequote([-=<{(],[)}>=-])]dnl
+[[m4_bpatsubst(-=<{(-=<{($1)}>=-)}>=-, -=<{($2)}>=-,
+              -=<{(], [)}>=-)]m4_changequote([, ])])
 
 
 
@@ -1571,10 +1881,14 @@ m4_changequote([, ])])
 #    act\
 #    ive])end
 #    => active activeend
+#
+# In m4, m4_bpatsubst is expensive, so first check for a newline.
 m4_define([m4_flatten],
-[m4_translit(m4_bpatsubst([[[$1]]], [\\
+[m4_if(m4_index([$1], [
+]), [-1], [[$1]],
+       [m4_translit(m4_bpatsubst([[[$1]]], [\\
 ]), [
-], [ ])])
+], [ ])])])
 
 
 # m4_strip(STRING)
@@ -1587,18 +1901,20 @@ m4_define([m4_flatten],
 #    m4_strip([  active <tab> <tab>active ])end
 #    => active activeend
 #
-# Because we want to preserve active symbols, STRING must be double-quoted.
+# First, notice that we guarantee trailing space.  Why?  Because regular
+# expressions are greedy, and `.* ?' would always group the space into the
+# .* portion.  The algorithm is simpler by avoiding `?' at the end.  The
+# algorithm correctly strips everything if STRING is just ` '.
 #
-# Then notice the 2 last patterns: they are in charge of removing the
+# Then notice the second pattern: it is in charge of removing the
 # leading/trailing spaces.  Why not just `[^ ]'?  Because they are
-# applied to doubly quoted strings, i.e. more or less [[STRING]].  So
-# if there is a leading space in STRING, then it is the *third*
-# character, since there are two leading `['; equally for the last pattern.
+# applied to over-quoted strings, i.e. more or less [STRING], due
+# to the limitations of m4_bpatsubsts.  So the leading space in STRING
+# is the *second* character; equally for the trailing space.
 m4_define([m4_strip],
-[m4_bpatsubsts([[$1]],
+[m4_bpatsubsts([$1 ],
               [[        ]+], [ ],
-              [^\(..\) ],    [\1],
-              [ \(..\)$],    [\1])])
+              [^. ?\(.*\) .$], [[[\1]]])])
 
 
 # m4_normalize(STRING)
@@ -1639,6 +1955,40 @@ m4_define([_m4_join],
 [m4_if([$#$2], [2], [],
        [m4_if([$2], [], [], [[$1$2]])$0([$1], m4_shift2($@))])])
 
+# m4_joinall(SEP, ARG1, ARG2...)
+# ------------------------------
+# Produce ARG1SEPARG2...SEPARGn.  An empty ARG results in back-to-back SEP.
+# No expansion is performed on SEP or ARGs.
+m4_define([m4_joinall], [[$2]_$0([$1], m4_shift($@))])
+m4_define([_m4_joinall],
+[m4_if([$#], [2], [], [[$1$3]$0([$1], m4_shift2($@))])])
+
+# m4_combine([SEPARATOR], PREFIX-LIST, [INFIX], SUFFIX...)
+# --------------------------------------------------------
+# Produce the pairwise combination of every element in the quoted,
+# comma-separated PREFIX-LIST with every element from the SUFFIX arguments.
+# Each pair is joined with INFIX, and pairs are separated by SEPARATOR.
+# No expansion occurs on SEPARATOR, INFIX, or elements of either list.
+#
+# For example:
+#   m4_combine([, ], [[a], [b], [c]], [-], [1], [2], [3])
+#   => 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 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_defn([m4_echo]))])]]dnl
+[[m4_foreach([m4_Prefix], [$2],
+            [m4_foreach([m4_Suffix], ]m4_dquote(m4_dquote(m4_shift3($@)))[,
+       [m4_Separator([$1])[]_m4_defn([m4_Prefix])[$3]_m4_defn(
+                                                     [m4_Suffix])])])]]dnl
+[[_m4_popdef([m4_Separator])])])
+
 
 # m4_append(MACRO-NAME, STRING, [SEPARATOR])
 # ------------------------------------------
@@ -1647,13 +1997,16 @@ m4_define([_m4_join],
 # in which case no SEPARATOR is added.  Be aware that the criterion is
 # `not being defined', and not `not being empty'.
 #
+# Note that neither STRING nor SEPARATOR are expanded here; rather, when
+# you expand MACRO-NAME, they will be expanded at that point in time.
+#
 # This macro is robust to active symbols.  It can be used to grow
 # strings.
 #
-#    | m4_define(active, ACTIVE)
-#    | m4_append([sentence], [This is an])
-#    | m4_append([sentence], [ active ])
-#    | m4_append([sentence], [symbol.])
+#    | m4_define(active, ACTIVE)dnl
+#    | m4_append([sentence], [This is an])dnl
+#    | m4_append([sentence], [ active ])dnl
+#    | m4_append([sentence], [symbol.])dnl
 #    | sentence
 #    | m4_undefine([active])dnl
 #    | sentence
@@ -1662,28 +2015,69 @@ m4_define([_m4_join],
 #
 # It can be used to define hooks.
 #
-#    | m4_define(active, ACTIVE)
-#    | m4_append([hooks], [m4_define([act1], [act2])])
-#    | m4_append([hooks], [m4_define([act2], [active])])
-#    | m4_undefine([active])
+#    | m4_define(active, ACTIVE)dnl
+#    | m4_append([hooks], [m4_define([act1], [act2])])dnl
+#    | m4_append([hooks], [m4_define([act2], [active])])dnl
+#    | m4_undefine([active])dnl
 #    | act1
 #    | hooks
 #    | act1
 #    => act1
 #    =>
 #    => active
+#
+# It can also be used to create lists, although this particular usage was
+# broken prior to autoconf 2.62.
+#    | m4_append([list], [one], [, ])dnl
+#    | m4_append([list], [two], [, ])dnl
+#    | m4_append([list], [three], [, ])dnl
+#    | list
+#    | m4_dquote(list)
+#    => one, two, three
+#    => [one],[two],[three]
+#
+# Note that m4_append can benefit from amortized O(n) m4 behavior, if
+# the underlying m4 implementation is smart enough to avoid copying existing
+# contents when enlarging a macro's definition into any pre-allocated storage
+# (m4 1.4.x unfortunately does not implement this optimization).  We do
+# not implement m4_prepend, since it is inherently O(n^2) (pre-allocated
+# storage only occurs at the end of a macro, so the existing contents must
+# always be moved).
+#
+# Use _m4_defn for speed.
 m4_define([m4_append],
-[m4_define([$1],
-          m4_ifdef([$1], [m4_defn([$1])$3])[$2])])
+[m4_define([$1], m4_ifdef([$1], [_m4_defn([$1])[$3]])[$2])])
 
-# m4_append_uniq(MACRO-NAME, STRING, [SEPARATOR])
-# -----------------------------------------------
-# As `m4_append', but append only if not yet present.
+
+# m4_append_uniq(MACRO-NAME, STRING, [SEPARATOR], [IF-UNIQ], [IF-DUP])
+# --------------------------------------------------------------------
+# Like `m4_append', but append only if not yet present.  Additionally,
+# expand IF-UNIQ if STRING was appended, or IF-DUP if STRING was already
+# present.  Also, warn if SEPARATOR is not empty and occurs within STRING,
+# as the algorithm no longer guarantees uniqueness.
+#
+# Note that while m4_append can be O(n) (depending on the quality of the
+# underlying M4 implementation), m4_append_uniq is inherently O(n^2)
+# because each append operation searches the entire string.
 m4_define([m4_append_uniq],
+[m4_ifval([$3], [m4_if(m4_index([$2], [$3]), [-1], [],
+                      [m4_warn([syntax],
+                               [$0: `$2' contains `$3'])])])_$0($@)])
+m4_define([_m4_append_uniq],
 [m4_ifdef([$1],
-         [m4_bmatch([$3]m4_defn([$1])[$3], m4_re_escape([$3$2$3]), [],
-                    [m4_append($@)])],
-         [m4_append($@)])])
+         [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])])
+
+# m4_append_uniq_w(MACRO-NAME, STRINGS)
+# -------------------------------------
+# For each of the words in the whitespace separated list STRINGS, append
+# only the unique strings to the definition of MACRO-NAME.
+#
+# Use _m4_defn for speed.
+m4_define([m4_append_uniq_w],
+[m4_foreach_w([m4_Word], [$2],
+             [_m4_append_uniq([$1], _m4_defn([m4_Word]), [ ])])])
 
 
 # m4_text_wrap(STRING, [PREFIX], [FIRST-PREFIX], [WIDTH])
@@ -1694,6 +2088,9 @@ m4_define([m4_append_uniq],
 # if the length of FIRST-PREFIX is greater than that of PREFIX, then
 # FIRST-PREFIX will be left alone on the first line.
 #
+# No expansion occurs on the contents STRING, PREFIX, or FIRST-PREFIX,
+# although quadrigraphs are correctly recognized.
+#
 # Typical outputs are:
 #
 # m4_text_wrap([Short string */], [   ], [/* ], 20)
@@ -1719,56 +2116,78 @@ m4_define([m4_append_uniq],
 # we really want to bother with people trying each single corner
 # of a software?
 #
-# more important:
-# FIXME: handle quadrigraphs correctly, both in TEXT and in FIRST_PREFIX.
-#
-# This macro does not leave a trailing space behind the last word,
-# what complicates it a bit.  The algorithm is stupid simple: all the
-# words are preceded by m4_Separator which is defined to empty for the
-# first word, and then ` ' (single space) for all the others.
+# This macro does not leave a trailing space behind the last word of a line,
+# which complicates it a bit.  The algorithm is otherwise stupid and simple:
+# all the words are preceded by m4_Separator which is defined to empty for
+# the first word, and then ` ' (single space) for all the others.
+#
+# 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_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).
 m4_define([m4_text_wrap],
-[m4_pushdef([m4_Prefix], [$2])dnl
-m4_pushdef([m4_Prefix1], m4_default([$3], [m4_Prefix]))dnl
-m4_pushdef([m4_Width], m4_default([$4], 79))dnl
-m4_pushdef([m4_Cursor], m4_len(m4_Prefix1))dnl
-m4_pushdef([m4_Separator], [])dnl
-m4_Prefix1[]dnl
-m4_if(m4_eval(m4_Cursor > m4_len(m4_Prefix)),
-      1, [m4_define([m4_Cursor], m4_len(m4_Prefix))
-m4_Prefix])[]dnl
-m4_foreach_w([m4_Word], [$1],
-[m4_define([m4_Cursor], m4_eval(m4_Cursor + m4_len(m4_defn([m4_Word])) + 1))dnl
-dnl New line if too long, else insert a space unless it is the first
-dnl of the words.
-m4_if(m4_eval(m4_Cursor > m4_Width),
-      1, [m4_define([m4_Cursor],
-                   m4_eval(m4_len(m4_Prefix) + m4_len(m4_defn([m4_Word])) + 
1))]
-m4_Prefix,
-       [m4_Separator])[]dnl
-m4_defn([m4_Word])[]dnl
-m4_define([m4_Separator], [ ])])dnl
-m4_popdef([m4_Separator])dnl
-m4_popdef([m4_Cursor])dnl
-m4_popdef([m4_Width])dnl
-m4_popdef([m4_Prefix1])dnl
-m4_popdef([m4_Prefix])dnl
-])
+[_$0([$1], [$2], m4_if([$3], [], [[$2]], [[$3]]),
+     m4_if([$4], [], [79], [[$4]]))])
+m4_define([_m4_text_wrap],
+m4_do(dnl set up local variables, to avoid repeated calculations
+[[m4_pushdef([m4_Indent], m4_qlen([$2]))]],
+[[m4_pushdef([m4_Cursor], m4_qlen([$3]))]],
+[[m4_pushdef([m4_Separator], [m4_define([m4_Separator], [ ])])]],
+dnl expand the first prefix, then check its length vs. regular prefix
+dnl same length: nothing special
+dnl prefix1 longer: output on line by itself, and reset cursor
+dnl prefix1 shorter: pad to length of prefix, and reset cursor
+[[[$3]m4_cond([m4_Cursor], m4_Indent, [],
+             [m4_eval(m4_Cursor > m4_Indent)], [1], [
+[$2]m4_define([m4_Cursor], m4_Indent)],
+             [m4_format([%*s], m4_max([0],
+  m4_eval(m4_Indent - m4_Cursor)), [])m4_define([m4_Cursor], m4_Indent)])]],
+dnl now, for each word, compute the curser after the word is output, then
+dnl check if the cursor would exceed the wrap column
+dnl if so, reset cursor, and insert newline and prefix
+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_defn([m4_Word]))
+                    + 1))m4_if(m4_eval(m4_Cursor > ([$4])),
+      [1], [m4_define([m4_Cursor],
+                     m4_eval(m4_Indent + m4_qlen(_m4_defn([m4_Word])) + 1))
+[$2]],
+      [m4_Separator[]])_m4_defn([m4_Word])])]],
+dnl finally, clean up the local variabls
+[[_m4_popdef([m4_Separator], [m4_Cursor], [m4_Indent])]]))
 
 
 # m4_text_box(MESSAGE, [FRAME-CHARACTER = `-'])
 # ---------------------------------------------
+# Turn MESSAGE into:
+#  ## ------- ##
+#  ## MESSAGE ##
+#  ## ------- ##
+# using FRAME-CHARACTER in the border.
 m4_define([m4_text_box],
address@hidden:@@%:@ m4_bpatsubst([$1], [.], m4_if([$2], [], [[-]], [[$2]])) 
@%:@@%:@
+[m4_pushdef([m4_Border],
+           m4_translit(m4_format([%*s], m4_qlen(m4_expand([$1])), []),
+                       [ ], m4_if([$2], [], [[-]], [[$2]])))dnl
address@hidden:@@%:@ m4_Border @%:@@%:@
 @%:@@%:@ $1 @%:@@%:@
address@hidden:@@%:@ m4_bpatsubst([$1], [.], m4_if([$2], [], [[-]], [[$2]])) 
@%:@@%:@[]dnl
address@hidden:@@%:@ m4_Border @%:@@%:@_m4_popdef([m4_Border])dnl
 ])
 
 
 # m4_qlen(STRING)
 # ---------------
 # Expands to the length of STRING after autom4te converts all quadrigraphs.
+#
+# Avoid bpatsubsts for the common case of no quadrigraphs.
 m4_define([m4_qlen],
-[m4_len(m4_bpatsubsts([[$1]], address@hidden(<:\|:>\|S|\|%:\)@], [P], 
[@&address@hidden))])
+[m4_if(m4_index([$1], address@hidden), [-1], [m4_len([$1])],
+       [m4_len(m4_bpatsubst([[$1]],
+                           
address@hidden(\(<:\|:>\|S|\|%:\|\{:\|:\}\)\(@\)\|&address@hidden)],
+                           [\3]))])])
 
 
 # m4_qdelta(STRING)
@@ -1784,16 +2203,6 @@ m4_define([m4_qdelta],
 ## 13. Number processing.  ##
 ## ----------------------- ##
 
-# m4_sign(A)
-# ----------
-#
-# The sign of the integer A.
-m4_define([m4_sign],
-[m4_bmatch([$1],
-          [^-], -1,
-          [^0+], 0,
-                 1)])
-
 # m4_cmp(A, B)
 # ------------
 # Compare two integer expressions.
@@ -1801,28 +2210,86 @@ m4_define([m4_sign],
 # A = B ->  0
 # A > B ->  1
 m4_define([m4_cmp],
-[m4_sign(m4_eval([$1 - $2]))])
+[m4_eval((([$1]) > ([$2])) - (([$1]) < ([$2])))])
 
 
 # m4_list_cmp(A, B)
 # -----------------
 #
-# Compare the two lists of integers A and B.  For instance:
-#   m4_list_cmp((1, 0),     (1))    ->  0
-#   m4_list_cmp((1, 0),     (1, 0)) ->  0
-#   m4_list_cmp((1, 2),     (1, 0)) ->  1
-#   m4_list_cmp((1, 2, 3),  (1, 2)) ->  1
-#   m4_list_cmp((1, 2, -3), (1, 2)) -> -1
-#   m4_list_cmp((1, 0),     (1, 2)) -> -1
-#   m4_list_cmp((1),        (1, 2)) -> -1
+# Compare the two lists of integer expressions A and B.  For instance:
+#   m4_list_cmp([1, 0],     [1])    ->  0
+#   m4_list_cmp([1, 0],     [1, 0]) ->  0
+#   m4_list_cmp([1, 2],     [1, 0]) ->  1
+#   m4_list_cmp([1, 2, 3],  [1, 2]) ->  1
+#   m4_list_cmp([1, 2, -3], [1, 2]) -> -1
+#   m4_list_cmp([1, 0],     [1, 2]) -> -1
+#   m4_list_cmp([1],        [1, 2]) -> -1
+#   m4_define([xa], [oops])dnl
+#   m4_list_cmp([[0xa]],    [5+5])  -> 0
+#
+# Rather than face the overhead of m4_case, we use a helper function whose
+# expansion includes the name of the macro to invoke on the tail, either
+# m4_ignore or m4_unquote.  This is particularly useful when comparing
+# long lists, since less text is being expanded for deciding when to end
+# recursion.  The recursion is between a pair of macros that alternate
+# which list is trimmed by one element; this is more efficient than
+# calling m4_cdr on both lists from a single macro.
 m4_define([m4_list_cmp],
-[m4_if([$1$2], [()()], 0,
-       [$1], [()], [$0((0), [$2])],
-       [$2], [()], [$0([$1], (0))],
-       [m4_case(m4_cmp(m4_car$1, m4_car$2),
-               -1, -1,
-                1, 1,
-                0, [$0((m4_shift$1), (m4_shift$2))])])])
+[m4_if([$1], [$2], [0], [_m4_list_cmp_1([$1], $2)])])
+
+m4_define([_m4_list_cmp],
+[m4_if([$1], [], [0m4_ignore], [$2], [0], [m4_unquote], [$2m4_ignore])])
+
+m4_define([_m4_list_cmp_1],
+[_m4_list_cmp_2([$2], m4_dquote(m4_shift2($@)), $1)])
+
+m4_define([_m4_list_cmp_2],
+[_m4_list_cmp([$1$3], m4_cmp([$3+0], [$1+0]))(
+  [_m4_list_cmp_1(m4_dquote(m4_shift3($@)), $2)])])
+
+# m4_max(EXPR, ...)
+# m4_min(EXPR, ...)
+# -----------------
+# Return the decimal value of the maximum (or minimum) in a series of
+# integer expressions.
+#
+# M4 1.4.x doesn't provide ?:.  Hence this huge m4_eval.  Avoid m4_eval
+# if both arguments are identical, but be aware of m4_max(0xa, 10) (hence
+# the use of <=, not just <, in the second multiply).
+m4_define([m4_max],
+[m4_if([$#], [0], [m4_fatal([too few arguments to $0])],
+       [$#], [1], [m4_eval([$1])],
+       [$#$1], [2$2], [m4_eval([$1])],
+       [$#], [2], [_$0($@)],
+       [_m4_minmax([_$0], $@)])])
+
+m4_define([_m4_max],
+[m4_eval((([$1]) > ([$2])) * ([$1]) + (([$1]) <= ([$2])) * ([$2]))])
+
+m4_define([m4_min],
+[m4_if([$#], [0], [m4_fatal([too few arguments to $0])],
+       [$#], [1], [m4_eval([$1])],
+       [$#$1], [2$2], [m4_eval([$1])],
+       [$#], [2], [_$0($@)],
+       [_m4_minmax([_$0], $@)])])
+
+m4_define([_m4_min],
+[m4_eval((([$1]) < ([$2])) * ([$1]) + (([$1]) >= ([$2])) * ([$2]))])
+
+# _m4_minmax(METHOD, ARG1, ARG2...)
+# ---------------------------------
+# Common recursion code for m4_max and m4_min.  METHOD must be _m4_max
+# or _m4_min, and there must be at least two arguments to combine.
+m4_define([_m4_minmax],
+[m4_if([$#], [3], [$1([$2], [$3])],
+       [$0([$1], $1([$2], [$3]), m4_shift3($@))])])
+
+
+# m4_sign(A)
+# ----------
+# The sign of the integer expression A.
+m4_define([m4_sign],
+[m4_eval((([$1]) > 0) - (([$1]) < 0))])
 
 
 
@@ -1833,23 +2300,31 @@ m4_define([m4_list_cmp],
 
 # m4_version_unletter(VERSION)
 # ----------------------------
-# Normalize beta version numbers with letters to numbers only for comparison.
+# Normalize beta version numbers with letters to numeric expressions, which
+# can then be handed to m4_eval for the purpose of comparison.
 #
 #   Nl -> (N+1).-1.(l#)
 #
-#i.e., 2.14a -> 2.15.-1.1, 2.14b -> 2.15.-1.2, etc.
-# This macro is absolutely not robust to active macro, it expects
-# reasonable version numbers and is valid up to `z', no double letters.
+# for example:
+#   [2.14a] -> [2.14+1.-1.[0r36:a]] -> 2.15.-1.10
+#   [2.14b] -> [2.15+1.-1.[0r36:b]] -> 2.15.-1.11
+#   [2.61aa.b] -> [2.61+1.-1.[0r36:aa],+1.-1.[0r36:b]] -> 2.62.-1.370.1.-1.11
+#
+# This macro expects reasonable version numbers, but can handle double
+# letters and does not expand any macros.  Original version strings can
+# use both `.' and `-' separators.
+#
+# Inline constant expansions, to avoid m4_defn overhead.
+# _m4_version_unletter is the real workhorse used by m4_version_compare,
+# but since [0r36:a] is less readable than 10, we provide a wrapper for
+# human use.
 m4_define([m4_version_unletter],
-[m4_translit(m4_bpatsubsts([$1],
-                          [\([0-9]+\)\([abcdefghi]\)],
-                            [m4_eval(\1 + 1).-1.\2],
-                          [\([0-9]+\)\([jklmnopqrs]\)],
-                            [m4_eval(\1 + 1).-1.1\2],
-                          [\([0-9]+\)\([tuvwxyz]\)],
-                            [m4_eval(\1 + 1).-1.2\2]),
-            [abcdefghijklmnopqrstuvwxyz],
-            [12345678901234567890123456])])
+[m4_map_sep([m4_eval], [.],
+           m4_dquote(m4_dquote_elt(m4_unquote(_$0([$1])))))])
+m4_define([_m4_version_unletter],
+[m4_bpatsubst(m4_translit([[[$1]]], [.-], [,,]),]dnl
+m4_dquote(m4_dquote(m4_defn([m4_cr_Letters])))[[+],
+             [+1,-1,[0r36:\&]])])
 
 
 # m4_version_compare(VERSION-1, VERSION-2)
@@ -1859,8 +2334,7 @@ m4_define([m4_version_unletter],
 #   0 if           =
 #   1 if           >
 m4_define([m4_version_compare],
-[m4_list_cmp((m4_split(m4_version_unletter([$1]), [\.])),
-            (m4_split(m4_version_unletter([$2]), [\.])))])
+[m4_list_cmp(_m4_version_unletter([$1]), _m4_version_unletter([$2]))])
 
 
 # m4_PACKAGE_NAME
@@ -1888,9 +2362,330 @@ m4_ifdef([m4_PACKAGE_VERSION],
 [[m4_fatal([m4sugar/version.m4 not found])]]))
 
 
+## ------------------ ##
+## 15. Set handling.  ##
+## ------------------ ##
+
+# Autoconf likes to create arbitrarily large sets; for example, as of
+# this writing, the configure.ac for coreutils tracks a set of more
+# than 400 AC_SUBST.  How do we track all of these set members,
+# without introducing duplicates?  We could use m4_append_uniq, with
+# the set NAME residing in the contents of the macro NAME.
+# Unfortunately, m4_append_uniq is quadratic for set creation, because
+# it costs O(n) to search the string for each of O(n) insertions; not
+# to mention that with m4 1.4.x, even using m4_append is slow, costing
+# O(n) rather than O(1) per insertion.  Other set operations, not used
+# by Autoconf but still possible by manipulation of the definition
+# tracked in macro NAME, include O(n) deletion of one element and O(n)
+# computation of set size.  Because the set is exposed to the user via
+# the definition of a single macro, we cannot cache any data about the
+# set without risking the cache being invalidated by the user
+# redefining NAME.
+#
+# Can we do better?  Yes, because m4 gives us an O(1) search function
+# for free: ifdef.  Additionally, even m4 1.4.x gives us an O(1)
+# insert operation for free: pushdef.  But to use these, we must
+# represent the set via a group of macros; to keep the set consistent,
+# we must hide the set so that the user can only manipulate it through
+# accessor macros.  The contents of the set are maintained through two
+# access points; _m4_set([name]) is a pushdef stack of values in the
+# set, useful for O(n) traversal of the set contents; while the
+# existence of _m4_set([name],value) with no particular value is
+# useful for O(1) querying of set membership.  And since the user
+# cannot externally manipulate the set, we are free to add additional
+# caching macros for other performance improvements.  Deletion can be
+# O(1) per element rather than O(n), by reworking the definition of
+# _m4_set([name],value) to be 0 or 1 based on current membership, and
+# adding _m4_set_cleanup(name) to defer the O(n) cleanup of
+# _m4_set([name]) until we have another reason to do an O(n)
+# traversal.  The existence of _m4_set_cleanup(name) can then be used
+# elsewhere to determine if we must dereference _m4_set([name],value),
+# or assume that definition implies set membership.  Finally, size can
+# be tracked in an O(1) fashion with _m4_set_size(name).
+#
+# The quoting in _m4_set([name],value) is chosen so that there is no
+# ambiguity with a set whose name contains a comma, and so that we can
+# supply the value via _m4_defn([_m4_set([name])]) without needing any
+# quote manipulation.
+
+# m4_set_add(SET, VALUE, [IF-UNIQ], [IF-DUP])
+# -------------------------------------------
+# Add VALUE as an element of SET.  Expand IF-UNIQ on the first
+# addition, and IF-DUP if it is already in the set.  Addition of one
+# element is O(1), such that overall set creation is O(n).
+#
+# We do not want to add a duplicate for a previously deleted but
+# unpruned element, but it is just as easy to check existence directly
+# as it is to query _m4_set_cleanup($1).
+m4_define([m4_set_add],
+[m4_ifdef([_m4_set([$1],$2)],
+         [m4_if(m4_indir([_m4_set([$1],$2)]), [0],
+                [m4_define([_m4_set([$1],$2)],
+                           [1])_m4_set_size([$1], [m4_incr])$3], [$4])],
+         [m4_define([_m4_set([$1],$2)],
+                    [1])m4_pushdef([_m4_set([$1])],
+                                   [$2])_m4_set_size([$1], [m4_incr])$3])])
+
+# m4_set_add_all(SET, VALUE...)
+# -----------------------------
+# Add each VALUE into SET.  This is O(n) in the number of VALUEs, and
+# can be faster than calling m4_set_add for each VALUE.
+#
+# Implement two recursion helpers; the check variant is slower but
+# handles the case where an element has previously been removed but
+# not pruned.  The recursion helpers ignore their second argument, so
+# that we can use the faster m4_shift2 and 2 arguments, rather than
+# _m4_shift2 and one argument, as the signal to end recursion.
+m4_define([m4_set_add_all],
+[m4_define([_m4_set_size($1)], m4_eval(m4_set_size([$1])
+  + m4_len(m4_ifdef([_m4_set_cleanup($1)], [_$0_check], [_$0])([$1], $@))))])
+
+m4_define([_m4_set_add_all],
+[m4_if([$#], [2], [],
+       [m4_ifdef([_m4_set([$1],$3)], [],
+                [m4_define([_m4_set([$1],$3)], [1])m4_pushdef([_m4_set([$1])],
+          [$3])-])$0([$1], m4_shift2($@))])])
+
+m4_define([_m4_set_add_all_check],
+[m4_if([$#], [2], [],
+       [m4_set_add([$1], [$3])$0([$1], m4_shift2($@))])])
+
+# m4_set_contains(SET, VALUE, [IF-PRESENT], [IF-ABSENT])
+# ------------------------------------------------------
+# Expand IF-PRESENT if SET contains VALUE, otherwise expand IF-ABSENT.
+# This is always O(1).
+m4_define([m4_set_contains],
+[m4_ifdef([_m4_set_cleanup($1)],
+         [m4_if(m4_ifdef([_m4_set([$1],$2)],
+                   [m4_indir([_m4_set([$1],$2)])], [0]), [1], [$3], [$4])],
+         [m4_ifdef([_m4_set([$1],$2)], [$3], [$4])])])
+
+# m4_set_contents(SET, [SEP])
+# ---------------------------
+# Expand to a single string containing all the elements in SET,
+# separated by SEP, without modifying SET.  No provision is made for
+# disambiguating set elements that contain non-empty SEP as a
+# sub-string, or for recognizing a set that contains only the empty
+# string.  Order of the output is not guaranteed.  If any elements
+# have been previously removed from the set, this action will prune
+# the unused memory.  This is O(n) in the size of the set before
+# pruning.
+#
+# Use _m4_popdef for speed.  The existence of _m4_set_cleanup($1)
+# determines which version of _1 helper we use.
+m4_define([m4_set_contents],
+[m4_ifdef([_m4_set_cleanup($1)], [_$0_1c], [_$0_1])([$1])_$0_2([$1],
+    [_m4_defn([_m4_set_($1)])], [[$2]])])
+
+# _m4_set_contents_1(SET)
+# _m4_set_contents_1c(SET)
+# _m4_set_contents_2(SET, SEP, PREP)
+# ----------------------------------
+# Expand to a list of quoted elements currently in the set, separated
+# by SEP, and moving PREP in front of SEP on recursion.  To avoid
+# nesting limit restrictions, the algorithm must be broken into two
+# parts; _1 destructively copies the stack in reverse into
+# _m4_set_($1), producing no output; then _2 destructively copies
+# _m4_set_($1) back into the stack in reverse.  SEP is expanded while
+# _m4_set_($1) contains the current element, so a SEP containing
+# _m4_defn([_m4_set_($1)]) can produce output in the order the set was
+# created.  Behavior is undefined if SEP tries to recursively list or
+# modify SET in any way other than calling m4_set_remove on the
+# current element.  Use _1 if all entries in the stack are guaranteed
+# to be in the set, and _1c to prune removed entries.  Uses _m4_defn
+# and _m4_popdef for speed.
+m4_define([_m4_set_contents_1],
+[m4_ifdef([_m4_set([$1])], [m4_pushdef([_m4_set_($1)],
+    _m4_defn([_m4_set([$1])]))_m4_popdef([_m4_set([$1])])$0([$1])])])
+
+m4_define([_m4_set_contents_1c],
+[m4_ifdef([_m4_set([$1])],
+         [m4_set_contains([$1], _m4_defn([_m4_set([$1])]),
+                  [m4_pushdef([_m4_set_($1)], _m4_defn([_m4_set([$1])]))],
+                  [_m4_popdef([_m4_set([$1],]_m4_defn(
+      [_m4_set([$1])])[)])])_m4_popdef([_m4_set([$1])])$0([$1])],
+         [_m4_popdef([_m4_set_cleanup($1)])])])
+
+m4_define([_m4_set_contents_2],
+[m4_ifdef([_m4_set_($1)], [m4_pushdef([_m4_set([$1])],
+    _m4_defn([_m4_set_($1)]))$2[]_m4_popdef([_m4_set_($1)])$0([$1], [$3$2])])])
+
+# m4_set_delete(SET)
+# ------------------
+# Delete all elements in SET, and reclaim any memory occupied by the
+# set.  This is O(n) in the set size.
+#
+# Use _m4_defn and _m4_popdef for speed.
+m4_define([m4_set_delete],
+[m4_ifdef([_m4_set([$1])],
+         [_m4_popdef([_m4_set([$1],]_m4_defn([_m4_set([$1])])[)],
+                     [_m4_set([$1])])$0([$1])],
+         [m4_ifdef([_m4_set_cleanup($1)],
+                   [_m4_popdef([_m4_set_cleanup($1)])])m4_ifdef(
+                   [_m4_set_size($1)],
+                   [_m4_popdef([_m4_set_size($1)])])])])
+
+# m4_set_difference(SET1, SET2)
+# -----------------------------
+# Produce a LIST of quoted elements that occur in SET1 but not SET2.
+# Output a comma prior to any elements, to distinguish the empty
+# string from no elements.  This can be directly used as a series of
+# arguments, such as for m4_join, or wrapped inside quotes for use in
+# m4_foreach.  Order of the output is not guaranteed.
+#
+# Short-circuit the idempotence relation.  Use _m4_defn for speed.
+m4_define([m4_set_difference],
+[m4_if([$1], [$2], [],
+       [m4_set_foreach([$1], [_m4_element],
+                      [m4_set_contains([$2], _m4_defn([_m4_element]), [],
+                                       [,_m4_defn([_m4_element])])])])])
+
+# m4_set_dump(SET, [SEP])
+# -----------------------
+# Expand to a single string containing all the elements in SET,
+# separated by SEP, then delete SET.  In general, if you only need to
+# list the contents once, this is faster than m4_set_contents.  No
+# provision is made for disambiguating set elements that contain
+# non-empty SEP as a sub-string.  Order of the output is not
+# guaranteed.  This is O(n) in the size of the set before pruning.
+#
+# Use _m4_popdef for speed.  Use existence of _m4_set_cleanup($1) to
+# decide if more expensive recursion is needed.
+m4_define([m4_set_dump],
+[m4_ifdef([_m4_set_size($1)],
+         [_m4_popdef([_m4_set_size($1)])])m4_ifdef([_m4_set_cleanup($1)],
+    [_$0_check], [_$0])([$1], [], [$2])])
+
+# _m4_set_dump(SET, SEP, PREP)
+# _m4_set_dump_check(SET, SEP, PREP)
+# ----------------------------------
+# Print SEP and the current element, then delete the element and
+# recurse with empty SEP changed to PREP.  The check variant checks
+# whether the element has been previously removed.  Use _m4_defn and
+# _m4_popdef for speed.
+m4_define([_m4_set_dump],
+[m4_ifdef([_m4_set([$1])],
+         [[$2]_m4_defn([_m4_set([$1])])_m4_popdef([_m4_set([$1],]_m4_defn(
+               [_m4_set([$1])])[)], [_m4_set([$1])])$0([$1], [$2$3])])])
+
+m4_define([_m4_set_dump_check],
+[m4_ifdef([_m4_set([$1])],
+         [m4_set_contains([$1], _m4_defn([_m4_set([$1])]),
+                          [[$2]_m4_defn([_m4_set([$1])])])_m4_popdef(
+    [_m4_set([$1],]_m4_defn([_m4_set([$1])])[)],
+    [_m4_set([$1])])$0([$1], [$2$3])],
+         [_m4_popdef([_m4_set_cleanup($1)])])])
+
+# m4_set_empty(SET, [IF-EMPTY], [IF-ELEMENTS])
+# --------------------------------------------
+# Expand IF-EMPTY if SET has no elements, otherwise IF-ELEMENTS.
+m4_define([m4_set_empty],
+[m4_ifdef([_m4_set_size($1)],
+         [m4_if(m4_indir([_m4_set_size($1)]), [0], [$2], [$3])], [$2])])
+
+# m4_set_foreach(SET, VAR, ACTION)
+# --------------------------------
+# For each element of SET, define VAR to the element and expand
+# ACTION.  ACTION should not recursively list SET's contents, add
+# elements to SET, nor delete any element from SET except the one
+# currently in VAR.  The order that the elements are visited in is not
+# guaranteed.  This is faster than the corresponding m4_foreach([VAR],
+#   m4_indir([m4_dquote]m4_set_listc([SET])), [ACTION])
+m4_define([m4_set_foreach],
+[m4_pushdef([$2])m4_ifdef([_m4_set_cleanup($1)],
+    [_m4_set_contents_1c], [_m4_set_contents_1])([$1])_m4_set_contents_2([$1],
+       [m4_define([$2], _m4_defn([_m4_set_($1)]))$3[]])m4_popdef([$2])])
+
+# m4_set_intersection(SET1, SET2)
+# -------------------------------
+# Produce a LIST of quoted elements that occur in both SET1 or SET2.
+# Output a comma prior to any elements, to distinguish the empty
+# string from no elements.  This can be directly used as a series of
+# arguments, such as for m4_join, or wrapped inside quotes for use in
+# m4_foreach.  Order of the output is not guaranteed.
+#
+# Iterate over the smaller set, and short-circuit the idempotence
+# relation.  Use _m4_defn for speed.
+m4_define([m4_set_intersection],
+[m4_if([$1], [$2], [m4_set_listc([$1])],
+       m4_eval(m4_set_size([$2]) < m4_set_size([$1])), [1], [$0([$2], [$1])],
+       [m4_set_foreach([$1], [_m4_element],
+                      [m4_set_contains([$2], _m4_defn([_m4_element]),
+                                       [,_m4_defn([_m4_element])])])])])
+
+# m4_set_list(SET)
+# m4_set_listc(SET)
+# -----------------
+# Produce a LIST of quoted elements of SET.  This can be directly used
+# as a series of arguments, such as for m4_join or m4_set_add_all, or
+# wrapped inside quotes for use in m4_foreach or m4_map.  With
+# m4_set_list, there is no way to distinguish an empty set from a set
+# containing only the empty string; with m4_set_listc, a leading comma
+# is output if there are any elements.
+m4_define([m4_set_list],
+[m4_ifdef([_m4_set_cleanup($1)], [_m4_set_contents_1c],
+         [_m4_set_contents_1])([$1])_m4_set_contents_2([$1],
+              [_m4_defn([_m4_set_($1)])], [,])])
+
+m4_define([m4_set_listc],
+[m4_ifdef([_m4_set_cleanup($1)], [_m4_set_contents_1c],
+         [_m4_set_contents_1])([$1])_m4_set_contents_2([$1],
+              [,_m4_defn([_m4_set_($1)])])])
+
+# m4_set_remove(SET, VALUE, [IF-PRESENT], [IF-ABSENT])
+# ----------------------------------------------------
+# If VALUE is an element of SET, delete it and expand IF-PRESENT.
+# Otherwise expand IF-ABSENT.  Deleting a single value is O(1),
+# although it leaves memory occupied until the next O(n) traversal of
+# the set which will compact the set.
+#
+# Optimize if the element being removed is the most recently added,
+# since defining _m4_set_cleanup($1) slows down so many other macros.
+# In particular, this plays well with m4_set_foreach.
+m4_define([m4_set_remove],
+[m4_set_contains([$1], [$2], [_m4_set_size([$1],
+    [m4_decr])m4_if(_m4_defn([_m4_set([$1])]), [$2],
+                   [_m4_popdef([_m4_set([$1],$2)], [_m4_set([$1])])],
+                   [m4_define([_m4_set_cleanup($1)])m4_define(
+                     [_m4_set([$1],$2)], [0])])$3], [$4])])
+
+# m4_set_size(SET)
+# ----------------
+# Expand to the number of elements currently in SET.  This operation
+# is O(1), and thus more efficient than m4_count(m4_set_list([SET])).
+m4_define([m4_set_size],
+[m4_ifdef([_m4_set_size($1)], [m4_indir([_m4_set_size($1)])], [0])])
+
+# _m4_set_size(SET, ACTION)
+# -------------------------
+# ACTION must be either m4_incr or m4_decr, and the size of SET is
+# changed accordingly.  If the set is empty, ACTION must not be
+# m4_decr.
+m4_define([_m4_set_size],
+[m4_define([_m4_set_size($1)],
+          m4_ifdef([_m4_set_size($1)], [$2(m4_indir([_m4_set_size($1)]))],
+                   [1]))])
+
+# m4_set_union(SET1, SET2)
+# ------------------------
+# Produce a LIST of double quoted elements that occur in either SET1
+# or SET2, without duplicates.  Output a comma prior to any elements,
+# to distinguish the empty string from no elements.  This can be
+# directly used as a series of arguments, such as for m4_join, or
+# wrapped inside quotes for use in m4_foreach.  Order of the output is
+# not guaranteed.
+#
+# We can rely on the fact that m4_set_listc prunes SET1, so we don't
+# need to check _m4_set([$1],element) for 0.  Use _m4_defn for speed.
+# Short-circuit the idempotence relation.
+m4_define([m4_set_union],
+[m4_set_listc([$1])m4_if([$1], [$2], [], [m4_set_foreach([$2], [_m4_element],
+  [m4_ifdef([_m4_set([$1],]_m4_defn([_m4_element])[)], [],
+           [,_m4_defn([_m4_element])])])])])
+
 
 ## ------------------- ##
-## 15. File handling.  ##
+## 16. File handling.  ##
 ## ------------------- ##
 
 
@@ -1912,7 +2707,7 @@ m4_if(m4_sysval, [0], [],
 
 
 ## ------------------------ ##
-## 16. Setting M4sugar up.  ##
+## 17. Setting M4sugar up.  ##
 ## ------------------------ ##
 
 
@@ -1925,6 +2720,14 @@ m4_define([m4_init],
 m4_pattern_forbid([^_?m4_])
 m4_pattern_forbid([^dnl$])
 
+# If __m4_version__ is defined, we assume that we are being run by M4
+# 1.6 or newer, and thus that $@ recursion is linear; nothing further
+# needs to be done.  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.
+m4_ifndef([__m4_version__], [m4_builtin([include], [m4sugar/foreach.m4])])
+
 # _m4_divert_diversion should be defined:
 m4_divert_push([KILL])
 
diff --git a/src/output.c b/src/output.c
index 80fef44..585b90e 100644
--- a/src/output.c
+++ b/src/output.c
@@ -473,7 +473,7 @@ output_skeleton (void)
   FILE *in;
   FILE *out;
   int filter_fd[2];
-  char const *argv[7];
+  char const *argv[9];
   pid_t pid;
 
   /* Compute the names of the package data dir and skeleton files.  */
@@ -524,6 +524,8 @@ output_skeleton (void)
   {
     int i = 0;
     argv[i++] = m4;
+    argv[i++] = "-I";
+    argv[i++] = pkgdatadir;
     if (trace_flag & trace_m4)
       argv[i++] = "-dV";
     argv[i++] = full_m4sugar;
-- 
1.5.6.4







reply via email to

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