hush: more fixes to variable expansion, more testcases
This commit is contained in:
parent
03eb8bf6ce
commit
764d59d488
69
shell/hush.c
69
shell/hush.c
@ -1308,6 +1308,8 @@ static void pseudo_exec_argv(char **argv)
|
|||||||
_exit(EXIT_SUCCESS);
|
_exit(EXIT_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
argv = do_variable_expansion(argv);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check if the command matches any of the builtins.
|
* Check if the command matches any of the builtins.
|
||||||
* Depending on context, this might be redundant. But it's
|
* Depending on context, this might be redundant. But it's
|
||||||
@ -1316,7 +1318,7 @@ static void pseudo_exec_argv(char **argv)
|
|||||||
*/
|
*/
|
||||||
for (x = bltins; x->cmd; x++) {
|
for (x = bltins; x->cmd; x++) {
|
||||||
if (strcmp(argv[0], x->cmd) == 0) {
|
if (strcmp(argv[0], x->cmd) == 0) {
|
||||||
debug_printf("builtin exec %s\n", argv[0]);
|
debug_printf_exec("running builtin '%s'\n", argv[0]);
|
||||||
rcode = x->function(argv);
|
rcode = x->function(argv);
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
_exit(rcode);
|
_exit(rcode);
|
||||||
@ -1334,6 +1336,7 @@ static void pseudo_exec_argv(char **argv)
|
|||||||
* to find ourself... */
|
* to find ourself... */
|
||||||
#if ENABLE_FEATURE_SH_STANDALONE
|
#if ENABLE_FEATURE_SH_STANDALONE
|
||||||
debug_printf("running applet %s\n", argv[0]);
|
debug_printf("running applet %s\n", argv[0]);
|
||||||
|
// FIXME: check NOEXEC bit, and EXEC if not set!
|
||||||
run_applet_and_exit(argv[0], argv);
|
run_applet_and_exit(argv[0], argv);
|
||||||
// is it ok that run_applet_and_exit() does exit(), not _exit()?
|
// is it ok that run_applet_and_exit() does exit(), not _exit()?
|
||||||
// NB: IIRC on NOMMU we are after _vfork_, not fork!
|
// NB: IIRC on NOMMU we are after _vfork_, not fork!
|
||||||
@ -1674,6 +1677,7 @@ static int run_pipe_real(struct pipe *pi)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (single_fg && child->argv != NULL) {
|
if (single_fg && child->argv != NULL) {
|
||||||
|
char **argv_expanded, **free_me;
|
||||||
char **argv = child->argv;
|
char **argv = child->argv;
|
||||||
|
|
||||||
for (i = 0; is_assignment(argv[i]); i++)
|
for (i = 0; is_assignment(argv[i]); i++)
|
||||||
@ -1714,16 +1718,7 @@ static int run_pipe_real(struct pipe *pi)
|
|||||||
putenv(xstrdup(p));
|
putenv(xstrdup(p));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (child->sp) {
|
free_me = NULL;
|
||||||
char *str;
|
|
||||||
|
|
||||||
str = make_string(argv + i);
|
|
||||||
debug_printf_exec(": parse_string_outer '%s'\n", str);
|
|
||||||
parse_string_outer(str, FLAG_EXIT_FROM_LOOP | FLAG_REPARSING);
|
|
||||||
free(str);
|
|
||||||
debug_printf_exec("run_pipe_real return %d\n", last_return_code);
|
|
||||||
return last_return_code;
|
|
||||||
}
|
|
||||||
for (x = bltins; x->cmd; x++) {
|
for (x = bltins; x->cmd; x++) {
|
||||||
if (strcmp(argv[i], x->cmd) == 0) {
|
if (strcmp(argv[i], x->cmd) == 0) {
|
||||||
if (x->function == builtin_exec && argv[i+1] == NULL) {
|
if (x->function == builtin_exec && argv[i+1] == NULL) {
|
||||||
@ -1739,7 +1734,11 @@ static int run_pipe_real(struct pipe *pi)
|
|||||||
// TODO: fflush(NULL)?
|
// TODO: fflush(NULL)?
|
||||||
setup_redirects(child, squirrel);
|
setup_redirects(child, squirrel);
|
||||||
debug_printf_exec(": builtin '%s' '%s'...\n", x->cmd, argv[i+1]);
|
debug_printf_exec(": builtin '%s' '%s'...\n", x->cmd, argv[i+1]);
|
||||||
rcode = x->function(argv + i);
|
argv_expanded = argv + i;
|
||||||
|
if (child->sp) /* btw we can do it unconditionally... */
|
||||||
|
free_me = argv_expanded = do_variable_expansion(argv + i);
|
||||||
|
rcode = x->function(argv_expanded);
|
||||||
|
free(free_me);
|
||||||
restore_redirects(squirrel);
|
restore_redirects(squirrel);
|
||||||
debug_printf_exec("run_pipe_real return %d\n", rcode);
|
debug_printf_exec("run_pipe_real return %d\n", rcode);
|
||||||
return rcode;
|
return rcode;
|
||||||
@ -1750,9 +1749,13 @@ static int run_pipe_real(struct pipe *pi)
|
|||||||
const struct bb_applet *a = find_applet_by_name(argv[i]);
|
const struct bb_applet *a = find_applet_by_name(argv[i]);
|
||||||
if (a && a->nofork) {
|
if (a && a->nofork) {
|
||||||
setup_redirects(child, squirrel);
|
setup_redirects(child, squirrel);
|
||||||
debug_printf_exec(": run_nofork_applet '%s' '%s'...\n", argv[i], argv[i+1]);
|
|
||||||
save_nofork_data(&nofork_save);
|
save_nofork_data(&nofork_save);
|
||||||
rcode = run_nofork_applet_prime(&nofork_save, a, argv + i);
|
argv_expanded = argv + i;
|
||||||
|
if (child->sp)
|
||||||
|
free_me = argv_expanded = do_variable_expansion(argv + i);
|
||||||
|
debug_printf_exec(": run_nofork_applet '%s' '%s'...\n", argv_expanded[0], argv_expanded[1]);
|
||||||
|
rcode = run_nofork_applet_prime(&nofork_save, a, argv_expanded);
|
||||||
|
free(free_me);
|
||||||
restore_redirects(squirrel);
|
restore_redirects(squirrel);
|
||||||
debug_printf_exec("run_pipe_real return %d\n", rcode);
|
debug_printf_exec("run_pipe_real return %d\n", rcode);
|
||||||
return rcode;
|
return rcode;
|
||||||
@ -2049,7 +2052,7 @@ static int run_list_real(struct pipe *pi)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
/* insert next value from for_lcur */
|
/* insert next value from for_lcur */
|
||||||
//vda: does it need escaping?
|
/* vda: does it need escaping? */
|
||||||
pi->progs->argv[0] = xasprintf("%s=%s", for_varname, *for_lcur++);
|
pi->progs->argv[0] = xasprintf("%s=%s", for_varname, *for_lcur++);
|
||||||
pi->progs->glob_result.gl_pathv[0] = pi->progs->argv[0];
|
pi->progs->glob_result.gl_pathv[0] = pi->progs->argv[0];
|
||||||
}
|
}
|
||||||
@ -2359,7 +2362,13 @@ static void count_var_expansion_space(int *countp, int *lenp, char *arg)
|
|||||||
default:
|
default:
|
||||||
*p = '\0';
|
*p = '\0';
|
||||||
arg[0] = first_ch & 0x7f;
|
arg[0] = first_ch & 0x7f;
|
||||||
val = lookup_param(arg);
|
if (isdigit(arg[0])) {
|
||||||
|
i = xatoi_u(arg);
|
||||||
|
val = NULL;
|
||||||
|
if (i < global_argc)
|
||||||
|
val = global_argv[i];
|
||||||
|
} else
|
||||||
|
val = lookup_param(arg);
|
||||||
arg[0] = first_ch;
|
arg[0] = first_ch;
|
||||||
*p = SPECIAL_VAR_SYMBOL;
|
*p = SPECIAL_VAR_SYMBOL;
|
||||||
|
|
||||||
@ -2380,7 +2389,7 @@ static void count_var_expansion_space(int *countp, int *lenp, char *arg)
|
|||||||
|
|
||||||
/* Store given string, finalizing the word and starting new one whenever
|
/* Store given string, finalizing the word and starting new one whenever
|
||||||
* we encounter ifs char(s). This is used for expanding variable values.
|
* we encounter ifs char(s). This is used for expanding variable values.
|
||||||
* End-of-string does NOT finalize word, because cases like echo -$VAR- */
|
* End-of-string does NOT finalize word: think about 'echo -$VAR-' */
|
||||||
static int expand_on_ifs(char **list, int n, char **posp, const char *str)
|
static int expand_on_ifs(char **list, int n, char **posp, const char *str)
|
||||||
{
|
{
|
||||||
char *pos = *posp;
|
char *pos = *posp;
|
||||||
@ -2390,15 +2399,14 @@ static int expand_on_ifs(char **list, int n, char **posp, const char *str)
|
|||||||
memcpy(pos, str, word_len); /* store non-ifs chars */
|
memcpy(pos, str, word_len); /* store non-ifs chars */
|
||||||
pos += word_len;
|
pos += word_len;
|
||||||
str += word_len;
|
str += word_len;
|
||||||
if (!*str) /* EOL - do not finalize word */
|
|
||||||
break;
|
|
||||||
*pos++ = '\0';
|
|
||||||
if (n) debug_printf_expand("expand_on_ifs finalized list[%d]=%p '%s' "
|
|
||||||
"strlen=%d next=%p pos=%p\n", n-1, list[n-1], list[n-1],
|
|
||||||
strlen(list[n-1]), list[n-1] + strlen(list[n-1]) + 1, pos);
|
|
||||||
list[n++] = pos;
|
|
||||||
}
|
}
|
||||||
if (!*str) break; /* EOL, not ifs char */
|
if (!*str) /* EOL - do not finalize word */
|
||||||
|
break;
|
||||||
|
*pos++ = '\0';
|
||||||
|
if (n) debug_printf_expand("expand_on_ifs finalized list[%d]=%p '%s' "
|
||||||
|
"strlen=%d next=%p pos=%p\n", n-1, list[n-1], list[n-1],
|
||||||
|
strlen(list[n-1]), list[n-1] + strlen(list[n-1]) + 1, pos);
|
||||||
|
list[n++] = pos;
|
||||||
str += strspn(str, ifs); /* skip ifs chars */
|
str += strspn(str, ifs); /* skip ifs chars */
|
||||||
}
|
}
|
||||||
*posp = pos;
|
*posp = pos;
|
||||||
@ -2478,7 +2486,13 @@ static int expand_vars_to_list(char **list, int n, char **posp, char *arg)
|
|||||||
default:
|
default:
|
||||||
*p = '\0';
|
*p = '\0';
|
||||||
arg[0] = first_ch & 0x7f;
|
arg[0] = first_ch & 0x7f;
|
||||||
val = lookup_param(arg);
|
if (isdigit(arg[0])) {
|
||||||
|
int i = xatoi_u(arg);
|
||||||
|
val = NULL;
|
||||||
|
if (i < global_argc)
|
||||||
|
val = global_argv[i];
|
||||||
|
} else
|
||||||
|
val = lookup_param(arg);
|
||||||
arg[0] = first_ch;
|
arg[0] = first_ch;
|
||||||
*p = SPECIAL_VAR_SYMBOL;
|
*p = SPECIAL_VAR_SYMBOL;
|
||||||
if (!(first_ch & 0x80)) { /* unquoted var */
|
if (!(first_ch & 0x80)) { /* unquoted var */
|
||||||
@ -3541,9 +3555,6 @@ static void update_ifs_map(void)
|
|||||||
* from builtin_source() */
|
* from builtin_source() */
|
||||||
static int parse_stream_outer(struct in_str *inp, int parse_flag)
|
static int parse_stream_outer(struct in_str *inp, int parse_flag)
|
||||||
{
|
{
|
||||||
// FIXME: '{ true | exit 3; echo $? }' is parsed as a whole,
|
|
||||||
// as a result $? is replaced by 0, not 3!
|
|
||||||
|
|
||||||
struct p_context ctx;
|
struct p_context ctx;
|
||||||
o_string temp = NULL_O_STRING;
|
o_string temp = NULL_O_STRING;
|
||||||
int rcode;
|
int rcode;
|
||||||
|
0
shell/hush_test/hush-bugs/quote3.tests
Normal file → Executable file
0
shell/hush_test/hush-bugs/quote3.tests
Normal file → Executable file
5
shell/hush_test/hush-vars/var_expand_in_assign.right
Normal file
5
shell/hush_test/hush-vars/var_expand_in_assign.right
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
. .
|
||||||
|
.abc d e.
|
||||||
|
.abc d e.
|
||||||
|
.abc d e.
|
||||||
|
.abc d e.
|
15
shell/hush_test/hush-vars/var_expand_in_assign.tests
Executable file
15
shell/hush_test/hush-vars/var_expand_in_assign.tests
Executable file
@ -0,0 +1,15 @@
|
|||||||
|
if test $# = 0; then
|
||||||
|
exec "$THIS_SH" "$0" abc "d e"
|
||||||
|
fi
|
||||||
|
|
||||||
|
space=' '
|
||||||
|
echo .$space.
|
||||||
|
|
||||||
|
a=$*
|
||||||
|
echo .$a.
|
||||||
|
a=$@
|
||||||
|
echo .$a.
|
||||||
|
a="$*"
|
||||||
|
echo .$a.
|
||||||
|
a="$@"
|
||||||
|
echo .$a.
|
0
shell/hush_test/hush-vars/var_subst_in_for.tests
Normal file → Executable file
0
shell/hush_test/hush-vars/var_subst_in_for.tests
Normal file → Executable file
Loading…
x
Reference in New Issue
Block a user