[RFC PATCH 11/11] doc: commands: Recommend getopt() for option parsing

Simon Glass sjg at chromium.org
Fri May 15 22:33:02 CEST 2026


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 <sjg at chromium.org>
---

 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



More information about the U-Boot mailing list