Programming in M4sugar
* Redefined M4 Macros:: M4 builtins changed in M4sugar
+* Looping constructs:: Iteration in M4
* Evaluation Macros:: More quotation and evaluation control
* Forbidden Patterns:: Catching unexpanded macros
@menu
* Redefined M4 Macros:: M4 builtins changed in M4sugar
+* Looping constructs:: Iteration in M4
* Evaluation Macros:: More quotation and evaluation control
* Forbidden Patterns:: Catching unexpanded macros
@end menu
to recover the behavior of the builtin.
@end defmac
+
+
+@node Looping constructs
+@subsection Looping constructs
+
+The following macros implement loops in M4.
+
+@defmac m4_for (@var{var}, @var{first}, @var{last}, @ovar{step}, @var{expression})
+@msindex{for}
+Loop over the numeric values between @var{first} and @var{last}
+including bounds by increments of @var{step}. For each iteration,
+expand @var{expression} with the numeric value assigned to @var{var}.
+If @var{step} is omitted, it defaults to @samp{1} or @samp{-1} depending
+on the order of the limits. If given, @var{step} has to match this
+order.
+@end defmac
+
+@defmac m4_foreach (@var{var}, @var{list}, @var{expression})
+@msindex{foreach}
+Loop over the comma-separated m4 list @var{list}, assigning each value
+to @var{var}, and expand @var{expression}. The following example will
+output two lines:
+
+@example
+m4_foreach([myvar], [[foo], [bar, baz]],
+ [echo myvar
+])
+
+@end example
+@end defmac
+
+@defmac m4_foreach_w (@var{var}, @var{list}, @var{expression})
+@msindex{foreach_w}
+Loop over the whitespace-separated list @var{list}, assigning each value
+to @var{var}, and expand @var{expression}.
+
+The deprecated macro @code{AC_FOREACH} is an alias of
+@code{m4_foreach_w}.
+@end defmac
+
+
+
@node Evaluation Macros
@subsection Evaluation Macros
@code{AC_PATH_XTRA}
@end defmac
+@defmac AC_FOREACH
+@acindex{FOREACH}
+@code{m4_foreach_w}
+@end defmac
+
@defmac AC_FUNC_CHECK
@acindex{FUNC_CHECK}
@code{AC_CHECK_FUNC}
this scheme helps supporting more languages than plain C and C++.
@end itemize
-In addition to the change of syntax, the philosphy has changed too:
+In addition to the change of syntax, the philosophy has changed too:
while emphasis was put on speed at the expense of accuracy, today's
Autoconf promotes accuracy of the testing framework at, ahem@dots{}, the
expense of speed.
# Expand EXPRESSION defining VARIABLE to FROM, FROM + 1, ..., TO.
# Both limits are included, and bounds are checked for consistency.
m4_define([m4_for],
-[m4_case(m4_sign(m4_eval($3 - $2)),
- 1, [m4_assert(m4_sign(m4_default($4, 1)) == 1)],
- -1, [m4_assert(m4_sign(m4_default($4, -1)) == -1)])dnl
-m4_pushdef([$1], [$2])dnl
-m4_if(m4_eval([$3 > $2]), 1,
- [_m4_for([$1], [$3], m4_default([$4], 1), [$5])],
- [_m4_for([$1], [$3], m4_default([$4], -1), [$5])])dnl
+[m4_pushdef([$1], m4_eval([$2]))dnl
+m4_if(m4_eval(([$3]) > $1), 1,
+[m4_pushdef([_m4_step], m4_eval(m4_default([$4], 1)))dnl
+m4_assert(_m4_step > 0)dnl
+_m4_for([$1], m4_eval((([$3]) - $1) / _m4_step * _m4_step + $1), _m4_step, [$5])],
+ m4_eval(([$3]) < $1), 1,
+[m4_pushdef([_m4_step], m4_eval(m4_default([$4], -1)))dnl
+m4_assert(_m4_step < 0)dnl
+_m4_for([$1], m4_eval(($1 - ([$3])) / -(_m4_step) * _m4_step + $1), _m4_step, [$5])],
+ [m4_pushdef(_m4_step,[])dnl
+$5])[]dnl
+m4_popdef([_m4_step])dnl
m4_popdef([$1])])
-# _m4_for(VARIABLE, FIRST, LAST, STEP, EXPRESSION)
-# ------------------------------------------------
-# Core of the loop, no consistency checks.
+# _m4_for(VARIABLE, LAST, STEP, EXPRESSION)
+# -----------------------------------------
+# Core of the loop, no consistency checks, all arguments are plain numbers.
m4_define([_m4_for],
[$4[]dnl
m4_if($1, [$2], [],
AT_BANNER([M4sugar.])
-# Copyright (C) 2000, 2001, 2002, 2005 Free Software Foundation, Inc.
+# Copyright (C) 2000, 2001, 2002, 2005, 2006 Free Software Foundation, Inc.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# 02110-1301, USA.
-# AT_CHECK_M4SUGAR_TEXT(CODE, STDOUT, STDER)
-# ------------------------------------------
+# AT_CHECK_M4SUGAR_TEXT(CODE, STDOUT, STDERR)
+# -------------------------------------------
# Check that m4sugar CODE expands to STDOUT and emits STDERR.
m4_define([AT_CHECK_M4SUGAR_TEXT],
[
AT_CHECK_M4RE([m4_re_string], [9a@_c])
AT_CLEANUP
+
+## ---------- ##
+## M4 Loops. ##
+## ---------- ##
+
+AT_SETUP([M4 loops])
+
+AT_CHECK_M4SUGAR_TEXT([[dnl
+m4_define([myvar], [outer value])dnl
+m4_for([myvar], 1, 3, 1, [ myvar])
+m4_for([myvar], 1, 3, , [ myvar])
+m4_for([myvar], 3, 1,-1, [ myvar])
+m4_for([myvar], 3, 1, , [ myvar])
+m4_for([myvar], 1, 3, 2, [ myvar])
+m4_for([myvar], 3, 1,-2, [ myvar])
+m4_for([myvar],-1,-3,-2, [ myvar])
+m4_for([myvar],-3,-1, 2, [ myvar])
+dnl Make sure we recalculate the bounds correctly:
+m4_for([myvar], 1, 3, 3, [ myvar])
+m4_for([myvar], 1, 6, 3, [ myvar])
+m4_for([myvar],22,-7,-5, [ myvar])
+m4_for([myvar],-2,-7,-4, [ myvar])
+m4_for([myvar],-7,-2, 4, [ myvar])
+dnl Make sure we are not exposed to division truncation:
+m4_for([myvar], 2, 5, 2, [ myvar])
+m4_for([myvar],-5,-2, 2, [ myvar])
+m4_for([myvar], 5, 2,-2, [ myvar])
+m4_for([myvar],-2,-5,-2, [ myvar])
+dnl Make sure we do not divide by zero:
+m4_for([myvar], 1, 1, , [ myvar])
+m4_for([myvar], 1, 1,+2, [ myvar])
+m4_for([myvar], 1, 1,-2, [ myvar])
+dnl Make sure we do not loop endlessly
+m4_for([myval], 1, 1, 0, [ myval])
+dnl Make sure to properly parenthesize
+m4_for([myvar], 3-5, -2+8, , [ myvar])
+m4_for([myvar], -2+8, 3-5, , [ myvar])
+m4_for([myvar], 8, 16, 3 * 2, [ myvar])
+m4_for([myvar], 8, 16, -3 * -2, [ myvar])
+m4_for([myvar], [2<<2], [2<<3], [-3 * (-2)], [ myvar])
+m4_foreach([myvar], [[a], [b, c], [d], [e
+],[f]], [ myvar|])
+m4_foreach_w([myvar], [a b c, d,e f
+g], [ myvar|])
+myvar
+]],
+[[ 1 2 3
+ 1 2 3
+ 3 2 1
+ 3 2 1
+ 1 3
+ 3 1
+ -1 -3
+ -3 -1
+ 1
+ 1 4
+ 22 17 12 7 2 -3
+ -2 -6
+ -7 -3
+ 2 4
+ -5 -3
+ 5 3
+ -2 -4
+ 1
+ 1
+ 1
+ 1
+ -2 -1 0 1 2 3 4 5 6
+ 6 5 4 3 2 1 0 -1 -2
+ 8 14
+ 8 14
+ 8 14
+ a| b, c| d| e
+| f|
+ a| b| c,| d,e| f| g|
+outer value
+]], [])
+
+AT_DATA_M4SUGAR([script.4s],
+[[m4_init
+m4_divert_push([0])m4_wrap([m4_divert_pop([0])[]])dnl
+m4_for([myvar], 1, 3,-1, [ myvar])
+]])
+
+AT_CHECK_M4SUGAR([], 1, [],
+[[script.4s:3: error: assert failed: -1 > 0
+script.4s:3: the top level
+autom4te: m4 failed with exit status: 1
+]])
+
+AT_DATA_M4SUGAR([script.4s],
+[[m4_init
+m4_divert_push([0])m4_wrap([m4_divert_pop([0])[]])dnl
+m4_for([myvar], 1, 2, 0, [ myvar])
+]])
+
+AT_CHECK_M4SUGAR([], 1, [],
+[[script.4s:3: error: assert failed: 0 > 0
+script.4s:3: the top level
+autom4te: m4 failed with exit status: 1
+]])
+
+AT_DATA_M4SUGAR([script.4s],
+[[m4_init
+m4_divert_push([0])m4_wrap([m4_divert_pop([0])[]])dnl
+m4_for([myvar], 2, 1, 0, [ myvar])
+]])
+
+AT_CHECK_M4SUGAR([], 1, [],
+[[script.4s:3: error: assert failed: 0 < 0
+script.4s:3: the top level
+autom4te: m4 failed with exit status: 1
+]])
+AT_CLEANUP