From: Eric Blake Date: Mon, 20 Oct 2008 11:50:01 +0000 (-0600) Subject: Add AS_VAR_APPEND. X-Git-Tag: v2.63b~224 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=86ce15b622cdde04ec0569b22905c67168936407;p=thirdparty%2Fautoconf.git Add AS_VAR_APPEND. * lib/m4sugar/m4sh.m4 (_AS_VAR_APPEND_PREPARE) (_AS_VAR_APPEND_WORKS, AS_VAR_APPEND): New macros. (AS_PREPARE, _AS_PREPARE): Emit preparation. * tests/m4sh.at (AS@&t@_VAR_APPEND): New test. * doc/autoconf.texi (Polymorphic Variables) : Document new macro. : Mention ramification of `""` rules. * NEWS: Mention new macro. Signed-off-by: Eric Blake --- diff --git a/ChangeLog b/ChangeLog index f98b7086..d845609c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,15 @@ +2008-10-21 Eric Blake + + Add AS_VAR_APPEND. + * lib/m4sugar/m4sh.m4 (_AS_VAR_APPEND_PREPARE) + (_AS_VAR_APPEND_WORKS, AS_VAR_APPEND): New macros. + (AS_PREPARE, _AS_PREPARE): Emit preparation. + * tests/m4sh.at (AS@&t@_VAR_APPEND): New test. + * doc/autoconf.texi (Polymorphic Variables) : + Document new macro. + : Mention ramification of `""` rules. + * NEWS: Mention new macro. + 2008-10-21 Paolo Bonzini and Eric Blake diff --git a/NEWS b/NEWS index 147639b3..4ac8e8ad 100644 --- a/NEWS +++ b/NEWS @@ -17,7 +17,7 @@ GNU Autoconf NEWS - User visible changes. m4_set_map ** The following documented m4sh macros are new: - AS_LINENO_PREPARE AS_ME_PREPARE AS_VAR_COPY + AS_LINENO_PREPARE AS_ME_PREPARE AS_VAR_APPEND AS_VAR_COPY ** The following m4sh macros are documented now: AS_ECHO AS_ECHO_N AS_LITERAL_IF AS_UNSET AS_VAR_IF AS_VAR_POPDEF diff --git a/doc/autoconf.texi b/doc/autoconf.texi index eed40c56..25a73378 100644 --- a/doc/autoconf.texi +++ b/doc/autoconf.texi @@ -12070,6 +12070,31 @@ echo "$tmp"])]) @end example @end defmac +@defmac AS_VAR_APPEND (@var{var}, @var{text}) +@asindex{APPEND} +Emit shell code to append the shell expansion of @var{text} to the end +of the current contents of the polymorphic shell variable @var{var}, +taking advantage of shells that provide the @samp{+=} extension for more +efficient scaling. + +For situations where the final contents of @var{var} are relatively +short (less than 256 bytes), it is more efficient to use the simpler +code sequence of @code{@var{var}=$@{@var{var}@}@var{text}} (or its +polymorphic equivalent of @code{AS_VAR_COPY([tmp], [@var{var}])} and +@code{AS_VAR_SET([@var{var}], ["$tmp"@var{text}])}). But in the case +when the script will be repeatedly appending text into @code{var}, +issues of scaling start to become apparent. A naive implementation +requires execution time linear to the length of the current contents of +@var{var} as well as the length of @var{text} for a single append, for +an overall quadratic scaling with multiple appends. This macro takes +advantage of shells which provide the extension +@code{@var{var}+=@var{text}}, which can provide amortized constant time +for a single append, for an overall linear scaling with multiple +appends. Note that unlike @code{AS_VAR_SET}, this macro requires that +@var{text} be quoted properly to avoid field splitting and file name +expansion. +@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 @@ -12163,7 +12188,10 @@ header stdlib.h detected @defmac AS_VAR_SET (@var{var}, @ovar{value}) @asindex{VAR_SET} Emit shell code to assign the contents of the polymorphic shell variable -@var{var} to the shell expansion of @var{value}. +@var{var} to the shell expansion of @var{value}. @var{value} is not +subject to field splitting or file name expansion, so if command +substitution is used, it may be done with @samp{`""`} rather than using +an intermediate variable (@pxref{Shell Substitutions}). @end defmac @defmac AS_VAR_SET_IF (@var{var}, @ovar{if-set}, @ovar{if-undef}) diff --git a/lib/m4sugar/m4sh.m4 b/lib/m4sugar/m4sh.m4 index 9ef15f57..10537eb0 100644 --- a/lib/m4sugar/m4sh.m4 +++ b/lib/m4sugar/m4sh.m4 @@ -280,6 +280,7 @@ _AS_TEST_PREPARE _AS_TR_CPP_PREPARE _AS_TR_SH_PREPARE _AS_UNSET_PREPARE +_AS_VAR_APPEND_PREPARE m4_popdef([AS_REQUIRE])dnl ]) @@ -303,6 +304,7 @@ AS_REQUIRE([_AS_TEST_PREPARE]) 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]) m4_divert_pop[]dnl ]) @@ -1637,6 +1639,52 @@ AS_REQUIRE([_AS_TR_CPP_PREPARE])dnl # when passed through eval, and a polymorphic name is either type. +# _AS_VAR_APPEND_PREPARE +# ---------------------- +# Define as_func_append to the optimum definition for the current +# shell (bash and zsh provide the += assignment operator to avoid +# quadratic append growth over repeated appends). +m4_defun([_AS_VAR_APPEND_PREPARE], +[AS_FUNCTION_DESCRIBE([as_func_append], [VAR VALUE], +[Append the text in VALUE to the end of the definition contained in +VAR. Take advantage of any shell optimizations that allow amortized +linear growth over repeated appends, instead of the typical quadratic +growth present in naive implementations.]) +AS_IF([_AS_RUN(["AS_ESCAPE([_AS_VAR_APPEND_WORKS])"])], +[eval 'as_func_append () + { + eval $[]1+=\$[]2 + }'], +[as_func_append () + { + eval $[]1=\$$[]1\$[]2 + }]) # 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 +# contents of the polymorphic shell variable VAR, taking advantage of +# any shell optimizations that allow repeated appends to result in +# amortized linear scaling rather than quadratic behavior. This macro +# is not worth the overhead unless the expected final size of the +# contents of VAR outweigh the typical VALUE size of repeated appends. +# Note that unlike AS_VAR_SET, VALUE must be properly quoted to avoid +# field splitting and file name expansion. +m4_define([AS_VAR_APPEND], +[_AS_DETECT_SUGGESTED([_AS_VAR_APPEND_WORKS])dnl +AS_REQUIRE([_AS_VAR_APPEND_PREPARE], [], [M4SH-INIT-FN])dnl +as_func_append $1 $2]) + + # AS_VAR_COPY(DEST, SOURCE) # ------------------------- # Set the polymorphic shell variable DEST to the contents of the polymorphic @@ -1724,7 +1772,8 @@ m4_pushdef([$1], [$as_[$1]])])]) # AS_VAR_SET(VARIABLE, VALUE) # --------------------------- # Set the contents of the polymorphic shell VARIABLE to the shell -# expansion of VALUE. +# expansion of VALUE. VALUE is immune to field splitting and file +# name expansion. m4_define([AS_VAR_SET], [AS_LITERAL_IF([$1], [$1=$2], diff --git a/tests/m4sh.at b/tests/m4sh.at index b0ddafde..6ea63585 100644 --- a/tests/m4sh.at +++ b/tests/m4sh.at @@ -926,7 +926,7 @@ AT_CLEANUP ## AS_VAR_*. ## ## ---------- ## -AT_SETUP([AS@&t@_VAR]) +AT_SETUP([AS@&t@_VAR basics]) AT_KEYWORDS([m4sh AS@&t@_VAR_COPY AS@&t@_VAR_SET AS@&t@_VAR_GET]) AT_KEYWORDS([AS@&t@_VAR_TEST_SET AS@&t@_VAR_SET_IF AS@&t@_VAR_IF]) AT_KEYWORDS([AS@&t@_VAR_PUSHDEF AS@&t@_VAR_POPDEF]) @@ -1018,6 +1018,41 @@ ok AT_CLEANUP +## --------------- ## +## AS_VAR_APPEND. ## +## --------------- ## + +AT_SETUP([AS@&t@_VAR_APPEND]) +AT_KEYWORDS([m4sh AS@&t@_VAR]) + +AT_DATA_M4SH([script.as], [[dnl +AS_INIT +# Literals. +AS_VAR_APPEND([foo], ["hello, "]) +AS_VAR_APPEND([foo], [world]) +echo "$foo" +# Indirects via shell vars. +num=1 +AS_VAR_APPEND([foo$num], ['hello, ']) +AS_VAR_APPEND([foo$num], [`echo "world"`]) +echo "$foo1" +# Indirects via command substitution. +h=hello w=', world' +AS_VAR_APPEND([`echo foo2`], [${h}]) +AS_VAR_APPEND([`echo foo2`], ["$w"]) +echo "$foo2" +]]) + +AT_CHECK_M4SH +AT_CHECK([./script], [], +[[hello, world +hello, world +hello, world +]]) + +AT_CLEANUP + + ## ----------------- ## ## AS_INIT cleanup. ## ## ----------------- ##