hush: finish and enable optional case...esac support. Code size cost:
authorDenis Vlasenko <vda.linux@googlemail.com>
Mon, 28 Jul 2008 00:01:16 +0000 (00:01 -0000)
committerDenis Vlasenko <vda.linux@googlemail.com>
Mon, 28 Jul 2008 00:01:16 +0000 (00:01 -0000)
function                                             old     new   delta
run_list                                            1891    2075    +184
parse_stream                                        1764    1847     +83
expand_strvec_to_string                                -      83     +83
done_word                                            647     715     +68
static.reserved_list                                 144     168     +24
static.reserved_match                                  -      12     +12
done_pipe                                             95     105     +10
builtin_exit                                          48      46      -2
builtin_eval                                         127      54     -73
------------------------------------------------------------------------------
(add/remove: 2/0 grow/shrink: 5/2 up/down: 464/-75)           Total: 389 bytes

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

index f4a9e7b1c176e0a274867e3dfe11f3f0b3e858e2..ee2f832fae042e7b09e191dcedc24b19aab2e81d 100644 (file)
@@ -178,9 +178,11 @@ config HUSH
          hush is a very small shell (just 18k) and it has fairly complete
          Bourne shell grammar. It even handles all the normal flow control
          options such as if/then/elif/else/fi, for/in/do/done, while loops,
-         etc.
+         case/esac.
 
-         It does not handle case/esac, select, function, here documents ( <<
+         It uses only vfork, so it can be used on uClinux systems.
+
+         It does not handle select, functions, here documents ( <<
          word ), arithmetic expansion, aliases, brace expansion, tilde
          expansion, &> and >& redirection of stdout+stderr, etc.
 
@@ -232,6 +234,14 @@ config HUSH_LOOPS
        depends on HUSH
        help
          Enable for, while and until loops in hush.
+         As of 2008-07, break and continue statements are not supported.
+
+config HUSH_CASE
+       bool "Support case ... esac statement"
+       default n
+       depends on HUSH
+       help
+         Enable case ... esac statement in hush. +400 bytes.
 
 config LASH
        bool "lash"
@@ -249,7 +259,7 @@ config MSH
          shell to do. It is not always pedantically correct about Bourne
          shell grammar (try running the shell testscript "tests/sh.testcases"
          on it and compare vs bash) but for most things it works quite well.
-         It also uses only vfork, so it can be used on uClinux systems.
+         It uses only vfork, so it can be used on uClinux systems.
 
 comment "Bourne Shell Options"
        depends on MSH || LASH || HUSH || ASH
index cf6a18f86207db67d4eda832cf23362043c5a30c..5a565b392b62b0b78c689e30b74c3809d1dc18f4 100644 (file)
  * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
  */
 
-
-#include <glob.h>      /* glob, of course */
-/* #include <dmalloc.h> */
-
 #include "busybox.h" /* for APPLET_IS_NOFORK/NOEXEC */
-
-// TEMP
-#define ENABLE_HUSH_CASE 0
+#include <glob.h>
+/* #include <dmalloc.h> */
+#if ENABLE_HUSH_CASE
+#include <fnmatch.h>
+#endif
 
 
 #if !BB_MMU && ENABLE_HUSH_TICK
@@ -2064,6 +2062,10 @@ static int run_list(struct pipe *pi)
        rpipe = NULL;
 #endif
 
+       /* Past this point, all code paths should jump to ret: label
+        * in order to return, no direct "return" statements.
+        * This helps to ensure that no memory is leaked */
+
 #if ENABLE_HUSH_JOB
        /* Example of nested list: "while true; do { sleep 1 | exit 2; } done".
         * We are saving state before entering outermost list ("while...done")
@@ -2170,6 +2172,7 @@ static int run_list(struct pipe *pi)
                        if (!*for_lcur) {
                                /* for loop is over, clean up */
                                free(for_list);
+                               for_list = NULL;
                                for_lcur = NULL;
                                flag_rep = 0;
                                pi->progs->argv[0] = for_varname;
@@ -2195,14 +2198,21 @@ static int run_list(struct pipe *pi)
 #endif
 #if ENABLE_HUSH_CASE
                if (rword == RES_CASE) {
-                       case_word = pi->progs->argv[0];
+                       case_word = expand_strvec_to_string(pi->progs->argv);
+                       //bb_error_msg("case: arg:'%s' case_word:'%s'", pi->progs->argv[0], case_word);
                        continue;
                }
                if (rword == RES_MATCH) {
                        if (case_word) {
-                               next_if_code = strcmp(case_word, pi->progs->argv[0]);
-                               if (next_if_code == 0)
+                               char *pattern = expand_strvec_to_string(pi->progs->argv);
+                               /* TODO: which FNM_xxx flags to use? */
+                               next_if_code = fnmatch(pattern, case_word, /*flags:*/ 0);
+                               //bb_error_msg("fnmatch('%s','%s'):%d", pattern, case_word, next_if_code);
+                               free(pattern);
+                               if (next_if_code == 0) {
+                                       free(case_word);
                                        case_word = NULL;
+                               }
                                continue;
                        }
                        break;
@@ -2276,6 +2286,12 @@ static int run_list(struct pipe *pi)
        }
 #endif
        debug_printf_exec("run_list lvl %d return %d\n", run_list_level + 1, rcode);
+#if ENABLE_HUSH_LOOPS
+       free(for_list);
+#endif
+#if ENABLE_HUSH_CASE
+       free(case_word);
+#endif
        return rcode;
 }
 
diff --git a/shell/hush_test/hush-misc/case1.right b/shell/hush_test/hush-misc/case1.right
new file mode 100644 (file)
index 0000000..9b88658
--- /dev/null
@@ -0,0 +1,13 @@
+OK_1
+OK_21
+OK_22
+OK_23
+OK_31
+OK_32
+OK_41
+OK_42
+OK_43
+OK_44
+OK_51
+OK_52
+OK_53
diff --git a/shell/hush_test/hush-misc/case1.tests b/shell/hush_test/hush-misc/case1.tests
new file mode 100755 (executable)
index 0000000..15f60f3
--- /dev/null
@@ -0,0 +1,17 @@
+case w in a) echo SKIP;; w) echo OK_1;; w) echo WRONG;; esac
+
+t=w
+case $t in a) echo SKIP;; w) echo OK_21;; w) echo WRONG;; esac;
+case "$t" in a) echo SKIP;; w) echo OK_22;; w) echo WRONG;; esac;
+case w in a) echo SKIP;; $t) echo OK_23;; "$t") echo WRONG;; esac;
+
+case '' in a) echo SKIP;; w) echo WRONG;; *) echo OK_31;; esac;
+case '' in a) echo SKIP;; '') echo OK_32;; *) echo WRONG;; esac;
+
+case `echo w` in a) echo SKIP;; w) echo OK_41;; w) echo WRONG;; esac;
+case "`echo w`" in a) echo SKIP;; w) echo OK_42;; w) echo WRONG;; esac;
+case `echo w w` in a) echo SKIP;; w) echo WRONG;; 'w w') echo OK_43;; esac;
+case `echo w w` in a) echo SKIP;; w) echo WRONG;; w*) echo OK_44;; esac;
+
+case w in `echo w`) echo OK_51;; `echo WRONG >&2`w) echo WRONG;; esac;
+case w in `echo OK_52 >&2`) echo SKIP;; `echo`w) echo OK_53;; esac;