The getopt() helper in <getopt.h> has been available since 2020 but only two files in cmd/ actually use it; everything else hand-rolls argv loops to detect -x style flags. New commands keep using ad-hoc parsers because the developer guide for commands does not mention that a shared helper exists.
Add a "Parsing options" section to the commands documentation with a worked example. Signed-off-by: Simon Glass <[email protected]> --- doc/develop/commands.rst | 62 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/doc/develop/commands.rst b/doc/develop/commands.rst index 77a7a4d9c02..a1f0b59501d 100644 --- a/doc/develop/commands.rst +++ b/doc/develop/commands.rst @@ -118,6 +118,68 @@ CMD_RET_USAGE The command was called with invalid parameters. This value leads to the display of the usage string. +Parsing options +--------------- + +Commands that take options (``-x``, ``-f file``, etc.) should use the +getopt() helper in ``<getopt.h>`` rather than walking ``argv`` by hand. This +keeps option handling consistent across commands, supports grouped flags +(``-abc``) and arguments attached either to the option (``-ffile``) or in +the next argv entry (``-f file``), and produces sensible errors for unknown +or incomplete options. + +A typical use looks like: + +.. code-block:: c + + #include <getopt.h> + + static int do_foo(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) + { + struct getopt_state gs; + const char *file = NULL; + bool verbose = false; + int opt; + + getopt_init_state(&gs); + while ((opt = getopt(&gs, argc, argv, "vf:")) > 0) { + switch (opt) { + case 'v': + verbose = true; + break; + case 'f': + file = gs.arg; + break; + default: + return CMD_RET_USAGE; + } + } + + /* Positional arguments start at gs.index */ + if (gs.index >= argc) + return CMD_RET_USAGE; + + return do_the_work(file, verbose, argv[gs.index]); + } + +A few points worth noting: + +* Each command owns a ``struct getopt_state`` on the stack, so getopt() is + reentrant. There are no globals like ``optind`` or ``optarg``; the next + unparsed argument is at ``gs.index`` and the option argument (when one is + expected) is in ``gs.arg``. +* In the option string, ``x`` is a flag, ``x:`` requires an argument, and + ``x::`` takes an optional argument. +* Unlike POSIX getopt(), this implementation does **not** reorder ``argv``, + so options must appear before positional arguments. +* Returning ``CMD_RET_USAGE`` from the ``default`` case prints the command's + usage string for free; there is no need to call ``cmd_usage()`` directly. +* Use getopt_silent() if the command should suppress the built-in error + messages and report problems itself. + +For the full API, see :doc:`../api/getopt`. + Completion function ------------------- -- 2.43.0

