[PATCH v4 14/14] cmd: echo: Use getopt() for option parsing
Simon Glass
sjg at chromium.org
Wed Jul 1 13:42:34 CEST 2026
The open-coded check for -n only matches it as the first argument, so
'echo foo -n' treats -n as a literal argument while still relying on a
hand-rolled scan that exists in every option-parsing command. Convert
do_echo() to the getopt-state command signature and parse -n with
getopt().
Use a '+' prefix on the optstring so getopt() works in POSIX mode and
stops at the first non-option, matching the documented behaviour that
-n is only an option when it precedes the arguments. The positional
arguments are then printed from gs->argv[gs->index] onwards, so no
manual argc/argv juggling is needed. CMD_ECHO selects GETOPT.
This drops the cmd/echo.o text size from 334 to 320 bytes on sandbox.
Add a test case covering -n after an argument, which is now printed
literally with the trailing newline preserved.
Signed-off-by: Simon Glass <sjg at chromium.org>
---
(no changes since v1)
cmd/Kconfig | 1 +
cmd/echo.c | 26 ++++++++++++++------------
test/cmd/test_echo.c | 7 +++++++
3 files changed, 22 insertions(+), 12 deletions(-)
diff --git a/cmd/Kconfig b/cmd/Kconfig
index e100a08d271..8c73b136fa8 100644
--- a/cmd/Kconfig
+++ b/cmd/Kconfig
@@ -1927,6 +1927,7 @@ config CMD_CAT
config CMD_ECHO
bool "echo"
default y
+ select GETOPT
help
Echo args to console
diff --git a/cmd/echo.c b/cmd/echo.c
index d1346504cfb..ace6b71233b 100644
--- a/cmd/echo.c
+++ b/cmd/echo.c
@@ -5,27 +5,29 @@
*/
#include <command.h>
-#include <linux/string.h>
+#include <getopt.h>
-static int do_echo(struct cmd_tbl *cmdtp, int flag, int argc,
- char *const argv[])
+static int do_echo(struct getopt_state *gs)
{
- int i = 1;
bool space = false;
bool newline = true;
+ const char *arg;
+ int opt;
- if (argc > 1) {
- if (!strcmp(argv[1], "-n")) {
+ while ((opt = getopt(gs, "+n")) > 0) {
+ switch (opt) {
+ case 'n':
newline = false;
- ++i;
+ break;
+ default:
+ return CMD_RET_USAGE;
}
}
- for (; i < argc; ++i) {
- if (space) {
+ while ((arg = getopt_pop(gs))) {
+ if (space)
putc(' ');
- }
- puts(argv[i]);
+ puts(arg);
space = true;
}
@@ -35,7 +37,7 @@ static int do_echo(struct cmd_tbl *cmdtp, int flag, int argc,
return 0;
}
-U_BOOT_CMD(
+U_BOOT_CMD_GETOPT(
echo, CONFIG_SYS_MAXARGS, 1, do_echo,
"echo args to console",
"[-n] [args..]\n"
diff --git a/test/cmd/test_echo.c b/test/cmd/test_echo.c
index 7ed534742f7..64589e3656f 100644
--- a/test/cmd/test_echo.c
+++ b/test/cmd/test_echo.c
@@ -22,6 +22,13 @@ static struct test_data echo_data[] = {
/* Test new line handling */
{"echo -n 1 2 3; echo a b c",
"1 2 3a b c"},
+ /*
+ * Option parsing stops at the first non-option, so a -n which
+ * follows an argument is printed literally and the trailing
+ * newline is still emitted.
+ */
+ {"echo 1 -n 2",
+ "1 -n 2"},
/*
* Test handling of environment variables.
*
--
2.43.0
More information about the U-Boot
mailing list