2008-07-29 Eric Blake <ebb9@byu.net>
+ Tweak m4_do semantics.
+ * lib/m4sugar/m4sugar.m4 (m4_do): Don't concat final argument with
+ subsequent text.
+ * lib/m4sugar/foreach.m4 (m4_do): Don't concat intermediate
+ arguments, and avoid infinite loop.
+ * doc/autoconf.texi (Evaluation Macros) <m4_do>: Document the
+ behavior.
+ * tests/m4sugar.at (m4@&t@_do): New test.
+
Optimize m4_for.
* lib/m4sugar/m4sugar.m4 (m4_for): Use fewer macros.
(_m4_for): Take additional parameter, for fewer m4_indir calls.
@msindex{do}
This macro loops over its arguments and expands each @var{arg} in
sequence. Its main use is for readability; it allows the use of
-indentation and fewer @code{dnl} to result in the same expansion.
+indentation and fewer @code{dnl} to result in the same expansion. This
+macro guarantees that no expansion will be concatenated with subsequent
+text; to achieve full concatenation, use @code{m4_unquote(m4_join([],
+@var{arg@dots{}}))}.
+
+@example
+m4_define([ab],[1])m4_define([bc],[2])m4_define([abc],[3])dnl
+m4_do([a],[b])c
+@result{}abc
+m4_unquote(m4_join([],[a],[b]))c
+@result{}3
+m4_define([a],[A])m4_define([b],[B])m4_define([c],[C])dnl
+m4_define([AB],[4])m4_define([BC],[5])m4_define([ABC],[6])dnl
+m4_do([a],[b])c
+@result{}ABC
+m4_unquote(m4_join([],[a],[b]))c
+@result{}3
+@end example
@end defmac
@defmac m4_dquote (@var{arg}, @dots{})
# 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])
+# $1[]$2[]...[]$n[]_m4_popdef([_m4_do])
m4_define([m4_do],
-[m4_define([_$0], m4_pushdef([_$0])_m4_for([_$0], [1], [$#], [1],
- [$_$0])[[]_m4_popdef([_$0])])_$0($@)])
+[m4_if([$#], [0], [],
+ [m4_define([_$0], m4_pushdef([_$0])_m4_for([_$0], [1], [$#], [1],
+ [$_$0[[]]])[_m4_popdef([_$0])])_$0($@)])])
# m4_dquote_elt(ARGS)
# -------------------
#
# A bit easier than m4_join. m4_foreach to the rescue.
m4_define([m4_joinall],
-[[$2]m4_if([$#], [1], [], [$#], [2], [],
+[[$2]m4_if(m4_eval([$# <= 2]), [1], [],
[m4_foreach([_m4_arg], [m4_shift2($@)],
[[$1]_m4_defn([_m4_arg])])])])
# ------------------
# 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.
+# 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[]m4_do(m4_shift($@))])])
+ [$#], 1, [$1[]],
+ [$1[]$0(m4_shift($@))])])
# m4_dquote(ARGS)
# 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], [$*])
AT_CLEANUP
+## ------- ##
+## m4_do. ##
+## ------- ##
+
+AT_SETUP([m4@&t@_do])
+
+AT_CHECK_M4SUGAR_TEXT(
+[[m4_define([ab], [1])m4_define([bc], [2])m4_define([abc], [3])dnl
+m4_define([AB], [4])m4_define([BC], [5])m4_define([ABC], [6])dnl
+m4_do
+m4_do([a])
+m4_do([a], [b])c
+m4_unquote(m4_join([], [a], [b]))c
+m4_define([a], [A])m4_define([b], [B])m4_define([c], [C])dnl
+m4_do([a], [b])c
+m4_unquote(m4_join([], [a], [b]))c
+]],
+[[
+a
+abc
+3
+ABC
+3
+]])
+
+AT_CLEANUP
+
+
## ----------- ##
## m4_append. ##
## ----------- ##