From: Eric Blake Date: Mon, 27 Oct 2008 20:26:57 +0000 (-0600) Subject: Add AS_VAR_ARITH. X-Git-Tag: v2.63b~186 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=bc9d68de415c7ab4b23f3cab12d97457e3da7e27;p=thirdparty%2Fautoconf.git 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) : Document new macro. (Limitations of Usual Tools) : Mention portability problem if first argument starts with -. (Shell Substitutions) <$((expression))>: Mention it. * NEWS: Likewise. Signed-off-by: Eric Blake --- diff --git a/ChangeLog b/ChangeLog index 313124b97..d5b68adbb 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,17 @@ +2008-10-27 Eric Blake + + 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) : + Document new macro. + (Limitations of Usual Tools) : Mention portability problem + if first argument starts with -. + (Shell Substitutions) <$((expression))>: Mention it. + * NEWS: Likewise. + 2008-10-27 Eric Blake Use read, rather than `cat`, for safe one-line files. @@ -6,7 +20,7 @@ * lib/autoconf/general.m4 (_AC_COMPUTE_INT_RUN): Likewise. 2008-10-27 Paolo Bonzini - + * lib/autoconf/general.m4 (_AC_COMPUTE_INT_COMPILE, _AC_COMPUTE_INT_RUN): Add IF-SUCCESS argument. (_AC_COMPUTE_INT_BODY): New. diff --git a/NEWS b/NEWS index 5bdff4860..1f969b13d 100644 --- a/NEWS +++ b/NEWS @@ -20,7 +20,8 @@ GNU Autoconf NEWS - User visible changes. 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 diff --git a/doc/autoconf.texi b/doc/autoconf.texi index b89ce5b7a..c1427a67d 100644 --- a/doc/autoconf.texi +++ b/doc/autoconf.texi @@ -12121,6 +12121,27 @@ appends. Note that unlike @code{AS_VAR_SET}, this macro requires that 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 @@ -14034,10 +14055,10 @@ $ @kbd{pdksh -c 'echo $(( 010 ))'} 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 @@ -15880,6 +15901,14 @@ foo @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}. diff --git a/lib/m4sugar/m4sh.m4 b/lib/m4sugar/m4sh.m4 index 612406566..300923a23 100644 --- a/lib/m4sugar/m4sh.m4 +++ b/lib/m4sugar/m4sh.m4 @@ -266,6 +266,7 @@ m4_defun([_AS_PREPARE], )]dnl [_AS_UNSET_PREPARE _AS_VAR_APPEND_PREPARE +_AS_VAR_ARITH_PREPARE _AS_EXPR_PREPARE _AS_BASENAME_PREPARE @@ -301,6 +302,7 @@ AS_REQUIRE([_AS_TR_CPP_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[]]) @@ -1642,14 +1644,12 @@ AS_IF([_AS_RUN(["AS_ESCAPE([_AS_VAR_APPEND_WORKS])"])], }]) # 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 @@ -1666,6 +1666,49 @@ m4_defun_init([AS_VAR_APPEND], [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 diff --git a/tests/m4sh.at b/tests/m4sh.at index badc66814..e90e23193 100644 --- a/tests/m4sh.at +++ b/tests/m4sh.at @@ -1070,6 +1070,37 @@ hello, world 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. ## ## ----------------- ##