+2007-10-18 Eric Blake <ebb9@byu.net>
+
+ Fix AT_TESTED, AT_KEYWORDS.
+ * lib/m4sugar/m4sugar.m4 (m4_append_uniq): Warn if separator
+ occurs in string, as duplicates may be added.
+ (_m4_append_uniq): New helper macro.
+ (m4_append_uniq_w): New macro.
+ * lib/autotest/general.m4 (AT_TESTED, AT_KEYWORDS): Fix
+ duplication bug by using new macro.
+ (AT_INIT) <at_tested>: Restore newline separators. Invoke tested
+ programs with stdin redirected, so programs that don't
+ understand --version won't try to behave interactively.
+ * tests/autotest.at (Tested programs): Catch this bug.
+ * tests/m4sugar.at (m4@&t@_append): Test new macro.
+ * tests/local.at (AT_TESTED): Add m4, perl.
+ * doc/autoconf.texi (Text processing Macros): Document
+ m4_append_uniq_w, and update text on m4_append.
+ * NEWS: Document the addition.
+
2007-10-17 Eric Blake <ebb9@byu.net>
Function cleanup.
m4_pushdef([m4_append], [m4_define([$1],
m4_ifdef([$1], [m4_defn([$1])[$3]])[$2])])
Additionally, m4_append_uniq now takes optional parameters that can
- be used to take action depending on whether anything was appended.
+ be used to take action depending on whether anything was appended,
+ and warns if a non-empty separator occurs within the string being
+ appended, since that can lead to duplicates.
** The following m4sugar macros are new:
- m4_apply m4_combine m4_cond m4_count m4_dquote_elt m4_echo
- m4_expand m4_ignore m4_make_list m4_max m4_min m4_newline
- m4_shift2 m4_shift3 m4_unquote
+ m4_append_uniq_w m4_apply m4_combine m4_cond m4_count
+ m4_dquote_elt m4_echo m4_expand m4_ignore m4_make_list m4_max
+ m4_min m4_newline m4_shift2 m4_shift3 m4_unquote
** Warnings are now generated by default when an installer invokes
'configure' with an unknown --enable-* or --with-* option.
@code{m4_append_uniq} takes two optional parameters as of Autoconf 2.62;
@var{if-uniq} is expanded if @var{string} was appended, and
@var{if-duplicate} is expanded if @var{string} was already present.
+Also, @code{m4_append_uniq} warns if @var{separator} is not empty, but
+occurs within @var{string}, since that can lead to duplicates.
@example
m4_define([active], [ACTIVE])dnl
@end example
@end defmac
+@defmac m4_append_uniq_w (@var{macro-name}, @var{strings})
+@msindex{append_uniq_w}
+This macro was introduced in Autoconf 2.62. It is similar to
+@code{m4_append_uniq}, but treats @var{strings} as a whitespace
+separated list of words to append, and only appends unique words.
+@var{macro-name} is updated with a single space between new words.
+@example
+m4_append_uniq_w([numbers], [1 1 2])dnl
+m4_append_uniq_w([numbers], [ 2 3 ])dnl
+numbers
+@result{}1 2 3
+@end example
+@end defmac
+
@defmac m4_combine (@ovar{separator}, @var{prefix-list}, @ovar{infix}, @
@var{suffix-1}, @dots{})
@msindex{combine}
m4_wrap([m4_divert_text([DEFAULTS],
[
# List of the tested programs.
-at_tested='m4_ifdef([AT_tested], [AT_tested])'
+at_tested='m4_ifdef([AT_tested],
+ [m4_translit(m4_dquote(m4_defn([AT_tested])), [ ], m4_newline)])'
# List of the all the test groups.
at_groups_all='AT_groups_all'
# As many question marks as there are digits in the last test group number.
if test -f "$as_dir/$at_program"; then
{
AS_ECHO(["$at_srcdir/AT_LINE: $as_dir/$at_program --version"])
- "$as_dir/$at_program" --version
+ "$as_dir/$at_program" --version </dev/null
echo
} >&AS_MESSAGE_LOG_FD 2>&1
else
m4_append([AT_case],m4_if(m4_len(AT_option),1,[],[-])[-]AT_option, [ | ])dnl
m4_append([AT_case_no],[--no]AT_option, [ | ])dnl
m4_append([AT_case_arg],
- m4_if(m4_len(AT_option),1,[],[-])[-]AT_option[=*], [ | ])dnl
+ m4_if(m4_len(AT_option),1,[],[-])[-]AT_option[=*], [ | ])dnl
])dnl m4_foreach AT_option
dnl keep track so we or the user may process ACTION-IF-NOT-GIVEN
m4_divert_once([PARSE_ARGS_BEGIN],
# must correspond to the version of the package. PATH should be
# already preset so the proper executable will be selected.
m4_define([AT_TESTED],
-[m4_append_uniq([AT_tested], [$1], [
-])])
+[m4_append_uniq_w([AT_tested], [$1])])
# AT_COPYRIGHT(TEXT)
# AT_KEYWORDS(KEYWORDS)
# ---------------------
# Declare a list of keywords associated to the current test group.
+# The list is stored in lower case, since the -k option is case-insensitive.
m4_define([AT_KEYWORDS],
-[m4_append_uniq([AT_keywords], [$1], [ ])])
+[m4_append_uniq_w([AT_keywords], m4_tolower([[$1]]))])
# AT_CAPTURE_FILE(FILE)
# --------------------------------------------------------------------
# Like `m4_append', but append only if not yet present. Additionally,
# expand IF-UNIQ if STRING was appended, or IF-DUP if STRING was already
-# present.
+# present. Also, warn if SEPARATOR is not empty and occurs within STRING,
+# as the algorithm no longer guarantees uniqueness.
m4_define([m4_append_uniq],
+[m4_ifval([$3], [m4_if(m4_index([$2], [$3]), [-1], [],
+ [m4_warn([syntax],
+ [$0: `$2' contains `$3'])])])_$0($@)])
+m4_define([_m4_append_uniq],
[m4_ifdef([$1],
[m4_if(m4_index([$3]m4_builtin([defn], [$1])[$3], [$3$2$3]), [-1],
[m4_append([$1], [$2], [$3])$4], [$5])],
[m4_append([$1], [$2], [$3])$4])])
+# m4_append_uniq_w(MACRO-NAME, STRINGS)
+# -------------------------------------
+# For each of the words in the whitespace separated list STRINGS, append
+# only the unique strings to the definition of MACRO-NAME.
+#
+# Avoid overhead of m4_defn by using m4_builtin.
+m4_define([m4_append_uniq_w],
+[m4_foreach_w([m4_Word], [$2],
+ [_m4_append_uniq([$1], m4_builtin([defn], [m4_Word]), [ ])])])
+
# m4_text_wrap(STRING, [PREFIX], [FIRST-PREFIX], [WIDTH])
# -------------------------------------------------------
# And finally, an empty check should not cause a syntax error.
AT_CHECK_AT_TEST([Empty check], [AT_CHECK])
+# Check for tested programs. autoconf should only appear once.
+AT_CHECK_AT([Tested programs],
+[[AT_INIT([programs test suite])
+AT_TESTED([autoconf autom4te])
+AT_TESTED([autoconf])
+]], [], [], [], [],
+[AT_CHECK([[sed -n 's|.*/\([^ /]* --version\)|\1|p' micro-suite.log]], [],
+[[autoconf --version
+autom4te --version
+]])])
+
## ----------------------------------------------------- ##
## Newlines and command substitutions in test commands. ##
## ----------------------------------------------------- ##
AT_CHECK(:)
AT_CLEANUP
AT_SETUP(both)
-AT_KEYWORDS(key1)
-AT_KEYWORDS(key2)
+AT_KEYWORDS([key1 key2])
+AT_KEYWORDS([key1])
AT_CHECK(:)
AT_CLEANUP
]])
AT_CHECK_AUTOM4TE([--language=autotest -o k k.at])
+dnl check that AT_KEYWORDS does not duplicate words
+AT_CHECK([grep 'key1.*key1' k], [1])
# AT_CHECK_EGREP(PATTERN, STATUS, COUNT)
m4_define([AT_CHECK_EGREP],
m4_pattern_allow([^AS_EXIT$])
m4_pattern_allow([^m4_(define|shift)$])
+# Programs this package provides
AT_TESTED([autom4te autoconf autoheader autoupdate autoreconf ifnames])
+# Programs this package depends on
+AT_TESTED([m4 perl])
## ---------------- ##
m4_append([list], [three], [[, ]])dnl
list
m4_dquote(list)
+m4_append_uniq_w([numbers], [1 1 2])dnl
+m4_append_uniq_w([numbers], [ 2 3 ])dnl
+numbers
]],
[[This is an ACTIVE symbol.
This is an active symbol.
[one],[two],[three],[two]
one, two, three
[one, two, three]
+1 2 3
+]])
+
+AT_DATA_M4SUGAR([script.4s],
+[[m4_append_uniq([str], [a], [ ])
+m4_append_uniq([str], [a b], [ ])
+m4_divert([0])dnl
+str
+]])
+
+AT_CHECK_M4SUGAR([-o-], 0, [[a a b
+]], [[script.4s:2: warning: m4@&t@_append_uniq: `a b' contains ` '
]])
AT_CLEANUP