]> git.ipfire.org Git - thirdparty/autoconf.git/commitdiff
Fix m4_map regression from 2007-10-16.
authorEric Blake <ebb9@byu.net>
Fri, 15 Aug 2008 13:06:39 +0000 (07:06 -0600)
committerEric Blake <ebb9@byu.net>
Fri, 15 Aug 2008 13:06:39 +0000 (07:06 -0600)
* lib/m4sugar/m4sugar.m4 (_m4_apply): New macro.
(m4_map): Ignore empty sublists.  For a list consisting of only an
empty sublist, this restores 2.61 behavior of being a no-op.
(m4_map_sep): Likewise, and expand separator.
(m4_mapall, m4_mapall_sep): New macros, to regain 2.62 behavior.
(_m4_map): Rewrite, to be common base for all four variants.
* lib/m4sugar/foreach.m4 (_m4_map): Adjust to new prototype.
* tests/m4sugar.at (m4@&t@_map): Add tests.
* doc/autoconf.texi (Looping constructs) <m4_map>: Document new
macros, and mention ramifications of expanded separator.
* NEWS: Mention the change.

Signed-off-by: Eric Blake <ebb9@byu.net>
ChangeLog
NEWS
doc/autoconf.texi
lib/m4sugar/foreach.m4
lib/m4sugar/m4sugar.m4
tests/m4sugar.at

index 9df0fa666adffec096c606ffd3f845dbae6fc64f..d62576b789e1714fa3e9a51ea2cfbace5c89e660 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,18 @@
+2008-08-15  Eric Blake  <ebb9@byu.net>
+
+       Fix m4_map regression from 2007-10-16.
+       * lib/m4sugar/m4sugar.m4 (_m4_apply): New macro.
+       (m4_map): Ignore empty sublists.  For a list consisting of only an
+       empty sublist, this restores 2.61 behavior of being a no-op.
+       (m4_map_sep): Likewise, and expand separator.
+       (m4_mapall, m4_mapall_sep): New macros, to regain 2.62 behavior.
+       (_m4_map): Rewrite, to be common base for all four variants.
+       * lib/m4sugar/foreach.m4 (_m4_map): Adjust to new prototype.
+       * tests/m4sugar.at (m4@&t@_map): Add tests.
+       * doc/autoconf.texi (Looping constructs) <m4_map>: Document new
+       macros, and mention ramifications of expanded separator.
+       * NEWS: Mention the change.
+
 2008-08-14  Eric Blake  <ebb9@byu.net>
 
        Implement m4_transform_pair, to speed up AS_IF.
diff --git a/NEWS b/NEWS
index 30116971641961de84bfb807968f12ea105b57d0..96995567ca6b6682a9451dd6cb3ce0379d5e6d63 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -19,6 +19,14 @@ GNU Autoconf NEWS - User visible changes.
 
      AC_TYPE_SIGNAL
 
+** The macros m4_map and m4_map_sep now ignore any list elements
+   consisting of just empty quotes, and m4_map_sep now expands its
+   separator.  This fixes a regression in 2.62 when these macros were
+   first documented, for the sake of clients expecting the semantics
+   that these macros had prior to that time.  The new macros m4_mapall
+   and m4_mapall_sep, along with extra quoting of the separator, can
+   be used to get the semantics that m4_map_sep had in 2.62.
+
 ** Clients of m4_expand, such as AS_HELP_STRING and AT_SETUP, can now
    handle properly quoted but otherwise unbalanced parentheses (for
    some macros, this fixes a regression in 2.62).
@@ -27,10 +35,11 @@ GNU Autoconf NEWS - User visible changes.
    allowing the output of unbalanced parantheses in more contexts.
 
 ** The following m4sugar macros are new:
-   m4_joinall  m4_reverse  m4_set_add  m4_set_add_all  m4_set_contains
-   m4_set_contents  m4_set_delete  m4_set_difference  m4_set_dump
-   m4_set_empty  m4_set_foreach  m4_set_intersection  m4_set_list
-   m4_set_listc  m4_set_remove  m4_set_size  m4_set_union
+   m4_joinall  m4_mapall  m4_mapall_sep  m4_reverse  m4_set_add
+   m4_set_add_all  m4_set_contains  m4_set_contents  m4_set_delete
+   m4_set_difference  m4_set_dump  m4_set_empty  m4_set_foreach
+   m4_set_intersection  m4_set_list  m4_set_listc  m4_set_remove
+   m4_set_size  m4_set_union
 
 ** The following m4sugar macros now accept multiple arguments, as is the
    case with underlying m4:
index 61cccca656cd0837c56acddac9b877da3abd45c3..2ce88f807e6adbc37113774ec1c11fe42f283ade 100644 (file)
@@ -10822,24 +10822,49 @@ The deprecated macro @code{AC_FOREACH} is an alias of
 @end defmac
 
 @defmac m4_map (@var{macro}, @var{list})
+@defmacx m4_mapall (@var{macro}, @var{list})
 @defmacx m4_map_sep (@var{macro}, @var{separator}, @var{list})
+@defmacx m4_mapall_sep (@var{macro}, @var{separator}, @var{list})
+@msindex{map}
+@msindex{mapall}
+@msindex{map_sep}
+@msindex{mapall_sep}
 Loop over the comma separated quoted list of argument descriptions in
 @var{list}, and invoke @var{macro} with the arguments.  An argument
 description is in turn a comma-separated quoted list of quoted elements,
-suitable for @code{m4_apply}, making it possible to invoke @var{macro}
-without arguments if an argument description is empty.
-@code{m4_map_sep} additionally outputs @var{separator} between macro
-invocations, with no additional expansion of the separator.
+suitable for @code{m4_apply}.  The macros @code{m4_map} and
+@code{m4_map_sep} ignore empty argument descriptions, while
+@code{m4_mapall} and @code{m4_mapall_sep} invoke @var{macro} with no
+arguments.  The macros @code{m4_map_sep} and @code{m4_mapall_sep}
+additionally expand @var{separator} between invocations of @var{macro}.
+
+Note that @var{separator} is expanded, unlike in @code{m4_join}.  When
+separating output with commas, this means that the map result can be
+used as a series of arguments, by using a single-quoted comma as
+@var{separator}, or as a single string, by using a double-quoted comma.
+
 @example
 m4_map([m4_count], [])
 @result{}
 m4_map([ m4_count], [[],
                      [[1]],
                      [[1], [2]]])
+@result{} 1 2
+m4_mapall([ m4_count], [[],
+                        [[1]],
+                        [[1], [2]]])
 @result{} 0 1 2
 m4_map_sep([m4_eval], [,], [[[1+2]],
                             [[10], [16]]])
 @result{}3,a
+m4_map_sep([m4_echo], [,], [[[a]], [[b]]])
+@result{}a,b
+m4_count(m4_map_sep([m4_echo], [,], [[[a]], [[b]]]))
+@result{}2
+m4_map_sep([m4_echo], [[,]], [[[a]], [[b]]])
+@result{}a,b
+m4_count(m4_map_sep([m4_echo], [[,]], [[[a]], [[b]]]))
+@result{}1
 @end example
 @end defmac
 
index 53a2c7e24a0a1107306b23a331059ff957a21128..91a96430610715ba17f9c89842ded04a8c150b5a 100644 (file)
@@ -257,11 +257,16 @@ m4_define([m4_reverse],
 # 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.  m4_foreach to the rescue.
+# _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_foreach([_m4_elt], [m4_shift2($@)],
-                  [m4_apply([$1], m4_defn([_m4_elt]))])])])
+       [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...)
 # --------------------------------
index a5a07b9616e1cbaa5c8323bf7d30b040e9bd4480..b337370876cb200032161908b476f0777a31946e 100644 (file)
@@ -684,10 +684,17 @@ m4_define([m4_wrap_lifo],
 # ---------------------
 # Invoke MACRO, with arguments provided from the quoted list of
 # comma-separated quoted arguments.  If LIST is empty, invoke MACRO
-# without arguments.
+# without arguments.  The expansion will not be concatenated with
+# subsequent text.
 m4_define([m4_apply],
 [m4_if([$2], [], [$1], [$1($2)])[]])
 
+# _m4_apply(MACRO, LIST)
+# ----------------------
+# Like m4_apply, except do nothing if LIST is empty.
+m4_define([_m4_apply],
+[m4_if([$2], [], [], [$1($2)[]])])
+
 
 # m4_count(ARGS)
 # --------------
@@ -803,7 +810,7 @@ m4_define([m4_quote],  [[$*]])
 # ---------------
 # 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_map), this feature can be used to distinguish between
+# 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],
@@ -1002,31 +1009,63 @@ m4_define([m4_foreach_w],
 
 
 # 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.
-#
-# Since LIST may be quite large, we want to minimize how often it appears
-# in the expansion.  Rather than use m4_car/m4_cdr iteration, we unbox the
-# list, ignore the second argument, and use m4_shift2 to detect the end of
-# recursion.
+# m4_mapall(MACRO, LIST)
+# ----------------------
+# Invoke MACRO($1), MACRO($2) etc. where $1, $2... are the elements of
+# LIST.  $1, $2... must in turn be lists, appropriate for m4_apply.
+# If LIST contains an empty sublist, m4_map skips the expansion of
+# MACRO, while m4_mapall expands MACRO with no arguments.
+#
+# Since LIST may be quite large, we want to minimize how often it
+# appears in the expansion.  Rather than use m4_car/m4_cdr iteration,
+# we unbox the list, ignore the second argument, and use m4_shift2 to
+# detect the end of recursion.  The mismatch in () is intentional; see
+# _m4_map.  For m4_map, an empty list behaves like an empty sublist
+# and gets ignored; for m4_mapall, we must special-case the empty
+# list.
 m4_define([m4_map],
+[_m4_map([_m4_apply([$1]], [], $2)])
+
+m4_define([m4_mapall],
 [m4_if([$2], [], [],
-       [_$0([$1], [], $2)])])
-m4_define([_m4_map],
-[m4_if([$#], [2], [],
-       [m4_apply([$1], [$3])$0([$1], m4_shift2($@))])])
+       [_m4_map([m4_apply([$1]], [], $2)])])
 
 
 # m4_map_sep(MACRO, SEPARATOR, LIST)
-# ----------------------------------
-# Invoke MACRO($1), SEPARATOR, MACRO($2), ..., MACRO($N) where $1, $2... $N
-# are the elements of LIST, and are in turn lists appropriate for m4_apply.
-# SEPARATOR is not further expanded.
+# m4_mapall_sep(MACRO, SEPARATOR, LIST)
+# -------------------------------------
+# Invoke MACRO($1), SEPARATOR, MACRO($2), ..., MACRO($N) where $1,
+# $2... $N are the elements of LIST, and are in turn lists appropriate
+# for m4_apply.  SEPARATOR is expanded, in order to allow the creation
+# of a list of arguments by using a single-quoted comma as the
+# separator.  For each empty sublist, m4_map_sep skips the expansion
+# of MACRO and SEPARATOR, while m4_mapall_sep expands MACRO with no
+# arguments.
+#
+# For m4_mapall_sep, merely expand the first iteration without the
+# separator, then include separator as part of subsequent recursion.
+# For m4_map_sep, things are trickier - we don't know if the first
+# list element is an empty sublist, so we must define a self-modifying
+# helper macro and use that as the separator instead.
 m4_define([m4_map_sep],
+[m4_pushdef([m4_Sep], [m4_define([m4_Sep], _m4_defn([m4_unquote]))])]dnl
+[_m4_map([_m4_apply([m4_Sep([$2])[]$1]], [], $3)m4_popdef([m4_Sep])])
+
+m4_define([m4_mapall_sep],
 [m4_if([$3], [], [],
-       [m4_apply([$1], m4_car($3))_m4_map([[$2]$1], $3)])])
+       [m4_apply([$1], m4_car($3))_m4_map([m4_apply([$2[]$1]], $3)])])
 
+# _m4_map(PREFIX, IGNORED, SUBLIST, ...)
+# --------------------------------------
+# Common implementation for all four m4_map variants.  The mismatch in
+# the number of () is intentional.  PREFIX must supply a form of
+# m4_apply, the open `(', and the MACRO to be applied.  Each iteration
+# then appends `,', the current SUBLIST and the closing `)', then
+# recurses to the next SUBLIST.  IGNORED is an aid to ending recursion
+# efficiently.
+m4_define([_m4_map],
+[m4_if([$#], [2], [],
+       [$1, [$3])$0([$1], m4_shift2($@))])])
 
 # m4_transform(EXPRESSION, ARG...)
 # --------------------------------
index 8e9885ae472e44f69c4f211356bded9eb0f69839..75207e4dea6a209a66d3204a4234def748bf6027 100644 (file)
@@ -757,12 +757,12 @@ autom4te: m4 failed with exit status: 1
 AT_CLEANUP
 
 
-## --------------- ##
-## m4_map{,_sep}.  ##
-## --------------- ##
+## --------------------- ##
+## m4_map{,all}{,_sep}.  ##
+## --------------------- ##
 
 AT_SETUP([m4@&t@_map])
-AT_KEYWORDS([m4@&t@_apply])
+AT_KEYWORDS([m4@&t@_apply m4@&t@_map_sep m4@&t@_mapall m4@&t@_mapall_sep])
 AT_KEYWORDS([m4@&t@_count])
 
 AT_CHECK_M4SUGAR_TEXT([[dnl
@@ -770,8 +770,21 @@ m4_map([m4_count], [])
 m4_map([ m4_count], [[],
                      [[1]],
                      [[1], [2]]])
+m4_mapall([ m4_count], [[],
+                        [[1]],
+                        [[1], [2]]])
 m4_map_sep([m4_eval], [,], [[[1+2]],
                             [[10], [16]]])
+m4_count(m4_map_sep([m4_echo], [,], [[], [[1]], [[2]]]))
+m4_count(m4_mapall_sep([m4_echo], [,], [[], [[1]], [[2]]]))
+m4_map_sep([m4_eval], [[,]], [[[1+2]],
+                              [[10], [16]]])
+m4_count(m4_map_sep([m4_echo], [[,]], [[], [[1]], [[2]]]))
+m4_count(m4_mapall_sep([m4_echo], [[,]], [[], [[1]], [[2]]]))
+m4_map([-], [[]])
+m4_mapall([-], [[]])
+m4_map_sep([-], [:], [[]])
+m4_mapall_sep([-], [:], [[]])
 m4_define([a], [m4_if([$#], [0], [oops], [$1], [a], [pass], [oops])])dnl
 m4_define([a1], [oops])dnl
 m4_define([pass1], [oops])dnl
@@ -779,8 +792,18 @@ m4_map([a], [[[a]]])1
 m4_map([m4_unquote([a])], [m4_dquote([a])])
 ]],
 [[
+ 1 2
  0 1 2
 3,a
+2
+3
+3,a
+1
+1
+
+-
+
+-
 pass1
 pass
 ]], [])