2009-02-19 Eric Blake <ebb9@byu.net>
+ Use m4_translit more efficiently in AS_ESCAPE.
+ * lib/m4sugar/m4sh.m4 (_AS_ESCAPE): Alter API to take first byte
+ of set separately from rest.
+ (AS_ESCAPE, _AS_QUOTE_MODERN, AS_TR_SH, AS_VAR_GET): Adjust
+ callers.
+ * lib/autoconf/autoheader.m4 (AH_VERBATIM): Avoid duplicate
+ characters in translit request.
+ * doc/autoconf.texi (Common Shell Constructs) <AS_ESCAPE>:
+ Document the macro.
+ * NEWS: Likewise.
+
Mention recently documented macros.
* NEWS: Update list of new documentation.
** The following m4sh macros are documented now, but in some cases
with slightly different semantics than what the previous
undocumented version had:
- AS_ECHO AS_ECHO_N AS_EXIT AS_LITERAL_IF AS_UNSET AS_VAR_IF
- AS_VAR_POPDEF AS_VAR_PUSHDEF AS_VAR_SET AS_VAR_SET_IF
+ AS_ECHO AS_ECHO_N AS_ESCAPE AS_EXIT AS_LITERAL_IF AS_UNSET
+ AS_VAR_IF AS_VAR_POPDEF AS_VAR_PUSHDEF AS_VAR_SET AS_VAR_SET_IF
AS_VAR_TEST_SET AS_VERSION_COMPARE
** The m4sh macros AS_IF and AS_CASE can now be used in shell lists.
Redirections can be placed outside the macro invocation.
@end defmac
+@defmac AS_ESCAPE (@var{string}, @dvar{chars, `\"$})
+@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 have text that needs 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-doc (@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-doc; 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 example, this snippet
+will produce shell code that outputs the four lines @samp{"$foo" =
+"bar"}, @samp{macro}, @samp{a, b}, and @samp{a, \b}:
+
+@example
+foo=bar
+AS_ECHO(["AS_ESCAPE(["$foo" = ])AS_ESCAPE(["$foo"], [""])"])
+m4_define([macro], [a, [\b]])
+AS_ECHO(["AS_ESCAPE([[macro]])"])
+AS_ECHO(["AS_ESCAPE([macro])"])
+AS_ECHO(["AS_ESCAPE(m4_dquote(m4_expand([macro])))"])
+@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_EXIT (@dvar{status, $?})
@asindex{EXIT}
Emit code to exit the shell with @var{status}, defaulting to @samp{$?}.
# Interface with autoheader.
# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
-# 2002, 2008 Free Software Foundation, Inc.
+# 2002, 2008, 2009 Free Software Foundation, Inc.
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# Quote for Perl '' strings, which are those used by Autoheader.
m4_define([AH_VERBATIM],
[AS_LITERAL_IF([$1],
- [AH_OUTPUT([$1], AS_ESCAPE([[$2]], [\\'']))])])
+ [AH_OUTPUT([$1], AS_ESCAPE([[$2]], [\']))])])
# AH_TEMPLATE(KEY, DESCRIPTION)
m4_define([AS_ORIGINAL_STDIN_FD], [0])
-# AS_ESCAPE(STRING, [CHARS = $"`\])
+# AS_ESCAPE(STRING, [CHARS = `\"$])
# ---------------------------------
-# Escape the CHARS in STRING.
+# 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).
#
# Avoid the m4_bpatsubst if there are no interesting characters to escape.
# _AS_ESCAPE bypasses argument defaulting.
m4_define([AS_ESCAPE],
-[_$0([$1], m4_default([$2], [\"$`]))])
+[_$0([$1], m4_if([$2], [], [[`], [\"$]], [m4_substr([$2], [0], [1]), [$2]]))])
+
+# _AS_ESCAPE(STRING, KEY, SET)
+# ----------------------------
+# Backslash-escape all instances of the singly 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 newer m4's optimizations when m4_translit is
+# passed SET of size 2 or smaller.
m4_define([_AS_ESCAPE],
-[m4_if(m4_len([$1]),
- m4_len(m4_translit([[$1]], [$2])),
- [$1], [m4_bpatsubst([$1], [[$2]], [\\\&])])])
+[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)
[_AS_QUOTE_MODERN])([$1])])
m4_define([_AS_QUOTE_MODERN],
-[_AS_ESCAPE([$1], [`""])])
+[_AS_ESCAPE([$1], [`], [""])])
m4_define([_AS_QUOTE_OLD],
[m4_warn([obsolete],
m4_dquote(m4_dquote(m4_defn([m4_cr_not_symbols2])))[[,
[pp[]]]]dnl
m4_dquote(m4_dquote(m4_for(,1,255,,[[_]])))[[)],
- [`AS_ECHO(["_AS_ESCAPE(m4_dquote(m4_expand([$1])), [\`])"]) | $as_tr_sh`])])
+ [`AS_ECHO(["_AS_ESCAPE(m4_dquote(m4_expand([$1])),
+ [`], [\])"]) | $as_tr_sh`])])
# _AS_TR_CPP_PREPARE
m4_define([AS_VAR_GET],
[AS_LITERAL_IF([$1],
[$$1],
- [`eval 'as_val=${'_AS_ESCAPE([[$1]], [\`])'};AS_ECHO(["$as_val"])'`])])
+ [`eval 'as_val=${'_AS_ESCAPE([[$1]], [`], [\])'};AS_ECHO(["$as_val"])'`])])
# AS_VAR_IF(VARIABLE, VALUE, IF-TRUE, IF-FALSE)