shared/options: add option to generate a help line for custom option format

Sometimes we want to document what -RR or -vv does or some other
special thing. Let's allow this by (ab-)using long_code pointer
to store a preformatted string.
This commit is contained in:
Zbigniew Jędrzejewski-Szmek
2026-04-11 09:54:56 +02:00
parent 53c87c096c
commit 10e78e0b0e
2 changed files with 40 additions and 29 deletions
+34 -25
View File
@@ -21,8 +21,9 @@ static bool option_arg_required(const Option *opt) {
static bool option_is_metadata(const Option *opt) {
/* A metadata entry that is not a real option, like the group marker */
return FLAGS_SET(ASSERT_PTR(opt)->flags, OPTION_GROUP_MARKER) ||
FLAGS_SET(ASSERT_PTR(opt)->flags, OPTION_HELP_ENTRY);
return ASSERT_PTR(opt)->flags & (OPTION_GROUP_MARKER |
OPTION_HELP_ENTRY |
OPTION_HELP_ENTRY_VERBATIM);
}
static void shift_arg(char* argv[], int target, int source) {
@@ -313,30 +314,38 @@ int _option_parser_get_help_table(
/* No help string — we do not show the option */
continue;
char sc[3] = " ";
if (opt->short_code != 0)
xsprintf(sc, "-%c", opt->short_code);
_cleanup_free_ char *s = NULL;
/* We indent the option string by two spaces. We could set the minimum cell width and
* right-align for a similar result, but that'd be more work. This is only used for
* display.
*
* "=" is shown only when a long option is defined: -l --long=ARG, --long=ARG, -s ARG.
*/
bool need_eq = option_takes_arg(opt) && opt->long_code;
bool need_quote = opt->metavar && strchr(opt->metavar, ' ');
_cleanup_free_ char *s = strjoin(
" ",
sc,
" ",
opt->long_code ? "--" : "",
strempty(opt->long_code),
option_arg_optional(opt) ? "[" : "",
need_eq ? "=" : "",
need_quote ? "'" : "",
strempty(opt->metavar),
need_quote ? "'" : "",
option_arg_optional(opt) ? "]" : "");
if (FLAGS_SET(opt->flags, OPTION_HELP_ENTRY_VERBATIM)) {
assert(opt->long_code);
s = strjoin(" ",
opt->long_code);
} else {
char sc[3] = " ";
if (opt->short_code != 0)
xsprintf(sc, "-%c", opt->short_code);
/* We indent the option string by two spaces. We could set the minimum cell width and
* right-align for a similar result, but that'd be more work. This is only used for
* display.
*
* "=" is shown only when a long option is defined: -l --long=ARG, --long=ARG, -s ARG.
*/
bool need_eq = option_takes_arg(opt) && opt->long_code;
bool need_quote = opt->metavar && strchr(opt->metavar, ' ');
s = strjoin(" ",
sc,
" ",
opt->long_code ? "--" : "",
strempty(opt->long_code),
option_arg_optional(opt) ? "[" : "",
need_eq ? "=" : "",
need_quote ? "'" : "",
strempty(opt->metavar),
need_quote ? "'" : "",
option_arg_optional(opt) ? "]" : "");
}
if (!s)
return log_oom();
+6 -4
View File
@@ -5,10 +5,11 @@
#include "shared-forward.h"
typedef enum OptionFlags {
OPTION_OPTIONAL_ARG = 1U << 0, /* Same as optional_argument in getopt */
OPTION_STOPS_PARSING = 1U << 1, /* This option acts like "--" */
OPTION_GROUP_MARKER = 1U << 2, /* Fake option entry to separate groups */
OPTION_HELP_ENTRY = 1U << 3, /* Fake option entry to insert an additional help line */
OPTION_OPTIONAL_ARG = 1U << 0, /* Same as optional_argument in getopt */
OPTION_STOPS_PARSING = 1U << 1, /* This option acts like "--" */
OPTION_GROUP_MARKER = 1U << 2, /* Fake option entry to separate groups */
OPTION_HELP_ENTRY = 1U << 3, /* Fake option entry to insert an additional help line */
OPTION_HELP_ENTRY_VERBATIM = 1U << 4, /* Same, but use the long_code in the first column as written */
} OptionFlags;
typedef struct Option {
@@ -49,6 +50,7 @@ typedef struct Option {
#define OPTION_LONG_FLAGS(fl, lc, mv, h) OPTION_FULL(fl, /* sc= */ 0, lc, mv, h)
#define OPTION_SHORT(sc, mv, h) OPTION(sc, /* lc= */ NULL, mv, h)
#define OPTION_SHORT_FLAGS(fl, sc, mv, h) OPTION_FULL(fl, sc, /* lc= */ NULL, mv, h)
#define OPTION_HELP_VERBATIM(lc, h) OPTION_FULL(OPTION_HELP_ENTRY_VERBATIM, /* sc= */ 0, lc, /* mv= */ NULL, h)
#define OPTION_COMMON_HELP \
OPTION('h', "help", NULL, "Show this help")