-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

This fixes the foreach documentation for once and for all.  The examples
in the manual (at least, the examples in the solutions section :) are now
PROPERLY quoted (unlike what shipped in the examples directory in 1.4.7
and earlier), and linear in behavior (unlike what is currently in CVS
head, which is quadratic).  It documents lists "(like, this)" (which is
what was documented in the examples directory) or "`like, this'" (which is
the style m4sugar uses, albeit with different quote characters).  This
draws in part from the lessons learned from Autoconf's m4sugar, where in
2002 Akim realized that quadratic behavior in foreach was killing autoconf.
http://cvs.savannah.gnu.org/viewcvs/autoconf/lib/m4sugar/m4sugar.m4?root=autoconf&r1=2.60&r2=2.61
I also gave the info and pdf formats a once-over to ensure the new
sections look nice, which turned up a couple of other formatting issues.

Patch to head to follow.

As I see it, all that remains to get 1.4.8 out the door is Bruno's
approval of my pending patch to get mingw builds working again.

2006-10-20  Eric Blake  <[EMAIL PROTECTED]>

        * doc/m4.texinfo: Trailing '@comment' doesn't format nicely in
        TeX, so recognize '@w{ }' instead.  Likewise, @code{_name} at the
        end of a TeX line splits incorrectly.
        (Foreach, Improved foreach): Write these sections, borrowing ideas
        from CVS head and from m4sugar.
        * checks/get-them: Accomodate new way to show trailing space in
        examples.
        * examples/foreach.m4: Make usable in documentation.
        * examples/foreachq.m4: New file.
        * examples/foreachq2.m4: New file.
        * examples/foreach2.m4: New file.
        * NEWS: Document the documentation updates.

- --
Life is short - so eat dessert first!

Eric Blake             [EMAIL PROTECTED]
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.2.1 (Cygwin)
Comment: Public key at home.comcast.net/~ericblake/eblake.gpg
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org

iD8DBQFFOYvG84KuGfSFAYARAkmYAJsHazEMoNAwHHAN0m2AsI2+ng/nOQCeOIGq
UdfcI3rgUJht0voGJjHUnG8=
=FJqx
-----END PGP SIGNATURE-----
? doc/.am1200
Index: NEWS
===================================================================
RCS file: /sources/m4/m4/NEWS,v
retrieving revision 1.1.1.1.2.73
diff -u -p -r1.1.1.1.2.73 NEWS
--- NEWS        19 Oct 2006 23:13:05 -0000      1.1.1.1.2.73
+++ NEWS        21 Oct 2006 02:35:32 -0000
@@ -36,6 +36,8 @@ Version 1.4.8 - ?? ??? 2006, by ??  (CVS
   use `mkstemp' instead.  Additionally, `mkstemp' and `maketemp' are now
   well-defined even if the template argument does not end in six `X'
   characters.
+* The manual has been improved, including a new section on a composite
+  macro `foreach'.
 
 Version 1.4.7 - 25 September 2006, by Eric Blake  (CVS version 1.4.6a)
 
Index: checks/get-them
===================================================================
RCS file: /sources/m4/m4/checks/Attic/get-them,v
retrieving revision 1.1.1.1.2.6
diff -u -p -r1.1.1.1.2.6 get-them
--- checks/get-them     22 Aug 2006 16:13:38 -0000      1.1.1.1.2.6
+++ checks/get-them     21 Oct 2006 02:35:32 -0000
@@ -64,7 +64,7 @@ BEGIN {
   else
     prefix = "";
   gsub("@@", "@", $0);
-  gsub("@comment.*", "", $0);
+  gsub("@w{ }", " ", $0);
   gsub("@tabchar{}", "\t", $0);
   printf("%s%s\n", prefix, $0) >> file;
 }
Index: doc/m4.texinfo
===================================================================
RCS file: /sources/m4/m4/doc/m4.texinfo,v
retrieving revision 1.1.1.1.2.90
diff -u -p -r1.1.1.1.2.90 m4.texinfo
--- doc/m4.texinfo      19 Oct 2006 23:13:05 -0000      1.1.1.1.2.90
+++ doc/m4.texinfo      21 Oct 2006 02:35:34 -0000
@@ -1629,7 +1629,7 @@ define(`string', `The macro dnl is very 
 ')
 @result{}
 string
[EMAIL PROTECTED] macro @comment
[EMAIL PROTECTED] [EMAIL PROTECTED] }
 defn(`string')
 @result{}The macro dnl is very useful
 @result{}
@@ -2187,7 +2187,7 @@ It can, for example, be used for simple 
 include(`forloop.m4')
 @result{}
 forloop(`i', `1', `8', `i ')
[EMAIL PROTECTED] 2 3 4 5 6 7 8 @comment
[EMAIL PROTECTED] 2 3 4 5 6 7 [EMAIL PROTECTED] }
 @end example
 
 For-loops can be nested, like:
@@ -2207,12 +2207,12 @@ forloop(`i', `1', `4', `forloop(`j', `1'
 The implementation of the @code{forloop} macro is fairly
 straightforward.  The @code{forloop} macro itself is simply a wrapper,
 which saves the previous definition of the first argument, calls the
-internal macro @code{_forloop}, and re-establishes the saved definition of
-the first argument.
+internal macro @[EMAIL PROTECTED], and re-establishes the saved
+definition of the first argument.
 
-The macro @code{_forloop} expands the fourth argument once, and tests
-to see if the iterator has reached the final value.  If it has not
-finished, it increments the iterator (using the predefined macro
+The macro @[EMAIL PROTECTED] expands the fourth argument once, and
+tests to see if the iterator has reached the final value.  If it has
+not finished, it increments the iterator (using the predefined macro
 @code{incr}, @pxref{Incr}), and recurses.
 
 Here is an actual implementation of @code{forloop}, distributed as
@@ -2240,7 +2240,151 @@ macros; or @pxref{Improved forloop, , An
 @node Foreach
 @section Iteration by list contents
 
-FIXME - Fill out this section.
[EMAIL PROTECTED] for each loops
[EMAIL PROTECTED] loops, list iteration
[EMAIL PROTECTED] iterating over lists
+Here is an example of a loop macro that implements list iteration.
+
[EMAIL PROTECTED] Composite foreach (@var{iterator}, @var{paren-list}, 
@var{text})
[EMAIL PROTECTED] Composite foreachq (@var{iterator}, @var{quote-list}, 
@var{text})
+Takes the name in @var{iterator}, which must be a valid macro name, and
+successively assign it each value from @var{paren-list} or
[EMAIL PROTECTED]  In @code{foreach}, @var{paren-list} is a
+comma-separated list of elements contained in parentheses.  In
[EMAIL PROTECTED], @var{quote-list} is a comma-separated list of elements
+contained in a quoted string.  For each assignment to @var{iterator},
+append @var{text} to the overall expansion.  @var{text} may refer to
[EMAIL PROTECTED]  Any definition of @var{iterator} prior to this
+invocation is restored.
[EMAIL PROTECTED] deffn
+
+As an example, this displays each word in a list inside of a sentence,
+using an implementation of @code{foreach} distributed as
[EMAIL PROTECTED]@value{VERSION}/@/examples/@/foreach.m4}, and @code{foreachq}
+in @[EMAIL PROTECTED]/@/examples/@/foreachq.m4}.
+
[EMAIL PROTECTED]
+include(`foreach.m4')
[EMAIL PROTECTED]
+foreach(`x', (foo, bar, foobar), `Word was: x
+')dnl
[EMAIL PROTECTED] was: foo
[EMAIL PROTECTED] was: bar
[EMAIL PROTECTED] was: foobar
+include(`foreachq.m4')
[EMAIL PROTECTED]
+foreachq(`x', `foo, bar, foobar', `Word was: x
+')dnl
[EMAIL PROTECTED] was: foo
[EMAIL PROTECTED] was: bar
[EMAIL PROTECTED] was: foobar
[EMAIL PROTECTED] example
+
+It is possible to be more complex; each element of the @var{paren-list}
+or @var{quote-list} can itself be a list, to pass as further arguments
+to a helper macro.  This example generates a shell case statement:
+
[EMAIL PROTECTED]
+include(`foreach.m4')
[EMAIL PROTECTED]
+define(`_case', `  $1)
+    $2=" $1";;
+')dnl
+define(`_cat', `$1$2')dnl
+case $`'1 in
[EMAIL PROTECTED] $1 in
+foreach(`x', `(`(`a', `vara')', `(`b', `varb')', `(`c', `varc')')',
+        `_cat(`_case', x)')dnl
[EMAIL PROTECTED]  a)
[EMAIL PROTECTED]    vara=" a";;
[EMAIL PROTECTED]  b)
[EMAIL PROTECTED]    varb=" b";;
[EMAIL PROTECTED]  c)
[EMAIL PROTECTED]    varc=" c";;
+esac
[EMAIL PROTECTED]
[EMAIL PROTECTED] example
+
+The implementation of the @code{foreach} macro is a bit more involved;
+it is a wrapper around two helper macros.  First, @[EMAIL PROTECTED] is
+needed to grab the first element of a list.  Second,
[EMAIL PROTECTED]@w{_foreach}} implements the recursion, successively walking
+through the original list.  Here is a simple implementation of
[EMAIL PROTECTED]:
+
[EMAIL PROTECTED]
+undivert(`foreach.m4')dnl
[EMAIL PROTECTED](`-1')
[EMAIL PROTECTED] foreach(x, (item_1, item_2, ..., item_n), stmt)
[EMAIL PROTECTED]   parenthesized list, simple version
[EMAIL PROTECTED](`foreach', `pushdef(`$1')_foreach($@@)popdef(`$1')')
[EMAIL PROTECTED](`_arg1', `$1')
[EMAIL PROTECTED](`_foreach', `ifelse(`$2', `()', `',
[EMAIL PROTECTED]  `define(`$1', _arg1$2)$3`'$0(`$1', (shift$2), `$3')')')
[EMAIL PROTECTED]'dnl
[EMAIL PROTECTED] example
+
+Unfortunately, that implementation is not robust to macro names as list
+elements.  Each iteration of @[EMAIL PROTECTED] is stripping another
+layer of quotes, leading to erratic results if list elements are not
+already fully expanded.  The first cut at implementing @code{foreachq}
+takes this into account.  Also, when using quoted elements in a
[EMAIL PROTECTED], the overall list must be quoted.  A @var{quote-list}
+has the nice property of requiring fewer characters to create a list
+containing the same quoted elements.  To see the difference between the
+two macros, we attempt to pass double-quoted macro names in a list,
+expecting the macro name on output after one layer of quotes is removed
+during list iteration and the final layer removed during the final
+rescan:
+
[EMAIL PROTECTED]
+define(`a', `1')define(`b', `2')define(`c', `3')
[EMAIL PROTECTED]
+include(`foreach.m4')
[EMAIL PROTECTED]
+include(`foreachq.m4')
[EMAIL PROTECTED]
+foreach(`x', `(``a'', ``(b'', ``c)'')', `x
+')
[EMAIL PROTECTED]
[EMAIL PROTECTED](2)1
[EMAIL PROTECTED]
[EMAIL PROTECTED], x
[EMAIL PROTECTED])
+foreachq(`x', ```a'', ``(b'', ``c)''', `x
+')dnl
[EMAIL PROTECTED]
[EMAIL PROTECTED](b
[EMAIL PROTECTED])
[EMAIL PROTECTED] example
+
+Obviously, @code{foreachq} did a better job; here is its implementation:
+
[EMAIL PROTECTED]
+undivert(`foreachq.m4')dnl
[EMAIL PROTECTED](`quote.m4')dnl
[EMAIL PROTECTED](`-1')
[EMAIL PROTECTED] foreachq(x, `item_1, item_2, ..., item_n', stmt)
[EMAIL PROTECTED]   quoted list, simple version
[EMAIL PROTECTED](`foreachq', `pushdef(`$1')_foreachq($@@)popdef(`$1')')
[EMAIL PROTECTED](`_arg1', `$1')
[EMAIL PROTECTED](`_foreachq', `ifelse(quote($2), `', `',
[EMAIL PROTECTED]  `define(`$1', `_arg1($2)')$3`'$0(`$1', `shift($2)', `$3')')')
[EMAIL PROTECTED]'dnl
[EMAIL PROTECTED] example
+
+Notice that @[EMAIL PROTECTED] had to use the helper macro
[EMAIL PROTECTED] defined earlier (@pxref{Shift}), to ensure that the
+embedded @code{ifelse} call does not go haywire if a list element
+contains a comma.  Unfortunately, this implementation of @code{foreachq}
+has its own severe flaw.  Whereas the @code{foreach} implementation was
+linear, this macro is quadratic in the number of list elements, and is
+much more likely to trip up the limit set by the command line option
[EMAIL PROTECTED] (or @option{-L}, @pxref{Limits control, ,
+Invoking m4}).  (It is possible to have robust iteration with linear
+behavior for either list style.  See if you can learn from the best
+elements of both of these implementations to create robust macros; or
[EMAIL PROTECTED] foreach, , Answers}).
 
 @node Debugging
 @chapter How to debug macros and input
@@ -3937,7 +4081,7 @@ patsubst(`GNUs not Unix', `\w*', `(\&)')
 patsubst(`GNUs not Unix', `\w+', `(\&)')
 @result{}(GNUs) (not) (Unix)
 patsubst(`GNUs not Unix', `[A-Z][a-z]+')
[EMAIL PROTECTED] not @comment
[EMAIL PROTECTED] [EMAIL PROTECTED] }
 patsubst(`GNUs not Unix', `not', `NOT\')
 @error{}m4:stdin:6: Warning: trailing \ ignored in replacement
 @result{}GNUs NOT Unix
@@ -4307,10 +4451,10 @@ environment of @code{m4}.  If defined, e
 string.
 @end deffn
 
-When @acronym{GNU} extensions are in effect (that is, when you did not use the
[EMAIL PROTECTED] option, @pxref{Limits control, , Invoking m4}),
[EMAIL PROTECTED] @code{m4} will
-define the macro @code{__gnu__} to expand to the empty string.
+When @acronym{GNU} extensions are in effect (that is, when you did not
+use the @option{-G} option, @pxref{Limits control, , Invoking m4}),
[EMAIL PROTECTED] @code{m4} will define the macro @[EMAIL PROTECTED] to
+expand to the empty string.
 
 @example
 __gnu__
@@ -4320,15 +4464,15 @@ ifdef(`__gnu__', `Extensions are active'
 @end example
 
 @cindex platform macro
-On UNIX systems, @acronym{GNU} @code{m4} will define @code{__unix__} by
-default, or @code{unix} when the @option{-G} option is specified.
+On UNIX systems, @acronym{GNU} @code{m4} will define @[EMAIL PROTECTED]
+by default, or @code{unix} when the @option{-G} option is specified.
 
 On native Windows systems, @acronym{GNU} @code{m4} will define
[EMAIL PROTECTED] by default, or @code{windows} when the @option{-G}
-option is specified.
[EMAIL PROTECTED]@w{__windows__}} by default, or @code{windows} when the
[EMAIL PROTECTED] option is specified.
 
-On OS/2 systems, @acronym{GNU} @code{m4} will define @code{__os2__} by
-default, or @code{os2} when the @option{-G} option is specified.
+On OS/2 systems, @acronym{GNU} @code{m4} will define @[EMAIL PROTECTED]
+by default, or @code{os2} when the @option{-G} option is specified.
 
 If @acronym{GNU} @code{m4} does not provide a platform macro for your system,
 please report that as a bug.
@@ -4719,16 +4863,16 @@ foo
 @result{}6
 @end example
 
-The @code{__program__} macro behaves like @samp{$0} in shell
+The @[EMAIL PROTECTED] macro behaves like @samp{$0} in shell
 terminology.  If you invoke @code{m4} through an absolute path or a link
 with a different spelling, rather than by relying on a @env{PATH} search
-for plain @samp{m4}, it will affect how @code{__program__} expands.  The
-intent is that you can use it to produce error messages with the same
-formatting that @code{m4} produces internally.  It can also be used
+for plain @samp{m4}, it will affect how @[EMAIL PROTECTED] expands.
+The intent is that you can use it to produce error messages with the
+same formatting that @code{m4} produces internally.  It can also be used
 within @code{syscmd} (@pxref{Syscmd}) to pick the same version of
 @code{m4} that is currently running, rather than whatever version of
[EMAIL PROTECTED] happens to be first in @env{PATH}.  It was first introduced
-in @acronym{GNU} M4 1.4.6.
[EMAIL PROTECTED] happens to be first in @env{PATH}.  It was first introduced in
[EMAIL PROTECTED] M4 1.4.6.
 
 @node M4exit
 @section Exiting from @code{m4}
@@ -5069,8 +5213,8 @@ Macros can be called indirectly through 
 
 @item
 The name of the program, the current input file, and the current input
-line number are accessible through the builtins @code{__program__},
[EMAIL PROTECTED], and @code{__line__} (@pxref{Location}).
+line number are accessible through the builtins @[EMAIL PROTECTED],
[EMAIL PROTECTED]@w{__file__}}, and @[EMAIL PROTECTED] (@pxref{Location}).
 
 @item
 The format of the output from @code{dumpdef} and macro tracing can be
@@ -5342,7 +5486,7 @@ name.  It does not do any sanity checkin
 only permits decimal numbers for bounds.  Here is an improved version,
 shipped as @[EMAIL PROTECTED]/@/examples/@/forloop2.m4}; this
 version also optimizes based on the fact that the starting bound does
-not need to be passed to the helper @code{_forloop}.
+not need to be passed to the helper @[EMAIL PROTECTED]
 
 @example
 undivert(`forloop2.m4')dnl
@@ -5379,7 +5523,199 @@ additional bells and whistles in its @co
 @node Improved foreach
 @section Solution for @code{foreach}
 
-FIXME - add content.
+The @code{foreach} and @code{foreachq} macros (@pxref{Foreach}) as
+presented earlier each have flaws.  First, we will examine and fix the
+quadratic behavior of @code{foreachq}:
+
[EMAIL PROTECTED]
+include(`foreachq.m4')
[EMAIL PROTECTED]
+traceon(`shift')debugmode(`aq')
[EMAIL PROTECTED]
+foreachq(`x', ``1', `2', `3', `4'', `x
+')dnl
[EMAIL PROTECTED]
[EMAIL PROTECTED]: -3- shift(`1', `2', `3', `4')
[EMAIL PROTECTED]: -2- shift(`1', `2', `3', `4')
[EMAIL PROTECTED]
[EMAIL PROTECTED]: -4- shift(`1', `2', `3', `4')
[EMAIL PROTECTED]: -3- shift(`2', `3', `4')
[EMAIL PROTECTED]: -3- shift(`1', `2', `3', `4')
[EMAIL PROTECTED]: -2- shift(`2', `3', `4')
[EMAIL PROTECTED]
[EMAIL PROTECTED]: -5- shift(`1', `2', `3', `4')
[EMAIL PROTECTED]: -4- shift(`2', `3', `4')
[EMAIL PROTECTED]: -3- shift(`3', `4')
[EMAIL PROTECTED]: -4- shift(`1', `2', `3', `4')
[EMAIL PROTECTED]: -3- shift(`2', `3', `4')
[EMAIL PROTECTED]: -2- shift(`3', `4')
[EMAIL PROTECTED]
[EMAIL PROTECTED]: -6- shift(`1', `2', `3', `4')
[EMAIL PROTECTED]: -5- shift(`2', `3', `4')
[EMAIL PROTECTED]: -4- shift(`3', `4')
[EMAIL PROTECTED]: -3- shift(`4')
[EMAIL PROTECTED] example
+
+Each successive iteration was adding more quoted @code{shift}
+invocations, and the entire list contents were passing through every
+iteration.  In general, when recursing, it is a good idea to make the
+recursion use fewer arguments, rather than adding additional quoted
+uses of @code{shift}.  By doing so, @code{m4} uses less memory, invokes
+fewer macros, is less likely to run into machine limits, and most
+importantly, performs faster.  The fixed version of @code{foreachq} can
+be found in @[EMAIL PROTECTED]/@/examples/@/foreachq2.m4}:
+
[EMAIL PROTECTED]
+include(`foreachq2.m4')
[EMAIL PROTECTED]
+undivert(`foreachq2.m4')dnl
[EMAIL PROTECTED](`quote.m4')dnl
[EMAIL PROTECTED](`-1')
[EMAIL PROTECTED] foreachq(x, `item_1, item_2, ..., item_n', stmt)
[EMAIL PROTECTED]   quoted list, improved version
[EMAIL PROTECTED](`foreachq', `pushdef(`$1')_foreachq($@@)popdef(`$1')')
[EMAIL PROTECTED](`_arg1q', ``$1'')
[EMAIL PROTECTED](`_rest', `ifelse(`$#', `1', `', `dquote(shift($@@))')')
[EMAIL PROTECTED](`_foreachq', `ifelse(`$2', `', `',
[EMAIL PROTECTED]  `define(`$1', _arg1q($2))$3`'$0(`$1', _rest($2), `$3')')')
[EMAIL PROTECTED]'dnl
+traceon(`shift')debugmode(`aq')
[EMAIL PROTECTED]
+foreachq(`x', ``1', `2', `3', `4'', `x
+')dnl
[EMAIL PROTECTED]
[EMAIL PROTECTED]: -3- shift(`1', `2', `3', `4')
[EMAIL PROTECTED]
[EMAIL PROTECTED]: -3- shift(`2', `3', `4')
[EMAIL PROTECTED]
[EMAIL PROTECTED]: -3- shift(`3', `4')
[EMAIL PROTECTED]
[EMAIL PROTECTED] example
+
+Note that the fixed version calls unquoted helper macros in
[EMAIL PROTECTED]@w{_foreachq}} to trim elements immediately; those helper 
macros
+in turn must re-supply the layer of quotes lost in the macro invocation.
+Contrast the use of @[EMAIL PROTECTED], which quotes the first list
+element, with @[EMAIL PROTECTED] of the earlier implementation that
+returned the first list element directly.
+
+For a different approach, the improved version of @code{foreach},
+available in @[EMAIL PROTECTED]/@/examples/@/foreach2.m4}, simply
+overquotes the arguments to @[EMAIL PROTECTED] to begin with, using
[EMAIL PROTECTED]  Then @[EMAIL PROTECTED] can just use
[EMAIL PROTECTED]@w{_arg1}} to remove the extra layer of quoting that was added 
up
+front:
+
[EMAIL PROTECTED]
+include(`foreach2.m4')
[EMAIL PROTECTED]
+undivert(`foreach2.m4')dnl
[EMAIL PROTECTED](`quote.m4')dnl
[EMAIL PROTECTED](`-1')
[EMAIL PROTECTED] foreach(x, (item_1, item_2, ..., item_n), stmt)
[EMAIL PROTECTED]   parenthesized list, improved version
[EMAIL PROTECTED](`foreach', `pushdef(`$1')_foreach(`$1',
[EMAIL PROTECTED]  (dquote(dquote_elt$2)), `$3')popdef(`$1')')
[EMAIL PROTECTED](`_arg1', `$1')
[EMAIL PROTECTED](`_foreach', `ifelse(`$2', `(`')', `',
[EMAIL PROTECTED]  `define(`$1', _arg1$2)$3`'$0(`$1', (dquote(shift$2)), 
`$3')')')
[EMAIL PROTECTED]'dnl
+traceon(`shift')debugmode(`aq')
[EMAIL PROTECTED]
+foreach(`x', `(`1', `2', `3', `4')', `x
+')dnl
[EMAIL PROTECTED]: -4- shift(`1', `2', `3', `4')
[EMAIL PROTECTED]: -4- shift(`2', `3', `4')
[EMAIL PROTECTED]: -4- shift(`3', `4')
[EMAIL PROTECTED]
[EMAIL PROTECTED]: -3- shift(``1'', ``2'', ``3'', ``4'')
[EMAIL PROTECTED]
[EMAIL PROTECTED]: -3- shift(``2'', ``3'', ``4'')
[EMAIL PROTECTED]
[EMAIL PROTECTED]: -3- shift(``3'', ``4'')
[EMAIL PROTECTED]
[EMAIL PROTECTED]: -3- shift(``4'')
[EMAIL PROTECTED] example
+
+In summary, recursion over list elements is trickier than it appeared at
+first glance, but provides a powerful idiom within @code{m4} processing.
+As a final demonstration, both list styles are now able to handle
+several scenarios that would wreak havoc on the original
+implementations.  This points out one other difference between the two
+list styles.  @code{foreach} evaluates unquoted list elements only once,
+in preparation for calling @[EMAIL PROTECTED]  But @code{foreachq}
+evaluates unquoted list elements twice while visiting the first list
+element, once in @[EMAIL PROTECTED] and once in @[EMAIL PROTECTED]  When
+deciding which list style to use, one must take into account whether
+repeating the side effects of unquoted list elements will have any
+detrimental effects.
+
[EMAIL PROTECTED]
+include(`foreach2.m4')
[EMAIL PROTECTED]
+include(`foreachq2.m4')
[EMAIL PROTECTED]
+dnl 0-element list:
+foreach(`x', `', `<x>') / foreachq(`x', `', `<x>')
[EMAIL PROTECTED] /@w{ }
+dnl 1-element list of empty element
+foreach(`x', `()', `<x>') / foreachq(`x', ``'', `<x>')
[EMAIL PROTECTED]<> / <>
+dnl 2-element list of empty elements
+foreach(`x', `(`',`')', `<x>') / foreachq(`x', ``',`'', `<x>')
[EMAIL PROTECTED]<><> / <><>
+dnl 1-element list of a comma
+foreach(`x', `(`,')', `<x>') / foreachq(`x', ``,'', `<x>')
[EMAIL PROTECTED]<,> / <,>
+dnl 2-element list of unbalanced parentheses
+foreach(`x', `(`(', `)')', `<x>') / foreachq(`x', ``(', `)'', `<x>')
[EMAIL PROTECTED]<(><)> / <(><)>
+define(`active', `ACT, IVE')
[EMAIL PROTECTED]
+traceon(`active')
[EMAIL PROTECTED]
+dnl list of unquoted macros; expansion occurs before recursion
+foreach(`x', `(active, active)', `<x>
+')dnl
[EMAIL PROTECTED]: -4- active -> `ACT, IVE'
[EMAIL PROTECTED]: -4- active -> `ACT, IVE'
[EMAIL PROTECTED]<ACT>
[EMAIL PROTECTED]<IVE>
[EMAIL PROTECTED]<ACT>
[EMAIL PROTECTED]<IVE>
+foreachq(`x', `active, active', `<x>
+')dnl
[EMAIL PROTECTED]: -3- active -> `ACT, IVE'
[EMAIL PROTECTED]: -3- active -> `ACT, IVE'
[EMAIL PROTECTED]<ACT>
[EMAIL PROTECTED]: -3- active -> `ACT, IVE'
[EMAIL PROTECTED]: -3- active -> `ACT, IVE'
[EMAIL PROTECTED]<IVE>
[EMAIL PROTECTED]<ACT>
[EMAIL PROTECTED]<IVE>
+dnl list of quoted macros; expansion occurs during recursion
+foreach(`x', `(`active', `active')', `<x>
+')dnl
[EMAIL PROTECTED]: -1- active -> `ACT, IVE'
[EMAIL PROTECTED]<ACT, IVE>
[EMAIL PROTECTED]: -1- active -> `ACT, IVE'
[EMAIL PROTECTED]<ACT, IVE>
+foreachq(`x', ``active', `active'', `<x>
+')dnl
[EMAIL PROTECTED]: -1- active -> `ACT, IVE'
[EMAIL PROTECTED]<ACT, IVE>
[EMAIL PROTECTED]: -1- active -> `ACT, IVE'
[EMAIL PROTECTED]<ACT, IVE>
+dnl list of double-quoted macro names; no expansion
+foreach(`x', `(``active'', ``active'')', `<x>
+')dnl
[EMAIL PROTECTED]<active>
[EMAIL PROTECTED]<active>
+foreachq(`x', ```active'', ``active''', `<x>
+')dnl
[EMAIL PROTECTED]<active>
[EMAIL PROTECTED]<active>
[EMAIL PROTECTED] example
 
 @node Improved cleardivert
 @section Solution for @code{cleardivert}
@@ -5419,12 +5755,13 @@ undivert
 @section Solution for @code{fatal_error}
 
 The @code{fatal_error} macro (@pxref{M4exit}) is not robust to versions
-of @acronym{GNU} M4 earlier than 1.4.8, where invoking @code{__file__}
-(@pxref{Location}) inside @code{m4wrap} would result in an empty string,
-and @code{__line__} resulted in @samp{0} even though all files start at
-line 1.  Furthermore, versions earlier than 1.4.6 did not support the
[EMAIL PROTECTED] macro.  If you want @code{fatal_error} to work across
-the entire 1.4.x release series, a better implementation would be:
+of @acronym{GNU} M4 earlier than 1.4.8, where invoking
[EMAIL PROTECTED]@w{__file__}} (@pxref{Location}) inside @code{m4wrap} would 
result
+in an empty string, and @[EMAIL PROTECTED] resulted in @samp{0} even
+though all files start at line 1.  Furthermore, versions earlier than
+1.4.6 did not support the @[EMAIL PROTECTED] macro.  If you want
[EMAIL PROTECTED] to work across the entire 1.4.x release series, a
+better implementation would be:
 
 @example
 define(`fatal_error',
Index: examples/foreach.m4
===================================================================
RCS file: /sources/m4/m4/examples/foreach.m4,v
retrieving revision 1.1.1.1
diff -u -p -r1.1.1.1 foreach.m4
--- examples/foreach.m4 17 Feb 2000 03:03:19 -0000      1.1.1.1
+++ examples/foreach.m4 21 Oct 2006 02:35:34 -0000
@@ -1,19 +1,8 @@
-divert(-1)
+divert(`-1')
 # foreach(x, (item_1, item_2, ..., item_n), stmt)
-define(`foreach', `pushdef(`$1', `')_foreach(`$1', `$2', `$3')popdef(`$1')')
+#   parenthesized list, simple version
+define(`foreach', `pushdef(`$1')_foreach($@)popdef(`$1')')
 define(`_arg1', `$1')
-define(`_foreach', 
-       `ifelse(`$2', `()', ,
-               `define(`$1', _arg1$2)$3`'_foreach(`$1', (shift$2), `$3')')')
-# traceon(`define', `foreach', `_foreach', `ifelse')
-divert
-foreach(`x', `(foo, bar, foobar)', `Word was: x
-')
-# Something more complex, from Pierre Gaumond <[EMAIL PROTECTED]>.
-define(`case', `  $1)
-    $2=" -$1";;
-')dnl
-define(`_cat', `$1$2')dnl
-`case' "$1" in
-foreach(`x', ((a, vara), (b, varb), (c, varc)), `_cat(`case', x)')dnl
-esac
+define(`_foreach', `ifelse(`$2', `()', `',
+  `define(`$1', _arg1$2)$3`'$0(`$1', (shift$2), `$3')')')
+divert`'dnl
Index: examples/foreach2.m4
===================================================================
RCS file: examples/foreach2.m4
diff -N examples/foreach2.m4
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ examples/foreach2.m4        21 Oct 2006 02:35:34 -0000
@@ -0,0 +1,10 @@
+include(`quote.m4')dnl
+divert(`-1')
+# foreach(x, (item_1, item_2, ..., item_n), stmt)
+#   parenthesized list, improved version
+define(`foreach', `pushdef(`$1')_foreach(`$1',
+  (dquote(dquote_elt$2)), `$3')popdef(`$1')')
+define(`_arg1', `$1')
+define(`_foreach', `ifelse(`$2', `(`')', `',
+  `define(`$1', _arg1$2)$3`'$0(`$1', (dquote(shift$2)), `$3')')')
+divert`'dnl
Index: examples/foreachq.m4
===================================================================
RCS file: examples/foreachq.m4
diff -N examples/foreachq.m4
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ examples/foreachq.m4        21 Oct 2006 02:35:34 -0000
@@ -0,0 +1,9 @@
+include(`quote.m4')dnl
+divert(`-1')
+# foreachq(x, `item_1, item_2, ..., item_n', stmt)
+#   quoted list, simple version
+define(`foreachq', `pushdef(`$1')_foreachq($@)popdef(`$1')')
+define(`_arg1', `$1')
+define(`_foreachq', `ifelse(quote($2), `', `',
+  `define(`$1', `_arg1($2)')$3`'$0(`$1', `shift($2)', `$3')')')
+divert`'dnl
Index: examples/foreachq2.m4
===================================================================
RCS file: examples/foreachq2.m4
diff -N examples/foreachq2.m4
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ examples/foreachq2.m4       21 Oct 2006 02:35:34 -0000
@@ -0,0 +1,10 @@
+include(`quote.m4')dnl
+divert(`-1')
+# foreachq(x, `item_1, item_2, ..., item_n', stmt)
+#   quoted list, improved version
+define(`foreachq', `pushdef(`$1')_foreachq($@)popdef(`$1')')
+define(`_arg1q', ``$1'')
+define(`_rest', `ifelse(`$#', `1', `', `dquote(shift($@))')')
+define(`_foreachq', `ifelse(`$2', `', `',
+  `define(`$1', _arg1q($2))$3`'$0(`$1', _rest($2), `$3')')')
+divert`'dnl
_______________________________________________
M4-patches mailing list
[email protected]
http://lists.gnu.org/mailman/listinfo/m4-patches

Reply via email to