getopt32long does not allow handling options iteratively
this is in preparation of adding an option to split strings
which can be used for shebangs
---
 coreutils/env.c | 75 ++++++++++++++++++++++++++++++++++---------------
 1 file changed, 53 insertions(+), 22 deletions(-)

diff --git a/coreutils/env.c b/coreutils/env.c
index e9d3e883e..9ca1fad2d 100644
--- a/coreutils/env.c
+++ b/coreutils/env.c
@@ -50,51 +50,82 @@
 //usage:     "\n       -u NAME Remove variable from environment"
 
 #include "libbb.h"
+#include <getopt.h>
+
+static struct option const long_options[] = {
+       {"ignore-environment", no_argument,       0,  'i' },
+       {"null",               no_argument,       0,  '0' },
+       {"unset",              required_argument, 0,  'u' },
+       {0,                    0,                 0,  0 }
+};
+
+static char const short_options[] = "+iu:0";
+
+static char const **unset_vars;
+static int num_unset_vars;
+
+static void add_unset_var (char const *var)
+{
+       unset_vars = xrealloc(unset_vars, num_unset_vars + 1);
+       unset_vars[num_unset_vars++] = var;
+}
 
 int env_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
-int env_main(int argc UNUSED_PARAM, char **argv)
+int env_main(int argc, char **argv)
 {
        unsigned opts;
-       llist_t *unset_env = NULL;
-
-       opts = getopt32long(argv, "+i0u:*",
-                       "ignore-environment\0" No_argument       "i"
-                       "null\0"               No_argument       "0"
-                       "unset\0"              Required_argument "u"
-                       , &unset_env
-       );
-       argv += optind;
-       if (argv[0] && LONE_DASH(argv[0])) {
-               opts |= 1;
-               ++argv;
+       int optc;
+       bool ignore_environment = false;
+       bool null_terminate_output = false;
+
+       while ((optc = getopt_long(argc, argv, short_options, long_options, 
NULL)) != -1) {
+               switch (optc)
+               {
+               case 'i':
+                       ignore_environment = true;
+                       break;
+               case 'u':
+                       add_unset_var(optarg);
+                       break;
+               case '0':
+                       null_terminate_output = true;
+                       break;
+               default:
+                       exit(EXIT_FAILURE);
+               }
        }
-       if (opts & 1) {
+
+       if (optind < argc && LONE_DASH(argv[optind])) {
+               ignore_environment = true;
+               ++optind;
+       }
+       if (ignore_environment) {
                clearenv();
        }
-       while (unset_env) {
-               char *var = llist_pop(&unset_env);
+
+       for (int i = 0; i < num_unset_vars; ++i) {
                /* This does not handle -uVAR=VAL
                 * (coreutils _sets_ the variable in that case): */
                /*unsetenv(var);*/
                /* This does, but uses somewhan undocumented feature that
                 * putenv("name_without_equal_sign") unsets the variable: */
-               putenv(var);
+               putenv(unset_vars[i]);
        }
 
-       while (*argv && (strchr(*argv, '=') != NULL)) {
+       while (optind < argc && (strchr(argv[optind], '=') != NULL)) {
                if (putenv(*argv) < 0) {
                        bb_simple_perror_msg_and_die("putenv");
                }
-               ++argv;
+               ++optind;
        }
 
-       if (argv[0]) {
-               BB_EXECVP_or_die(argv);
+       if (optind < argc) {
+               BB_EXECVP_or_die(&argv[optind]);
        }
 
        if (environ) { /* clearenv() may set environ == NULL! */
                char **ep;
-               opts = (opts & 2) ? 0 : '\n';
+               opts = null_terminate_output ? 0 : '\n';
                for (ep = environ; *ep; ep++) {
                        printf("%s%c", *ep, opts);
                }
-- 
2.30.2

_______________________________________________
busybox mailing list
[email protected]
https://lists.busybox.net/mailman/listinfo/busybox

Reply via email to