+2008-10-27 Eric Blake <ebb9@byu.net>
+
+ Add AS_VAR_ARITH.
+ * lib/m4sugar/m4sh.m4 (_AS_VAR_ARITH_PREPARE, _AS_VAR_ARITH_WORKS)
+ (AS_VAR_ARITH): New macros.
+ (_AS_PREPARE, AS_PREPARE): Emit preparation.
+ * tests/m4sh.at (AS@&t@_VAR_ARITH): New test.
+ * doc/autoconf.texi (Polymorphic Variables) <AS_VAR_ARITH>:
+ Document new macro.
+ (Limitations of Usual Tools) <expr>: Mention portability problem
+ if first argument starts with -.
+ (Shell Substitutions) <$((expression))>: Mention it.
+ * NEWS: Likewise.
+
2008-10-27 Eric Blake <ebb9@byu.net>
Use read, rather than `cat`, for safe one-line files.
* lib/autoconf/general.m4 (_AC_COMPUTE_INT_RUN): Likewise.
2008-10-27 Paolo Bonzini <bonzini@gnu.org>
-
+
* lib/autoconf/general.m4 (_AC_COMPUTE_INT_COMPILE,
_AC_COMPUTE_INT_RUN): Add IF-SUCCESS argument.
(_AC_COMPUTE_INT_BODY): New.
m4_copy m4_rename
** The following documented m4sh macros are new:
- AS_LINENO_PREPARE AS_ME_PREPARE AS_VAR_APPEND AS_VAR_COPY
+ AS_LINENO_PREPARE AS_ME_PREPARE AS_VAR_APPEND AS_VAR_ARITH
+ AS_VAR_COPY
** The following m4sh macros are documented now:
AS_ECHO AS_ECHO_N AS_EXIT AS_LITERAL_IF AS_UNSET AS_VAR_IF
expansion.
@end defmac
+@defmac AS_VAR_ARITH (@var{var}, @var{expression})
+@asindex{ARITH}
+Emit shell code to compute the arithmetic expansion of @var{expression},
+assigning the result as the contents of the polymorphic shell variable
+@var{var}. The code takes advantage of shells that provide @samp{$(())}
+for fewer forks, but uses @command{expr} as a fallback. Therefore, the
+syntax for a valid @var{expression} is rather limited: all operators
+must occur as separate shell arguments and with proper quoting, there is
+no portable equality operator, all variables containing numeric values
+must be expanded prior to the computation, all numeric values must be
+provided in decimal without leading zeroes, and the first shell argument
+should not be a negative number. In the following example, this snippet
+will print @samp{(2+3)*4 == 20}.
+
+@example
+bar=3
+AS_VAR_ARITH([foo], [\( 2 + $bar \) \* 4])
+echo "(2+$bar)*4 == $foo"
+@end example
+@end defmac
+
@defmac AS_VAR_COPY (@var{dest}, @var{source})
@asindex{VAR_COPY}
Emit shell code to assign the contents of the polymorphic shell variable
When it is available, using arithmetic expansion provides a noticeable
speedup in script execution; but testing for support requires
-@command{eval} to avoid syntax errors. If shell function support can
-be assumed, then this construct can be used to assign @samp{foo}
-to an arithmetic result, provided all numeric arguments are provided in
-decimal and without a leading zero:
+@command{eval} to avoid syntax errors. The following construct is used
+by @code{AS_VAR_ARITH} to provide arithmetic computation when all
+arguments are provided in decimal and without a leading zero, and all
+operators are properly quoted and appear as distinct arguments:
@example
if ( eval 'test $(( 1 + 1 )) = 2' ) 2>/dev/null; then
@item @command{expr}
@c -----------------
@prindex @command{expr}
+Not all implementations obey the Posix rule that @samp{--} separates
+options from arguments; likewise, not all implementations provide the
+extension to Posix that the first argument can be treated as part of a
+valid expression rather than an invalid option if it begins with
+@samp{-}. When performing arithmetic, use @samp{expr 0 + $var} if
+@samp{$var} might be a negative number, to keep @command{expr} from
+interpreting it as an option.
+
No @command{expr} keyword starts with @samp{X}, so use @samp{expr
X"@var{word}" : 'X@var{regex}'} to keep @command{expr} from
misinterpreting @var{word}.
)]dnl
[_AS_UNSET_PREPARE
_AS_VAR_APPEND_PREPARE
+_AS_VAR_ARITH_PREPARE
_AS_EXPR_PREPARE
_AS_BASENAME_PREPARE
AS_REQUIRE([_AS_TR_SH_PREPARE])
AS_REQUIRE([_AS_UNSET_PREPARE])
AS_REQUIRE([_AS_VAR_APPEND_PREPARE], [], [M4SH-INIT-FN])
+AS_REQUIRE([_AS_VAR_ARITH_PREPARE], [], [M4SH-INIT-FN])
m4_divert_pop[]])
}]) # as_func_append
])
-
# _AS_VAR_APPEND_WORKS
# --------------------
# Output a shell test to discover whether += works.
m4_define([_AS_VAR_APPEND_WORKS],
[as_var=1; as_var+=2; test x$as_var = x12])
-
# AS_VAR_APPEND(VAR, VALUE)
# -------------------------
# Append the shell expansion of VALUE to the end of the existing
[as_func_append $1 $2])
+# _AS_VAR_ARITH_PREPARE
+# ---------------------
+# Define as_func_arith to the optimum definition for the current
+# shell (using POSIX $(()) where supported).
+m4_defun([_AS_VAR_ARITH_PREPARE],
+[AS_FUNCTION_DESCRIBE([as_func_arith], [ARG...],
+[Perform arithmetic evaluation on the ARGs, and store the result in
+the global $as_val. Take advantage of shells that can avoid forks.
+The arguments must be portable across $(()) and expr.])
+AS_IF([_AS_RUN(["AS_ESCAPE([_AS_VAR_ARITH_WORKS])"])],
+[eval 'as_func_arith ()
+ {
+ as_val=$(( $[]* ))
+ }'],
+[as_func_arith ()
+ {
+ as_val=`expr "$[]@"`
+ }]) # as_func_arith
+])
+
+# _AS_VAR_ARITH_WORKS
+# -------------------
+# Output a shell test to discover whether $(()) works.
+m4_define([_AS_VAR_ARITH_WORKS],
+[test $(( 1 + 1 )) = 2])
+
+# AS_VAR_ARITH(VAR, EXPR)
+# -----------------------
+# Perform the arithmetic evaluation of the arguments in EXPR, and set
+# contents of the polymorphic shell variable VAR to the result, taking
+# advantage of any shell optimizations that perform arithmetic without
+# forks. Note that numbers occuring within EXPR must be written in
+# decimal, and without leading zeroes; variables containing numbers
+# must be expanded prior to arithmetic evaluation; the first argument
+# must not be a negative number; there is no portable equality
+# operator; and operators must be given as separate arguments and
+# properly quoted.
+m4_defun_init([AS_VAR_ARITH],
+[_AS_DETECT_SUGGESTED([_AS_VAR_ARITH_WORKS])]dnl
+[AS_REQUIRE([_AS_VAR_ARITH_PREPARE], [], [M4SH-INIT-FN])],
+[as_func_arith $2 && AS_VAR_SET([$1], [$as_val])])
+
+
# AS_VAR_COPY(DEST, SOURCE)
# -------------------------
# Set the polymorphic shell variable DEST to the contents of the polymorphic
AT_CLEANUP
+## -------------- ##
+## AS_VAR_ARITH. ##
+## -------------- ##
+
+AT_SETUP([AS@&t@_VAR_ARITH])
+AT_KEYWORDS([m4sh AS@&t@_VAR])
+
+AT_DATA_M4SH([script.as], [[dnl
+AS_INIT
+# Literals.
+AS_VAR_ARITH([foo], [1 + 1])
+echo "$foo"
+# Indirects via shell vars.
+num=1
+AS_VAR_ARITH([foo$num], [\( 2 + 3 \) \* 4])
+echo "$foo1"
+# Indirects via command substitution.
+AS_VAR_ARITH([`echo foo2`], [0 + -2 + $foo1 / 2])
+echo "$foo2"
+]])
+
+AT_CHECK_M4SH
+AT_CHECK([./script], [],
+[[2
+20
+8
+]])
+
+AT_CLEANUP
+
+
## ----------------- ##
## AS_INIT cleanup. ##
## ----------------- ##