hush: fix bug with local environment vars in pipes; simplify parse_stream()
function old new delta parse_stream 1238 1218 -20 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 0/1 up/down: 0/-20) Total: -20 bytes
This commit is contained in:
70
shell/hush.c
70
shell/hush.c
@@ -1657,8 +1657,7 @@ static char **o_finalize_list(o_string *o, int n)
|
|||||||
|
|
||||||
/* Expansion can recurse */
|
/* Expansion can recurse */
|
||||||
#if ENABLE_HUSH_TICK
|
#if ENABLE_HUSH_TICK
|
||||||
static int process_command_subs(o_string *dest,
|
static int process_command_subs(o_string *dest, struct in_str *input);
|
||||||
struct in_str *input, const char *subst_end);
|
|
||||||
#endif
|
#endif
|
||||||
static char *expand_string_to_string(const char *str);
|
static char *expand_string_to_string(const char *str);
|
||||||
static int parse_stream_dquoted(o_string *dest, struct in_str *input, int dquote_end);
|
static int parse_stream_dquoted(o_string *dest, struct in_str *input, int dquote_end);
|
||||||
@@ -1814,7 +1813,7 @@ static int expand_vars_to_list(o_string *output, int n, char *arg, char or_mask)
|
|||||||
//TODO: can we just stuff it into "output" directly?
|
//TODO: can we just stuff it into "output" directly?
|
||||||
debug_printf_subst("SUBST '%s' first_ch %x\n", arg, first_ch);
|
debug_printf_subst("SUBST '%s' first_ch %x\n", arg, first_ch);
|
||||||
setup_string_in_str(&input, arg);
|
setup_string_in_str(&input, arg);
|
||||||
process_command_subs(&subst_result, &input, NULL);
|
process_command_subs(&subst_result, &input);
|
||||||
debug_printf_subst("SUBST RES '%s'\n", subst_result.data);
|
debug_printf_subst("SUBST RES '%s'\n", subst_result.data);
|
||||||
val = subst_result.data;
|
val = subst_result.data;
|
||||||
goto store_val;
|
goto store_val;
|
||||||
@@ -1971,7 +1970,6 @@ static int expand_vars_to_list(o_string *output, int n, char *arg, char or_mask)
|
|||||||
}
|
}
|
||||||
} /* default: */
|
} /* default: */
|
||||||
} /* switch (char after <SPECIAL_VAR_SYMBOL>) */
|
} /* switch (char after <SPECIAL_VAR_SYMBOL>) */
|
||||||
|
|
||||||
if (val) {
|
if (val) {
|
||||||
o_addQstr(output, val, strlen(val));
|
o_addQstr(output, val, strlen(val));
|
||||||
}
|
}
|
||||||
@@ -2265,7 +2263,7 @@ static void pseudo_exec_argv(nommu_save_t *nommu_save, char **argv, int assignme
|
|||||||
if (argv_expanded) {
|
if (argv_expanded) {
|
||||||
argv = argv_expanded;
|
argv = argv_expanded;
|
||||||
} else {
|
} else {
|
||||||
argv = expand_strvec_to_strvec(argv);
|
argv = expand_strvec_to_strvec(argv + assignment_cnt);
|
||||||
#if !BB_MMU
|
#if !BB_MMU
|
||||||
nommu_save->argv = argv;
|
nommu_save->argv = argv;
|
||||||
#endif
|
#endif
|
||||||
@@ -3628,7 +3626,6 @@ static int done_word(o_string *word, struct parse_context *ctx)
|
|||||||
ctx->ctx_dsemicolon = 0;
|
ctx->ctx_dsemicolon = 0;
|
||||||
} else
|
} else
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (!command->argv /* if it's the first word... */
|
if (!command->argv /* if it's the first word... */
|
||||||
#if ENABLE_HUSH_LOOPS
|
#if ENABLE_HUSH_LOOPS
|
||||||
&& ctx->ctx_res_w != RES_FOR /* ...not after FOR or IN */
|
&& ctx->ctx_res_w != RES_FOR /* ...not after FOR or IN */
|
||||||
@@ -3767,8 +3764,7 @@ static FILE *generate_stream_from_list(struct pipe *head)
|
|||||||
|
|
||||||
/* Return code is exit status of the process that is run. */
|
/* Return code is exit status of the process that is run. */
|
||||||
static int process_command_subs(o_string *dest,
|
static int process_command_subs(o_string *dest,
|
||||||
struct in_str *input,
|
struct in_str *input)
|
||||||
const char *subst_end)
|
|
||||||
{
|
{
|
||||||
int retcode, ch, eol_cnt;
|
int retcode, ch, eol_cnt;
|
||||||
o_string result = NULL_O_STRING;
|
o_string result = NULL_O_STRING;
|
||||||
@@ -3777,7 +3773,7 @@ static int process_command_subs(o_string *dest,
|
|||||||
struct in_str pipe_str;
|
struct in_str pipe_str;
|
||||||
|
|
||||||
/* Recursion to generate command */
|
/* Recursion to generate command */
|
||||||
retcode = parse_stream(&result, &inner, input, subst_end);
|
retcode = parse_stream(&result, &inner, input, NULL);
|
||||||
if (retcode != 0)
|
if (retcode != 0)
|
||||||
return retcode; /* syntax error or EOF */
|
return retcode; /* syntax error or EOF */
|
||||||
o_free(&result);
|
o_free(&result);
|
||||||
@@ -4236,9 +4232,11 @@ static int parse_stream(o_string *dest, struct parse_context *ctx,
|
|||||||
* A single-quote triggers a bypass of the main loop until its mate is
|
* A single-quote triggers a bypass of the main loop until its mate is
|
||||||
* found. When recursing, quote state is passed in via dest->o_escape. */
|
* found. When recursing, quote state is passed in via dest->o_escape. */
|
||||||
|
|
||||||
debug_printf_parse("parse_stream entered, end_trigger='%s' dest->o_assignment:%d\n", end_trigger, dest->o_assignment);
|
debug_printf_parse("parse_stream entered, end_trigger='%s' "
|
||||||
initialize_context(ctx);
|
"dest->o_assignment:%d\n", end_trigger, dest->o_assignment);
|
||||||
|
|
||||||
|
dest->o_assignment = MAYBE_ASSIGNMENT;
|
||||||
|
initialize_context(ctx);
|
||||||
is_in_dquote = dest->o_escape;
|
is_in_dquote = dest->o_escape;
|
||||||
while (1) {
|
while (1) {
|
||||||
if (is_in_dquote) {
|
if (is_in_dquote) {
|
||||||
@@ -4269,51 +4267,47 @@ static int parse_stream(o_string *dest, struct parse_context *ctx,
|
|||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
/* m is SPECIAL ($,`), IFS, or ORDINARY_IF_QUOTED (*,#)
|
/* m is SPECIAL ($,`), IFS, or ORDINARY_IF_QUOTED (*,#) */
|
||||||
*/
|
|
||||||
if (m == CHAR_IFS) {
|
if (m == CHAR_IFS) {
|
||||||
|
if (ch == EOF)
|
||||||
|
goto ret_EOF;
|
||||||
if (done_word(dest, ctx)) {
|
if (done_word(dest, ctx)) {
|
||||||
debug_printf_parse("parse_stream return 1: done_word!=0\n");
|
debug_printf_parse("parse_stream return 1: done_word!=0\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
if (ch == EOF)
|
if (ch == '\n') {
|
||||||
goto ret_EOF;
|
|
||||||
/* If we aren't performing a substitution, treat
|
|
||||||
* a newline as a command separator.
|
|
||||||
* [why don't we handle it exactly like ';'? --vda] */
|
|
||||||
if (end_trigger && ch == '\n') {
|
|
||||||
#if ENABLE_HUSH_CASE
|
#if ENABLE_HUSH_CASE
|
||||||
/* "case ... in <newline> word) ..." -
|
/* "case ... in <newline> word) ..." -
|
||||||
* newlines are ignored (but ';' wouldn't be) */
|
* newlines are ignored (but ';' wouldn't be) */
|
||||||
if (dest->length == 0 // && argv[0] == NULL
|
if (ctx->command->argv == NULL
|
||||||
&& ctx->ctx_res_w == RES_MATCH
|
&& ctx->ctx_res_w == RES_MATCH
|
||||||
) {
|
) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
/* Treat newline as a command separator.
|
||||||
|
* [why don't we handle it exactly like ';'? --vda] */
|
||||||
done_pipe(ctx, PIPE_SEQ);
|
done_pipe(ctx, PIPE_SEQ);
|
||||||
dest->o_assignment = MAYBE_ASSIGNMENT;
|
dest->o_assignment = MAYBE_ASSIGNMENT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (end_trigger) {
|
if (end_trigger && strchr(end_trigger, ch)) {
|
||||||
if (strchr(end_trigger, ch)) {
|
/* Special case: (...word) makes last word terminate,
|
||||||
/* Special case: (...word) makes last word terminate,
|
* as if ';' is seen */
|
||||||
* as if ';' is seen */
|
if (ch == ')') {
|
||||||
if (ch == ')') {
|
done_word(dest, ctx);
|
||||||
done_word(dest, ctx);
|
|
||||||
//err chk?
|
//err chk?
|
||||||
done_pipe(ctx, PIPE_SEQ);
|
done_pipe(ctx, PIPE_SEQ);
|
||||||
dest->o_assignment = MAYBE_ASSIGNMENT;
|
dest->o_assignment = MAYBE_ASSIGNMENT;
|
||||||
}
|
}
|
||||||
/* What do we check here? */
|
/* What do we check here? */
|
||||||
if (!HAS_KEYWORDS
|
if (!HAS_KEYWORDS
|
||||||
IF_HAS_KEYWORDS(|| (ctx->ctx_res_w == RES_NONE && ctx->old_flag == 0))
|
IF_HAS_KEYWORDS(|| (ctx->ctx_res_w == RES_NONE && ctx->old_flag == 0))
|
||||||
) {
|
) {
|
||||||
debug_printf_parse("parse_stream return 0: end_trigger char found\n");
|
debug_printf_parse("parse_stream return 0: end_trigger char found\n");
|
||||||
/* this makes us return 0, not -1 */
|
/* this makes us return 0, not -1 */
|
||||||
end_trigger = NULL;
|
end_trigger = NULL;
|
||||||
goto ret;
|
goto ret;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (m == CHAR_IFS)
|
if (m == CHAR_IFS)
|
||||||
|
6
shell/hush_test/hush-vars/var_in_pipes.right
Normal file
6
shell/hush_test/hush-vars/var_in_pipes.right
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
b=1
|
||||||
|
b=2
|
||||||
|
b=3
|
||||||
|
b=4
|
||||||
|
b=5
|
||||||
|
b=6
|
7
shell/hush_test/hush-vars/var_in_pipes.tests
Executable file
7
shell/hush_test/hush-vars/var_in_pipes.tests
Executable file
@@ -0,0 +1,7 @@
|
|||||||
|
b=1 env | grep ^b=
|
||||||
|
true | b=2 env | grep ^b=
|
||||||
|
a=1 true | b=3 env | grep ^b=
|
||||||
|
|
||||||
|
(b=4 env) | grep ^b=
|
||||||
|
(true | b=5 env) | grep ^b=
|
||||||
|
(a=1 true | b=6 env) | grep ^b=
|
Reference in New Issue
Block a user