- don't free user-supplied string (via -e)
[oweals/busybox.git] / libbb / getopt32.c
index 9e53dfd084746e9e40ba91104d4e43f545465e2f..9dba44db26cd05d9484db562d003a195533f2d85 100644 (file)
@@ -117,7 +117,7 @@ const char *opt_complementary
         if w is given once, GNU ps sets the width to 132,
         if w is given more than once, it is "unlimited"
 
-        int w_counter = 0;
+        int w_counter = 0; // must be initialized!
         opt_complementary = "ww";
         getopt32(argv, "w", &w_counter);
         if (w_counter)
@@ -137,7 +137,7 @@ const char *opt_complementary
         opt_complementary = "vv:b::b-c:c-b";
         f = getopt32(argv, "vb:c", &my_b, &verbose_level);
         if (f & 2)       // -c after -b unsets -b flag
-                while (my_b) { dosomething_with(my_b->data); my_b = my_b->link; }
+                while (my_b) dosomething_with(llist_pop(&my_b));
         if (my_b)        // but llist is stored if -b is specified
                 free_llist(my_b);
         if (verbose_level) printf("verbose level is %d\n", verbose_level);
@@ -220,7 +220,7 @@ Special characters:
  "x--x" Variation of the above, it means that -x option should occur
         at most once.
 
- "a+:"  A plus after a char in opt_complementary means that the parameter
+ "a+  A plus after a char in opt_complementary means that the parameter
         for this option is a nonnegative integer. It will be processed
         with xatoi_u() - allowed range is 0..INT_MAX.
 
@@ -255,7 +255,7 @@ Special characters:
         For example from "id" applet:
 
         // Don't allow -n -r -rn -ug -rug -nug -rnug
-        opt_complementary = "r?ug:n?ug:?u--g:g--u";
+        opt_complementary = "r?ug:n?ug:u--g:g--u";
         flags = getopt32(argv, "rnug");
 
         This example allowed only:
@@ -285,6 +285,10 @@ const char *const bb_argv_dash[] = { "-", NULL };
 
 const char *opt_complementary;
 
+/* Many small applets don't want to suck in stdio.h only because
+ * they need to parse options by calling us */
+#define DONT_USE_PRINTF 1
+
 enum {
        PARAM_STRING,
        PARAM_LIST,
@@ -312,7 +316,7 @@ const char *applet_long_options;
 
 uint32_t option_mask32;
 
-uint32_t
+uint32_t FAST_FUNC
 getopt32(char **argv, const char *applet_opts, ...)
 {
        int argc;
@@ -335,7 +339,8 @@ getopt32(char **argv, const char *applet_opts, ...)
 #define SHOW_USAGE_IF_ERROR     1
 #define ALL_ARGV_IS_OPTS        2
 #define FIRST_ARGV_IS_OPT       4
-#define FREE_FIRST_ARGV_IS_OPT  8
+#define FREE_FIRST_ARGV_IS_OPT  (8 * !DONT_USE_PRINTF)
+
        int spec_flgs = 0;
 
        argc = 0;
@@ -490,9 +495,15 @@ getopt32(char **argv, const char *applet_opts, ...)
 
        if (spec_flgs & FIRST_ARGV_IS_OPT) {
                if (argv[1] && argv[1][0] != '-' && argv[1][0] != '\0') {
+#if DONT_USE_PRINTF
+                       char *pp = alloca(strlen(argv[1]) + 2);
+                       *pp = '-';
+                       strcpy(pp + 1, argv[1]);
+                       argv[1] = pp;
+#else
                        argv[1] = xasprintf("-%s", argv[1]);
-                       if (ENABLE_FEATURE_CLEAN_UP)
-                               spec_flgs |= FREE_FIRST_ARGV_IS_OPT;
+                       spec_flgs |= FREE_FIRST_ARGV_IS_OPT;
+#endif
                }
        }
 
@@ -545,11 +556,15 @@ getopt32(char **argv, const char *applet_opts, ...)
                if (on_off->counter)
                        (*(on_off->counter))++;
                if (on_off->param_type == PARAM_LIST) {
-                       llist_add_to_end((llist_t **)(on_off->optarg), optarg);
+                       if (optarg)
+                               llist_add_to_end((llist_t **)(on_off->optarg), optarg);
                } else if (on_off->param_type == PARAM_INT) {
-                       *(unsigned*)(on_off->optarg) = xatoi_u(optarg);
+                       if (optarg)
+//TODO: xatoi_u indirectly pulls in printf machinery
+                               *(unsigned*)(on_off->optarg) = xatoi_u(optarg);
                } else if (on_off->optarg) {
-                       *(char **)(on_off->optarg) = optarg;
+                       if (optarg)
+                               *(char **)(on_off->optarg) = optarg;
                }
                if (pargv != NULL)
                        break;
@@ -570,10 +585,9 @@ getopt32(char **argv, const char *applet_opts, ...)
                }
        }
 
-#if (ENABLE_AR || ENABLE_TAR) && ENABLE_FEATURE_CLEAN_UP
        if (spec_flgs & FREE_FIRST_ARGV_IS_OPT)
                free(argv[1]);
-#endif
+
        /* check depending requires for given options */
        for (on_off = complementary; on_off->opt_char; on_off++) {
                if (on_off->requires && (flags & on_off->switch_on) &&