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.
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"
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
* 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
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")
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;
#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;
}
#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;
}
--- /dev/null
+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
--- /dev/null
+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;