2007-10-15 Eric Blake <ebb9@byu.net>
+ Enhance AS_HELP_STRING.
+ * lib/m4sugar/m4sugar.m4 (m4_text_wrap): Don't expand arguments,
+ and reduce number of expansions.
+ * lib/m4sugar/m4sh.m4 (AS_HELP_STRING): Rework to use m4_expand,
+ and to take indent and wrap column numbers.
+ * tests/m4sh.at (AS@&t@_HELP_STRING): Update the test.
+ * doc/autoconf.texi (Pretty Help Strings): Document details about
+ arguments.
+ (Text processing Macros): Minor tweaks.
+ * NEWS: Document this change.
+
Fix 2007-10-03 regression with AT_SETUP([a, b]).
* lib/m4sugar/m4sugar.m4 (m4_expand): New macro.
(m4_text_box): Use it.
** AC_USE_SYSTEM_EXTENSIONS now defines _ALL_SOURCE for Interix platforms.
-** AS_HELP_STRING no longer underquotes its first argument.
+** AS_HELP_STRING no longer underquotes its first argument; it also handles
+ the case where the first argument contains single-quoted commas.
+ For example, "AS_HELP_STRING([-a, [--arg[=foo]]], [bar])" produces:
+ " -a, --arg=[foo] bar"
+ Additionally, the macro now takes two additional arguments,
+ indent-column and wrap-column; these should not normally be needed,
+ but can be used to fine-tune how the output text is wrapped.
** The command 'autoconf -' now correctly processes a file from stdin.
@code{m4_append} can be used to grow strings, and @code{m4_append_uniq}
to grow strings without duplicating substrings. Additionally,
-@code{m4_append_uniq} takes two optional parameters; @var{if-uniq} is
-expanded if @var{string} was appended, and @var{if-duplicate} is
-expanded if @var{string} was already present.
+@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.
@example
m4_define([active], [ACTIVE])dnl
trailing whitespace. If given, @var{prefix1} is prepended to the first
line, and @var{prefix} is prepended to each continuation line. As a
special case, if @var{prefix1} is longer than @var{prefix}, the first
-line will consist solely of @var{prefix1}.
+line will consist solely of @var{prefix1}. No expansions occur on
+@var{prefix}, @var{prefix1}, or the words of @var{string}, although
+quadrigraphs are recognized.
For some examples:
@example
-m4_text_wrap([Short string */], [@ @ @ ], [/* ], [20])
+m4_text_wrap([Short string */], [ ], [/* ], [20])
@result{}/* Short string */
-m4_text_wrap([Much longer string */], [@ @ @ ], [/* ], [20])
+m4_text_wrap([Much longer string */], [ ], [/* ], [20])
@result{}/* Much longer
-@result{}@ @ @ string */
-m4_text_wrap([Short doc.], [@ @ @ @ @ @ @ @ @ @ ], [@ @ --short ], [30])
-@result{}@ @ --short Short doc.
-m4_text_wrap([Short doc.], [@ @ @ @ @ @ @ @ @ @ ], [@ @ --too-wide ], [30])
-@result{}@ @ --too-wide
-@result{}@ @ @ @ @ @ @ @ @ @ Short doc.
-m4_text_wrap([Super long documentation.], [@ @ @ @ @ ],
- [@ @ --too-wide ], 30)
-@result{}@ @ --too-wide
-@result{}@ @ @ @ @ Super long
-@result{}@ @ @ @ @ documentation.
+@result{} string */
+m4_text_wrap([Short doc.], [ ], [ --short ], [30])
+@result{} --short Short doc.
+m4_text_wrap([Short doc.], [ ], [ --too-wide ], [30])
+@result{} --too-wide
+@result{} Short doc.
+m4_text_wrap([Super long documentation.], [ ],
+ [ --too-wide ], 30)
+@result{} --too-wide
+@result{} Super long
+@result{} documentation.
@end example
@end defmac
strings} do. This is the purpose of the @code{AS_HELP_STRING} macro.
@anchor{AS_HELP_STRING}
-@defmac AS_HELP_STRING (@var{left-hand-side}, @var{right-hand-side})
+@defmac AS_HELP_STRING (@var{left-hand-side}, @var{right-hand-side} @
+ @dvar{indent-column, 26}, @dvar{wrap-column, 79})
@asindex{HELP_STRING}
Expands into an help string that looks pretty when the user executes
[use_foo=no])
@end example
-The second argument of @code{AS_HELP_STRING} is
-not a literal, and should not be double quoted.
-@xref{Autoconf Language}, for a more detailed explanation.
Then the last few lines of @samp{configure --help} appear like
this:
--with-foo use foo (default is no)
@end example
+Macro expansion is performed on the first argument. However, the second
+argument of @code{AS_HELP_STRING} is treated as a whitespace separated
+list of text to be reformatted, and is not subject to macro expansion.
+Since it is not expanded, it should not be double quoted.
+@xref{Autoconf Language}, for a more detailed explanation.
+
The @code{AS_HELP_STRING} macro is particularly helpful when the
@var{left-hand-side} and/or @var{right-hand-side} are composed of macro
arguments, as shown in the following example.
@example
AC_DEFUN([MY_ARG_WITH],
- [AC_ARG_WITH([$1],
- [AS_HELP_STRING([--with-$1], [use $1 (default is $2)])],
+ [AC_ARG_WITH(m4_translit([[$1]], [_], [-]),
+ [AS_HELP_STRING([--with-m4_translit([$1], [_], [-])],
+ [use $1 (default is $2)])],
[use_[]$1=$withval],
[use_[]$1=$2])])
+MY_ARG_WITH([a_b], [no])
+@end example
+@noindent
+Here, the last few lines of @samp{configure --help} will include:
+
+@example
+--enable and --with options recognized:
+ --with-a-b use a_b (default is no)
+@end example
+
+The parameters @var{indent-column} and @var{wrap-column} were introduced
+in Autoconf 2.62. Generally, they should not be specified; they exist
+for fine-tuning of the wrapping.
+@example
+AS_HELP_STRING([--option], [description of option])
+@result{} --option description of option
+AS_HELP_STRING([--option], [description of option], [15], [30])
+@result{} --option description of
+@result{} option
@end example
@end defmac
_ASBOX])
-# AS_HELP_STRING(LHS, RHS, [COLUMN])
-# ----------------------------------
+# AS_HELP_STRING(LHS, RHS, [INDENT-COLUMN = 26], [WRAP-COLUMN = 79])
+# ------------------------------------------------------------------
+#
+# Format a help string so that it looks pretty when the user executes
+# "script --help". This macro takes up to four arguments, a
+# "left hand side" (LHS), a "right hand side" (RHS), a decimal
+# INDENT-COLUMN which is the column where wrapped lines should begin
+# (the default of 26 is recommended), and a decimal WRAP-COLUMN which is
+# the column where lines should wrap (the default of 79 is recommended).
+# LHS is expanded, RHS is not.
#
-# Format a help string so that it looks pretty when
-# the user executes "script --help". This macro takes three
-# arguments, a "left hand side" (LHS), a "right hand side" (RHS), and
-# the COLUMN which is a string of white spaces which leads to the
-# the RHS column (default: 26 white spaces).
+# For backwards compatibility not documented in the manual, INDENT-COLUMN
+# can also be specified as a string of white spaces, whose width
+# determines the indentation column. Using TABs in INDENT-COLUMN is not
+# recommended, since screen width of TAB is not computed.
#
# The resulting string is suitable for use in other macros that require
# a help string (e.g. AC_ARG_WITH).
# "--with-readline", while the RHS is "support fancy command line
# editing".
#
-# If the LHS contains more than (COLUMN - 3) characters, then the LHS is
-# terminated with a newline so that the RHS starts on a line of its own
-# beginning with COLUMN. In the default case, this corresponds to an
+# If the LHS contains more than (INDENT-COLUMN - 3) characters, then the
+# LHS is terminated with a newline so that the RHS starts on a line of its
+# own beginning at INDENT-COLUMN. In the default case, this corresponds to an
# LHS with more than 23 characters.
#
# Therefore, in the example, if the LHS were instead
# know quadrigraphs.
#
m4_define([AS_HELP_STRING],
-[m4_pushdef([AS_Prefix], m4_default([$3], [ ]))dnl
-m4_pushdef([AS_Prefix_Format],
- [ %-]m4_eval(m4_len(AS_Prefix) - 3)[s ])dnl [ %-23s ]
-m4_text_wrap([$2], AS_Prefix, m4_format(AS_Prefix_Format, [[$1]]))dnl
-m4_popdef([AS_Prefix_Format])dnl
-m4_popdef([AS_Prefix])dnl
+[m4_text_wrap([$2], m4_cond([[$3]], [], [ ],
+ [m4_eval([$3]+0)], [0], [[$3]],
+ [m4_format([[%*s]], [$3], [])]),
+ m4_expand([ $1 ]), [$4])dnl
])# AS_HELP_STRING
# if the length of FIRST-PREFIX is greater than that of PREFIX, then
# FIRST-PREFIX will be left alone on the first line.
#
+# No expansion occurs on the contents STRING, PREFIX, or FIRST-PREFIX,
+# although quadrigraphs are correctly recognized.
+#
# Typical outputs are:
#
# m4_text_wrap([Short string */], [ ], [/* ], 20)
# all the words are preceded by m4_Separator which is defined to empty for
# the first word, and then ` ' (single space) for all the others.
#
-# The algorithm overquotes m4_Prefix1 to avoid m4_defn overhead, and bypasses
-# m4_popdef overhead with m4_builtin since no user macro expansion occurs in
-# the meantime.
+# The algorithm overquotes m4_Prefix and m4_Prefix1 to avoid m4_defn
+# overhead, and bypasses m4_popdef overhead with m4_builtin since no user
+# macro expansion occurs in the meantime. Also, the definition is written
+# with m4_do, to avoid time wasted on dnl during expansion (since this is
+# already a time-consuming macro).
m4_define([m4_text_wrap],
-[m4_pushdef([m4_Prefix], [$2])dnl
-m4_pushdef([m4_Prefix1], m4_dquote(m4_default([$3], [m4_Prefix])))dnl
-m4_pushdef([m4_Width], m4_default([$4], 79))dnl
-m4_pushdef([m4_Cursor], m4_qlen(m4_Prefix1))dnl
-m4_pushdef([m4_Separator], [])dnl
-m4_Prefix1[]dnl
-m4_cond([m4_eval(m4_qlen(m4_Prefix1) > m4_len(m4_Prefix))],
- [1], [m4_define([m4_Cursor], m4_len(m4_Prefix))
-m4_Prefix],
- [m4_eval(m4_qlen(m4_Prefix1) < m4_len(m4_Prefix))],
- [0], [],
- [m4_define([m4_Cursor], m4_len(m4_Prefix))[]dnl
-m4_format([%*s],
- m4_max([0], m4_eval(m4_len(m4_Prefix) - m4_qlen(m4_Prefix1))),
- [])])[]dnl
-m4_foreach_w([m4_Word], [$1],
-[m4_define([m4_Cursor],
- m4_eval(m4_Cursor + m4_qlen(m4_builtin([defn], [m4_Word])) + 1))dnl
-dnl New line if too long, else insert a space unless it is the first
-dnl of the words.
-m4_if(m4_eval(m4_Cursor > m4_Width),
- 1, [m4_define([m4_Cursor],
- m4_eval(m4_len(m4_Prefix)
- + m4_qlen(m4_builtin([defn], [m4_Word])) + 1))]
-m4_Prefix,
- [m4_Separator])[]dnl
-m4_builtin([defn], [m4_Word])[]dnl
-m4_define([m4_Separator], [ ])])dnl
-m4_builtin([popdef], [m4_Separator])dnl
-m4_builtin([popdef], [m4_Cursor])dnl
-m4_builtin([popdef], [m4_Width])dnl
-m4_builtin([popdef], [m4_Prefix1])dnl
-m4_builtin([popdef], [m4_Prefix])dnl
-])
+m4_do(dnl set up local variables, to avoid repeated calculations
+[[m4_pushdef([m4_Prefix], [[$2]])]],
+[[m4_pushdef([m4_Prefix1], m4_if([$3], [], [m4_Prefix], [[[$3]]]))]],
+[[m4_pushdef([m4_Width], m4_default([$4], 79))]],
+[[m4_pushdef([m4_Indent], m4_qlen(m4_Prefix))]],
+[[m4_pushdef([m4_Cursor], m4_qlen(m4_Prefix1))]],
+[[m4_pushdef([m4_Separator], [m4_define([m4_Separator], [ ])])]],
+dnl expand the first prefix, then check its length vs. regular prefix
+dnl same length: nothing special
+dnl prefix1 longer: output on line by itself, and reset cursor
+dnl prefix1 shorter: pad to length of prefix, and reset cursor
+[[m4_Prefix1[]m4_cond([m4_Cursor], m4_Indent, [],
+ [m4_eval(m4_Cursor > m4_Indent)], [1], [
+m4_Prefix[]m4_define([m4_Cursor], m4_Indent)],
+ [m4_format([%*s], m4_max([0],
+ m4_eval(m4_Indent - m4_Cursor)), [])m4_define([m4_Cursor], m4_Indent)])]],
+dnl now, for each word, compute the curser after the word is output, then
+dnl check if the cursor would exceed the wrap column
+dnl if so, reset cursor, and insert newline and prefix
+dnl if not, insert the separator (usually a space)
+dnl either way, insert the word
+[[m4_foreach_w([m4_Word], [$1],
+ [m4_define([m4_Cursor],
+ m4_eval(m4_Cursor + m4_qlen(m4_builtin([defn], [m4_Word]))
+ + 1))m4_if(m4_eval(m4_Cursor > m4_Width),
+ [1], [m4_define([m4_Cursor],
+ m4_eval(m4_Indent
+ + m4_qlen(m4_builtin([defn], [m4_Word])) + 1))
+m4_Prefix[]],
+ [m4_Separator[]])m4_builtin([defn], [m4_Word])])]],
+dnl finally, clean up the local variabls
+[[m4_builtin([popdef], [m4_Separator])]],
+[[m4_builtin([popdef], [m4_Cursor])]],
+[[m4_builtin([popdef], [m4_Indent])]],
+[[m4_builtin([popdef], [m4_Width])]],
+[[m4_builtin([popdef], [m4_Prefix1])]],
+[[m4_builtin([popdef], [m4_Prefix])]]))
# m4_text_box(MESSAGE, [FRAME-CHARACTER = `-'])
## AS_HELP_STRING ##
## -------------- ##
-# I'm not totally certain that we want to enforce the defaults here,
-# but at least it is being tested.
-
AT_SETUP([AS@&t@_HELP_STRING])
+AT_KEYWORDS([m4@&t@_text_wrap])
AT_DATA_M4SH([script.as],
[[AS_INIT
[some other t[]t which should wrap at our default of 80 characters.])"
echo "AS_HELP_STRING([[--foo[=bar]1234567890123]],
[some other t[]t which should wrap at our default of 80 characters.])"
+m4_define([mac], [MACRO])dnl
+echo "AS_HELP_STRING([--mac], [mac])"
+echo "AS_HELP_STRING([--o1, --o2], [two
+options, one description])"
+echo "AS_HELP_STRING([--tune1], [check out the tuned formatting],
+[ ])"
+echo "AS_HELP_STRING([--tune2], [check out the tuned formatting],
+[12])"
+echo "AS_HELP_STRING([--tune3], [check out the tuned formatting],
+[], [40])"
+echo "AS_HELP_STRING([--tune4], [check out the tuned formatting],
+[12], [40])"
]])
AT_CHECK_M4SH
--foo[=bar]1234567890123
some other t[]t which should wrap at our default of
80 characters.
+ --MACRO mac
+ --o1, --o2 two options, one description
+ --tune1 check out the tuned formatting
+ --tune2 check out the tuned formatting
+ --tune3 check out the
+ tuned
+ formatting
+ --tune4 check out the tuned
+ formatting
]])
AT_CLEANUP