2010-07-02 Eric Blake <eblake@redhat.com>
+ Add optional argument to AS_LITERAL_IF.
+ * lib/m4sugar/m4sh.m4 (_AS_LITERAL_IF): Rewrite to generate macro
+ name, without using m4_cond.
+ (_AS_LITERAL_IF_, _AS_LITERAL_IF_YES, _AS_LITERAL_IF_NO): New
+ helpers.
+ (AS_LITERAL_IF, AS_LITERAL_WORD_IF, _AS_TR_SH, _AS_TR_CPP)
+ (_AS_VAR_PUSHDEF): Adjust callers.
+ * lib/autoconf/types.m4 (AC_CHECK_ALIGNOF): Relax restrictions on
+ invalid bytes, since this allows inline struct layouts.
+ (_AC_CHECK_ALIGNOF): New helper macro.
+ * tests/m4sh.at (AS@&t@_LITERAL_IF): Update test.
+ * doc/autoconf.texi (Polymorphic Variables) <AS_LITERAL_IF>:
+ Update documentation.
+
Use AS_LITERAL_WORD_IF as appropriate.
* lib/autoconf/autoheader.m4 (AH_VERBATIM): Use new macro.
* lib/autoconf/general.m4 (AC_REQUIRE_AUX_FILE, AC_CACHE_VAL)
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})
+@defmac AS_LITERAL_IF (@var{expression}, @ovar{if-literal}, @ovar{if-not}, @
+ @dvar{if-simple-ref, @var{if-not}})
+@defmacx AS_LITERAL_WORD_IF (@var{expression}, @ovar{if-literal}, @
+ @ovar{if-not}, @dvar{if-simple-ref, @var{if-not}})
@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.
-@code{AS_LITERAL_WORD_IF} only expands
+@code{`expr`}), then @var{if-not} is expanded. Sometimes, it is
+possible to output optimized code if @var{expression} consists only of
+shell variable expansions (such as @code{$@{var@}}), in which case
+@var{if-simple-ref} can be provided; but defaulting to @var{if-not}
+should always be safe. @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}.
@samp{_}).
This example shows how to read the contents of the shell variable
-@code{bar}, exercising both arguments to @code{AS_LITERAL_IF}. It
+@code{bar}, exercising all three arguments to @code{AS_LITERAL_IF}. It
results in a script that will output the line @samp{hello} three times.
@example
[AS_LITERAL_IF([$1],
[echo "$$1"],
[AS_VAR_COPY([tmp], [$1])
- echo "$tmp"])])
+ echo "$tmp"],
+ [eval 'echo "$'"$1"\"])])
foo=bar bar=hello
MY_ACTION([bar])
MY_ACTION([`echo bar`])
# AC_CHECK_ALIGNOF(TYPE, [INCLUDES = DEFAULT-INCLUDES])
# -----------------------------------------------------
+# TYPE can include braces and semicolon, which AS_TR_CPP and AS_TR_SH
+# (correctly) recognize as potential shell metacharacters. So we
+# have to flatten problematic characters ourselves to guarantee that
+# AC_DEFINE_UNQUOTED will see a literal.
AC_DEFUN([AC_CHECK_ALIGNOF],
-[AS_LITERAL_IF([$1], [],
- [m4_fatal([$0: requires literal arguments])])]dnl
+[m4_if(m4_index(m4_translit([[$1]], [`\"], [$]), [$]), [-1], [],
+ [m4_fatal([$0: requires literal arguments])])]dnl
+[_$0([$1], [$2], m4_translit([[$1]], [{;}], [___]))])
+
+m4_define([_AC_CHECK_ALIGNOF],
[# The cast to long int works around a bug in the HP C Compiler,
# see AC_CHECK_SIZEOF for more information.
-_AC_CACHE_CHECK_INT([alignment of $1], [AS_TR_SH([ac_cv_alignof_$1])],
+_AC_CACHE_CHECK_INT([alignment of $1], [AS_TR_SH([ac_cv_alignof_$3])],
[(long int) offsetof (ac__type_alignof_, y)],
[AC_INCLUDES_DEFAULT([$2])
#ifndef offsetof
# define offsetof(type, member) ((char *) &((type *) 0)->member - (char *) 0)
#endif
typedef struct { char x; $1 y; } ac__type_alignof_;],
- [if test "$AS_TR_SH([ac_cv_type_$1])" = yes; then
+ [if test "$AS_TR_SH([ac_cv_type_$3])" = yes; then
AC_MSG_FAILURE([cannot compute alignment of $1], 77)
else
- AS_TR_SH([ac_cv_alignof_$1])=0
+ AS_TR_SH([ac_cv_alignof_$3])=0
fi])
-AC_DEFINE_UNQUOTED(AS_TR_CPP(alignof_$1), $AS_TR_SH([ac_cv_alignof_$1]),
+AC_DEFINE_UNQUOTED(AS_TR_CPP(alignof_$3), $AS_TR_SH([ac_cv_alignof_$3]),
[The normal alignment of `$1', in bytes.])
])# AC_CHECK_ALIGNOF
INCLUDES, setting cache variable VAR accordingly.])],
[_$0_BODY])]dnl
[AS_LITERAL_IF([$1], [], [m4_fatal([$0: requires literal arguments])])]dnl
-[m4_if(m4_index([$1], [.]), -1, [m4_fatal([$0: Did not see any dot in `$1'])])]dnl
+[m4_if(m4_index([$1], [.]), [-1],
+ [m4_fatal([$0: Did not see any dot in `$1'])])]dnl
[AS_VAR_PUSHDEF([ac_Member], [ac_cv_member_$1])]dnl
[ac_fn_[]_AC_LANG_ABBREV[]_check_member "$LINENO" ]dnl
[m4_bpatsubst([$1], [^\([^.]*\)\.\(.*\)], ["\1" "\2"]) "ac_Member" ]dnl
m4_dquote(m4_dquote(m4_defn([m4_cr_symbols1])))[[))], [0], [-])])
-# AS_LITERAL_IF(EXPRESSION, IF-LITERAL, IF-NOT-LITERAL)
+# AS_LITERAL_IF(EXPRESSION, IF-LITERAL, IF-NOT-LITERAL,
+# [IF-SIMPLE-REF = IF-NOT-LITERAL])
# -----------------------------------------------------
# If EXPRESSION has no shell indirections ($var or `expr`), expand
-# IF-LITERAL, else IF-NOT-LITERAL.
+# IF-LITERAL, else IF-NOT-LITERAL. In some cases, IF-NOT-LITERAL
+# must be complex to safely deal with ``, while a simpler
+# expression IF-SIMPLE-REF can be used if the indirection
+# involves only shell variable expansion (as in ${varname}).
#
# EXPRESSION is treated as a literal if it results in the same
# interpretation whether it is unquoted or contained within double
# 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
+# literal, because it has different globbing. Note, however, that
+# while `${a+b}' is neither a literal nor a simple ref, `a+b' is a
+# literal. 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.
#
# 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.
+# characters are normalized into `$' if they can form simple refs
+# (${a}), `+' if they can potentially form literals (a+b), ``' if they
+# can interfere with m4 parsing, or left alone otherwise. If both `$'
+# and `+' are left, it is treated as a complex reference (${a+b}),
+# even though it could technically be a simple reference (${a}+b).
# _AS_LITERAL_IF_ only has to check for an empty string after removing
-# the normalized characters.
+# one of the two normalized characters.
#
# Rather than expand m4_defn every time AS_LITERAL_IF is expanded, we
-# inline its expansion up front.
+# inline its expansion up front. _AS_LITERAL_IF expands to the name
+# of a macro that takes three arguments: IF-SIMPLE-REF,
+# IF-NOT-LITERAL, IF-LITERAL. It also takes an optional argument of
+# any additional characters to allow as literals (useful for AS_TR_SH
+# and AS_TR_CPP to perform inline conversion of whitespace to _). The
+# order of the arguments allows reuse of m4_default.
m4_define([AS_LITERAL_IF],
-[_$0(m4_expand([$1]), [$2], [$3])])
+[_$0(m4_expand([$1]), [ ][
+])([$4], [$3], [$2])])
m4_define([_AS_LITERAL_IF],
-[m4_if(m4_cond([m4_eval(m4_index([$1], [@S|@]) == -1)], [0], [],
- [m4_index(m4_translit([$1], [[]`'\"$4,#()]]]dnl
-m4_dquote(m4_dquote(m4_defn([m4_cr_symbols2])))[[, [$$$$$$$5]), [$])],
- [-1], [-]), [-], [$2], [$3])])
+[m4_if(m4_index([$1], [@S|@]), [-1], [$0_(m4_translit([$1],
+ [-:%/@{}[]#(),.$2]]]m4_dquote(m4_dquote(m4_defn([m4_cr_symbols2])))[[,
+ [+++++$$`````]))], [$0_NO])])
-# AS_LITERAL_WORD_IF(EXPRESSION, IF-LITERAL, IF-NOT-LITERAL)
+m4_define([_AS_LITERAL_IF_],
+[m4_if(m4_translit([$1], [+]), [], [$0YES],
+ m4_translit([$1], [$]), [], [m4_default], [$0NO])])
+
+m4_define([_AS_LITERAL_IF_YES], [$3])
+m4_define([_AS_LITERAL_IF_NO], [$2])
+
+# AS_LITERAL_WORD_IF(EXPRESSION, IF-LITERAL, IF-NOT-LITERAL,
+# [IF-SIMPLE-REF = 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_LITERAL_IF(m4_expand([$1]))([$4], [$3], [$2])])
# AS_TMPDIR(PREFIX, [DIRECTORY = $TMPDIR [= /tmp]])
[_$0(m4_expand([$1]))])
m4_define([_AS_TR_SH],
-[_AS_LITERAL_IF([$1], [$0_LITERAL], [$0_INDIR])([$1])])
+[_AS_LITERAL_IF([$1], [ ][
+])([], [$0_INDIR], [$0_LITERAL])([$1])])
m4_define([_AS_TR_SH_LITERAL],
[m4_translit([[$1]],
[_$0(m4_expand([$1]))])
m4_define([_AS_TR_CPP],
-[_AS_LITERAL_IF([$1], [$0_LITERAL], [$0_INDIR])([$1])])
+[_AS_LITERAL_IF([$1], [ ][
+])([], [$0_INDIR], [$0_LITERAL])([$1])])
m4_define([_AS_TR_CPP_LITERAL],
[m4_translit([$1],
[_$0([$1], m4_expand([$2]))])
m4_define([_AS_VAR_PUSHDEF],
-[_AS_LITERAL_IF([$2],
- [m4_pushdef([$1], [_AS_TR_SH_LITERAL([$2])])],
- [as_$1=_AS_TR_SH_INDIR([$2])
-m4_pushdef([$1], [$as_[$1]])])])
+[_AS_LITERAL_IF([$2], [ ][
+])([], [as_$1=_AS_TR_SH_INDIR([$2])
+m4_pushdef([$1], [$as_[$1]])],
+[m4_pushdef([$1], [_AS_TR_SH_LITERAL([$2])])])])
# AS_VAR_SET(VARIABLE, VALUE)
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$it], [ERR1], [ERR2], [ok]) 5
+echo AS_LITERAL_IF([l${it}], [ERR1], [ERR2], [ok]) 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]) 10
m4_define([mac], [l$it])
echo AS_LITERAL_IF([mac], [ERR], [ok]) 11
-echo AS_LITERAL_IF([mac], [ERR1], [ok], [fixme]) 12
+echo AS_LITERAL_IF([mac], [ERR1], [ERR2], [ok]) 12
m4_define([mac], [l``it])
echo AS_LITERAL_IF([mac], [ERR], [ok]) 13
echo AS_LITERAL_IF([mac], [ERR1], [ok], [ERR2]) 14