[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