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

Reply via email to