From e21a053e190be6c0c82187b7df6877732385e917 Mon Sep 17 00:00:00 2001 From: Martijn Dekker Date: Thu, 21 Jan 2021 00:02:01 +0000 Subject: [PATCH] libast: optget: improve usage messages, adding help info line For example, this changes 'typeset -Q' (a bad option) from: | ksh: typeset: -Q: unknown option | Usage: typeset [-bflmnprstuxACHS] [-a[type]] [-i[base]] [-E[n]] | [-F[n]] [-L[n]] [-M[mapping]] [-R[n]] [-X[n]] | [-h string] [-T[tname]] [-Z[n]] [name[=value]...] | Or: typeset [ options ] -f [name...] to: | ksh: typeset: -Q: unknown option | Usage: typeset [-bflmnprstuxACHS] [-a[type]] [-i[base]] [-E[n]] | [-F[n]] [-L[n]] [-M[mapping]] [-R[n]] [-X[n]] | [-h string] [-T[tname]] [-Z[n]] [name[=value]...] | Or: typeset -f [name...] | Help: typeset [ --help | --man ] 2>&1 src/lib/libast/misc/optget.c: args(): - Revert the changes done in 6916a873 and ae92cd89. The --help and --man labels weren't added consistently (they did not show up in the example above) whereas they did show up unnecessarily in the manual page itself. - In the usage section and usage messges, only show an [ options ] label on the first usage line; don't redundantly repeat on second and further ("Or:") lines. - In usage and --help (but not --man), add a new "Help:" line telling the user about the --help and --man options. This replaces the reverted changes. Show the 2>&1 redirection as a reminder that you need to do this to pipe it into a pager, as everything is written to standard error! - Add some comments clarifying what I think this code does... src/cmd/ksh93/tests/builtins.sh: - Update to match changes in getopts usage output. --- src/cmd/ksh93/tests/builtins.sh | 17 ++++++++++------- src/lib/libast/misc/optget.c | 31 ++++++++++++++++++++++++------- 2 files changed, 34 insertions(+), 14 deletions(-) diff --git a/src/cmd/ksh93/tests/builtins.sh b/src/cmd/ksh93/tests/builtins.sh index fe48f1d44..ebbb94aaf 100755 --- a/src/cmd/ksh93/tests/builtins.sh +++ b/src/cmd/ksh93/tests/builtins.sh @@ -907,21 +907,24 @@ function testusage { actual=$(testusage -\?) expect='Usage: testusage [-xyz] [ name=value ... ] - Or: testusage [ options ] -y [ name ... ]' + Or: testusage -y [ name ... ] + Help: testusage [ --help | --man ] 2>&1' [[ $actual == "$expect" ]] || err_exit "getopts: '-?' output" \ "(expected $(printf %q "$expect"), got $(printf %q "$actual"))" actual=$(testusage --\?x) -expect='Usage: testusage [ options | --help | --man ] [ name=value ... ] - Or: testusage [ options ] -y [ name ... ] +expect='Usage: testusage [ options ] [ name=value ... ] + Or: testusage -y [ name ... ] + Help: testusage [ --help | --man ] 2>&1 OPTIONS -x, --xylophone Lorem.' [[ $actual == "$expect" ]] || err_exit "getopts: '--?x' output" \ "(expected $(printf %q "$expect"), got $(printf %q "$actual"))" actual=$(testusage --help) -expect='Usage: testusage [ options | --help | --man ] [ name=value ... ] - Or: testusage [ options ] -y [ name ... ] +expect='Usage: testusage [ options ] [ name=value ... ] + Or: testusage -y [ name ... ] + Help: testusage [ --help | --man ] 2>&1 OPTIONS -x, --xylophone Lorem. -y, --ypsilon Ipsum. @@ -934,8 +937,8 @@ expect='NAME foo - bar SYNOPSIS - foo [ options | --help | --man ] [ name=value ... ] - foo [ options | --help | --man ] -y [ name ... ] + foo [ options ] [ name=value ... ] + foo -y [ name ... ] DESC Baz. diff --git a/src/lib/libast/misc/optget.c b/src/lib/libast/misc/optget.c index cafa2565c..35cb3cfc3 100644 --- a/src/lib/libast/misc/optget.c +++ b/src/lib/libast/misc/optget.c @@ -1634,28 +1634,37 @@ args(register Sfio_t* sp, register char* p, register int n, int flags, int style t = (char*)memchr(p, '\n', n); if (style >= STYLE_man) { + int firstline = !a; + /* --man page: print command name */ if (!(a = id)) a = "..."; - sfprintf(sp, "\t%s%s%s%s[%s%s%s%s%s|%s%s--help%s%s|%s%s--man%s%s]", - font(FONT_BOLD, style, 1), a, font(FONT_BOLD, style, 0), b, - b, font(FONT_ITALIC, style, 1), o, font(FONT_ITALIC, style, 0), b, - b, font(FONT_ITALIC, style, 1), font(FONT_ITALIC, style, 0), b, - b, font(FONT_ITALIC, style, 1), font(FONT_ITALIC, style, 0), b); + sfprintf(sp, "\t%s%s%s", font(FONT_BOLD, style, 1), a, font(FONT_BOLD, style, 0)); + if (firstline) + { + /* Append "[ options ]" label */ + sfprintf(sp, "%s[%s%s%s%s%s]", + b, b, font(FONT_ITALIC, style, 1), o, font(FONT_ITALIC, style, 0), b); + } } else if (a) - sfprintf(sp, "%*.*s%s%s%s[%s%s%s]", OPT_USAGE - 1, OPT_USAGE - 1, T(NiL, ID, "Or:"), b, a, b, b, o, b); + { + /* Usage/--help, line 2+: specific usages. Prefix by "Or:" */ + sfprintf(sp, "%*.*s%s%s", OPT_USAGE - 1, OPT_USAGE - 1, T(NiL, ID, "Or:"), b, a); + } else { + /* Usage on unknown long option error: no short options are printed, so print "[ options ]" */ if (!(a = error_info.id) && !(a = id)) a = "..."; if (!sfstrtell(sp)) - sfprintf(sp, "[%s%s%s|%s--help%s|%s--man%s]", b, o, b, b, b, b, b); + sfprintf(sp, "[%s%s%s]", b, o, b); } if (!t) break; i = ++t - p; if (i) { + /* Print options for usage line */ sfputr(sp, b, -1); if (X(catalog)) { @@ -1668,6 +1677,7 @@ args(register Sfio_t* sp, register char* p, register int n, int flags, int style else sfwrite(sp, p, i); } + /* New line */ if (style == STYLE_html) sfputr(sp, "
", '\n'); else if (style == STYLE_nroff) @@ -1683,8 +1693,15 @@ args(register Sfio_t* sp, register char* p, register int n, int flags, int style } } } + /* Print options for the last usage line */ if (n) label(sp, sep, p, 0, n, 0, style, 0, ip, version, id, catalog); + /* In usage/--help messages, tell the user how to get more help */ + if (style < STYLE_man) + { + sfprintf(sp, "\n%*.*s%s%s [%s--help%s|%s--man%s] 2>&1", + OPT_USAGE - 1, OPT_USAGE - 1, T(NiL, ID, "Help:"), b, a, b, b, b, b); + } } /*