]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
shared/options: add option to generate a help line for custom option format
authorZbigniew Jędrzejewski-Szmek <zbyszek@amutable.com>
Fri, 10 Apr 2026 17:06:00 +0000 (19:06 +0200)
committerZbigniew Jędrzejewski-Szmek <zbyszek@amutable.com>
Sat, 11 Apr 2026 07:54:56 +0000 (09:54 +0200)
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.

src/shared/options.c
src/shared/options.h

index e5206e641d80b84e633f34b8af3f34053e4d52d6..dc2fb34cf62f2199965d8edef7a1fa5cefc88667 100644 (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);
-
-                /* 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) ? "]" : "");
+                _cleanup_free_ char *s = NULL;
+
+                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();
 
index e834cbededa4f776a4db26963c6438225c2baeaf..e8256059d15cb171dbdccd0fedb67086dbd73d43 100644 (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")