Skip to content

Dummy pull request to show verb table draft#40771

Closed
keszybz wants to merge 11 commits intosystemd:mainfrom
keszybz:dummy-pull-request-to-show-verb-table-draft
Closed

Dummy pull request to show verb table draft#40771
keszybz wants to merge 11 commits intosystemd:mainfrom
keszybz:dummy-pull-request-to-show-verb-table-draft

Conversation

@keszybz
Copy link
Member

@keszybz keszybz commented Feb 20, 2026

@poettering See last commit for example of verb handling

keszybz and others added 10 commits February 19, 2026 22:12
The basic idea is that we'll have "one source of truth" for the list of
options. Currently, this is split between:
  1. struct option options[] array for long options
  2. the short option parameter to getopt_long()
  3. --help
so it is easy to forget to add or update one of those places where
appropriate.

The code is easier to read when various parts are written in the same
order. This is true even for the generated code, which is properly
formatted and should be as readable as the original.

Using a generator allows us to define various parts of the boilerplate
just once. Over time, if we discover that the same pattern is used in
multiple files, we can move it to the generator.

The C file contains the parsing code, and metadata about option names
and help strings in comments with custom formatting. That is parsed
and file is generated with C code, and that file is #include'd into
the source file.

To view the generated code, use:
  tools/make_option_parser.py src/path/to/foo.c
This is a bit convoluted because of our template system which means that
executables are processed in the top-level build directory and because
of clangd which would be confused if the top-level directory was used
for intermediate files. So the generation is split out to a subdir
similarly to version.h.
--version was not documented. Fixup for 0d1d512.
--host, --machine, --no-ask-password stamps are added to the generator.
--cat-config, --tldr stamps are added to the generator.
Some cosmetic differences in descriptions are made.
--quiet was miscategorized as a command (172fadd),
--usr-hash and --usr-hash-sig were not listed (10b8d65).
Cosmetic adjustments to help strings.
I got confused, I thought that match stmts are allowed.
@keszybz keszybz marked this pull request as draft February 20, 2026 14:32
@keszybz keszybz force-pushed the dummy-pull-request-to-show-verb-table-draft branch from 74146e2 to 11f9973 Compare February 20, 2026 14:34

args = parser.parse_args()

input = open(args.input).read().splitlines()

Check warning

Code scanning / CodeQL

File is not always closed Warning

File is opened but is not closed.
@keszybz
Copy link
Member Author

keszybz commented Feb 20, 2026

Ah, this works for systemd-id128, but fails if the verb list is empty, i.e. for everything else. I hope that is good enough for a basic PoC. Fixed with a temporary condition to disable the verb table generation if one is already present in the file.

This compiled and mostly works, but is incomplete:
- verb help is skipped (because verb_help was is not defined in source .c)
- argument count parsing is not done: can we figure out
  (minargs, maxargs) from the help spec? If not, we need to configure
  that somehow.

Generated code:

  #define OPTSTRING "hjpPa:u"

  static int help(void);

  static int _unused_ verb_help(int argc, char *argv[], void *userdata) {
          return help();
  }

  #define OPTION_HELP_GENERATED \
          "  -h --help             Show this help\n" \
          "     --version          Show package version\n" \
          "     --no-pager         Do not start the pager\n" \
          "     --no-legend        Do not show headers or footers\n" \
          "     --json=FORMAT      Output as JSON (one of pretty, short, off)\n" \
          "  -j                    Equivalent to --json=pretty (on TTY) or --json=short\n" \
          "                        (otherwise)\n" \
          "  -p --pretty           Generate samples of program code\n" \
          "  -P --value            Only print the value\n" \
          "  -a --app-specific=ID  Generate app-specific IDs\n" \
          "  -u --uuid             Output in UUID format\n" \
          ""

  #define VERB_HELP_GENERATED \
          "  new                   Generate a new ID\n" \
          "  machine-id            Print the ID of current machine\n" \
          "  boot-id               Print the ID of current boot\n" \
          "  invocation-id         Print the ID of current invocation\n" \
          "  var-uuid              Print the UUID for the /var/ partition\n" \
          "  show [NAME|UUID]      Print one or more UUIDs\n" \
          ""

  enum {
          OPTION_HELP         = 'h',
          OPTION_VERSION      = 0x101,
          OPTION_NO_PAGER     = 0x102,
          OPTION_NO_LEGEND    = 0x103,
          OPTION_JSON         = 0x104,
          OPTION_SHORT_j      = 'j',
          OPTION_PRETTY       = 'p',
          OPTION_VALUE        = 'P',
          OPTION_APP_SPECIFIC = 'a',
          OPTION_UUID         = 'u',
  };

  static const struct option options[] = {
          { "help",         no_argument,       NULL, OPTION_HELP         },
          { "version",      no_argument,       NULL, OPTION_VERSION      },
          { "no-pager",     no_argument,       NULL, OPTION_NO_PAGER     },
          { "no-legend",    no_argument,       NULL, OPTION_NO_LEGEND    },
          { "json",         required_argument, NULL, OPTION_JSON         },
          { "pretty",       no_argument,       NULL, OPTION_PRETTY       },
          { "value",        no_argument,       NULL, OPTION_VALUE        },
          { "app-specific", required_argument, NULL, OPTION_APP_SPECIFIC },
          { "uuid",         no_argument,       NULL, OPTION_UUID         },
          {}
  };

  static int verb_new(int, char**, void*);
  static int verb_machine_id(int, char**, void*);
  static int verb_boot_id(int, char**, void*);
  static int verb_invocation_id(int, char**, void*);
  static int verb_var_uuid(int, char**, void*);
  static int verb_show(int, char**, void*);

  static const Verb verbs[] = {
          { "new",           VERB_ANY, 1,        0, verb_new           },
          { "machine-id",    VERB_ANY, 1,        0, verb_machine_id    },
          { "boot-id",       VERB_ANY, 1,        0, verb_boot_id       },
          { "invocation-id", VERB_ANY, 1,        0, verb_invocation_id },
          { "var-uuid",      VERB_ANY, 1,        0, verb_var_uuid      },
          { "show",          VERB_ANY, VERB_ANY, 0, verb_show          },
          {}
  };
@keszybz keszybz force-pushed the dummy-pull-request-to-show-verb-table-draft branch from 11f9973 to 37c9cbb Compare February 20, 2026 16:17
@keszybz keszybz closed this Mar 2, 2026
@github-actions github-actions bot removed the please-review PR is ready for (re-)review by a maintainer label Mar 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Development

Successfully merging this pull request may close these issues.

1 participant