do_env_export() is one of the gnarliest hand-rolled parsers in the env code. It walks each - argument by hand, opens an inner while (*++arg) to split grouped flags, tracks an fmt counter to reject a second -b/-c/-t and uses a goto NXTARG to skip the rest of the current element after -s has eaten the following argument for its size.
Replace all of that with getopt(). Move do_env_export() to the getopt-state command signature, declared with U_BOOT_CMD_MKENT_GETOPT(). The -s argument arrives in gs->arg. Move the format-flag mutual-exclusion check after the option loop (it is a per-command rule, not an option-parsing rule) and read the trailing positional list from gs->argv[gs->index]. Keep the + prefix on the optstring so getopt() stops at the first non-option, exactly as the hand-rolled loop did. While here, write the text-format filesize with env_set_hex() rather than an open-coded sprintf() into a stack buffer. This drops the buffer and matches the binary path, which already uses env_set_hex(); the only visible change is that the value is now lower-case hex (its consumers read it with hextoul(), which is case-insensitive). Check the return value of both env_set_hex() calls and return 1 on failure, rather than ignoring it. Route the env subcommand dispatch in do_env() through cmd_invoke() so subcommands using either signature are called correctly. CMD_EXPORTENV selects GETOPT so the parser is linked in on boards that do not already enable it. Also redo the sep_err logic, use env_set_hex() and shorten error messages to reduce code size. Signed-off-by: Simon Glass <[email protected]> --- (no changes since v2) Changes in v2: - Redo the sep_err logic to reduce code size cmd/Kconfig | 1 + cmd/nvedit.c | 80 +++++++++++++++++++++++++--------------------------- 2 files changed, 39 insertions(+), 42 deletions(-) diff --git a/cmd/Kconfig b/cmd/Kconfig index 3c5abddd31f..e3d92055f17 100644 --- a/cmd/Kconfig +++ b/cmd/Kconfig @@ -704,6 +704,7 @@ config CMD_ASKENV config CMD_EXPORTENV bool "env export" default y + select GETOPT help Export environments. diff --git a/cmd/nvedit.c b/cmd/nvedit.c index 636bddee1be..c74898a05fb 100644 --- a/cmd/nvedit.c +++ b/cmd/nvedit.c @@ -29,6 +29,7 @@ #include <console.h> #include <env.h> #include <env_internal.h> +#include <getopt.h> #include <log.h> #include <search.h> #include <errno.h> @@ -631,10 +632,8 @@ static int do_env_delete(struct cmd_tbl *cmdtp, int flag, * * => env import -d -t ${backup_addr} */ -static int do_env_export(struct cmd_tbl *cmdtp, int flag, - int argc, char *const argv[]) +static int do_env_export(struct getopt_state *gs) { - char buf[32]; ulong addr; char *ptr, *cmd, *res; size_t size = 0; @@ -643,52 +642,48 @@ static int do_env_export(struct cmd_tbl *cmdtp, int flag, char sep = '\n'; int chk = 0; int fmt = 0; + int argc; + char *const *argv; + int opt; - cmd = *argv; + cmd = gs->argv[0]; - 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 's': /* size given */ - if (--argc <= 0) - return cmd_usage(cmdtp); - size = hextoul(*++argv, NULL); - goto NXTARG; - case 't': /* text format */ - if (fmt++) - goto sep_err; - sep = '\n'; - break; - default: - return CMD_RET_USAGE; - } + while ((opt = getopt(gs, "+bcs:t")) > 0) { + switch (opt) { + case 'b': /* raw binary format */ + sep = '\0'; + fmt++; + break; + case 'c': /* external checksum format */ + sep = '\0'; + chk = 1; + fmt++; + break; + case 's': /* size given */ + size = hextoul(gs->arg, NULL); + break; + case 't': /* text format */ + sep = '\n'; + fmt++; + break; + default: + return CMD_RET_USAGE; } -NXTARG: ; } + if (fmt > 1) + goto sep_err; - if (argc < 1) + if (gs->index >= gs->argc) return CMD_RET_USAGE; - addr = hextoul(argv[0], NULL); + addr = hextoul(getopt_pop(gs), NULL); ptr = map_sysmem(addr, size); if (size) memset(ptr, '\0', size); - argc--; - argv++; + argc = gs->argc - gs->index; + argv = &gs->argv[gs->index]; if (sep) { /* export as text file */ len = hexport_r(&env_htab, sep, @@ -699,8 +694,8 @@ NXTARG: ; errno); return 1; } - sprintf(buf, "%zX", (size_t)len); - env_set("filesize", buf); + if (env_set_hex("filesize", len)) + return 1; return 0; } @@ -728,7 +723,8 @@ NXTARG: ; envp->flags = ENV_REDUND_ACTIVE; #endif } - env_set_hex("filesize", len + offsetof(env_t, data)); + if (env_set_hex("filesize", len + offsetof(env_t, data))) + return 1; return 0; @@ -1077,7 +1073,7 @@ static struct cmd_tbl cmd_env_sub[] = { U_BOOT_CMD_MKENT(flags, 1, 0, do_env_flags, "", ""), #endif #if defined(CONFIG_CMD_EXPORTENV) - U_BOOT_CMD_MKENT(export, 4, 0, do_env_export, "", ""), + U_BOOT_CMD_MKENT_GETOPT(export, 4, 0, do_env_export, "", ""), #endif #if defined(CONFIG_CMD_GREPENV) U_BOOT_CMD_MKENT(grep, CONFIG_SYS_MAXARGS, 1, do_env_grep, "", ""), @@ -1127,7 +1123,7 @@ static int do_env(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) cp = find_cmd_tbl(argv[0], cmd_env_sub, ARRAY_SIZE(cmd_env_sub)); if (cp) - return cp->cmd(cmdtp, flag, argc, argv); + return cmd_invoke(cp, flag, argc, argv); return CMD_RET_USAGE; } -- 2.43.0

