[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
branch-1_4 foreach documentation
From: |
Eric Blake |
Subject: |
branch-1_4 foreach documentation |
Date: |
Fri, 20 Oct 2006 20:53:58 -0600 |
User-agent: |
Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.0.7) Gecko/20060909 Thunderbird/1.5.0.7 Mnenhy/0.7.4.666 |
-----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 <address@hidden>
* 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 address@hidden
-----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
address@hidden macro @comment
address@hidden address@hidden }
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 ')
address@hidden 2 3 4 5 6 7 8 @comment
address@hidden 2 3 4 5 6 7 address@hidden }
@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 @address@hidden, 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 @address@hidden 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.
address@hidden for each loops
address@hidden loops, list iteration
address@hidden iterating over lists
+Here is an example of a loop macro that implements list iteration.
+
address@hidden Composite foreach (@var{iterator}, @var{paren-list}, @var{text})
address@hidden 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
address@hidden In @code{foreach}, @var{paren-list} is a
+comma-separated list of elements contained in parentheses. In
address@hidden, @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
address@hidden Any definition of @var{iterator} prior to this
+invocation is restored.
address@hidden deffn
+
+As an example, this displays each word in a list inside of a sentence,
+using an implementation of @code{foreach} distributed as
address@hidden@value{VERSION}/@/examples/@/foreach.m4}, and @code{foreachq}
+in @address@hidden/@/examples/@/foreachq.m4}.
+
address@hidden
+include(`foreach.m4')
address@hidden
+foreach(`x', (foo, bar, foobar), `Word was: x
+')dnl
address@hidden was: foo
address@hidden was: bar
address@hidden was: foobar
+include(`foreachq.m4')
address@hidden
+foreachq(`x', `foo, bar, foobar', `Word was: x
+')dnl
address@hidden was: foo
address@hidden was: bar
address@hidden was: foobar
address@hidden 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:
+
address@hidden
+include(`foreach.m4')
address@hidden
+define(`_case', ` $1)
+ $2=" $1";;
+')dnl
+define(`_cat', `$1$2')dnl
+case $`'1 in
address@hidden $1 in
+foreach(`x', `(`(`a', `vara')', `(`b', `varb')', `(`c', `varc')')',
+ `_cat(`_case', x)')dnl
address@hidden a)
address@hidden vara=" a";;
address@hidden b)
address@hidden varb=" b";;
address@hidden c)
address@hidden varc=" c";;
+esac
address@hidden
address@hidden example
+
+The implementation of the @code{foreach} macro is a bit more involved;
+it is a wrapper around two helper macros. First, @address@hidden is
+needed to grab the first element of a list. Second,
address@hidden@w{_foreach}} implements the recursion, successively walking
+through the original list. Here is a simple implementation of
address@hidden:
+
address@hidden
+undivert(`foreach.m4')dnl
address@hidden(`-1')
address@hidden foreach(x, (item_1, item_2, ..., item_n), stmt)
address@hidden parenthesized list, simple version
address@hidden(`foreach', `pushdef(`$1')_foreach($@@)popdef(`$1')')
address@hidden(`_arg1', `$1')
address@hidden(`_foreach', `ifelse(`$2', `()', `',
address@hidden `define(`$1', _arg1$2)$3`'$0(`$1', (shift$2), `$3')')')
address@hidden'dnl
address@hidden example
+
+Unfortunately, that implementation is not robust to macro names as list
+elements. Each iteration of @address@hidden 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
address@hidden, 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:
+
address@hidden
+define(`a', `1')define(`b', `2')define(`c', `3')
address@hidden
+include(`foreach.m4')
address@hidden
+include(`foreachq.m4')
address@hidden
+foreach(`x', `(``a'', ``(b'', ``c)'')', `x
+')
address@hidden
address@hidden(2)1
address@hidden
address@hidden, x
address@hidden)
+foreachq(`x', ```a'', ``(b'', ``c)''', `x
+')dnl
address@hidden
address@hidden(b
address@hidden)
address@hidden example
+
+Obviously, @code{foreachq} did a better job; here is its implementation:
+
address@hidden
+undivert(`foreachq.m4')dnl
address@hidden(`quote.m4')dnl
address@hidden(`-1')
address@hidden foreachq(x, `item_1, item_2, ..., item_n', stmt)
address@hidden quoted list, simple version
address@hidden(`foreachq', `pushdef(`$1')_foreachq($@@)popdef(`$1')')
address@hidden(`_arg1', `$1')
address@hidden(`_foreachq', `ifelse(quote($2), `', `',
address@hidden `define(`$1', `_arg1($2)')$3`'$0(`$1', `shift($2)', `$3')')')
address@hidden'dnl
address@hidden example
+
+Notice that @address@hidden had to use the helper macro
address@hidden 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
address@hidden (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
address@hidden 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]+')
address@hidden not @comment
address@hidden address@hidden }
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
address@hidden option, @pxref{Limits control, , Invoking m4}),
address@hidden @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}),
address@hidden @code{m4} will define the macro @address@hidden 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 @address@hidden
+by default, or @code{unix} when the @option{-G} option is specified.
On native Windows systems, @acronym{GNU} @code{m4} will define
address@hidden by default, or @code{windows} when the @option{-G}
-option is specified.
address@hidden@w{__windows__}} by default, or @code{windows} when the
address@hidden 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 @address@hidden
+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 @address@hidden 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 @address@hidden 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
address@hidden happens to be first in @env{PATH}. It was first introduced
-in @acronym{GNU} M4 1.4.6.
address@hidden happens to be first in @env{PATH}. It was first introduced in
address@hidden 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__},
address@hidden, and @code{__line__} (@pxref{Location}).
+line number are accessible through the builtins @address@hidden,
address@hidden@w{__file__}}, and @address@hidden (@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 @address@hidden/@/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 @address@hidden
@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}:
+
address@hidden
+include(`foreachq.m4')
address@hidden
+traceon(`shift')debugmode(`aq')
address@hidden
+foreachq(`x', ``1', `2', `3', `4'', `x
+')dnl
address@hidden
address@hidden: -3- shift(`1', `2', `3', `4')
address@hidden: -2- shift(`1', `2', `3', `4')
address@hidden
address@hidden: -4- shift(`1', `2', `3', `4')
address@hidden: -3- shift(`2', `3', `4')
address@hidden: -3- shift(`1', `2', `3', `4')
address@hidden: -2- shift(`2', `3', `4')
address@hidden
address@hidden: -5- shift(`1', `2', `3', `4')
address@hidden: -4- shift(`2', `3', `4')
address@hidden: -3- shift(`3', `4')
address@hidden: -4- shift(`1', `2', `3', `4')
address@hidden: -3- shift(`2', `3', `4')
address@hidden: -2- shift(`3', `4')
address@hidden
address@hidden: -6- shift(`1', `2', `3', `4')
address@hidden: -5- shift(`2', `3', `4')
address@hidden: -4- shift(`3', `4')
address@hidden: -3- shift(`4')
address@hidden 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 @address@hidden/@/examples/@/foreachq2.m4}:
+
address@hidden
+include(`foreachq2.m4')
address@hidden
+undivert(`foreachq2.m4')dnl
address@hidden(`quote.m4')dnl
address@hidden(`-1')
address@hidden foreachq(x, `item_1, item_2, ..., item_n', stmt)
address@hidden quoted list, improved version
address@hidden(`foreachq', `pushdef(`$1')_foreachq($@@)popdef(`$1')')
address@hidden(`_arg1q', ``$1'')
address@hidden(`_rest', `ifelse(`$#', `1', `', `dquote(shift($@@))')')
address@hidden(`_foreachq', `ifelse(`$2', `', `',
address@hidden `define(`$1', _arg1q($2))$3`'$0(`$1', _rest($2), `$3')')')
address@hidden'dnl
+traceon(`shift')debugmode(`aq')
address@hidden
+foreachq(`x', ``1', `2', `3', `4'', `x
+')dnl
address@hidden
address@hidden: -3- shift(`1', `2', `3', `4')
address@hidden
address@hidden: -3- shift(`2', `3', `4')
address@hidden
address@hidden: -3- shift(`3', `4')
address@hidden
address@hidden example
+
+Note that the fixed version calls unquoted helper macros in
address@hidden@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 @address@hidden, which quotes the first list
+element, with @address@hidden of the earlier implementation that
+returned the first list element directly.
+
+For a different approach, the improved version of @code{foreach},
+available in @address@hidden/@/examples/@/foreach2.m4}, simply
+overquotes the arguments to @address@hidden to begin with, using
address@hidden Then @address@hidden can just use
address@hidden@w{_arg1}} to remove the extra layer of quoting that was added up
+front:
+
address@hidden
+include(`foreach2.m4')
address@hidden
+undivert(`foreach2.m4')dnl
address@hidden(`quote.m4')dnl
address@hidden(`-1')
address@hidden foreach(x, (item_1, item_2, ..., item_n), stmt)
address@hidden parenthesized list, improved version
address@hidden(`foreach', `pushdef(`$1')_foreach(`$1',
address@hidden (dquote(dquote_elt$2)), `$3')popdef(`$1')')
address@hidden(`_arg1', `$1')
address@hidden(`_foreach', `ifelse(`$2', `(`')', `',
address@hidden `define(`$1', _arg1$2)$3`'$0(`$1', (dquote(shift$2)), `$3')')')
address@hidden'dnl
+traceon(`shift')debugmode(`aq')
address@hidden
+foreach(`x', `(`1', `2', `3', `4')', `x
+')dnl
address@hidden: -4- shift(`1', `2', `3', `4')
address@hidden: -4- shift(`2', `3', `4')
address@hidden: -4- shift(`3', `4')
address@hidden
address@hidden: -3- shift(``1'', ``2'', ``3'', ``4'')
address@hidden
address@hidden: -3- shift(``2'', ``3'', ``4'')
address@hidden
address@hidden: -3- shift(``3'', ``4'')
address@hidden
address@hidden: -3- shift(``4'')
address@hidden 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 @address@hidden But @code{foreachq}
+evaluates unquoted list elements twice while visiting the first list
+element, once in @address@hidden and once in @address@hidden 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.
+
address@hidden
+include(`foreach2.m4')
address@hidden
+include(`foreachq2.m4')
address@hidden
+dnl 0-element list:
+foreach(`x', `', `<x>') / foreachq(`x', `', `<x>')
address@hidden /@w{ }
+dnl 1-element list of empty element
+foreach(`x', `()', `<x>') / foreachq(`x', ``'', `<x>')
address@hidden<> / <>
+dnl 2-element list of empty elements
+foreach(`x', `(`',`')', `<x>') / foreachq(`x', ``',`'', `<x>')
address@hidden<><> / <><>
+dnl 1-element list of a comma
+foreach(`x', `(`,')', `<x>') / foreachq(`x', ``,'', `<x>')
address@hidden<,> / <,>
+dnl 2-element list of unbalanced parentheses
+foreach(`x', `(`(', `)')', `<x>') / foreachq(`x', ``(', `)'', `<x>')
address@hidden<(><)> / <(><)>
+define(`active', `ACT, IVE')
address@hidden
+traceon(`active')
address@hidden
+dnl list of unquoted macros; expansion occurs before recursion
+foreach(`x', `(active, active)', `<x>
+')dnl
address@hidden: -4- active -> `ACT, IVE'
address@hidden: -4- active -> `ACT, IVE'
address@hidden<ACT>
address@hidden<IVE>
address@hidden<ACT>
address@hidden<IVE>
+foreachq(`x', `active, active', `<x>
+')dnl
address@hidden: -3- active -> `ACT, IVE'
address@hidden: -3- active -> `ACT, IVE'
address@hidden<ACT>
address@hidden: -3- active -> `ACT, IVE'
address@hidden: -3- active -> `ACT, IVE'
address@hidden<IVE>
address@hidden<ACT>
address@hidden<IVE>
+dnl list of quoted macros; expansion occurs during recursion
+foreach(`x', `(`active', `active')', `<x>
+')dnl
address@hidden: -1- active -> `ACT, IVE'
address@hidden<ACT, IVE>
address@hidden: -1- active -> `ACT, IVE'
address@hidden<ACT, IVE>
+foreachq(`x', ``active', `active'', `<x>
+')dnl
address@hidden: -1- active -> `ACT, IVE'
address@hidden<ACT, IVE>
address@hidden: -1- active -> `ACT, IVE'
address@hidden<ACT, IVE>
+dnl list of double-quoted macro names; no expansion
+foreach(`x', `(``active'', ``active'')', `<x>
+')dnl
address@hidden<active>
address@hidden<active>
+foreachq(`x', ```active'', ``active''', `<x>
+')dnl
address@hidden<active>
address@hidden<active>
address@hidden 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
address@hidden 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
address@hidden@w{__file__}} (@pxref{Location}) inside @code{m4wrap} would result
+in an empty string, and @address@hidden resulted in @samp{0} even
+though all files start at line 1. Furthermore, versions earlier than
+1.4.6 did not support the @address@hidden macro. If you want
address@hidden 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 <address@hidden>.
-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
- branch-1_4 foreach documentation,
Eric Blake <=