From d67c52e8527291fd7d4dcc78c364b3dba84a2f14 Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Fri, 15 Aug 2008 11:46:20 -0600 Subject: [PATCH 1/1] 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 --- 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 ffdc2b7a..15ae566b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,11 @@ 2008-08-15 Eric Blake + 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 a2e4a1b6..ce15daca 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 00000000..e54e30e8 --- /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 . + +# 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], [$@], [,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 be390961..b9ccd5b5 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], [$@], [$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], [[$@]]) - - -# 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], [$@], [$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], [$@], [$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], [[$@]]) + + +# 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], [$@]) + + +# 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 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], -[@%:@@%:@ 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 +@%:@@%:@ m4_Border @%:@@%:@ @%:@@%:@ $1 @%:@@%:@ -@%:@@%:@ m4_bpatsubst([$1], [.], m4_if([$2], [], [[-]], [[$2]])) @%:@@%:@[]dnl +@%:@@%:@ 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]], [@\(<:\|:>\|S|\|%:\)@], [P], [@&t@]))]) +[m4_if(m4_index([$1], [@]), [-1], [m4_len([$1])], + [m4_len(m4_bpatsubst([[$1]], + [@\(\(<:\|:>\|S|\|%:\|\{:\|:\}\)\(@\)\|&t@\)], + [\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 80fef444..585b90e0 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; -- 2.45.2