The nested while/switch parser walks each -prefixed argv element by hand. The -- end-of-options marker is implemented by a case '-' arm that does 'goto DONE' to jump out of both the inner switch and the outer argv walker, leaving the remaining argv to be treated as positionals by hexport_r().
getopt() handles all of that natively: grouped flags (-nb), the '--' boundary (it returns -1 and advances past --), unknown-option errors and option permutation so 'env grep arch -n' works the same as 'env grep -n arch'. The goto, the label, and the case '-' arm all disappear. Pass "envb" or "nvb" to getopt() depending on IS_ENABLED(CONFIG_REGEX) so -e is not advertised when regex is compiled out, and guard the case 'e' arm with the same check so it costs nothing in the regex-off build. Move the missing-argument check to after parsing. The existing argc < 2 check fires only when no args at all are given; the new gs.nonopts < 1 check also catches 'env grep -n' (options but no search pattern), where the previous version would silently let hexport_r() run with an empty pattern list. CMD_GREPENV selects GETOPT so the parser is linked in on boards that did not already enable it. Tweak the var declarations to use Reverse Christmas Tree. Signed-off-by: Simon Glass <[email protected]> --- cmd/Kconfig | 1 + cmd/nvedit.c | 56 +++++++++++++++++++++++++--------------------------- 2 files changed, 28 insertions(+), 29 deletions(-) diff --git a/cmd/Kconfig b/cmd/Kconfig index eb7c85c1fe9..8ba7b1e6bd1 100644 --- a/cmd/Kconfig +++ b/cmd/Kconfig @@ -721,6 +721,7 @@ config CMD_EDITENV config CMD_GREPENV bool "search env" + select GETOPT help Allow for searching environment variables diff --git a/cmd/nvedit.c b/cmd/nvedit.c index 636bddee1be..8561c408992 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> @@ -131,45 +132,42 @@ static int do_env_print(struct cmd_tbl *cmdtp, int flag, int argc, static int do_env_grep(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) { - char *res = NULL; int len, grep_how, grep_what; - - if (argc < 2) - return CMD_RET_USAGE; + struct getopt_state gs; + char *res = NULL; + int opt; grep_how = H_MATCH_SUBSTR; /* default: substring search */ grep_what = H_MATCH_BOTH; /* default: grep names and values */ - while (--argc > 0 && **++argv == '-') { - char *arg = *argv; - while (*++arg) { - switch (*arg) { -#ifdef CONFIG_REGEX - case 'e': /* use regex matching */ - grep_how = H_MATCH_REGEX; - break; -#endif - case 'n': /* grep for name */ - grep_what = H_MATCH_KEY; - break; - case 'v': /* grep for value */ - grep_what = H_MATCH_DATA; - break; - case 'b': /* grep for both */ - grep_what = H_MATCH_BOTH; - break; - case '-': - goto DONE; - default: - return CMD_RET_USAGE; - } + getopt_init_state(&gs, argc, argv); + while ((opt = getopt(&gs, IS_ENABLED(CONFIG_REGEX) ? "envb" + : "nvb")) > 0) { + switch (opt) { + case 'e': /* use regex matching */ + if (IS_ENABLED(CONFIG_REGEX)) + grep_how = H_MATCH_REGEX; + break; + case 'n': /* grep for name */ + grep_what = H_MATCH_KEY; + break; + case 'v': /* grep for value */ + grep_what = H_MATCH_DATA; + break; + case 'b': /* grep for both */ + grep_what = H_MATCH_BOTH; + break; + default: + return CMD_RET_USAGE; } } -DONE: + if (gs.nonopts < 1) + return CMD_RET_USAGE; + len = hexport_r(&env_htab, '\n', flag | grep_what | grep_how, - &res, 0, argc, argv); + &res, 0, gs.nonopts, &gs.args[gs.index]); if (len > 0) { puts(res); -- 2.43.0

