From d690f68554f1c1301975bc0ab0e479e6870b3589 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Mon, 30 Mar 2009 06:50:54 +0000 Subject: [PATCH] implement `unset` semantics as required by POSIX --- shell/hush.c | 44 ++++++++++++++++++++++----- shell/hush_test/hush-vars/unset.right | 19 ++++++++++++ shell/hush_test/hush-vars/unset.tests | 36 ++++++++++++++++++++++ 3 files changed, 92 insertions(+), 7 deletions(-) create mode 100644 shell/hush_test/hush-vars/unset.right create mode 100755 shell/hush_test/hush-vars/unset.tests diff --git a/shell/hush.c b/shell/hush.c index a7aa32abe..cd6e12b11 100644 --- a/shell/hush.c +++ b/shell/hush.c @@ -1000,21 +1000,21 @@ static int set_local_var(char *str, int flg_export) return 0; } -static void unset_local_var(const char *name) +static int unset_local_var(const char *name) { struct variable *cur; struct variable *prev = prev; /* for gcc */ int name_len; if (!name) - return; + return EXIT_SUCCESS; name_len = strlen(name); cur = G.top_var; while (cur) { if (strncmp(cur->varstr, name, name_len) == 0 && cur->varstr[name_len] == '=') { if (cur->flg_read_only) { bb_error_msg("%s: readonly variable", name); - return; + return EXIT_FAILURE; } /* prev is ok to use here because 1st variable, HUSH_VERSION, * is ro, and we cannot reach this code on the 1st pass */ @@ -1024,11 +1024,12 @@ static void unset_local_var(const char *name) if (!cur->max_len) free(cur->varstr); free(cur); - return; + return EXIT_SUCCESS; } prev = cur; cur = cur->next; } + return EXIT_SUCCESS; } @@ -5025,11 +5026,40 @@ static int builtin_umask(char **argv) return EXIT_SUCCESS; } +/* http://www.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#unset */ static int builtin_unset(char **argv) { - /* bash always returns true */ - unset_local_var(argv[1]); - return EXIT_SUCCESS; + size_t i; + int ret; + bool var = true; + + if (!argv[1]) + return EXIT_SUCCESS; + + i = 0; + if (argv[1][0] == '-') { + switch (argv[1][1]) { + case 'v': break; + case 'f': if (ENABLE_HUSH_FUNCTIONS) { var = false; break; } + default: + bb_error_msg("unset: %s: invalid option", argv[1]); + return EXIT_FAILURE; + } + ++i; + } + + ret = EXIT_SUCCESS; + while (argv[++i]) { + if (var) { + if (unset_local_var(argv[i])) + ret = EXIT_FAILURE; + } +#if ENABLE_HUSH_FUNCTIONS + else + unset_local_func(argv[i]); +#endif + } + return ret; } /* http://www.opengroup.org/onlinepubs/9699919799/utilities/wait.html */ diff --git a/shell/hush_test/hush-vars/unset.right b/shell/hush_test/hush-vars/unset.right new file mode 100644 index 000000000..8dea7c40d --- /dev/null +++ b/shell/hush_test/hush-vars/unset.right @@ -0,0 +1,19 @@ +hush: unset: -: invalid option +1 +hush: unset: -m: invalid option +1 +0 +___ +0 f g +0 g +0 +___ +0 f g +0 +0 f g +0 +___ +hush: HUSH_VERSION: readonly variable +1 f g +hush: HUSH_VERSION: readonly variable +1 diff --git a/shell/hush_test/hush-vars/unset.tests b/shell/hush_test/hush-vars/unset.tests new file mode 100755 index 000000000..f59ce5923 --- /dev/null +++ b/shell/hush_test/hush-vars/unset.tests @@ -0,0 +1,36 @@ +# check invalid options are rejected +unset - +echo $? +unset -m a b c +echo $? + +# check funky usage +unset +echo $? + +# check normal usage +echo ___ +f=f g=g +echo $? $f $g +unset f +echo $? $f $g +unset g +echo $? $f $g + +echo ___ +f=f g=g +echo $? $f $g +unset f g +echo $? $f $g +f=f g=g +echo $? $f $g +unset -v f g +echo $? $f $g + +# check read only vars +echo ___ +f=f g=g +unset HUSH_VERSION +echo $? $f $g +unset f HUSH_VERSION g +echo $? $f $g