hush: export -n support
authorDenis Vlasenko <vda.linux@googlemail.com>
Mon, 20 Apr 2009 22:04:21 +0000 (22:04 -0000)
committerDenis Vlasenko <vda.linux@googlemail.com>
Mon, 20 Apr 2009 22:04:21 +0000 (22:04 -0000)
function                                             old     new   delta
builtin_export                                       206     256     +50
set_local_var                                        248     265     +17
expand_variables                                    2204    2203      -1

shell/Config.in
shell/hush.c
shell/hush_test/hush-misc/export-n.right [new file with mode: 0644]
shell/hush_test/hush-misc/export-n.tests [new file with mode: 0755]

index 6cc11ce..57969f0 100644 (file)
@@ -232,6 +232,13 @@ config HUSH_FUNCTIONS
        help
          Enable support for shell functions in hush. +800 bytes.
 
+config HUSH_EXPORT_N
+       bool "Support export '-n' option"
+       default n
+       depends on HUSH
+       help
+         Enable support for export '-n' option in hush. It is a bash extension.
+
 config LASH
        bool "lash (deprecated: aliased to hush)"
        default n
index d086526..d59a5de 100644 (file)
@@ -1253,10 +1253,10 @@ static const char *get_local_var_value(const char *src)
 /* str holds "NAME=VAL" and is expected to be malloced.
  * We take ownership of it.
  * flg_export:
- *  0: do not export
- *  1: export
- * -1: if NAME is set, leave export status alone
- *     if NAME is not set, do not export
+ *  0: do not change export flag
+ *     (if creating new variable, flag will be 0)
+ *  1: set export flag and putenv the variable
+ * -1: clear export flag and unsetenv the variable
  * flg_read_only is set only when we handle -R var=val
  */
 #if BB_MMU
@@ -1297,6 +1297,7 @@ static int set_local_var(char *str, int flg_export, int flg_read_only)
                        free(str);
                        return -1;
                }
+//TODO: optimize out redundant unsetenv/putenv's?
                debug_printf_env("%s: unsetenv '%s'\n", __func__, str);
                unsetenv(str); /* just in case */
                *value = '=';
@@ -1331,8 +1332,13 @@ static int set_local_var(char *str, int flg_export, int flg_read_only)
        if (flg_export == 1)
                cur->flg_export = 1;
        if (cur->flg_export) {
-               debug_printf_env("%s: putenv '%s'\n", __func__, cur->varstr);
-               return putenv(cur->varstr);
+               if (flg_export == -1) {
+                       cur->flg_export = 0;
+                       /* unsetenv was already done */
+               } else {
+                       debug_printf_env("%s: putenv '%s'\n", __func__, cur->varstr);
+                       return putenv(cur->varstr);
+               }
        }
        return 0;
 }
@@ -2214,7 +2220,7 @@ static int expand_vars_to_list(o_string *output, int n, char *arg, char or_mask)
                                                                val = NULL;
                                                        } else {
                                                                char *new_var = xasprintf("%s=%s", var, val);
-                                                               set_local_var(new_var, -1, 0);
+                                                               set_local_var(new_var, 0, 0);
                                                        }
                                                }
                                        }
@@ -6400,7 +6406,9 @@ static void print_escaped(const char *s)
 
 static int builtin_export(char **argv)
 {
-       if (*++argv == NULL) {
+       unsigned opt_unexport;
+
+       if (argv[1] == NULL) {
                char **e = environ;
                if (e) {
                        while (*e) {
@@ -6426,15 +6434,33 @@ static int builtin_export(char **argv)
                return EXIT_SUCCESS;
        }
 
+#if ENABLE_HUSH_EXPORT_N
+       opt_unexport = getopt32(argv, "+n"); /* "+": stop at 1st non-option */
+       argv += optind;
+#else
+       opt_unexport = 0;
+       argv++;
+#endif
+
        do {
                char *name = *argv;
 
-               /* So far we do not check that name is valid */
+               /* So far we do not check that name is valid (TODO?) */
+
                if (strchr(name, '=') == NULL) {
-                       /* Exporting a name without a =VALUE */
                        struct variable *var;
 
                        var = get_local_var(name);
+                       if (opt_unexport) {
+                               /* export -n NAME (without =VALUE) */
+                               if (var) {
+                                       var->flg_export = 0;
+                                       debug_printf_env("%s: unsetenv '%s'\n", __func__, name);
+                                       unsetenv(name);
+                               } /* else: export -n NOT_EXISTING_VAR: no-op */
+                               continue;
+                       }
+                       /* export NAME (without =VALUE) */
                        if (var) {
                                var->flg_export = 1;
                                debug_printf_env("%s: putenv '%s'\n", __func__, var->varstr);
@@ -6448,10 +6474,13 @@ static int builtin_export(char **argv)
                         * We just set it to "" and export. */
                        name = xasprintf("%s=", name);
                } else {
-                       /* Exporting VAR=VALUE */
+                       /* (Un)exporting NAME=VALUE */
                        name = xstrdup(name);
                }
-               set_local_var(name, 1, 0);
+               set_local_var(name,
+                       /*export:*/ (opt_unexport ? -1 : 1),
+                       /*readonly:*/ 0
+               );
        } while (*++argv);
 
        return EXIT_SUCCESS;
diff --git a/shell/hush_test/hush-misc/export-n.right b/shell/hush_test/hush-misc/export-n.right
new file mode 100644 (file)
index 0000000..3d55bf7
--- /dev/null
@@ -0,0 +1,10 @@
+export aaa1="'''"
+export aaa2=''
+export aaa3="'''"'abc'
+export aaa8='8'
+aaa9=9
+aaa10=10
+Nothing:
+Nothing:
+Nothing:
+Done
diff --git a/shell/hush_test/hush-misc/export-n.tests b/shell/hush_test/hush-misc/export-n.tests
new file mode 100755 (executable)
index 0000000..5252a1e
--- /dev/null
@@ -0,0 +1,37 @@
+export aaa1="'''"
+export aaa2=""
+export aaa3="'''abc"
+export | grep aaa.=
+
+export -n aaa1
+unset aaa2; export -n aaa2="ghi"
+export -n aaa3="klm"
+export | grep aaa.=
+
+export aaa4=4 aaa5=5
+export -n aaa4=4n
+export -n aaa5
+export | grep aaa.=
+
+export aaa5=5 aaa6=6 aaa7=7 aaa8=8
+export -n aaa5 aaa6=6n aaa7
+export | grep aaa.=
+
+aaa9=9
+export -n aaa9
+set | grep ^aaa9=
+
+export aaa10=10
+export -n aaa10
+set | grep ^aaa10=
+
+
+export EXPORTED=qwe
+export -nnnnnn nnnnnn; echo "Nothing:"; env | grep nnnnnn
+
+export -n EXPORTED=123; echo "Nothing:"; env | grep ^EXPORTED
+
+export EXPORTED=qwe
+export -n EXPORTED; EXPORTED=123; echo "Nothing:"; env | grep ^EXPORTED
+
+echo Done