hush: finish and enable optional case...esac support. Code size cost:

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
This commit is contained in:
Denis Vlasenko 2008-07-28 00:01:16 +00:00
parent 8d523cbcd7
commit be709c24d4
4 changed files with 69 additions and 13 deletions

View File

@ -178,9 +178,11 @@ config HUSH
hush is a very small shell (just 18k) and it has fairly complete hush is a very small shell (just 18k) and it has fairly complete
Bourne shell grammar. It even handles all the normal flow control 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, 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 word ), arithmetic expansion, aliases, brace expansion, tilde
expansion, &> and >& redirection of stdout+stderr, etc. expansion, &> and >& redirection of stdout+stderr, etc.
@ -232,6 +234,14 @@ config HUSH_LOOPS
depends on HUSH depends on HUSH
help help
Enable for, while and until loops in hush. 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 config LASH
bool "lash" bool "lash"
@ -249,7 +259,7 @@ config MSH
shell to do. It is not always pedantically correct about Bourne shell to do. It is not always pedantically correct about Bourne
shell grammar (try running the shell testscript "tests/sh.testcases" shell grammar (try running the shell testscript "tests/sh.testcases"
on it and compare vs bash) but for most things it works quite well. 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" comment "Bourne Shell Options"
depends on MSH || LASH || HUSH || ASH depends on MSH || LASH || HUSH || ASH

View File

@ -67,14 +67,12 @@
* Licensed under the GPL v2 or later, see the file LICENSE in this tarball. * 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 */ #include "busybox.h" /* for APPLET_IS_NOFORK/NOEXEC */
#include <glob.h>
// TEMP /* #include <dmalloc.h> */
#define ENABLE_HUSH_CASE 0 #if ENABLE_HUSH_CASE
#include <fnmatch.h>
#endif
#if !BB_MMU && ENABLE_HUSH_TICK #if !BB_MMU && ENABLE_HUSH_TICK
@ -2064,6 +2062,10 @@ static int run_list(struct pipe *pi)
rpipe = NULL; rpipe = NULL;
#endif #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 #if ENABLE_HUSH_JOB
/* Example of nested list: "while true; do { sleep 1 | exit 2; } done". /* Example of nested list: "while true; do { sleep 1 | exit 2; } done".
* We are saving state before entering outermost list ("while...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) { if (!*for_lcur) {
/* for loop is over, clean up */ /* for loop is over, clean up */
free(for_list); free(for_list);
for_list = NULL;
for_lcur = NULL; for_lcur = NULL;
flag_rep = 0; flag_rep = 0;
pi->progs->argv[0] = for_varname; pi->progs->argv[0] = for_varname;
@ -2195,14 +2198,21 @@ static int run_list(struct pipe *pi)
#endif #endif
#if ENABLE_HUSH_CASE #if ENABLE_HUSH_CASE
if (rword == RES_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; continue;
} }
if (rword == RES_MATCH) { if (rword == RES_MATCH) {
if (case_word) { if (case_word) {
next_if_code = strcmp(case_word, pi->progs->argv[0]); char *pattern = expand_strvec_to_string(pi->progs->argv);
if (next_if_code == 0) /* 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; case_word = NULL;
}
continue; continue;
} }
break; break;
@ -2276,6 +2286,12 @@ static int run_list(struct pipe *pi)
} }
#endif #endif
debug_printf_exec("run_list lvl %d return %d\n", run_list_level + 1, rcode); 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; return rcode;
} }

View File

@ -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

View File

@ -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;