From: Eric Blake Date: Tue, 16 Mar 2010 21:51:23 +0000 (-0600) Subject: Add AS_LITERAL_WORD_IF. X-Git-Tag: v2.66~11 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=07263c965a03c979f4712c6c5cfe9243911af0f9;p=thirdparty%2Fautoconf.git Add AS_LITERAL_WORD_IF. * lib/m4sugar/m4sh.m4 (_AS_LITERAL_IF): Also reject shell quoting characters as non-literal, and provide way to reject space. (AS_LITERAL_WORD_IF): New macro. * doc/autoconf.texi (Polymorphic Variables) : Document new macro. Fix example to match reality. * NEWS: Document change and new macro. * tests/m4sh.at (AS@&t@_LITERAL_IF): Update test. Signed-off-by: Eric Blake --- diff --git a/ChangeLog b/ChangeLog index 601b1695..354e9486 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,14 @@ 2010-07-02 Eric Blake + Add AS_LITERAL_WORD_IF. + * lib/m4sugar/m4sh.m4 (_AS_LITERAL_IF): Also reject shell quoting + characters as non-literal, and provide way to reject space. + (AS_LITERAL_WORD_IF): New macro. + * doc/autoconf.texi (Polymorphic Variables) : + Document new macro. Fix example to match reality. + * NEWS: Document change and new macro. + * tests/m4sh.at (AS@&t@_LITERAL_IF): Update test. + Optimize AC_DEFINE. * lib/autoconf/general.m4 (_AC_DEFINE_Q): Avoid overhead of AS_LITERAL_IF. diff --git a/NEWS b/NEWS index eecb9f6c..c5e5ded2 100644 --- a/NEWS +++ b/NEWS @@ -38,6 +38,11 @@ GNU Autoconf NEWS - User visible changes. AT_ARG_OPTION has been changed in that the negative of a long option --OPTION is now --no-OPTION rather than --noOPTION. +** The macro AS_LITERAL_IF is slightly more conservative; text + containing shell quotes are no longer treated as literals. + Furthermore, a new macro, AS_LITERAL_WORD_IF, adds an additional + level of checking that no whitespace occurs in literals. + * Major changes in Autoconf 2.65 (2009-11-21) [stable] Released by Eric Blake, based on git versions 2.64.*. diff --git a/doc/autoconf.texi b/doc/autoconf.texi index 6353f870..ab7ed934 100644 --- a/doc/autoconf.texi +++ b/doc/autoconf.texi @@ -13299,23 +13299,47 @@ undefined if expansion of an indirect variable does not result in a literal variable name. @defmac AS_LITERAL_IF (@var{expression}, @ovar{if-literal}, @ovar{if-not}) +@defmacx AS_LITERAL_WORD_IF (@var{expression}, @ovar{if-literal}) @asindex{LITERAL_IF} +@asindex{LITERAL_WORD_IF} If the expansion of @var{expression} is definitely a shell literal, expand @var{if-literal}. If the expansion of @var{expression} looks like it might contain shell indirections (such as @code{$var} or -@code{`expr`}), then @var{if-not} is expanded. In order to reduce the -time spent deciding whether an expression is literal, the implementation -is somewhat conservative (for example, @samp{'[$]'} is a single-quoted -shell literal, but causes @var{if-not} to be expanded). While this -macro is often used for recognizing shell variable names, it can also be -used in other contexts. +@code{`expr`}), then @var{if-not} is expanded. +@code{AS_LITERAL_WORD_IF} only expands +@var{if-literal} if @var{expression} looks like a single shell word, +containing no whitespace; while @code{AS_LITERAL_IF} allows whitespace +in @var{expression}. + +In order to reduce the time spent recognizing whether an +@var{expression} qualifies as a literal or a simple indirection, the +implementation is somewhat conservative: @var{expression} must be a +single shell word (possibly after stripping whitespace), consisting only +of bytes that would have the same meaning whether unquoted or enclosed +in double quotes (for example, @samp{a.b} results in @var{if-literal}, +even though it is not a valid shell variable name; while both @samp{'a'} +and @samp{[$]} result in @var{if-not}, because they behave differently +than @samp{"'a'"} and @samp{"[$]"}). This macro can be used in contexts +for recognizing portable file names (such as in the implementation of +@code{AC_LIBSOURCE}), or coupled with some transliterations for forming +valid variable names (such as in the implementation of @code{AS_TR_SH}, +which uses an additional @code{m4_translit} to convert @samp{.} to +@samp{_}). + +This example shows how to read the contents of the shell variable +@code{bar}, exercising both arguments to @code{AS_LITERAL_IF}. It +results in a script that will output the line @samp{hello} three times. @example AC_DEFUN([MY_ACTION], [AS_LITERAL_IF([$1], -[echo "$1"], -[AS_VAR_COPY([tmp], [$1]) -echo "$tmp"])]) + [echo "$$1"], + [AS_VAR_COPY([tmp], [$1]) + echo "$tmp"])]) +foo=bar bar=hello +MY_ACTION([bar]) +MY_ACTION([`echo bar`]) +MY_ACTION([$foo]) @end example @end defmac diff --git a/lib/m4sugar/m4sh.m4 b/lib/m4sugar/m4sh.m4 index 024498d4..41b92f6e 100644 --- a/lib/m4sugar/m4sh.m4 +++ b/lib/m4sugar/m4sh.m4 @@ -1519,15 +1519,24 @@ m4_dquote(m4_dquote(m4_defn([m4_cr_symbols1])))[[))], [0], [-])]) # AS_LITERAL_IF(EXPRESSION, IF-LITERAL, IF-NOT-LITERAL) # ----------------------------------------------------- -# If EXPRESSION has shell indirections ($var or `expr`), expand +# If EXPRESSION has no shell indirections ($var or `expr`), expand # IF-LITERAL, else IF-NOT-LITERAL. -# This is an *approximation*: for instance EXPRESSION = `\$' is -# definitely a literal, but will not be recognized as such. +# +# EXPRESSION is treated as a literal if it results in the same +# interpretation whether it is unquoted or contained within double +# quotes, with the exception that whitespace is ignored (on the +# assumption that it will be flattened to _). Therefore, neither `\$' +# nor `a''b' is a literal, since both backslash and single quotes have +# different quoting behavior in the two contexts; and `a*' is not a +# literal, because it has different globbing. +# This macro is an *approximation*: it is possible that +# there are some EXPRESSIONs which the shell would treat as literals, +# but which this macro does not recognize. # # Why do we reject EXPRESSION expanding with `[' or `]' as a literal? # Because AS_TR_SH is MUCH faster if it can use m4_translit on literals # instead of m4_bpatsubst; but m4_translit is much tougher to do safely -# if `[' is translated. +# if `[' is translated. That, and file globbing matters. # # Note that the quadrigraph @S|@ can result in non-literals, but outright # rejecting all @ would make AC_INIT complain on its bug report address. @@ -1535,10 +1544,14 @@ m4_dquote(m4_dquote(m4_defn([m4_cr_symbols1])))[[))], [0], [-])]) # We used to use m4_bmatch(m4_quote($1), [[`$]], [$3], [$2]), but # profiling shows that it is faster to use m4_translit. # -# Because the translit is stripping quotes, it must also neutralize anything -# that might be in a macro name, as well as comments, commas, or unbalanced -# parentheses. All the problem characters are unified so that a single -# m4_index can scan the result. +# Because the translit is stripping quotes, it must also neutralize +# anything that might be in a macro name, as well as comments, commas, +# or unbalanced parentheses. Valid shell variable characters and +# unambiguous literal characters are deleted (`a.b'), and remaining +# characters are normalized into `$' if they are special to the +# shell or to m4 parsing, and left alone otherwise. +# _AS_LITERAL_IF_ only has to check for an empty string after removing +# the normalized characters. # # Rather than expand m4_defn every time AS_LITERAL_IF is expanded, we # inline its expansion up front. @@ -1547,10 +1560,19 @@ m4_define([AS_LITERAL_IF], m4_define([_AS_LITERAL_IF], [m4_if(m4_cond([m4_eval(m4_index([$1], [@S|@]) == -1)], [0], [], - [m4_index(m4_translit([$1], [[]`,#()]]]dnl -m4_dquote(m4_dquote(m4_defn([m4_cr_symbols2])))[[, [$$$]), [$])], + [m4_index(m4_translit([$1], [[]`'\"$4,#()]]]dnl +m4_dquote(m4_dquote(m4_defn([m4_cr_symbols2])))[[, [$$$$$$$5]), [$])], [-1], [-]), [-], [$2], [$3])]) +# AS_LITERAL_WORD_IF(EXPRESSION, IF-LITERAL, IF-NOT-LITERAL) +# ---------------------------------------------------------- +# Like AS_LITERAL_IF, except that spaces and tabs in EXPRESSION +# are treated as non-literal. +m4_define([AS_LITERAL_WORD_IF], +[_AS_LITERAL_IF(m4_expand([$1]), [$2], [$3], [ ][ +], [$$$])]) + + # AS_TMPDIR(PREFIX, [DIRECTORY = $TMPDIR [= /tmp]]) # ------------------------------------------------- diff --git a/tests/m4sh.at b/tests/m4sh.at index 05cea853..5b3a55db 100644 --- a/tests/m4sh.at +++ b/tests/m4sh.at @@ -1077,20 +1077,31 @@ AT_CLEANUP ## --------------- ## AT_SETUP([AS@&t@_LITERAL_IF]) -AT_KEYWORDS([m4sh]) +AT_KEYWORDS([m4sh AS@&t@_LITERAL_WORD_IF]) AT_DATA_M4SH([script.as], [[dnl AS_INIT echo AS_LITERAL_IF([lit], [ok], [ERR]) 1 -echo AS_LITERAL_IF([l$it], [ERR], [ok]) 2 -echo AS_LITERAL_IF([l`case a in b) ;; esac`it], [ERR], [ok]) 3 -m4_define([mac], [lit]) -echo AS_LITERAL_IF([mac], [ok], [ERR]) 4 -echo AS_LITERAL_IF([mac($, ``)], [ok], [ERR]) 5 +echo AS_LITERAL_IF([l-/.it], [ok], [ERR]) 2 +echo AS_LITERAL_IF([l''it], [ERR], [ok]) 3 +echo AS_LITERAL_IF([l$it], [ERR], [ok]) 4 +echo AS_LITERAL_IF([l$it], [ERR1], [ok], [fixme]) 5 +echo AS_LITERAL_IF([l${it}], [ERR1], [ok], [fixme]) 6 +echo AS_LITERAL_IF([l`case a in b) ;; esac`it], [ERR], [ok]) 7 +echo AS_LITERAL_IF([l`case a in b) ;; esac`it], [ERR1], [ok], [ERR2]) 8 +m4_define([mac], [l-/.it]) +echo AS_LITERAL_IF([mac], [ok], [ERR]) 9 +echo AS_LITERAL_IF([mac($, ``)], [ok], [ERR]) 10 m4_define([mac], [l$it]) -echo AS_LITERAL_IF([mac], [ERR], [ok]) 6 +echo AS_LITERAL_IF([mac], [ERR], [ok]) 11 +echo AS_LITERAL_IF([mac], [ERR1], [ok], [fixme]) 12 m4_define([mac], [l``it]) -echo AS_LITERAL_IF([mac], [ERR], [ok]) 7 +echo AS_LITERAL_IF([mac], [ERR], [ok]) 13 +echo AS_LITERAL_IF([mac], [ERR1], [ok], [ERR2]) 14 +echo AS_LITERAL_IF([ a ][ +b], [ok], [ok]) 15 +echo AS_LITERAL_WORD_IF([ a ][ +b], [ERR], [ok]) 16 ]]) AT_CHECK_M4SH @@ -1102,6 +1113,15 @@ ok 4 ok 5 ok 6 ok 7 +ok 8 +ok 9 +ok 10 +ok 11 +ok 12 +ok 13 +ok 14 +ok 15 +ok 16 ]]) AT_CLEANUP