[RFC PATCH v2 00/17] Tidy command option parsing and use it a bit

Simon Glass sjg at chromium.org
Wed May 20 01:31:26 CEST 2026


We have had getopt() for over five years but it is not much used. It is
much easier to understand arg-parsing using getopt() and it avoids
common errors. As the named maintainer I decided to look at how to make
more use of it.

So this series explores the impact of converting a few commands to use
getopt() instead of ad-hoc parsing. It updates getopt() to handle flags
anywhere in the cmdline and provides a few helpers to reduce
boilerplate.

The chosen commands are:

- echo: very simple with one flag and fixed ordering (worst case?)
- hash: fairly simple with just one flag
- env grep/export/import - fuller examples

The series also adds a recommendation to use getopt() for new commands.

To try to reduce the code-size increase, a lower-case function is added
and called from a few places. The difference is fairly marginal.

v2 includes further attempts to reduce code size, by making reordering
a Kconfig option, dropping some printing and some intensive optimisation
of the env commands.

Overall, the result is not ideal (see below) with about a 850-byte
size-increase on arm64:
  01: smbios: Do not fall back on devicetree without valid mapping
     aarch64:  w+   firefly-rk3399
  02: lib: string: Add strlower()
  03: cmd: ini: Use strlower() to normalise case
  04: fs: fat: Use strlower() to normalise case
     aarch64: (for 1/1 boards) all -24.0 text -24.0
  05: boot: pxe_utils: Use strlower() in get_string()
     aarch64: (for 1/1 boards) all -36.0 text -36.0
  06: lib: getopt: Permute by default with inline reorder
  07: lib: getopt: Add getopt_pop() helper
  08: cmd: echo: Use getopt() with '+' prefix for option parsing
     aarch64: (for 1/1 boards) all +1243.0 rodata +175.0 text +1068.0
  09: cmd: hash: Use getopt() for option parsing
  10: cmd: nvedit: Use getopt() in env grep
  11: cmd: nvedit: Use getopt() in env export
     aarch64: (for 1/1 boards) all -5.0 rodata +27.0 text -32.0
  12: cmd: nvedit: Use getopt() in env import
     aarch64: (for 1/1 boards) all +45.0 rodata -55.0 text +100.0
  13: lib: getopt: Tidy up two minor redundancies
     aarch64: (for 1/1 boards) all -4.0 text -4.0
  14: lib: getopt: Drop printed error messages and the silent variant
     aarch64: (for 1/1 boards) all -129.0 rodata -61.0 text -68.0
  15: lib: getopt: Merge the optional and required-argument branches
     aarch64: (for 1/1 boards) all -84.0 text -84.0
  16: lib: getopt: Hoist the arg_index==1 guard
     aarch64: (for 1/1 boards) all -4.0 text -4.0
  17: lib: getopt: Add a Kconfig to drop the permutation code
     aarch64: (for 1/1 boards) all -80.0 text -80.0
  18: doc: commands: Recommend getopt() for option parsing

for a total of:

  18: doc: commands: Recommend getopt() for option parsing
     aarch64: (for 1/1 boards) all +922.0 rodata +86.0 text +836.0

Ideally we would use getopt() everywhere. The small increase in each
case is partially resolved in v2, but it isn't clear that this would be
achieveable in every case in future.

One option would be to make the getopt_init_state() in command.c and
pass struct getopt_state to the commands. This would reduce code size at
each size, but obviously requires a different command signature, unless
a global is used.

Another small improvement could be to include a getopt function to
return the next arg as hex.

Ideas are welcome!

Changes in v2:
- Use "permute" terminology in docs and comments
- Move the working argv array to the top of struct getopt_state and
  rename it from @args to @argv (drops inter-field padding too)
- Refine kerneldoc for @index
- Restore the original worked example in getopt()'s kerneldoc
- Add tests for permuted argv, a required argument missing after a
  leading non-option, and the '+' prefix
- Redo the sep_err logic to reduce code size

Simon Glass (17):
  lib: string: Add strlower()
  cmd: ini: Use strlower() to normalise case
  fs: fat: Use strlower() to normalise case
  boot: pxe_utils: Use strlower() in get_string()
  lib: getopt: Permute by default with inline reorder
  lib: getopt: Add getopt_pop() helper
  cmd: echo: Use getopt() with '+' prefix for option parsing
  cmd: hash: Use getopt() for option parsing
  cmd: nvedit: Use getopt() in env grep
  cmd: nvedit: Use getopt() in env export
  cmd: nvedit: Use getopt() in env import
  lib: getopt: Tidy up two minor redundancies
  lib: getopt: Drop printed error messages and the silent variant
  lib: getopt: Merge the optional and required-argument branches
  lib: getopt: Hoist the arg_index==1 guard
  lib: getopt: Add a Kconfig to drop the permutation code
  doc: commands: Recommend getopt() for option parsing

 boot/pxe_utils.c         |  12 +-
 cmd/Kconfig              |   4 +
 cmd/bdinfo.c             |   4 +-
 cmd/echo.c               |  23 ++--
 cmd/hash.c               |  37 +++---
 cmd/ini.c                |  21 ++--
 cmd/log.c                |  12 +-
 cmd/nvedit.c             | 240 ++++++++++++++++++---------------------
 doc/develop/commands.rst |  62 ++++++++++
 env/common.c             |   2 +-
 fs/fat/fat.c             |  20 +---
 fs/fat/fat_write.c       |   2 +-
 include/getopt.h         | 100 ++++++++++------
 include/linux/string.h   |  12 ++
 lib/Kconfig              |  14 +++
 lib/getopt.c             | 140 +++++++++++++----------
 lib/string.c             |  10 ++
 test/cmd/test_echo.c     |  10 ++
 test/lib/getopt.c        |  47 +++++++-
 test/lib/string.c        |  27 +++++
 20 files changed, 497 insertions(+), 302 deletions(-)

---
base-commit: 215496fec59b3fa09256b4fb62f92af46e2ec7f9
branch: clid2

-- 
2.43.0



More information about the U-Boot mailing list