autoconf-patches
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH 2/7] Add AS_LITERAL_WORD_IF.


From: Eric Blake
Subject: [PATCH 2/7] Add AS_LITERAL_WORD_IF.
Date: Fri, 2 Jul 2010 13:37:47 -0600

* 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) <AS_LITERAL_IF>:
Document new macro.  Fix example to match reality.
* NEWS: Document change and new macro.
* tests/m4sh.at (AS@&address@hidden): Update test.

Signed-off-by: Eric Blake <address@hidden>
---
 ChangeLog           |    9 +++++++++
 NEWS                |    5 +++++
 doc/autoconf.texi   |   42 +++++++++++++++++++++++++++++++++---------
 lib/m4sugar/m4sh.m4 |   42 ++++++++++++++++++++++++++++++++----------
 tests/m4sh.at       |   36 ++++++++++++++++++++++++++++--------
 5 files changed, 107 insertions(+), 27 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 601b169..354e948 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,14 @@
 2010-07-02  Eric Blake  <address@hidden>

+       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) <AS_LITERAL_IF>:
+       Document new macro.  Fix example to match reality.
+       * NEWS: Document change and new macro.
+       * tests/m4sh.at (AS@&address@hidden): 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 eecb9f6..c5e5ded 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 6353f87..ab7ed93 100644
--- a/doc/autoconf.texi
+++ b/doc/autoconf.texi
@@ -13299,23 +13299,47 @@ Polymorphic Variables
 literal variable name.

 @defmac AS_LITERAL_IF (@var{expression}, @ovar{if-literal}, @ovar{if-not})
address@hidden AS_LITERAL_WORD_IF (@var{expression}, @ovar{if-literal})
 @asindex{LITERAL_IF}
address@hidden
 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
address@hidden), 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.
address@hidden), then @var{if-not} is expanded.
address@hidden only expands
address@hidden 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
address@hidden 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
address@hidden), 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
address@hidden).
+
+This example shows how to read the contents of the shell variable
address@hidden, 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 024498d..41b92f6 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], address@hidden|@]) == -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 05cea85..5b3a55d 100644
--- a/tests/m4sh.at
+++ b/tests/m4sh.at
@@ -1077,20 +1077,31 @@ AT_CLEANUP
 ## --------------- ##

 AT_SETUP([AS@&address@hidden)
-AT_KEYWORDS([m4sh])
+AT_KEYWORDS([m4sh AS@&address@hidden)

 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
-- 
1.7.1




reply via email to

[Prev in Thread] Current Thread [Next in Thread]