+2008-10-17 Eric Blake <ebb9@byu.net>
+
+ Document m4_map_args.
+ * lib/m4sugar/m4sugar.m4 (m4_transform, m4_transform_pair):
+ Rename...
+ (m4_map_args, m4_map_args_pair): ...to these names, and document.
+ (m4_version_unletter): Use the interface.
+ * lib/m4sugar/foreach.m4 (m4_map_args, m4_map_args_pair)
+ (_m4_map_args_, _m4_map_args_pair_, _m4_map_args_pair_end):
+ Perform same renames.
+ * lib/m4sugar/m4sh.m4 (AS_CASE, AS_IF): Adjust callers.
+ * tests/m4sugar.at (m4@&t@_map_args): New test.
+ (recursion): Adjust caller.
+ * tests/m4sh.at (AS@&t@_IF and AS@&t@_CASE): Likewise.
+ * doc/autoconf.texi (Looping constructs) <m4_map_args>: Document
+ this interface.
+ * NEWS: Mention the new macros.
+
2008-10-17 Eric Blake <ebb9@byu.net>
Reduce vertical whitespace in configure.
** Configure scripts now use shell functions.
** The following m4sugar macros are new:
- m4_default_quoted
+ m4_default_quoted m4_map_args m4_map_args_pair
** The following documented m4sh macros are new:
AS_LINENO_PREPARE AS_ME_PREPARE AS_VAR_COPY
@end example
@end defmac
+@defmac m4_map_args (@var{macro}, @var{arg}@dots{})
+@msindex{map_args}
+Repeatedly invoke @var{macro} with each successive @var{arg} as its
+argument. In the following example, three solutions are presented with
+the same expansion; the solution using @code{m4_map_args} is the most
+efficient.
+@example
+m4_define([active], [ACTIVE])dnl
+m4_foreach([var], [[plain], [active]], [ m4_echo(m4_defn([var]))])
+@result{} plain active
+m4_map([ m4_echo], [[[plain]], [[active]]])
+@result{} plain active
+m4_map_args([ m4_echo], [plain], [active])
+@result{} plain active
+@end example
+@end defmac
+
+@defmac m4_map_args_pair (@var{macro}, @dvar{macro-end, macro}, @
+ @var{arg}@dots{})
+@msindex{map_args_pair}
+For every pair of arguments @var{arg}, invoke @var{macro} with two
+arguments. If there is an odd number of arguments, invoke
+@var{macro-end}, which defaults to @var{macro}, with the remaining
+argument.
+
+@example
+m4_map_args_pair([, m4_reverse], [], [1], [2], [3])
+@result{}, 2, 1, 3
+m4_map_args_pair([, m4_reverse], [, m4_dquote], [1], [2], [3])
+@result{}, 2, 1, [3]
+m4_map_args_pair([, m4_reverse], [, m4_dquote], [1], [2], [3], [4])
+@result{}, 2, 1, 4, 3
+@end example
+@end defmac
+
@defmac m4_shiftn (@var{count}, @dots{})
@defmacx m4_shift2 (@dots{})
@defmacx m4_shift3 (@dots{})
m4_define([_m4_map_],
[[$$1, [$$2])]])
-# m4_transform(EXPRESSION, ARG...)
-# --------------------------------
+# m4_map_args(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],
+# Invoke the temporary macro _m4_map_args, defined as:
+# $1([$2])[]$1([$3])[]...$1([$m])[]_m4_popdef([_m4_map_args])
+m4_define([m4_map_args],
[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_],
+m4_define([_m4_map_args_],
[[$$1([$$2])[]]])
-# m4_transform_pair(EXPRESSION, [END-EXPR = EXPRESSION], ARG...)
-# --------------------------------------------------------------
+# m4_map_args_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])
+# Build the temporary macro _m4_map_args_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],
+# [$m])[]m4_default([$2], [$1])([$m+1])[]_m4_popdef([_m4_map_args_pair])
+m4_define([m4_map_args_pair],
[m4_if([$#], [0], [m4_fatal([$0: too few arguments: $#])],
[$#], [1], [m4_fatal([$0: too few arguments: $#: $1])],
[$#], [2], [],
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_],
+m4_define([_m4_map_args_pair_],
[[$$1([$$2], [$$3])[]]])
-m4_define([_m4_transform_pair_end],
+m4_define([_m4_map_args_pair_end],
[m4_if(m4_eval([$3 & 1]), [1], [[m4_default([$$2], [$$1])([$$3])[]]])])
# m4_join(SEP, ARG1, ARG2...)
m4_defun([AS_CASE],
[m4_ifval([$2$3],
[case $1 in
-m4_transform_pair([_$0], [_$0_DEFAULT], m4_shift($@))dnl
+m4_map_args_pair([_$0], [_$0_DEFAULT], m4_shift($@))dnl
esac
])dnl
])# AS_CASE
[m4_ifval([$2$3],
[if $1; then
m4_default([$2], [:])
-m4_transform_pair([_$0], [_$0_ELSE], m4_shift2($@))dnl
+m4_map_args_pair([_$0], [_$0_ELSE], m4_shift2($@))dnl
fi
])dnl
])# AS_IF
[m4_if([$#], [2], [],
[$1, [$3])$0([$1], m4_shift2($@))])])
-# m4_transform(EXPRESSION, ARG...)
-# --------------------------------
+# m4_map_args(EXPRESSION, ARG...)
+# -------------------------------
# Expand EXPRESSION([ARG]) for each argument. More efficient than
# m4_foreach([var], [ARG...], [EXPRESSION(m4_defn([var]))])
#
# Please keep foreach.m4 in sync with any adjustments made here.
-m4_define([m4_transform],
+m4_define([m4_map_args],
[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...)
-# --------------------------------------------------------------
+# m4_map_args_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
+# m4_map_args_pair([show], [], [a], [b], [c], [d], [e])dnl
# => (a,b)
# => (c,d)
# => (e)
#
# Please keep foreach.m4 in sync with any adjustments made here.
-m4_define([m4_transform_pair],
+m4_define([m4_map_args_pair],
[m4_if([$#], [0], [m4_fatal([$0: too few arguments: $#])],
[$#], [1], [m4_fatal([$0: too few arguments: $#: $1])],
[$#], [2], [],
# Nl -> (N+1).-1.(l#)
#
# 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
+# [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
#
# 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.
+# but since [0r36:a] and commas are less readable than 10 and dots, we
+# provide a wrapper for human use.
m4_define([m4_version_unletter],
-[m4_map_sep([m4_eval], [.],
- m4_dquote(m4_dquote_elt(m4_unquote(_$0([$1])))))])
+[m4_substr(m4_map_args([.m4_eval], m4_unquote(_$0([$1]))), [1])])
m4_define([_m4_version_unletter],
[m4_bpatsubst(m4_translit([[[$1]]], [.-], [,,]),]dnl
m4_dquote(m4_dquote(m4_defn([m4_cr_Letters])))[[+],
## ------------------- ##
AT_SETUP([AS@&t@_IF and AS@&t@_CASE])
-AT_KEYWORDS([m4sh m4@&t@_transform_pair])
+AT_KEYWORDS([m4sh m4@&t@_map_args_pair])
AT_DATA_M4SH([script.as], [[dnl
AS_INIT
AT_CLEANUP
+## --------------------- ##
+## m4_map_args{,_pair}. ##
+## --------------------- ##
+
+AT_SETUP([m4@&t@_map_args])
+AT_KEYWORDS([m4@&t@_map_args_pair m4@&t@_reverse])
+
+AT_CHECK_M4SUGAR_TEXT([[m4_define([active], [ACTIVE])dnl
+m4_map_args([ m4_echo])
+m4_map_args([ m4_echo], [plain], [active])
+m4_map_args([m4_unquote], [plain], [active])
+m4_map_args_pair([, m4_reverse], [])
+m4_map_args_pair([, m4_reverse], [], [1])
+m4_map_args_pair([, m4_reverse], [], [1], [2])
+m4_map_args_pair([, m4_reverse], [], [1], [2], [3])
+m4_map_args_pair([, m4_reverse], [], [1], [2], [3], [4])
+m4_map_args_pair([, m4_reverse], [, m4_dquote], [1])
+m4_map_args_pair([, m4_reverse], [, m4_dquote], [1], [2])
+m4_map_args_pair([, m4_reverse], [, m4_dquote], [1], [2], [3])
+m4_map_args_pair([, m4_reverse], [, m4_dquote], [1], [2], [3], [4])
+]],
+[[
+ plain active
+plainACTIVE
+
+, 1
+, 2, 1
+, 2, 1, 3
+, 2, 1, 4, 3
+, [1]
+, 2, 1
+, 2, 1, [3]
+, 2, 1, 4, 3
+]])
+
+AT_CLEANUP
+
+
## ------------ ##
## m4_combine. ##
## ------------ ##
AT_KEYWORDS([m4@&t@_foreach m4@&t@_foreach_w m4@&t@_case m4@&t@_cond
m4@&t@_bpatsubsts m4@&t@_shiftn m4@&t@_do m4@&t@_dquote_elt m4@&t@_reverse
m4@&t@_map m4@&t@_join m4@&t@_joinall m4@&t@_list_cmp m4@&t@_max m4@&t@_min
-m4@&t@_bmatch m4@&t@_transform m4@&t@_transform_pair])
+m4@&t@_bmatch m4@&t@_map_args m4@&t@_map_args_pair])
dnl This test completes in a reasonable time if m4_foreach is linear,
dnl but thrashes if it is quadratic. If we are testing with m4 1.4.x,
m4_bmatch([9997]m4_for([i], [1], [10000], [], [,^i$]))
m4_define([up], [m4_define([$1], m4_incr($1))$1])m4_define([j], 0)dnl
m4_cond(m4_for([i], [1], [10000], [], [[up([j])], [9990], i,]) [oops]) j
-m4_count(m4_transform_pair([,m4_quote], []m4_transform([,m4_echo]m4_for([i],
+m4_count(m4_map_args_pair([,m4_quote], []m4_map_args([,m4_echo]m4_for([i],
[1], [10000], [], [,i]))))
m4_divert_pop(0)
]])
m4_bmatch([9997]m4_for([i], [1], [10000], [], [,^i$]))
m4_define([up], [m4_define([$1], m4_incr($1))$1])m4_define([j], 0)dnl
m4_cond(m4_for([i], [1], [10000], [], [[up([j])], [9990], i,]) [oops]) j
-m4_count(m4_transform_pair([,m4_quote], []m4_transform([,m4_echo]m4_for([i],
+m4_count(m4_map_args_pair([,m4_quote], []m4_map_args([,m4_echo]m4_for([i],
[1], [10000], [], [,i]))))
m4_divert_pop(0)
]])