following a comma in the original @var{arg}. Any time multiple
arguments are collected into one with @code{m4_quote}, the M4 argument
collection rules discard the whitespace. However, with @code{m4_expand},
-whitespace is discarded only if it results from unquoted commas in the
-expansion of macros contained in @var{arg}.
+whitespace is preserved, even after the expansion of macros contained in
+@var{arg}.
Note that @code{m4_expand} cannot parse everything. The expansion of
@var{arg} must not contain unbalanced quotes (although quadrigraphs can
m4_quote(active, active)
@result{}ACT,IVE,ACT,IVE
m4_expand([active, active])
-@result{}ACT,IVE, ACT,IVE
+@result{}ACT, IVE, ACT, IVE
m4_quote(active2, active2)
@result{}ACT, IVE,ACT, IVE
m4_expand([active2, active2])
# --------------
# 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 (however, it does not preserve whitespace after any unquoted
-# commas encountered in the expansion).
+# 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
+# => ACT, IVE, ACT, IVE
#
# Unfortunately, due to limitations in m4, ARG must contain balanced quotes
# (use quadrigraphs) and balanced parentheses (use creative shell comments
# when writing shell case statements).
#
-# Splitting a quoted ARG on `,' preserves space, but produces a quoted list.
-# Unquote the list, then expand each argument while preserving the leading
-# spaces; finally, collect each argument back into the final string.
-m4_define([m4_expand],
-[m4_quote(_$0(m4_unquote(m4_split([$1], [,]))))])
-
-# _m4_expand(ARGS)
-# ----------------
-# Return the expansion of each ARG, separated by `,'. Less efficient than
-# m4_unquote, but preserves quoted leading space in each ARG.
+# 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_if([$#], [0], [],
- [$#], [1], [$1],
- [$1,$0(m4_shift($@))])])
+[m4_changequote([(], [)])$1m4_changequote`'m4_changequote(`[', `]')])
# m4_ignore(ARGS)
# as the algorithm no longer guarantees uniqueness.
m4_define([m4_append_uniq],
[m4_ifval([$3], [m4_if(m4_index([$2], [$3]), [-1], [],
- [m4_warn([syntax],
- [$0: `$2' contains `$3'])])])_$0($@)])
+ [m4_warn([syntax],
+ [$0: `$2' contains `$3'])])])_$0($@)])
m4_define([_m4_append_uniq],
[m4_ifdef([$1],
[m4_if(m4_index([$3]m4_builtin([defn], [$1])[$3], [$3$2$3]), [-1],
# Avoid overhead of m4_defn by using m4_builtin.
m4_define([m4_append_uniq_w],
[m4_foreach_w([m4_Word], [$2],
- [_m4_append_uniq([$1], m4_builtin([defn], [m4_Word]), [ ])])])
+ [_m4_append_uniq([$1], m4_builtin([defn], [m4_Word]), [ ])])])
# m4_text_wrap(STRING, [PREFIX], [FIRST-PREFIX], [WIDTH])
## -------------- ##
AT_SETUP([AS@&t@_HELP_STRING])
-AT_KEYWORDS([m4@&t@_text_wrap])
+AT_KEYWORDS([m4@&t@_text_wrap m4@&t@_expand])
AT_DATA_M4SH([script.as],
[[AS_INIT
echo "AS_HELP_STRING([--mac], [mac])"
echo "AS_HELP_STRING([--o1, --o2], [two
options, one description])"
+echo "AS_HELP_STRING([[[--o3, --o4]]], [comma inside literal quoting])"
echo "AS_HELP_STRING([--tune1], [check out the tuned formatting],
[ ])"
echo "AS_HELP_STRING([--tune2], [check out the tuned formatting],
80 characters.
--MACRO mac
--o1, --o2 two options, one description
+ [--o3, --o4] comma inside literal quoting
--tune1 check out the tuned formatting
--tune2 check out the tuned formatting
--tune3 check out the