WIP: replace AS_ESCAPE and _AS_QUOTE with AS_QUOTE_D.

AS_ESCAPE is difficult or even impossible to use correctly,
depending on what you’re trying to do with it:

+ AS_ESCAPE([text], [`\"]) is intended to permit variable interpolation
  but prevent command substitution.  This does not work anymore,
  because we have $(...) command substitution nowadays, Solaris 10
  notwithstanding.
+ It is incorrect to leave \ or " out of the [chars] argument, but people
  do this all the dang time both in our own code and in third-party code.
+ It is incorrect to put anything in [chars] besides $ ` \ ", but people
  also do this.  In particular, 'AS_ESCAPE([text], [\'])' *does not*
  produce a correct single-quoted string, but at least one third-party
  m4 macro does this anyway.
+ In most cases you need to write AS_ESCAPE(m4_dquote(m4_expand([text])))
  or else M4 macros inside [text] will be expanded *after* the quotation
  process is complete, and the text they expand to won’t get escaped.
  *Our* code using AS_ESCAPE was diligent about this, but almost no
  no third-party uses bothered.
+ Almost all uses of AS_ESCAPE are constructing double-quoted strings,
  so it would be more ergonomic if it added the outermost quotes for you.

(All assertions about third-party code courtesy of
<http://codesearch.debian.net/search?q=%5CbAS_ESCAPE%5Cb+-pkg%3Aautoconf+-pkg%3Aautoconf2.69&literal=0>.)

The internal _AS_QUOTE macro is also almost impossible to use
correctly, for the above reasons plus the fact that it includes some
20-year-old *internal* backward compatibility logic that doesn’t
distinguish ${variable} from $(command) either.

Replace with a safer API:

+ New macro AS_QUOTE_S([text]) turns TEXT into a single-quoted string,
  *correctly* escaping embedded single quotes, and supplying an outer
  pair of quotes. Macros in TEXT are expanded once before quotation.

+ New macro AS_QUOTE_D([text], [interpolation]) turns TEXT into a
  double-quoted string, supplying an outer pair of quotes. Macros in
  TEXT are expanded once before quotation.

  The INTERPOLATION argument is a comma-separated list of keywords
  specifying what types of interpolation will be permitted:

    - ‘allow-vars’: Allow variable and arithmetic interpolation.
    - ‘allow-commands’: Allow command substitution.

  If the argument is empty or omitted, no interpolation is allowed.

  This is intentionally verbose and there is no ‘allow-all’, because
  I want people to think hard about if it’s really a good idea before
  enabling command substitution, and I want it to be easy to find all
  the place’s it’s being used.  (Almost all uses of AS_ESCAPE, both
  internally and externally, want either no interpolation or only
  variable interpolation.)  Both `...` and $(...) are handled correctly
  in all modes.

+ AS_ESCAPE is changed to map each of the valid possibilities for CHARS
  to the AS_QUOTE_D interpolation mode that was probably intended,
  papering over the bugs in third party macros.  (For example, both
  [`\"] and [`] by itself will be mapped to allow-vars mode, because
  we presume that someone who wrote [‘] didn’t think it through and
  there’s a latent bug.)  Invalid CHARS arguments now raise an error
  instead of silently doing something nonsensical.  All uses trigger
  a -Wobsolete warning.  AS_ESCAPE cannot be autoupdated to AS_QUOTE_D
  (because it’s an m4sh macro, and because autoupdate can’t edit out
  the surrounding quote marks) so instead I wrote a whole bunch of
  advice for manual conversion in the manual.

WIP: buggy (partially but not entirely because of the bugs in
m4_join_uniq); one internal use of AS_ESCAPE remains; need to
write tests and NEWS; unresolved design decisions including

+ should ‘allow-arithmetic’ be a third interpolation keyword, separate
  from ‘allow-vars’?
+ do we want a public API for escaping *without* adding surrounding
  quotes? Autotest was doing this but it didn’t particularly need to.
+ should the result of AS_QUOTE_[DS] be M4-quoted? Currently it isn’t.
+ is expand-once-then-quote [i.e. shellquote(m4_dquote(m4_expand([text])))]
  the most ergonomic behavior?
This commit is contained in:
Zack Weinberg 2024-06-26 14:42:44 -04:00
parent 4ffd73054a
commit ec192f7fc9
7 changed files with 319 additions and 163 deletions

View File

@ -13959,6 +13959,7 @@ namespaces.
@menu
* Common Shell Constructs:: Portability layer for common shell constructs
* Shell Quotation:: Turning text into quoted strings
* Polymorphic Variables:: Support for indirect variable names
* Initialization Macros:: Macros to establish a sane shell environment
* File Descriptor Macros:: File descriptor macros for input and output
@ -14041,55 +14042,6 @@ for portability, should not include more than one newline. The bytes of
Redirections can be placed outside the macro invocation.
@end defmac
@c We cannot use @dvar because the macro expansion mistreats backslashes.
@defmac AS_ESCAPE (@var{string}, @r{[}@var{chars} = @samp{`\"$}@r{]})
@asindex{ESCAPE}
Expands to @var{string}, with any characters in @var{chars} escaped with
a backslash (@samp{\}). @var{chars} should be at most four bytes long,
and only contain characters from the set @samp{`\"$}; however,
characters may be safely listed more than once in @var{chars} for the
sake of syntax highlighting editors. The current implementation expands
@var{string} after adding escapes; if @var{string} contains macro calls
that in turn expand to text needing shell quoting, you can use
@code{AS_ESCAPE(m4_dquote(m4_expand([string])))}.
The default for @var{chars} (@samp{\"$`}) is the set of characters
needing escapes when @var{string} will be used literally within double
quotes. One common variant is the set of characters to protect when
@var{string} will be used literally within back-ticks or an unquoted
here-document (@samp{\$`}). Another common variant is @samp{""}, which can
be used to form a double-quoted string containing the same expansions
that would have occurred if @var{string} were expanded in an unquoted
here-document; however, when using this variant, care must be taken that
@var{string} does not use double quotes within complex variable
expansions (such as @samp{$@{foo-`echo "hi"`@}}) that would be broken
with improper escapes.
This macro is often used with @code{AS_ECHO}. For an example, observe
the output generated by the shell code generated from this snippet:
@example
foo=bar
AS_ECHO(["AS_ESCAPE(["$foo" = ])AS_ESCAPE(["$foo"], [""])"])
@result{}"$foo" = "bar"
m4_define([macro], [a, [\b]])
AS_ECHO(["AS_ESCAPE([[macro]])"])
@result{}macro
AS_ECHO(["AS_ESCAPE([macro])"])
@result{}a, b
AS_ECHO(["AS_ESCAPE(m4_dquote(m4_expand([macro])))"])
@result{}a, \b
@end example
@comment Should we add AS_ESCAPE_SINGLE? If we do, we can optimize in
@comment the case of @var{string} that does not contain '.
To escape a string that will be placed within single quotes, use:
@example
m4_bpatsubst([[@var{string}]], ['], ['\\''])
@end example
@end defmac
@defmac AS_EXECUTABLE_P (@var{file})
@asindex{EXECUTABLE_P}
Emit code to probe whether @var{file} is a regular file with executable
@ -14202,6 +14154,79 @@ glibc (@pxref{String/Array Comparison, , String/Array Comparison, libc,
The GNU C Library}).
@end defmac
@node Shell Quotation
@section Shell Quotation
M4sh provides two macros for fabricating shell quoted strings from text.
@defmac AS_QUOTE_S (@var{string})
@asindex{QUOTE_S}
Convert @var{string} into a single-quoted shell string.
@samp{'} within @var{string} will be mapped to @samp{'\''}.
@var{string} is taken literally---it cannot be the contents of a shell
variable. M4 macros within @var{string} will be expanded, once, before
quotation.
@end defmac
@defmac AS_QUOTE_D (@var{string}, @ovar{interpolation})
@asindex{QUOTE_D}
Convert @var{string} into a double-quoted shell string, escaping
special characters with @samp{\} as necessary. @var{string} is taken
literally---it cannot be the contents of a shell variable. M4 macros
within @var{string} will be expanded, once, before quotation.
The @var{interpolation} argument controls whether anything can be
interpolated into the string when the shell script runs. By default, or
when this argument is empty, nothing will be interpolated. The possible
non-empty values for @var{interpolation} are:
@table @code
@item allow-vars
Allow variables and arithmetic expressions to be interpolated.
For example:
@smallexample
@group
AWK=gawk
echo AS_QUOTE_D([checking whether $AWK supports 'asorti'],
[allow-vars])
@expansion{} AWK=gawk
@expansion{} echo "checking whether $AWK supports 'asorti'"
@result{} checking whether gawk supports 'asorti'
@end group
@end smallexample
@noindent
Without @samp{allow-vars}, the output would instead be @samp{checking
whether $AWK supports 'asorti'}.
@strong{Compatibility note:} Arithmetic expressions are part of the
POSIX shell standard, but are not universally implemented; see
@ref{shell-arithmetic,, the discussion of @samp{$((@var{expression}))}}
in @ref{Shell Substitutions}. In Autoconf scripts it is better to use
@code{AS_VAR_ARITH} and then interpolate the variable holding the
result.
@item allow-commands
Allow execution of embedded commands, written either with
@samp{`@var{command}`} or with @samp{$(@var{command})}. (Even today,
not all shells implement @samp{$(@var{command})}, so truly portable
scripts still need to avoid it; but @emph{defensive} quotation requires
us to assume that it @emph{does} work.)
@strong{Caution:} Embedded commands that contain nested double-quoted
strings will be mangled (handling them correctly is beyond M4's parsing
capabilities). Instead, assign the result of the command to a shell
variable and use variable interpolation.
@item allow-vars,allow-commands
@itemx allow-commands,allow-vars
Allow both of the above kinds of interpolation.
@end table
@end defmac
@node Polymorphic Variables
@section Support for indirect variable names
@cindex variable name indirection
@ -16961,6 +16986,7 @@ echo $(case x in x) echo hello;; esac)
@end example
@anchor{shell-arithmetic}
@item $((@var{expression}))
@cindex @code{$((@var{expression}))}
Arithmetic expansion is not portable as some shells (most
@ -24817,6 +24843,90 @@ This macro was renamed @code{AC_DECL_YYTEXT}, which in turn was
integrated into @code{AC_PROG_LEX} (@pxref{AC_PROG_LEX}).
@end defmac
@defmac AS_ESCAPE (@var{string}, @ovar{chars})
@asindex{ESCAPE}
This macro has been superseded by @code{AS_QUOTE_D} and @code{AS_QUOTE_S}
(@pxref{Shell Quotation}). @command{autoupdate} does not attempt to
update uses of @code{AS_ESCAPE}, because the update will usually require
modifying surrounding code, which @command{autoupdate} cannot do.
Like @code{AS_QUOTE_D}, @code{AS_ESCAPE} escapes special characters for
use inside shell double-quoted strings. However, it is harder to use
correctly: it does not put quotation marks around @var{string}, it does
not expand M4 macros in @var{string} before escaping special characters,
and many of the values of the @var{chars} argument will produce
improperly quoted results for some strings.
@samp{"AS_ESCAPE(m4_dquote(m4_expand([string])))"} is completely
equivalent to @samp{AS_QUOTE_D([string])}. Watch out for the
surrounding quotation marks! They were necessary with @code{AS_ESCAPE}
but become incorrect with @code{AS_QUOTE_D}.
In most cases, it is also correct to replace
@samp{"AS_ESCAPE([string])"}, without the pre-expansion, with
@samp{AS_QUOTE_D([string])}. If @var{string} should not be expanded
at all, use either @samp{AS_QUOTE_D([[string]])} or
@samp{AS_QUOTE_D(m4_dquote([string]))}
as appropriate.
If you actually need M4 macros within @var{string} to be expanded
and any special characters from the expansion @emph{not} to be escaped,
split up the string like this:
@samp{AS_QUOTE_D([prefix])"macro"AS_QUOTE_D([suffix])}. This will
produce @samp{"prefix""expanded text""suffix"} in the output; the
doubled quote marks will be removed by the shell.
Uses of @code{AS_ESCAPE} with the @var{chars} argument fall into
four classes, as shown in the table below:
@c Without the trailing hard spaces on the first line,
@c the HTML render has no whitespace between the columns!
@multitable {@code{`$"\@ @ `$"@ @ `$\@ @ `$@ @ @ }} {@samp{AS_QUOTE_D([...], [allow-commands,allow-vars])}}
@headitem @var{chars} arg @tab Replace with@dots{}
@item
@t{`$"\@ @ `$"@ @ `$\@ @ `$@ @ @ }
@tab
@samp{AS_QUOTE_D([...])}
@item
@t{@ `"\@ @ @ `"@ @ @ `\@ @ @ `}
@tab
@samp{AS_QUOTE_D([...], [allow-vars])}
@item
@t{@ $"\@ @ @ $"@ @ @ $\@ @ @ $}
@tab
@samp{AS_QUOTE_D([...], [allow-commands])}
@item
@t{@ @ "\@ @ @ @ "@ @ @ @ \}
@tab
@samp{AS_QUOTE_D([...], [allow-commands,allow-vars])}
@end multitable
The order of characters within @var{chars} is not significant, and
duplicate characters are ignored: @samp{"`} and @samp{`""} are both the
same as @samp{`"} and should be mapped to @code{allow-vars}.
Uses of @code{AS_ESCAPE} with any characters in @var{chars} besides
@samp{"}, @samp{`}, @samp{$}, and/or @samp{\} are incorrect, and have no
@code{AS_QUOTE_D} equivalent. In particular, @code{AS_ESCAPE} cannot
generate @emph{single-quoted} strings (but @code{AS_QUOTE_S} can).
@strong{Compatibility Note:} Prior to Autoconf 2.73, the various
possibilities for @var{chars} on each row of the table above were not
equivalent. The behavior of older @code{AS_ESCAPE} only matches the
behavior of @code{AS_QUOTE_D} for the first possibility listed in each
row.
When @code{AS_ESCAPE} is used for its intended purpose of generating
double-quoted shell strings, it is a @emph{bug} to use any of the other
possibilities: they would cause it not to quote all @var{string}s
correctly. Therefore, in Autoconf 2.73 and later, @code{AS_ESCAPE}
treats all the possibilities on each row as equivalent to the first.
If you were using @code{AS_ESCAPE} off-label and really wanted the
old behavior of @samp{AS_ESCAPE([@var{string}], [`$])} (for example),
change it to @samp{m4_bpatsubst([@var{string}], [[`$]], [\\\&])}.
@end defmac
@node Autoconf 1
@section Upgrading From Version 1
@cindex Upgrading autoconf

View File

@ -46,7 +46,7 @@ m4_define([AH_OUTPUT], [])
# Quote for Perl '' strings, which are those used by Autoheader.
m4_define([AH_VERBATIM],
[AS_LITERAL_WORD_IF([$1],
[AH_OUTPUT(_m4_expand([$1]), AS_ESCAPE([[$2]], [\']))])])
[AH_OUTPUT(_m4_expand([$1]), m4_bpatsubst([[$2]], [[\']], [\\\&]))])])
# AH_TEMPLATE(KEY, DESCRIPTION)

View File

@ -2359,7 +2359,7 @@ m4_define([AC_DEFINE], [_AC_DEFINE_Q([_$0], $@)])
# Append the pre-expanded STRING and a newline to confdefs.h, as if by
# a quoted here-doc.
m4_define([_AC_DEFINE],
[AS_ECHO(["AS_ESCAPE([[$1]])"]) >>confdefs.h])
[AS_ECHO([AS_QUOTE_D([[$1]])]) >>confdefs.h])
# AC_DEFINE_UNQUOTED(VARIABLE, [VALUE], [DESCRIPTION])
@ -2377,11 +2377,11 @@ m4_define([AC_DEFINE_UNQUOTED], [_AC_DEFINE_Q([_$0], $@)])
# avoid AS_ECHO if "#" is present to avoid confusing m4 with comments,
# but quadrigraphs are fine in that case.
m4_define([_AC_DEFINE_UNQUOTED],
[m4_if(m4_bregexp([$1], [#\|\\\|`\|\(\$\|@S|@\)\((|{|@{:@\)]), [-1],
[AS_ECHO(["AS_ESCAPE([$1], [""])"]) >>confdefs.h],
[m4_bmatch([$1], [#\|\\\|`\|\(\$\|@S|@\)\((|{|@{:@\)],
[cat >>confdefs.h <<_ACEOF
[$1]
_ACEOF])])
_ACEOF],
[AS_ECHO([AS_QUOTE_D([$1])]) >>confdefs.h])])
# _AC_DEFINE_Q(MACRO, VARIABLE, [VALUE], [DESCRIPTION])
@ -2738,7 +2738,7 @@ AC_DEFUN([AC_TRY_COMMAND],
# -------------------
AC_DEFUN([AC_RUN_LOG],
[_AC_RUN_LOG([$1],
[AS_ECHO(["$as_me:${as_lineno-$LINENO}: AS_ESCAPE([$1])"])])])
[AS_ECHO(["$as_me:${as_lineno-$LINENO}: "AS_QUOTE_D([$1])])])])
@ -3187,7 +3187,8 @@ dnl Initialize each $ac_[]_AC_LANG_ABBREV[]_undeclared_builtin_options once.
[AC_REQUIRE([_AC_UNDECLARED_BUILTIN_]_AC_LANG_ABBREV)]dnl
[AS_VAR_PUSHDEF([ac_Symbol], [ac_cv_have_decl_$1])]dnl
[ac_fn_check_decl ]dnl
["$LINENO" "$1" "ac_Symbol" "AS_ESCAPE([AC_INCLUDES_DEFAULT([$4])], [""])" ]dnl
["$LINENO" "$1" "ac_Symbol" ]dnl
[AS_QUOTE_D([AC_INCLUDES_DEFAULT([$4])], [allow-commands,allow-vars]) ]dnl
["$ac_[]_AC_LANG_ABBREV[]_undeclared_builtin_options" "_AC_LANG_PREFIX[]FLAGS"]
[AS_VAR_IF([ac_Symbol], [yes], [$2], [$3])]dnl
[AS_VAR_POPDEF([ac_Symbol])]dnl
@ -3401,7 +3402,7 @@ AC_DEFUN([AC_COMPUTE_INT],
be computed])],
[_$0_BODY])]dnl
[AS_IF([ac_fn_[]_AC_LANG_ABBREV[]_compute_int "$LINENO" "$2" "$1" ]dnl
["AS_ESCAPE([$3], [""])"],
[AS_QUOTE_D([$3], [allow-commands,allow-vars])],
[], [$4])
])# AC_COMPUTE_INT

View File

@ -90,7 +90,8 @@ AC_DEFUN([_AC_CHECK_HEADER_COMPILE],
[_AC_CHECK_HEADER_COMPILE_FN()]dnl
[AS_VAR_PUSHDEF([ac_Header], [ac_cv_header_$1])]dnl
[ac_fn_[]_AC_LANG_ABBREV[]_check_header_compile ]dnl
["$LINENO" "$1" "ac_Header" "AS_ESCAPE([AC_INCLUDES_DEFAULT([$4])], [""])"
["$LINENO" "$1" "ac_Header" ]dnl
[AS_QUOTE_D([AC_INCLUDES_DEFAULT([$4])], [allow-commands,allow-vars])
AS_VAR_IF([ac_Header], [yes], [$2], [$3])
AS_VAR_POPDEF([ac_Header])])# _AC_CHECK_HEADER_COMPILE

View File

@ -155,7 +155,7 @@ AC_DEFUN([_AC_CHECK_TYPE_NEW],
[$0_BODY])]dnl
[AS_VAR_PUSHDEF([ac_Type], [ac_cv_type_$1])]dnl
[ac_fn_[]_AC_LANG_ABBREV[]_check_type "$LINENO" "$1" "ac_Type" ]dnl
["AS_ESCAPE([AC_INCLUDES_DEFAULT([$4])], [""])"
[AS_QUOTE_D([AC_INCLUDES_DEFAULT([$4])], [allow-commands,allow-vars])
AS_VAR_IF([ac_Type], [yes], [$2], [$3])
AS_VAR_POPDEF([ac_Type])dnl
])# _AC_CHECK_TYPE_NEW
@ -944,7 +944,7 @@ AC_DEFUN([AC_CHECK_MEMBER],
[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
["AS_ESCAPE([AC_INCLUDES_DEFAULT([$4])], [""])"
[AS_QUOTE_D([AC_INCLUDES_DEFAULT([$4])], [allow-commands,allow-vars])
AS_VAR_IF([ac_Member], [yes], [$2], [$3])
AS_VAR_POPDEF([ac_Member])dnl
])# AC_CHECK_MEMBER

View File

@ -153,7 +153,7 @@ m4_defn([_AT_LINE_base]):__line__])
# _AT_LINE_ESCAPED
# ----------------
# Same as AT_LINE, but already escaped for the shell.
m4_define([_AT_LINE_ESCAPED], ["AS_ESCAPE(m4_dquote(AT_LINE))"])
m4_define([_AT_LINE_ESCAPED], [AS_QUOTE_D([AT_LINE])])
# _AT_NORMALIZE_TEST_GROUP_NUMBER(SHELL-VAR)
@ -449,7 +449,7 @@ at_color=m4_ifdef([AT_color], [AT_color], [no])
# numerical order.
at_format='m4_bpatsubst(m4_defn([AT_ordinal]), [.], [?])'
# Description of all the test groups.
at_help_all="AS_ESCAPE(m4_dquote(m4_defn([AT_help_all])))"
at_help_all=AS_QUOTE_D(m4_defn([AT_help_all]))
# List of the all the test groups.
at_groups_all=`AS_ECHO(["$at_help_all"]) | sed 's/;.*//'`
@ -1891,7 +1891,7 @@ m4_define([AT_ordinal], m4_incr(AT_ordinal))
m4_divert_push([TEST_GROUPS])dnl
[#AT_START_]AT_ordinal
at_fn_group_banner AT_ordinal 'm4_defn([AT_line])' \
"AS_ESCAPE(m4_dquote(m4_defn([AT_description])))" m4_format(["%*s"],
AS_QUOTE_D(m4_dquote(m4_defn([AT_description]))) m4_format(["%*s"],
m4_max(0, m4_eval(47 - m4_qlen(m4_defn([AT_description])))), [])m4_if(
AT_banner_ordinal, [0], [], [ AT_banner_ordinal])
m4_ifset([AT_prepare_each_test], [AT_prepare_each_test
@ -2001,7 +2001,7 @@ m4_define([AT_banner_ordinal], m4_incr(AT_banner_ordinal))
m4_divert_text([BANNERS],
[@%:@ Banner AT_banner_ordinal. AT_LINE
@%:@ Category starts at test group m4_incr(AT_ordinal).
at_banner_text_[]AT_banner_ordinal="AS_ESCAPE([$1])"])dnl
at_banner_text_[]AT_banner_ordinal=AS_QUOTE_D([$1])])dnl
])# AT_BANNER
@ -2076,17 +2076,21 @@ $2[]_ATEOF
# This may cause spurious failures when the test suite is run with '-x'.
#
_AT_DEFINE_SETUP([AT_CHECK],
[_AT_CHECK(m4_expand([$1]), [$2], AS_ESCAPE(m4_dquote(m4_expand([$3]))),
AS_ESCAPE(m4_dquote(m4_expand([$4]))), [$5], [$6])])
[_AT_CHECK(m4_expand([$1]), [$2],
AS_QUOTE_D([$3]),
AS_QUOTE_D([$4]),
[$5], [$6])])
# AT_CHECK_UNQUOTED(COMMANDS, [STATUS = 0], STDOUT, STDERR,
# [RUN-IF-FAIL], [RUN-IF-PASS])
# ---------------------------------------------------------
# Like AT_CHECK, but do not AS_ESCAPE shell metacharacters in the STDOUT
# Like AT_CHECK, but perform string interpolations in the STDOUT
# and STDERR arguments before running the comparison.
_AT_DEFINE_SETUP([AT_CHECK_UNQUOTED],
[_AT_CHECK(m4_expand([$1]), [$2], AS_ESCAPE(m4_dquote(m4_expand([$3])), [""]),
AS_ESCAPE(m4_dquote(m4_expand([$4])), [""]), [$5], [$6])])
[_AT_CHECK(m4_expand([$1]), [$2],
AS_QUOTE_D([$3], [allow-commands,allow-vars]),
AS_QUOTE_D([$4], [allow-commands,allow-vars]),
[$5], [$6])])
# AT_CHECK_NOESCAPE(COMMANDS, [STATUS = 0], STDOUT, STDERR,
# [RUN-IF-FAIL], [RUN-IF-PASS])
@ -2194,7 +2198,7 @@ dnl We know at build time that tracing COMMANDS is never safe.
dnl We know at build time that tracing COMMANDS is always safe.
[[at_fn_check_prepare_trace],]dnl
dnl COMMANDS may contain parameter expansions; expand them at runtime.
[[at_fn_check_prepare_dynamic "AS_ESCAPE([[$1]], [`\"])"])[]]dnl
[[at_fn_check_prepare_dynamic AS_QUOTE_D([[$1]], [allow-vars])])[]]dnl
[_m4_popdef([at_reason])])
@ -2202,28 +2206,28 @@ dnl COMMANDS may contain parameter expansions; expand them at runtime.
# -----------------------------
# These are subroutines of AT_CHECK. Using indirect dispatch is a tad
# faster than using m4_case, and these are called very frequently.
m4_define([AT_DIFF_STDERR(stderr)],
m4_define([AT_DIFF_STDERR("stderr")],
[echo stderr:; tee stderr <"$at_stderr"])
m4_define([AT_DIFF_STDERR(stderr-nolog)],
m4_define([AT_DIFF_STDERR("stderr-nolog")],
[echo stderr captured; cp "$at_stderr" stderr])
m4_define([AT_DIFF_STDERR(ignore)],
m4_define([AT_DIFF_STDERR("ignore")],
[echo stderr:; cat "$at_stderr"])
m4_define([AT_DIFF_STDERR(ignore-nolog)])
m4_define([AT_DIFF_STDERR(experr)],
m4_define([AT_DIFF_STDERR("ignore-nolog")])
m4_define([AT_DIFF_STDERR("experr")],
[$at_diff experr "$at_stderr" || at_failed=:])
m4_define([AT_DIFF_STDERR()],
m4_define([AT_DIFF_STDERR("")],
[at_fn_diff_devnull "$at_stderr" || at_failed=:])
m4_define([AT_DIFF_STDOUT(stdout)],
m4_define([AT_DIFF_STDOUT("stdout")],
[echo stdout:; tee stdout <"$at_stdout"])
m4_define([AT_DIFF_STDOUT(stdout-nolog)],
m4_define([AT_DIFF_STDOUT("stdout-nolog")],
[echo stdout captured; cp "$at_stdout" stdout])
m4_define([AT_DIFF_STDOUT(ignore)],
m4_define([AT_DIFF_STDOUT("ignore")],
[echo stdout:; cat "$at_stdout"])
m4_define([AT_DIFF_STDOUT(ignore-nolog)])
m4_define([AT_DIFF_STDOUT(expout)],
m4_define([AT_DIFF_STDOUT("ignore-nolog")])
m4_define([AT_DIFF_STDOUT("expout")],
[$at_diff expout "$at_stdout" || at_failed=:])
m4_define([AT_DIFF_STDOUT()],
m4_define([AT_DIFF_STDOUT("")],
[at_fn_diff_devnull "$at_stdout" || at_failed=:])
# _AT_CHECK(COMMANDS, [STATUS = 0], STDOUT, STDERR,
@ -2263,17 +2267,17 @@ m4_define([AT_DIFF_STDOUT()],
m4_define([_AT_CHECK],
[m4_define([AT_ingroup])]dnl
[{ set +x
AS_ECHO(["$at_srcdir/AT_LINE: AS_ESCAPE([[$1]])"])
AS_ECHO(["$at_srcdir/AT_LINE: "AS_QUOTE_D([[$1]])])
_AT_DECIDE_TRACEABLE([$1]) _AT_LINE_ESCAPED
( $at_check_trace; [$1]
) >>"$at_stdout" 2>>"$at_stderr" AS_MESSAGE_LOG_FD>&-
at_status=$? at_failed=false
$at_check_filter
m4_ifdef([AT_DIFF_STDERR($4)], [m4_indir([AT_DIFF_STDERR($4)])],
[echo >>"$at_stderr"; AS_ECHO([["$4"]]) | \
[echo >>"$at_stderr"; AS_ECHO([[$4]]) | \
$at_diff - "$at_stderr" || at_failed=:])
m4_ifdef([AT_DIFF_STDOUT($3)], [m4_indir([AT_DIFF_STDOUT($3)])],
[echo >>"$at_stdout"; AS_ECHO([["$3"]]) | \
[echo >>"$at_stdout"; AS_ECHO([[$3]]) | \
$at_diff - "$at_stdout" || at_failed=:])
m4_if([$2], [ignore], [at_fn_check_skip],
[at_fn_check_status m4_default([$2], [0])]) $at_status "$at_srcdir/AT_LINE"

View File

@ -222,7 +222,7 @@ dnl Remove any tests from suggested that are also required
[m4_set_map([_AS_DETECT_SUGGESTED_BODY], [_AS_DETECT_SUGGESTED_PRUNE])]dnl
[m4_pushdef([AS_EXIT], [exit m4_default(]m4_dquote([$][1])[, 1)])]dnl
[if test "x$CONFIG_SHELL" = x; then
as_bourne_compatible="AS_ESCAPE(_m4_expand([_AS_BOURNE_COMPATIBLE]))"
as_bourne_compatible=AS_QUOTE_D([_AS_BOURNE_COMPATIBLE])
_AS_DETECT_EXPAND([as_required], [_AS_DETECT_REQUIRED_BODY])
_AS_DETECT_EXPAND([as_suggested], [_AS_DETECT_SUGGESTED_BODY])
AS_IF([_AS_RUN(["$as_required"])],
@ -763,69 +763,109 @@ m4_define([AS_MESSAGE_LOG_FD])
# shuffle fd's.
m4_define([AS_ORIGINAL_STDIN_FD], [0])
# AS_QUOTE_S(TEXT)
# ----------------
# Quote TEXT for the shell, using single quotes. Expand macros within
# the text prior to quotation.
#
# With GNU m4 1.4.19, avoiding a call to m4_bpatsubst when it would
# have nothing to do is good for a ~2.5x speedup.
m4_define([AS_QUOTE_S], ['_$0(m4_dquote(m4_expand([$1])))'])
m4_define([_AS_QUOTE_S],
[m4_if([m4_index([$1], ['])], [-1],
[$1],
[m4_bpatsubst([$1], ['], ['\''])])])
# AS_ESCAPE(STRING, [CHARS = `\"$])
# AS_QUOTE_D(TEXT, [INTERPOLATION])
# ---------------------------------
# Add backslash escaping to the CHARS in STRING. In an effort to
# optimize use of this macro inside double-quoted shell constructs,
# the behavior is intentionally undefined if CHARS is longer than 4
# bytes, or contains bytes outside of the set [`\"$]. However,
# repeated bytes within the set are permissible (AS_ESCAPE([$1], [""])
# being a common way to be nice to syntax highlighting).
# Quote TEXT for the shell, using double quotes. Expand macros within
# the text prior to quotation. INTERPOLATION says what kinds of
# interpolations to allow:
#
# Avoid the m4_bpatsubst if there are no interesting characters to escape.
# _AS_ESCAPE bypasses argument defaulting.
# - blank/absent: no interpolation
# - allow-vars: allow interpolation of $var ${var} $((expr))
# - allow-commands: allow interpolation of `command` $(command)
# - allow-commands,allow-vars
# allow-vars,allow-commands
# allow both the above kinds of interpolation
# (there is intentionally no 'allow-all' because we want
# people to be able to find all cases where command interpolation
# is enabled by grepping for 'allow-commands').
m4_define([AS_QUOTE_D],
["_$0_QUOTE(m4_dquote(m4_expand([$1])), _$0_IARGCHECK([$2]))"])
# _AS_QUOTE_D_IARGCHECK(INTERPOLATION)
# ------------------------------------
# Evaluate the INTERPOLATION argument to AS_QUOTE_D. If it is valid,
# return a list of the second, third, fourth, and fifth arguments to
# _AS_QUOTE_D_QUOTE, otherwise issue an error.
m4_define([_AS_QUOTE_D_ARGCHECK],
[m4_case(m4_translit([[$1]], [ ][ ][
]),
[], [[$], [\"`], [$$$], [[\"$`]]],
[allow-vars], [[$], [\"`], [$$$], [[\"`]|\$(\($|[^(]\)]],
[allow-commands], [[$], [\"], [$$], [[\"]\|\$[a-zA-Z_{]\|\$((]],
[allow-commands,allow-vars], [["], [\], ["], [[\"]]],
[allow-vars,allow-commands], [["], [\], ["], [[\"]]],
[m4_fatal([invalid INTERPOLATION argument '$1' to AS_QUOTE_D])])])
# _AS_QUOTE_D_QUOTE(STRING, C, HARS, CCCC, REGEX)
# -----------------------------------------------
# Insert a backslash in STRING before every match for REGEX.
# C, HARS, and CCCC are hints for a performance hack: if C is not
# present in STRING after transliterating HARS to CCCC, then
# REGEX is assumed not to match anywhere within STRING.
# (As noted for AS_QUOTE_S, avoiding calls to m4_bpatsubst is good
# for a ~2.5x speedup even when the overhead of the translit and index
# are accounted for.
m4_define([_AS_QUOTE_D_QUOTE],
[m4_if(m4_index(m4_if([$3], [], [$1], [m4_translit([[$1]], [$3], [$4])]), [$2]),
[-1],
[$1],
[m4_bpatsubst([$1], [$5], [\\\&])])])
# AS_ESCAPE(STRING, [CHARS])
# --------------------------
# Superseded by AS_QUOTE_D. The differences are:
# - Does not wrap " ... " around the result.
# - Does not pre-expand the string.
# - CHARS is a much clumsier way to specify what interpolation to allow.
# Almost all existing uses of AS_ESCAPE with a non-default CHARS
# argument are incorrect per the original implementation.
# This compat stub attempts to map each possible value of CHARS
# (plus one more that wasn't supposed to happen at all) to an
# AS_QUOTE_D/S invocation that will do what was intended.
m4_define([AS_ESCAPE],
[_$0([$1], m4_if([$2], [], [[`], [\"$]], [m4_substr([$2], [0], [1]), [$2]]))])
[m4_warn([obsolete], [AS_ESCAPE is deprecated, change to AS_QUOTE_D or _S])]dnl
dnl Handle the most common case without going through _AS_ESCAPE_MAPCHARS,
dnl which is expensive.
dnl AS_ESCAPE was never intended to produce single-quoted strings but
dnl someone tried to use it that way anyway!
dnl https://sources.debian.org/src/fakechroot/2.20.1+ds-17/m4/check_func_argtypes.m4/?hl=111#L111
[m4_case([$2],
[], [_AS_QUOTE_D_QUOTE([$1], _AS_QUOTE_D_ARGCHECK([]))],
['], [_AS_QUOTE_S([$1])],
[''], [_AS_QUOTE_S([$1])],
[_AS_QUOTE_D_QUOTE([$1], _AS_QUOTE_D_ARGCHECK([]))])])
# [_AS_QUOTE_D_QUOTE([$1], _AS_QUOTE_D_IARGCHECK(_AS_ESCAPE_MAPCHARS([$2])))])])
# _AS_ESCAPE(STRING, KEY, SET)
# ----------------------------
# Backslash-escape all instances of the single byte KEY or up to four
# bytes in SET occurring in STRING. Although a character can occur
# multiple times, optimum efficiency occurs when KEY and SET are
# distinct, and when SET does not exceed two bytes. These particular
# semantics allow for the fewest number of parses of STRING, as well
# as taking advantage of the optimizations in m4 1.4.13+ when
# m4_translit is passed SET of size 2 or smaller.
m4_define([_AS_ESCAPE],
[m4_if(m4_index(m4_translit([[$1]], [$3], [$2$2$2$2]), [$2]), [-1],
[$0_], [m4_bpatsubst])([$1], [[$2$3]], [\\\&])])
m4_define([_AS_ESCAPE_], [$1])
# _AS_QUOTE(STRING)
# -----------------
# If there are quoted (via backslash) backquotes, output STRING
# literally and warn; otherwise, output STRING with ` and " quoted.
#
# Compatibility glue between the old AS_MSG suite which did not
# quote anything, and the modern suite which quotes the quotes.
# If STRING contains '\\' or '\$', it's modern.
# If STRING contains '\"' or '\`', it's old.
# Otherwise it's modern.
#
# Profiling shows that m4_index is 5 to 8x faster than m4_bregexp. The
# slower implementation used:
# m4_bmatch([$1],
# [\\[\\$]], [$2],
# [\\[`"]], [$3],
# [$2])
# The current implementation caters to the common case of no backslashes,
# to minimize m4_index expansions (hence the nested if).
m4_define([_AS_QUOTE],
[m4_cond([m4_index([$1], [\])], [-1], [_AS_QUOTE_MODERN],
[m4_eval(m4_index(m4_translit([[$1]], [$], [\]), [\\]) >= 0)],
[1], [_AS_QUOTE_MODERN],
[m4_eval(m4_index(m4_translit([[$1]], ["], [`]), [\`]) >= 0)],dnl"
[1], [_AS_QUOTE_OLD],
[_AS_QUOTE_MODERN])([$1])])
m4_define([_AS_QUOTE_MODERN],
[_AS_ESCAPE([$1], [`], [""])])
m4_define([_AS_QUOTE_OLD],
[m4_warn([obsolete],
[back quotes and double quotes must not be escaped in: $1])$1])
# The characters could be in any order and they could also be
# duplicated. M4 + M4sugar does have a "remove duplicate from list"
# mechanism, but it doesn't have "sort list" at all.
# m4_define([_AS_ESCAPE_MAPCHARS],
# [__AS_ESCAPE_MAPCHARS(m4_join_uniq([], m4_bpatsubst([$1], [.], [[\&],])))])
# m4_define([__AS_ESCAPE_MAPCHARS],
# [[[$1]] m4_bmatch([$1],
# [^\([$`][$`]\|[$`"][$`"][$`"]\|[$\`][$\`][$\`]\|[$`\"][$`\"][$`\"][$`\"]\)$],
# [],
# [^\([$]\|[\$][\$]\|["$]["$]\|[\"$][\"$][\"$]\)$],
# [allow-commands],
# [^\([`]\|[\`][\`]\|["`]["`]\|[\"`][\"`][\"`]\)$],
# [allow-vars],
# [^\([\\]|["]|[\"][\"]\)$],
# [allow-commands,allow-vars],
# [invalid])])
# [m4_fatal([invalid CHARS argument '$1' to AS_ESCAPE])])])
# _AS_ECHO_UNQUOTED(STRING, [FD = AS_MESSAGE_FD])
@ -837,9 +877,17 @@ m4_define([_AS_ECHO_UNQUOTED],
# _AS_ECHO(STRING, [FD = AS_MESSAGE_FD])
# --------------------------------------
# Protect STRING from backquote expansion, echo the result to FD.
# Protect STRING from backquote expansion but not variable expansion,
# echo the result to FD.
m4_define([_AS_ECHO],
[_AS_ECHO_UNQUOTED([_AS_QUOTE([$1])], [$2])])
[AS_ECHO([AS_QUOTE_D([$1], [allow-vars])]) >&m4_default([$2], [AS_MESSAGE_FD])])
# _AS_ECHO_N(STRING, [FD = AS_MESSAGE_FD])
# ----------------------------------------
# Same as _AS_ECHO, but echo doesn't return to a new line.
m4_define([_AS_ECHO_N],
[AS_ECHO_N([AS_QUOTE_D([$1], [allow-vars])]) >&m4_default([$2], [AS_MESSAGE_FD])])
# _AS_ECHO_LOG(STRING)
@ -850,13 +898,6 @@ m4_defun_init([_AS_ECHO_LOG],
[_AS_ECHO([$as_me:${as_lineno-$LINENO}: $1], AS_MESSAGE_LOG_FD)])
# _AS_ECHO_N(STRING, [FD = AS_MESSAGE_FD])
# ----------------------------------------
# Same as _AS_ECHO, but echo doesn't return to a new line.
m4_define([_AS_ECHO_N],
[AS_ECHO_N(["_AS_QUOTE([$1])"]) >&m4_default([$2], [AS_MESSAGE_FD])])
# AS_MESSAGE(STRING, [FD = AS_MESSAGE_FD])
# ----------------------------------------
# Output "`basename $0`: STRING" to the open file FD, and if logging
@ -913,7 +954,7 @@ _m4_popdef([AS_MESSAGE_LOG_FD])dnl
m4_defun_init([AS_ERROR],
[m4_append_uniq([_AS_CLEANUP],
[m4_divert_text([M4SH-INIT-FN], [_AS_ERROR_PREPARE[]])])],
[as_fn_error m4_default([$2], [$?]) "_AS_QUOTE([$1])"m4_ifval(AS_MESSAGE_LOG_FD,
[as_fn_error m4_default([$2], [$?]) AS_QUOTE_D([$1], [allow-vars])m4_ifval(AS_MESSAGE_LOG_FD,
[ "$LINENO" AS_MESSAGE_LOG_FD])])
@ -1462,8 +1503,7 @@ m4_define([_AS_BOX],
# _AS_BOX_LITERAL(MESSAGE, [FRAME-CHARACTER = '-'])
# -------------------------------------------------
m4_define([_AS_BOX_LITERAL],
[AS_ECHO(["_AS_ESCAPE(m4_dquote(m4_expand([m4_text_box($@)])), [`], [\"$])"])])
[AS_ECHO([AS_QUOTE_D([m4_text_box($@)])])])
# _AS_BOX_INDIR(MESSAGE, [FRAME-CHARACTER = '-'])
# -----------------------------------------------
@ -1886,7 +1926,7 @@ m4_define([_AS_TR_SH_LITERAL],
[pp[]]]m4_dquote(m4_for(,1,255,,[[_]]))[)])
m4_define([_AS_TR_SH_INDIR],
[`AS_ECHO(["_AS_ESCAPE([[$1]], [`], [\])"]) | sed "$as_sed_sh"`])
[`AS_ECHO([AS_QUOTE_D([$1], [allow-vars])]) | sed "$as_sed_sh"`])
# _AS_TR_CPP_PREPARE
@ -1920,7 +1960,7 @@ m4_define([_AS_TR_CPP_LITERAL],
[P[]]]m4_dquote(m4_defn([m4_cr_LETTERS])m4_for(,1,255,,[[_]]))[)])
m4_define([_AS_TR_CPP_INDIR],
[`AS_ECHO(["_AS_ESCAPE([[$1]], [`], [\])"]) | sed "$as_sed_cpp"`])
[`AS_ECHO([AS_QUOTE_D([$1], [allow-vars])]) | sed "$as_sed_cpp"`])
# _AS_TR_PREPARE
@ -1959,7 +1999,7 @@ m4_defun([_AS_VAR_APPEND_PREPARE],
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(m4_quote(_AS_VAR_APPEND_WORKS))"])],
AS_IF([_AS_RUN([AS_QUOTE_D([_AS_VAR_APPEND_WORKS])])],
[eval 'as_fn_append ()
{
eval $[]1+=\$[]2
@ -2000,7 +2040,7 @@ m4_defun([_AS_VAR_ARITH_PREPARE],
[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(m4_quote(_AS_VAR_ARITH_WORKS))"])],
AS_IF([_AS_RUN([AS_QUOTE_D([_AS_VAR_ARITH_WORKS])])],
[eval 'as_fn_arith ()
{
as_val=$(( $[]* ))
@ -2048,7 +2088,7 @@ m4_define([AS_VAR_COPY],
m4_define([AS_VAR_GET],
[AS_LITERAL_WORD_IF([$1],
[$$1],
[`eval 'as_val=${'_AS_ESCAPE([[$1]], [`], [\])'};AS_ECHO(["$as_val"])'`])])
[`eval 'as_val=\$$2;AS_ECHO(["$as_val"])'`])])
# AS_VAR_IF(VARIABLE, VALUE, IF-TRUE, IF-FALSE)
@ -2061,7 +2101,7 @@ m4_define([AS_VAR_IF],
[AS_VAR_COPY([as_val], [$1])
AS_IF(m4_ifval([$2], [[test "x$as_val" = x[]$2]], [[${as_val:+false} :]])],
[AS_IF(m4_ifval([$2],
[[eval test \"x\$"$1"\" = x"_AS_ESCAPE([$2], [`], [\"$])"]],
[[eval test \"x\$"$1"\" = x[]AS_QUOTE_D([$2])]],
[[eval \${$1:+false} :]])]),
[$3], [$4])])
@ -2128,7 +2168,7 @@ m4_pushdef([$1], [$as_[$1]])],
m4_define([AS_VAR_SET],
[AS_LITERAL_WORD_IF([$1],
[$1=$2],
[eval "$1=_AS_ESCAPE([$2], [`], [\"$])"])])
[eval "$1="AS_QUOTE_D([$2])])])
# AS_VAR_SET_IF(VARIABLE, IF-TRUE, IF-FALSE)