]> git.ipfire.org Git - thirdparty/autoconf.git/commitdiff
Warn if using unnamed diversion.
authorEric Blake <ebb9@byu.net>
Wed, 25 Nov 2009 00:20:33 +0000 (17:20 -0700)
committerEric Blake <ebb9@byu.net>
Sat, 5 Dec 2009 04:18:07 +0000 (21:18 -0700)
* lib/m4sugar/m4sugar.m4 (_m4_divert, m4_divert_push): Add
optional parameter, which controls warning.
(m4_divert_pop, m4_cleardivert, m4_divert_require)
(_m4_require_call): Adjust callers.
* lib/m4sugar/m4sh.m4 (AS_REQUIRE): Likewise.
* tests/m4sh.at (AT_DATA_LINENO): Avoid triggering the warning.
* tests/m4sugar.at (AT_CHECK_M4SUGAR_TEXT, m4@&t@_append)
(m4@&t@_text_wrap, recursion): Likewise.
(m4@&t@_warn, m4@&t@_divert_stack): Adjust expected output.
* tests/tools.at (autom4te and whitespace in file names)
(autoconf: the empty token): Avoid triggering the warning.
(autoconf: AC_PRESERVE_HELP_ORDER): New test.
* tests/mktests.sh (ac_exclude_list): Retire prior test.
* NEWS: Document the warning.
* doc/autoconf.texi (Redefined M4 Macros) <m4_divert>,
<m4_undivert>: Make even more explicit that using these directly
is discouraged.
(Diversion support): Further warn against improper diversion
changes.
<m4_divert_text>: Give an example of proper use.
Reported by Mike Frysinger.

Signed-off-by: Eric Blake <ebb9@byu.net>
ChangeLog
NEWS
doc/autoconf.texi
lib/m4sugar/m4sh.m4
lib/m4sugar/m4sugar.m4
tests/m4sh.at
tests/m4sugar.at
tests/mktests.sh
tests/tools.at

index 0ee8a521613dfb37877b83ba77637ee2802eea9d..e03604d6098c0a6e2f493c32832514bd9bc95ca3 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,28 @@
+2009-12-04  Eric Blake  <ebb9@byu.net>
+
+       Warn if using unnamed diversion.
+       * lib/m4sugar/m4sugar.m4 (_m4_divert, m4_divert_push): Add
+       optional parameter, which controls warning.
+       (m4_divert_pop, m4_cleardivert, m4_divert_require)
+       (_m4_require_call): Adjust callers.
+       * lib/m4sugar/m4sh.m4 (AS_REQUIRE): Likewise.
+       * tests/m4sh.at (AT_DATA_LINENO): Avoid triggering the warning.
+       * tests/m4sugar.at (AT_CHECK_M4SUGAR_TEXT, m4@&t@_append)
+       (m4@&t@_text_wrap, recursion): Likewise.
+       (m4@&t@_warn, m4@&t@_divert_stack): Adjust expected output.
+       * tests/tools.at (autom4te and whitespace in file names)
+       (autoconf: the empty token): Avoid triggering the warning.
+       (autoconf: AC_PRESERVE_HELP_ORDER): New test.
+       * tests/mktests.sh (ac_exclude_list): Retire prior test.
+       * NEWS: Document the warning.
+       * doc/autoconf.texi (Redefined M4 Macros) <m4_divert>,
+       <m4_undivert>: Make even more explicit that using these directly
+       is discouraged.
+       (Diversion support): Further warn against improper diversion
+       changes.
+       <m4_divert_text>: Give an example of proper use.
+       Reported by Mike Frysinger.
+
 2009-11-30  Ralf Wildenhues  <Ralf.Wildenhues@gmx.de>
 
        manual: AC_SEARCH_LIBS also prepends to LIBS.
diff --git a/NEWS b/NEWS
index 32fa9573f85efa989eaeb7049a94f9d635bdc705..97dcab0e8b5baa49e490e8c9c31fb7d58745b2af 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -5,6 +5,9 @@ GNU Autoconf NEWS - User visible changes.
 
 ** AC_FUNC_MMAP works in C++ mode again.  Regression introduced in 2.64.
 
+** Use of m4_divert without a named diversion now issues a syntax warning,
+   since it is seldom right to change diversions behind autoconf's back.
+
 * Major changes in Autoconf 2.65 (2009-11-21) [stable]
   Released by Eric Blake, based on git versions 2.64.*.
 
index bf6b7febcd91e7c8081288fd37126d7f056126cb..7d2c72ead2dcf89e9f0c07ae5383e9d13fda5737 100644 (file)
@@ -11116,7 +11116,11 @@ m4_divert_pop()m4_divert_push([@var{diversion}])
 @end example
 @noindent
 @xref{Diversion support}, for more details about the use of the
-diversion stack.
+diversion stack.  In particular, this implies that @var{diversion}
+should be a named diversion rather than a raw number.  But be aware that
+it is seldom necessary to explicitly change the diversion stack, and
+that when done incorrectly, it can lead to syntactically invalid
+scripts.
 @end defmac
 
 @defmac m4_dumpdef (@var{name}@dots{})
@@ -11210,7 +11214,9 @@ Unlike the M4 builtin, at least one @var{diversion} must be specified.
 Also, since the M4sugar diversion stack prefers named
 diversions, the use of @code{m4_undivert} to include files is risky.
 @xref{Diversion support}, for more details about the use of the
-diversion stack.
+diversion stack.  But be aware that it is seldom necessary to explicitly
+change the diversion stack, and that when done incorrectly, it can lead
+to syntactically invalid scripts.
 @end defmac
 
 @defmac m4_wrap (@var{text})
@@ -11298,12 +11304,19 @@ dubious syntactic constructs, incorrectly ordered macro calls.
 @node Diversion support
 @subsection Diversion support
 
-M4sugar makes heavy use of diversions, because it is often the case that
+M4sugar makes heavy use of diversions under the hood, because it is
+often the case that
 text that must appear early in the output is not discovered until late
 in the input.  Additionally, some of the topological sorting algorithms
 used in resolving macro dependencies use diversions.  However, most
 macros should not need to change diversions directly, but rather rely on
-higher-level M4sugar macros to manage diversions transparently.
+higher-level M4sugar macros to manage diversions transparently.  If you
+change diversions improperly, you risk generating a syntactically
+invalid script, because an incorrect diversion will violate assumptions
+made by many macros about whether prerequisite text has been previously
+output.  In short, if you manually change the diversion, you should not
+expect any macros provided by the Autoconf package to work until you
+have restored the diversion stack back to its original state.
 
 In the rare case that it is necessary to write a macro that explicitly
 outputs text to a different diversion, it is important to be aware of an
@@ -11334,9 +11347,10 @@ rescan of the output of @code{m4_do}.
 
 To make diversion management easier, M4sugar uses the concept of named
 diversions.  Rather than using diversion numbers directly, it is nicer
-to associate a name with each diversion; the diversion number associated
-with a particular diversion name is an implementation detail, so you
-should only use diversion names.  In general, you should not output text
+to associate a name with each diversion.  The diversion number associated
+with a particular diversion name is an implementation detail, and a
+syntax warning is issued if a diversion number is used instead of a
+name.  In general, you should not output text
 to a named diversion until after calling the appropriate initialization
 routine for your language (@code{m4_init}, @code{AS_INIT},
 @code{AT_INIT}, @dots{}), although there are some exceptions documented
@@ -11386,8 +11400,29 @@ used to set up state that is required across all tests.  This diversion
 will work even before @code{AT_INIT}.
 @end table
 
-For now, the named diversions of Autoconf and Autoheader, and the
-remaining diversions of Autotest, are not documented.  In other words,
+Autoconf inherits diversions from M4sh, and adds the following named
+diversions which developers can utilize.
+@table @code
+@item DEFAULTS
+This diversion contains shell variable assignments to set defaults that
+must be in place before arguments are parsed.  This diversion is placed
+early enough in @file{configure} that it is unsafe to expand any
+autoconf macros into this diversion.
+@item HELP_ENABLE
+If @code{AC_PRESERVE_HELP_ORDER} was used, then text placed in this
+diversion will be included as part of a quoted here-doc providing all of
+the @option{--help} output of @file{configure} related to options
+created by @code{AC_ARG_WITH} and @code{AC_ARG_ENABLE}.
+@item INIT_PREPARE
+This diversion occurs after all command line options have been parsed,
+but prior to the main body of the @file{configure} script.  This
+diversion is the last chance to insert shell code such as variable
+assignments or shell function declarations that will used by the
+expansion of other macros.
+@end table
+
+For now, the remaining named diversions of Autoconf, Autoheader, and
+Autotest are not documented.  In other words,
 intentionally outputting text into an undocumented diversion is subject
 to breakage in a future release of Autoconf.
 
@@ -11428,6 +11463,29 @@ affecting the current diversion.  Shorthand for:
 m4_divert_push([@var{diversion}])@var{content}
 m4_divert_pop([@var{diversion}])dnl
 @end example
+
+One use of @code{m4_divert_text} is to develop two related macros, where
+macro @samp{MY_A} does the work, but adjusts what work is performed
+based on whether the optional macro @samp{MY_B} has also been expanded.
+Of course, it is possible to use @code{AC_BEFORE} within @code{MY_A} to
+require that @samp{MY_B} occurs first, if it occurs at all.  But this
+imposes an ordering restriction on the user; it would be nicer if macros
+@samp{MY_A} and @samp{MY_B} can be invoked in either order.  The trick
+is to let @samp{MY_B} leave a breadcrumb in an early diversion, which
+@samp{MY_A} can then use to determine whether @samp{MY_B} has been
+expanded.
+
+@example
+AC_DEFUN([MY_A],
+[# various actions
+if test -n "$b_was_used"; then
+  # extra action
+fi])
+AC_DEFUN([MY_B],
+[AC_REQUIRE([MY_A])dnl
+m4_divert_text([INIT_PREPARE], [b_was_used=true])])
+@end example
+
 @end defmac
 
 @defmac m4_init
index 50dc71cb9da12aa2d698562da7e269e36e2d40dd..436474f276a3182d59c44b6d99f9dd1979b11fcd 100644 (file)
@@ -345,7 +345,7 @@ m4_divert_pop[]])
 # either m4_require([$1], [$2]) or m4_divert_require(desired, [$1], [$2]).
 m4_defun([AS_REQUIRE],
 [m4_define([_m4_divert_desired], [m4_default_quoted([$3], [M4SH-INIT])])]dnl
-[m4_if(m4_eval(_m4_divert_dump - 0 <= _m4_divert(_m4_divert_desired)),
+[m4_if(m4_eval(_m4_divert_dump - 0 <= _m4_divert(_m4_divert_desired, [-])),
        1, [m4_require(],
          [m4_divert_require(_m4_divert_desired,]) [$1], [$2])])
 
index e0cacfbdd6e8bae093cbba8b2eb9ed60de9bf0d1..cfdef725e7669679786d616de50808c48a409948 100644 (file)
@@ -1374,17 +1374,19 @@ m4_define([_m4_stack_reverse],
 m4_define([m4_cleardivert],
 [m4_if([$#], [0], [m4_fatal([$0: missing argument])],
        [_m4_divert_raw([-1])m4_undivert($@)_m4_divert_raw(
-        _m4_divert(_m4_defn([_m4_divert_diversion])))])])
+        _m4_divert(_m4_defn([_m4_divert_diversion]), [-]))])])
 
 
-# _m4_divert(DIVERSION-NAME or NUMBER)
-# ------------------------------------
+# _m4_divert(DIVERSION-NAME or NUMBER, [NOWARN])
+# ----------------------------------------------
 # If DIVERSION-NAME is the name of a diversion, return its number,
-# otherwise if it is a NUMBER return it.
+# otherwise if it is a NUMBER return it.  Issue a warning about
+# the use of a number instead of a name, unless NOWARN is provided.
 m4_define([_m4_divert],
 [m4_ifdef([_m4_divert($1)],
          [m4_indir([_m4_divert($1)])],
-         [$1])])
+         [m4_if([$2], [], [m4_warn([syntax],
+            [prefer named diversions])])$1])])
 
 # KILL is only used to suppress output.
 m4_define([_m4_divert(KILL)],           -1)
@@ -1420,13 +1422,15 @@ m4_define([m4_divert],
 [_m4_divert_raw(_m4_divert([$1]))])
 
 
-# m4_divert_push(DIVERSION-NAME)
-# ------------------------------
+# m4_divert_push(DIVERSION-NAME, [NOWARN])
+# ----------------------------------------
 # Change the diversion stream to DIVERSION-NAME, while stacking old values.
+# For internal use only: if NOWARN is not empty, DIVERSION-NAME can be a
+# number instead of a name.
 m4_define([m4_divert_push],
 [m4_divert_stack_push([$0], [$1])]dnl
 [m4_pushdef([_m4_divert_diversion], [$1])]dnl
-[_m4_divert_raw(_m4_divert([$1]))])
+[_m4_divert_raw(_m4_divert([$1], [$2]))])
 
 
 # m4_divert_pop([DIVERSION-NAME])
@@ -1442,7 +1446,7 @@ m4_define([m4_divert_pop],
 [_m4_popdef([_m4_divert_stack], [_m4_divert_diversion])]dnl
 [m4_ifdef([_m4_divert_diversion], [],
           [m4_fatal([too many m4_divert_pop])])]dnl
-[_m4_divert_raw(_m4_divert(_m4_defn([_m4_divert_diversion])))])
+[_m4_divert_raw(_m4_divert(_m4_defn([_m4_divert_diversion]), [-]))])
 
 
 # m4_divert_text(DIVERSION-NAME, CONTENT)
@@ -1928,7 +1932,7 @@ m4_define([m4_divert_require],
 [m4_if(_m4_divert_dump, [],
   [m4_fatal([$0($2): cannot be used outside of an m4_defun'd macro])])]dnl
 [m4_provide_if([$2], [],
-  [_m4_require_call([$2], [$3], _m4_divert([$1]))])])
+  [_m4_require_call([$2], [$3], _m4_divert([$1], [-]))])])
 
 
 # m4_defun(NAME, EXPANSION, [MACRO = m4_define])
@@ -2079,7 +2083,7 @@ m4_if([$0], [m4_require], [[m4_defun]], [[AC_DEFUN]])['d macro])])]dnl
 m4_define([_m4_require_call],
 [m4_pushdef([_m4_divert_grow], m4_decr(_m4_divert_grow))]dnl
 [m4_pushdef([_m4_diverting([$1])])m4_pushdef([_m4_diverting], [$1])]dnl
-[m4_divert_push(_m4_divert_grow)]dnl
+[m4_divert_push(_m4_divert_grow, [-])]dnl
 [m4_if([$2], [], [$1], [$2])
 m4_provide_if([$1], [m4_set_remove([_m4_provide], [$1])],
   [m4_warn([syntax], [$1 is m4_require'd but not m4_defun'd])])]dnl
index 5ff9fe8f5f753060a4b6c1bdacdfd726aaa0966b..ab623b4d33a883fce1a3dcc6c2fe3afcf5693f72 100644 (file)
@@ -50,7 +50,7 @@ AT_CHECK([test -n "${ZSH_VERSION+set}" && exit 77], ignore)
 m4_define([AT_DATA_LINENO],
 [AT_DATA([$1.tas],
 [[AS@&t@_INIT
-m4@&t@_divert_text([0], [
+m4@&t@_divert_text([], [
 if $2; then
   AS@&t@_UNSET([LINENO])
 fi
index aa30291812738231521e1804d6907470bb68d8b0..a96583c4b116cc708e4300bb0e7c3c62a9d7ed65 100644 (file)
@@ -26,9 +26,9 @@ m4_define([AT_CHECK_M4SUGAR_TEXT],
 [
 AT_DATA_M4SUGAR([script.4s],
 [[m4_init
-m4_divert_push(0)[]dnl
+m4_divert_push([])[]dnl
 ]$1[[]dnl
-m4_divert_pop(0)
+m4_divert_pop([])
 ]])
 
 AT_CHECK_M4SUGAR([-o-],, [$2], [$3])
@@ -263,11 +263,13 @@ m4_warn([syntax], [syntax])dnl
 ]])
 
 AT_CHECK_M4SUGAR([-o-], 0, [],
-[script.4s:7: warning: syntax
+[script.4s:4: warning: prefer named diversions
+script.4s:7: warning: syntax
 ])
 
 AT_CHECK_M4SUGAR([-o- -Wall -f], 0, [],
-[script.4s:5: warning: obsolete
+[script.4s:4: warning: prefer named diversions
+script.4s:5: warning: obsolete
 script.4s:6: warning: cross
 script.4s:2: cross_warning is expanded from...
 script.4s:6: the top level
@@ -297,25 +299,29 @@ AT_SETUP([m4@&t@_divert_stack])
 AT_KEYWORDS([m4@&t@_divert m4@&t@_divert_push m4@&t@_divert_pop
 m4@&t@_undivert m4@&t@_cleardivert m4@&t@_divert_text])
 
-AT_CHECK_M4SUGAR_TEXT([[1.m4_divert_stack
-m4_divert_push([10])2.m4_divert_stack
-m4_divert_text([20], [3.m4_divert_stack])dnl
-m4_divert([30])4.m4_divert_stack
-m4_divert_pop([30])dnl
-5.m4_undivert([20], [30])
+dnl This test names some diversions to avoid a warning.
+AT_CHECK_M4SUGAR_TEXT([[m4_define([_m4_divert(ten)], [10])dnl
+m4_define([_m4_divert(twenty)], [20])dnl
+m4_define([_m4_divert(thirty)], [30])dnl
+1.m4_divert_stack
+m4_divert_push([ten])2.m4_divert_stack
+m4_divert_text([twenty], [3.m4_divert_stack])dnl
+m4_divert([thirty])4.m4_divert_stack
+m4_divert_pop([thirty])dnl
+5.m4_undivert([twenty], [thirty])
 m4_pattern_allow([^m4_divert])dnl
-]], [[1.script.4s:2: m4@&t@_divert_push: 0
+]], [[1.script.4s:2: m4@&t@_divert_push:
 script.4s:1: m4@&t@_divert: KILL
-5.3.script.4s:5: m4@&t@_divert_push: 20
-script.4s:4: m4@&t@_divert_push: 10
-script.4s:2: m4@&t@_divert_push: 0
+5.3.script.4s:8: m4@&t@_divert_push: twenty
+script.4s:7: m4@&t@_divert_push: ten
+script.4s:2: m4@&t@_divert_push:
 script.4s:1: m4@&t@_divert: KILL
-4.script.4s:6: m4@&t@_divert: 30
-script.4s:2: m4@&t@_divert_push: 0
+4.script.4s:9: m4@&t@_divert: thirty
+script.4s:2: m4@&t@_divert_push:
 script.4s:1: m4@&t@_divert: KILL
 
-2.script.4s:4: m4@&t@_divert_push: 10
-script.4s:2: m4@&t@_divert_push: 0
+2.script.4s:7: m4@&t@_divert_push: ten
+script.4s:2: m4@&t@_divert_push:
 script.4s:1: m4@&t@_divert: KILL
 ]])
 
@@ -328,6 +334,12 @@ m4_cleardivert([2], [3])dnl
 ]],
 [[one
 four
+]],
+[[script.4s:4: warning: prefer named diversions
+script.4s:5: warning: prefer named diversions
+script.4s:6: warning: prefer named diversions
+script.4s:7: warning: prefer named diversions
+script.4s:8: warning: prefer named diversions
 ]])
 
 AT_DATA_M4SUGAR([script.4s],
@@ -1004,7 +1016,7 @@ AT_DATA_M4SUGAR([script.4s],
 [[m4_init[]dnl
 m4_append_uniq([str], [a], [ ])
 m4_append_uniq([str], [a b], [ ])
-m4_divert([0])dnl
+m4_divert([])dnl
 str
 ]])
 
@@ -1134,7 +1146,7 @@ AT_KEYWORDS([m4@&t@_escape])
 # m4-listification.
 
 AT_DATA_M4SUGAR([script.4s],
-[[m4_init[]m4_divert([0])dnl
+[[m4_init[]m4_divert([])dnl
 m4_define([a], [OOPS])dnl
 m4_escape([a[b $c#]d])
 m4_if(m4_escape([a[b $c#]d]), [a[b $c#]d], [oops],
@@ -1820,7 +1832,7 @@ dnl are testing with m4 1.6, we can rerun the test with __m4_version__
 dnl undefined to exercise the alternate code path.
 AT_DATA_M4SUGAR([script.4s],
 [[m4_init
-m4_divert_push(0)[]dnl
+m4_divert_push([])[]dnl
 m4_len(m4_foreach_w([j], m4_do(m4_for([i], [1], [10000], [], [,i ])), [j ]))
 m4_shiftn(9998m4_for([i], [1], [10000], [], [,i]))
 m4_len(m4_join([--],, m4_dquote_elt(m4_for([i], [1], [10000], [], [,i])),))
@@ -1841,7 +1853,7 @@ m4_define([up], [m4_define([$1], m4_incr($1))$1])m4_define([j], 0)dnl
 m4_cond(m4_for([i], [1], [10000], [], [[up([j])], [9990], i,]) [oops]) j
 m4_count(m4_map_args_pair([,m4_quote], []m4_map_args([,m4_echo]m4_for([i],
   [1], [10000], [], [,i]))))
-m4_divert_pop(0)
+m4_divert_pop([])
 ]])
 
 AT_CHECK_M4SUGAR([-o-], [0], [[48894
@@ -1877,7 +1889,7 @@ A
 5001
 m4_exit([0])])
 m4_init
-m4_divert_push(0)[]dnl
+m4_divert_push([])[]dnl
 m4_len(m4_foreach_w([j], m4_do(m4_for([i], [1], [10000], [], [,i ])), [j ]))
 m4_shiftn(9998m4_for([i], [1], [10000], [], [,i]))
 m4_len(m4_join([--],, m4_dquote_elt(m4_for([i], [1], [10000], [], [,i])),))
@@ -1898,7 +1910,7 @@ m4_define([up], [m4_define([$1], m4_incr($1))$1])m4_define([j], 0)dnl
 m4_cond(m4_for([i], [1], [10000], [], [[up([j])], [9990], i,]) [oops]) j
 m4_count(m4_map_args_pair([,m4_quote], []m4_map_args([,m4_echo]m4_for([i],
   [1], [10000], [], [,i]))))
-m4_divert_pop(0)
+m4_divert_pop([])
 ]])
 
 AT_CHECK_M4SUGAR([-o-], [0], [[48894
index d44d6b9f4173c87d2e0951472cc521d0f1cd9faf..9897599b6b5bc8c7a7fa67541744986f64edebd5 100755 (executable)
@@ -138,6 +138,9 @@ ac_exclude_list='
 
        # Already tested by AT_CHECK_MACRO.
        /^AC_OUTPUT$/ {next}
+
+       # Tested alongside m4_divert_text.
+       /^AC_PRESERVE_HELP_ORDER$/ {next}
 '
 
 
index e23ac04dca6273eff1c1d049a7d8e15cebd03f73..aa3f2585278d055f232635a77fc578c06fabfd71 100644 (file)
@@ -164,7 +164,7 @@ do
 
   cat >"$file" <<'END'
 [m4@&t@_init[]m4@&t@_include(foo.m4)
-m4@&t@_divert(0)d@&t@nl
+m4@&t@_divert([])d@&t@nl
 FOO]
 END
   cat >"$dir"/foo.m4 <<'END'
@@ -186,7 +186,7 @@ END
   cat >"$file" <<'END'
 [m4@&t@_init[]m4@&t@_include(foo.m4)
 m4@&t@_pattern_forbid([^bar$])
-m4@&t@_divert(0)d@&t@nl
+m4@&t@_divert([])d@&t@nl
 FOO]
 END
   rm -rf "$outfile" "$cachedir"
@@ -196,7 +196,7 @@ END
 
   cat >"$file" <<'END'
 [m4@&t@_init[]m4@&t@_include(foo.m4)
-m4@&t@_divert(0)d@&t@nl]
+m4@&t@_divert([])d@&t@nl]
 END
   rm -rf "$file.m4f"
   AT_CHECK_AUTOM4TE([-C "$cachedir" -I "$dir" --language=m4sugar --freeze -o "$file.m4f" "$file"])
@@ -464,7 +464,7 @@ AT_SETUP([autoconf: the empty token])
 
 AT_DATA_M4SH([configure.ac],
 [[m4_init[]m4_pattern_allow([^foo$])
-m4_divert([0])dnl
+m4_divert([])dnl
  line that begins with a space
 ]])
 
@@ -535,6 +535,41 @@ AT_CLEANUP
 
 
 
+# autoconf: AC_PRESERVE_HELP_ORDER
+# --------------------------------
+AT_SETUP([autoconf: AC_PRESERVE_HELP_ORDER])
+AT_KEYWORDS([m4@&t@_divert_text])
+
+AT_DATA_AUTOCONF([configure.ac],
+[[AC_INIT
+AC_PRESERVE_HELP_ORDER
+AC_ARG_WITH([one], [  --with-one])
+AC_ARG_ENABLE([two], [  --enable-two])
+m4_divert_text([HELP_ENABLE], [arbitrary $text])
+AC_ARG_WITH([three], [  --with-three])
+AC_OUTPUT
+]])
+
+AT_CHECK_AUTOCONF
+AT_CHECK_CONFIGURE([--help], [], [stdout])
+AT_CHECK([sed -n '/^Optional/,/^$/p' stdout], [],
+[[Optional Features and Packages:
+  --disable-option-checking  ignore unrecognized --enable/--with options
+  --disable-FEATURE       do not include FEATURE (same as --enable-FEATURE=no)
+  --enable-FEATURE[=ARG]  include FEATURE [ARG=yes]
+  --with-PACKAGE[=ARG]    use PACKAGE [ARG=yes]
+  --without-PACKAGE       do not use PACKAGE (same as --with-PACKAGE=no)
+  --with-one
+  --enable-two
+arbitrary $text
+  --with-three
+
+]])
+
+AT_CLEANUP
+
+
+
 ## --------- ##
 ## ifnames.  ##
 ## --------- ##