[RFC PATCH v2 11/17] cmd: nvedit: Use getopt() in env import

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


This is the other gnarly hand-rolled parser in nvedit.c

The code walks each -prefixed argv element by hand, opens an inner
while (*++arg) to split grouped flags, and tracks a fmt counter to
catch a second -b / -c / -t

getopt() collapses all of that. The mutex check for the format flags
stays in the case arms (it is a per-command rule, not an option-parsing
rule) and the trailing positional list is read straight out of
gs.args + gs.index with gs.nonopts as the count.

Permutation now lets options follow positional arguments, so an
out-of-order 'import 0x... -t -d' is accepted alongside the
conventional 'import -t -d 0x...'.

Tests cover a setenv/export/clear/import roundtrip with -d, and an
out-of-order 'import 0x... -t -d' invocation.

Adjust CMD_IMPORTENV to select GETOPT so the parser is linked in on
boards that did not already enable it.

Also redo the sep_err logic and error message, along with a fmt tweak
to reduce code size.

Signed-off-by: Simon Glass <sjg at chromium.org>
---

(no changes since v1)

 cmd/nvedit.c | 95 ++++++++++++++++++++++++----------------------------
 env/common.c |  2 +-
 2 files changed, 45 insertions(+), 52 deletions(-)

diff --git a/cmd/nvedit.c b/cmd/nvedit.c
index f2cad21b5f4..5fca52b58a7 100644
--- a/cmd/nvedit.c
+++ b/cmd/nvedit.c
@@ -750,64 +750,63 @@ static int do_env_export(struct cmd_tbl *cmdtp, int flag,
 static int do_env_import(struct cmd_tbl *cmdtp, int flag,
 			 int argc, char *const argv[])
 {
+	struct getopt_state gs;
 	ulong	addr;
-	char	*cmd, *ptr;
+	char	*ptr, *tok;
 	char	sep = '\n';
 	int	chk = 0;
 	int	fmt = 0;
 	int	del = 0;
 	int	crlf_is_lf = 0;
-	int	wl = 0;
 	size_t	size;
+	int	opt;
 
-	cmd = *argv;
-
-	while (--argc > 0 && **++argv == '-') {
-		char *arg = *argv;
-		while (*++arg) {
-			switch (*arg) {
-			case 'b':		/* raw binary format */
-				if (fmt++)
-					goto sep_err;
-				sep = '\0';
-				break;
-			case 'c':		/* external checksum format */
-				if (fmt++)
-					goto sep_err;
-				sep = '\0';
-				chk = 1;
-				break;
-			case 't':		/* text format */
-				if (fmt++)
-					goto sep_err;
-				sep = '\n';
-				break;
-			case 'r':		/* handle CRLF like LF */
-				crlf_is_lf = 1;
-				break;
-			case 'd':
-				del = 1;
-				break;
-			default:
-				return CMD_RET_USAGE;
-			}
+	getopt_init_state(&gs, argc, argv);
+	while ((opt = getopt(&gs, "bctrd")) > 0) {
+		fmt++;
+		switch (opt) {
+		case 'b':		/* raw binary format */
+			sep = '\0';
+			break;
+		case 'c':		/* external checksum format */
+			sep = '\0';
+			chk = 1;
+			break;
+		case 't':		/* text format (default) */
+			break;
+		case 'r':		/* handle CRLF like LF */
+			crlf_is_lf = 1;
+			fmt--;
+			break;
+		case 'd':
+			del = 1;
+			fmt--;
+			break;
+		default:
+			return CMD_RET_USAGE;
 		}
 	}
 
-	if (argc < 1)
+	if (gs.nonopts < 1)
+		return CMD_RET_USAGE;
+	if (fmt > 1) {
+		printf("## Error: %s: only one of -b/c/t allowed\n", argv[0]);
+
 		return CMD_RET_USAGE;
+	}
 
 	if (!fmt)
 		printf("## Warning: defaulting to text format\n");
 
-	if (sep != '\n' && crlf_is_lf )
+	if (sep != '\n' && crlf_is_lf)
 		crlf_is_lf = 0;
 
-	addr = hextoul(argv[0], NULL);
+	addr = hextoul(getopt_pop(&gs), NULL);
 	ptr = map_sysmem(addr, 0);
 
-	if (argc >= 2 && strcmp(argv[1], "-")) {
-		size = hextoul(argv[1], NULL);
+	tok = getopt_pop(&gs);		/* size, "-", or absent */
+	if (tok && strcmp(tok, "-")) {
+		size = hextoul(tok, NULL);
 	} else if (chk) {
 		puts("## Error: external checksum format must pass size\n");
 		return CMD_RET_FAILURE;
@@ -823,22 +822,19 @@ static int do_env_import(struct cmd_tbl *cmdtp, int flag,
 			++size;
 		}
 		if (size == MAX_ENV_SIZE) {
-			printf("## Warning: Input data exceeds %d bytes"
+			printf("## Warning: Input exceeds %d bytes"
 				" - truncated\n", MAX_ENV_SIZE);
 		}
 		size += 2;
-		printf("## Info: input data size = %zu = 0x%zX\n", size, size);
+		printf("## Info: input size = %zu = %#zX\n", size, size);
 	}
 
-	if (argc > 2)
-		wl = 1;
-
 	if (chk) {
 		uint32_t crc;
 		env_t *ep = (env_t *)ptr;
 
 		if (size <= offsetof(env_t, data)) {
-			printf("## Error: Invalid size 0x%zX\n", size);
+			printf("## Error: Invalid size %#zX\n", size);
 			return 1;
 		}
 
@@ -853,19 +849,16 @@ static int do_env_import(struct cmd_tbl *cmdtp, int flag,
 	}
 
 	if (!himport_r(&env_htab, ptr, size, sep, del ? 0 : H_NOCLEAR,
-		       crlf_is_lf, wl ? argc - 2 : 0, wl ? &argv[2] : NULL)) {
-		pr_err("## Error: Environment import failed: errno = %d\n",
+		       crlf_is_lf,
+		       gs.nonopts ?: 0,
+		       gs.nonopts ? &gs.argv[gs.index] : NULL)) {
+		pr_err("## Error: Environment import failed (err %dE)\n",
 		       errno);
 		return 1;
 	}
 	gd->flags |= GD_FLG_ENV_READY;
 
 	return 0;
-
-sep_err:
-	printf("## %s: only one of \"-b\", \"-c\" or \"-t\" allowed\n",
-		cmd);
-	return 1;
 }
 #endif
 
diff --git a/env/common.c b/env/common.c
index b2adbe93dbe..986400f912f 100644
--- a/env/common.c
+++ b/env/common.c
@@ -402,7 +402,7 @@ void env_set_default(const char *s, int flags)
 	if (himport_r(&env_htab, default_environment,
 			sizeof(default_environment), '\0', flags, 0,
 			0, NULL) == 0) {
-		pr_err("## Error: Environment import failed: errno = %d\n",
+		pr_err("## Error: Environment import failed (err %dE)\n",
 		       errno);
 		return;
 	}
-- 
2.43.0



More information about the U-Boot mailing list