hush: fix var3.tests
authorDenys Vlasenko <vda.linux@googlemail.com>
Sun, 2 Oct 2016 19:12:02 +0000 (21:12 +0200)
committerDenys Vlasenko <vda.linux@googlemail.com>
Sun, 2 Oct 2016 19:12:02 +0000 (21:12 +0200)
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
shell/hush.c
shell/hush_test/hush-bugs/var3.right [deleted file]
shell/hush_test/hush-bugs/var3.tests [deleted file]
shell/hush_test/hush-vars/var3.is.in.bugs [deleted file]
shell/hush_test/hush-vars/var3.right [new file with mode: 0644]
shell/hush_test/hush-vars/var3.tests [new file with mode: 0755]

index 8054d1d4561ec2abf3047179835f72f4281a3c2c..5990d690c3dbd520d9e1d34bc242ddebf6977a21 100644 (file)
@@ -8733,6 +8733,14 @@ static void helper_export_local(char **argv, int exp, int lvl)
                                        continue;
                                }
                        }
+#if ENABLE_HUSH_LOCAL
+                       if (exp == 0 /* local? */
+                        && var && var->func_nest_level == lvl
+                       ) {
+                               /* "local x=abc; ...; local x" - ignore second local decl */
+                               continue; 
+                       }
+#endif
                        /* Exporting non-existing variable.
                         * bash does not put it in environment,
                         * but remembers that it is exported,
@@ -8807,6 +8815,212 @@ static int FAST_FUNC builtin_local(char **argv)
 }
 #endif
 
+/* http://www.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#unset */
+static int FAST_FUNC builtin_unset(char **argv)
+{
+       int ret;
+       unsigned opts;
+
+       /* "!": do not abort on errors */
+       /* "+": stop at 1st non-option */
+       opts = getopt32(argv, "!+vf");
+       if (opts == (unsigned)-1)
+               return EXIT_FAILURE;
+       if (opts == 3) {
+               bb_error_msg("unset: -v and -f are exclusive");
+               return EXIT_FAILURE;
+       }
+       argv += optind;
+
+       ret = EXIT_SUCCESS;
+       while (*argv) {
+               if (!(opts & 2)) { /* not -f */
+                       if (unset_local_var(*argv)) {
+                               /* unset <nonexistent_var> doesn't fail.
+                                * Error is when one tries to unset RO var.
+                                * Message was printed by unset_local_var. */
+                               ret = EXIT_FAILURE;
+                       }
+               }
+#if ENABLE_HUSH_FUNCTIONS
+               else {
+                       unset_func(*argv);
+               }
+#endif
+               argv++;
+       }
+       return ret;
+}
+
+/* http://www.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#set
+ * built-in 'set' handler
+ * SUSv3 says:
+ * set [-abCefhmnuvx] [-o option] [argument...]
+ * set [+abCefhmnuvx] [+o option] [argument...]
+ * set -- [argument...]
+ * set -o
+ * set +o
+ * Implementations shall support the options in both their hyphen and
+ * plus-sign forms. These options can also be specified as options to sh.
+ * Examples:
+ * Write out all variables and their values: set
+ * Set $1, $2, and $3 and set "$#" to 3: set c a b
+ * Turn on the -x and -v options: set -xv
+ * Unset all positional parameters: set --
+ * Set $1 to the value of x, even if it begins with '-' or '+': set -- "$x"
+ * Set the positional parameters to the expansion of x, even if x expands
+ * with a leading '-' or '+': set -- $x
+ *
+ * So far, we only support "set -- [argument...]" and some of the short names.
+ */
+static int FAST_FUNC builtin_set(char **argv)
+{
+       int n;
+       char **pp, **g_argv;
+       char *arg = *++argv;
+
+       if (arg == NULL) {
+               struct variable *e;
+               for (e = G.top_var; e; e = e->next)
+                       puts(e->varstr);
+               return EXIT_SUCCESS;
+       }
+
+       do {
+               if (strcmp(arg, "--") == 0) {
+                       ++argv;
+                       goto set_argv;
+               }
+               if (arg[0] != '+' && arg[0] != '-')
+                       break;
+               for (n = 1; arg[n]; ++n) {
+                       if (set_mode((arg[0] == '-'), arg[n], argv[1]))
+                               goto error;
+                       if (arg[n] == 'o' && argv[1])
+                               argv++;
+               }
+       } while ((arg = *++argv) != NULL);
+       /* Now argv[0] is 1st argument */
+
+       if (arg == NULL)
+               return EXIT_SUCCESS;
+ set_argv:
+
+       /* NB: G.global_argv[0] ($0) is never freed/changed */
+       g_argv = G.global_argv;
+       if (G.global_args_malloced) {
+               pp = g_argv;
+               while (*++pp)
+                       free(*pp);
+               g_argv[1] = NULL;
+       } else {
+               G.global_args_malloced = 1;
+               pp = xzalloc(sizeof(pp[0]) * 2);
+               pp[0] = g_argv[0]; /* retain $0 */
+               g_argv = pp;
+       }
+       /* This realloc's G.global_argv */
+       G.global_argv = pp = add_strings_to_strings(g_argv, argv, /*dup:*/ 1);
+
+       n = 1;
+       while (*++pp)
+               n++;
+       G.global_argc = n;
+
+       return EXIT_SUCCESS;
+
+       /* Nothing known, so abort */
+ error:
+       bb_error_msg("set: %s: invalid option", arg);
+       return EXIT_FAILURE;
+}
+
+static int FAST_FUNC builtin_shift(char **argv)
+{
+       int n = 1;
+       argv = skip_dash_dash(argv);
+       if (argv[0]) {
+               n = atoi(argv[0]);
+       }
+       if (n >= 0 && n < G.global_argc) {
+               if (G.global_args_malloced) {
+                       int m = 1;
+                       while (m <= n)
+                               free(G.global_argv[m++]);
+               }
+               G.global_argc -= n;
+               memmove(&G.global_argv[1], &G.global_argv[n+1],
+                               G.global_argc * sizeof(G.global_argv[0]));
+               return EXIT_SUCCESS;
+       }
+       return EXIT_FAILURE;
+}
+
+/* Interruptibility of read builtin in bash
+ * (tested on bash-4.2.8 by sending signals (not by ^C)):
+ *
+ * Empty trap makes read ignore corresponding signal, for any signal.
+ *
+ * SIGINT:
+ * - terminates non-interactive shell;
+ * - interrupts read in interactive shell;
+ * if it has non-empty trap:
+ * - executes trap and returns to command prompt in interactive shell;
+ * - executes trap and returns to read in non-interactive shell;
+ * SIGTERM:
+ * - is ignored (does not interrupt) read in interactive shell;
+ * - terminates non-interactive shell;
+ * if it has non-empty trap:
+ * - executes trap and returns to read;
+ * SIGHUP:
+ * - terminates shell (regardless of interactivity);
+ * if it has non-empty trap:
+ * - executes trap and returns to read;
+ */
+static int FAST_FUNC builtin_read(char **argv)
+{
+       const char *r;
+       char *opt_n = NULL;
+       char *opt_p = NULL;
+       char *opt_t = NULL;
+       char *opt_u = NULL;
+       const char *ifs;
+       int read_flags;
+
+       /* "!": do not abort on errors.
+        * Option string must start with "sr" to match BUILTIN_READ_xxx
+        */
+       read_flags = getopt32(argv, "!srn:p:t:u:", &opt_n, &opt_p, &opt_t, &opt_u);
+       if (read_flags == (uint32_t)-1)
+               return EXIT_FAILURE;
+       argv += optind;
+       ifs = get_local_var_value("IFS"); /* can be NULL */
+
+ again:
+       r = shell_builtin_read(set_local_var_from_halves,
+               argv,
+               ifs,
+               read_flags,
+               opt_n,
+               opt_p,
+               opt_t,
+               opt_u
+       );
+
+       if ((uintptr_t)r == 1 && errno == EINTR) {
+               unsigned sig = check_and_run_traps();
+               if (sig && sig != SIGINT)
+                       goto again;
+       }
+
+       if ((uintptr_t)r > 1) {
+               bb_error_msg("%s", r);
+               r = (char*)(uintptr_t)1;
+       }
+
+       return (uintptr_t)r;
+}
+
 static int FAST_FUNC builtin_trap(char **argv)
 {
        int sig;
@@ -9075,175 +9289,6 @@ static int FAST_FUNC builtin_pwd(char **argv UNUSED_PARAM)
        return EXIT_SUCCESS;
 }
 
-/* Interruptibility of read builtin in bash
- * (tested on bash-4.2.8 by sending signals (not by ^C)):
- *
- * Empty trap makes read ignore corresponding signal, for any signal.
- *
- * SIGINT:
- * - terminates non-interactive shell;
- * - interrupts read in interactive shell;
- * if it has non-empty trap:
- * - executes trap and returns to command prompt in interactive shell;
- * - executes trap and returns to read in non-interactive shell;
- * SIGTERM:
- * - is ignored (does not interrupt) read in interactive shell;
- * - terminates non-interactive shell;
- * if it has non-empty trap:
- * - executes trap and returns to read;
- * SIGHUP:
- * - terminates shell (regardless of interactivity);
- * if it has non-empty trap:
- * - executes trap and returns to read;
- */
-static int FAST_FUNC builtin_read(char **argv)
-{
-       const char *r;
-       char *opt_n = NULL;
-       char *opt_p = NULL;
-       char *opt_t = NULL;
-       char *opt_u = NULL;
-       const char *ifs;
-       int read_flags;
-
-       /* "!": do not abort on errors.
-        * Option string must start with "sr" to match BUILTIN_READ_xxx
-        */
-       read_flags = getopt32(argv, "!srn:p:t:u:", &opt_n, &opt_p, &opt_t, &opt_u);
-       if (read_flags == (uint32_t)-1)
-               return EXIT_FAILURE;
-       argv += optind;
-       ifs = get_local_var_value("IFS"); /* can be NULL */
-
- again:
-       r = shell_builtin_read(set_local_var_from_halves,
-               argv,
-               ifs,
-               read_flags,
-               opt_n,
-               opt_p,
-               opt_t,
-               opt_u
-       );
-
-       if ((uintptr_t)r == 1 && errno == EINTR) {
-               unsigned sig = check_and_run_traps();
-               if (sig && sig != SIGINT)
-                       goto again;
-       }
-
-       if ((uintptr_t)r > 1) {
-               bb_error_msg("%s", r);
-               r = (char*)(uintptr_t)1;
-       }
-
-       return (uintptr_t)r;
-}
-
-/* http://www.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#set
- * built-in 'set' handler
- * SUSv3 says:
- * set [-abCefhmnuvx] [-o option] [argument...]
- * set [+abCefhmnuvx] [+o option] [argument...]
- * set -- [argument...]
- * set -o
- * set +o
- * Implementations shall support the options in both their hyphen and
- * plus-sign forms. These options can also be specified as options to sh.
- * Examples:
- * Write out all variables and their values: set
- * Set $1, $2, and $3 and set "$#" to 3: set c a b
- * Turn on the -x and -v options: set -xv
- * Unset all positional parameters: set --
- * Set $1 to the value of x, even if it begins with '-' or '+': set -- "$x"
- * Set the positional parameters to the expansion of x, even if x expands
- * with a leading '-' or '+': set -- $x
- *
- * So far, we only support "set -- [argument...]" and some of the short names.
- */
-static int FAST_FUNC builtin_set(char **argv)
-{
-       int n;
-       char **pp, **g_argv;
-       char *arg = *++argv;
-
-       if (arg == NULL) {
-               struct variable *e;
-               for (e = G.top_var; e; e = e->next)
-                       puts(e->varstr);
-               return EXIT_SUCCESS;
-       }
-
-       do {
-               if (strcmp(arg, "--") == 0) {
-                       ++argv;
-                       goto set_argv;
-               }
-               if (arg[0] != '+' && arg[0] != '-')
-                       break;
-               for (n = 1; arg[n]; ++n) {
-                       if (set_mode((arg[0] == '-'), arg[n], argv[1]))
-                               goto error;
-                       if (arg[n] == 'o' && argv[1])
-                               argv++;
-               }
-       } while ((arg = *++argv) != NULL);
-       /* Now argv[0] is 1st argument */
-
-       if (arg == NULL)
-               return EXIT_SUCCESS;
- set_argv:
-
-       /* NB: G.global_argv[0] ($0) is never freed/changed */
-       g_argv = G.global_argv;
-       if (G.global_args_malloced) {
-               pp = g_argv;
-               while (*++pp)
-                       free(*pp);
-               g_argv[1] = NULL;
-       } else {
-               G.global_args_malloced = 1;
-               pp = xzalloc(sizeof(pp[0]) * 2);
-               pp[0] = g_argv[0]; /* retain $0 */
-               g_argv = pp;
-       }
-       /* This realloc's G.global_argv */
-       G.global_argv = pp = add_strings_to_strings(g_argv, argv, /*dup:*/ 1);
-
-       n = 1;
-       while (*++pp)
-               n++;
-       G.global_argc = n;
-
-       return EXIT_SUCCESS;
-
-       /* Nothing known, so abort */
- error:
-       bb_error_msg("set: %s: invalid option", arg);
-       return EXIT_FAILURE;
-}
-
-static int FAST_FUNC builtin_shift(char **argv)
-{
-       int n = 1;
-       argv = skip_dash_dash(argv);
-       if (argv[0]) {
-               n = atoi(argv[0]);
-       }
-       if (n >= 0 && n < G.global_argc) {
-               if (G.global_args_malloced) {
-                       int m = 1;
-                       while (m <= n)
-                               free(G.global_argv[m++]);
-               }
-               G.global_argc -= n;
-               memmove(&G.global_argv[1], &G.global_argv[n+1],
-                               G.global_argc * sizeof(G.global_argv[0]));
-               return EXIT_SUCCESS;
-       }
-       return EXIT_FAILURE;
-}
-
 static int FAST_FUNC builtin_source(char **argv)
 {
        char *arg_path, *filename;
@@ -9334,43 +9379,6 @@ static int FAST_FUNC builtin_umask(char **argv)
        return !rc; /* rc != 0 - success */
 }
 
-/* http://www.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#unset */
-static int FAST_FUNC builtin_unset(char **argv)
-{
-       int ret;
-       unsigned opts;
-
-       /* "!": do not abort on errors */
-       /* "+": stop at 1st non-option */
-       opts = getopt32(argv, "!+vf");
-       if (opts == (unsigned)-1)
-               return EXIT_FAILURE;
-       if (opts == 3) {
-               bb_error_msg("unset: -v and -f are exclusive");
-               return EXIT_FAILURE;
-       }
-       argv += optind;
-
-       ret = EXIT_SUCCESS;
-       while (*argv) {
-               if (!(opts & 2)) { /* not -f */
-                       if (unset_local_var(*argv)) {
-                               /* unset <nonexistent_var> doesn't fail.
-                                * Error is when one tries to unset RO var.
-                                * Message was printed by unset_local_var. */
-                               ret = EXIT_FAILURE;
-                       }
-               }
-#if ENABLE_HUSH_FUNCTIONS
-               else {
-                       unset_func(*argv);
-               }
-#endif
-               argv++;
-       }
-       return ret;
-}
-
 /* http://www.opengroup.org/onlinepubs/9699919799/utilities/wait.html */
 static int FAST_FUNC builtin_wait(char **argv)
 {
diff --git a/shell/hush_test/hush-bugs/var3.right b/shell/hush_test/hush-bugs/var3.right
deleted file mode 100644 (file)
index 8eb0e33..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-1
-1
-
-
-0
diff --git a/shell/hush_test/hush-bugs/var3.tests b/shell/hush_test/hush-bugs/var3.tests
deleted file mode 100755 (executable)
index 97b102c..0000000
+++ /dev/null
@@ -1 +0,0 @@
-x=0; f() { local x=1; echo $x; local x; echo $x; unset x; echo $x; local x; echo $x; }; f; echo $x
diff --git a/shell/hush_test/hush-vars/var3.is.in.bugs b/shell/hush_test/hush-vars/var3.is.in.bugs
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/shell/hush_test/hush-vars/var3.right b/shell/hush_test/hush-vars/var3.right
new file mode 100644 (file)
index 0000000..8eb0e33
--- /dev/null
@@ -0,0 +1,5 @@
+1
+1
+
+
+0
diff --git a/shell/hush_test/hush-vars/var3.tests b/shell/hush_test/hush-vars/var3.tests
new file mode 100755 (executable)
index 0000000..97b102c
--- /dev/null
@@ -0,0 +1 @@
+x=0; f() { local x=1; echo $x; local x; echo $x; unset x; echo $x; local x; echo $x; }; f; echo $x