diff --git a/shell/hush.c b/shell/hush.c index 885561389..0c57803f1 100644 --- a/shell/hush.c +++ b/shell/hush.c @@ -522,7 +522,6 @@ typedef struct o_string { * possibly empty one: word"", wo''rd etc. */ smallint has_quoted_part; smallint has_empty_slot; - smallint o_assignment; /* 0:maybe, 1:yes, 2:no */ } o_string; enum { EXP_FLAG_SINGLEWORD = 0x80, /* must be 0x80 */ @@ -531,13 +530,6 @@ enum { * by prepending \ to *, ?, [, \ */ EXP_FLAG_ESC_GLOB_CHARS = 0x1, }; -enum { - MAYBE_ASSIGNMENT = 0, - DEFINITELY_ASSIGNMENT = 1, - NOT_ASSIGNMENT = 2, - /* Not an assignment, but next word may be: "if v=xyz cmd;" */ - WORD_IS_KEYWORD = 3, -}; /* Used for initialization: o_string foo = NULL_O_STRING; */ #define NULL_O_STRING { NULL } @@ -694,9 +686,11 @@ struct parse_context { struct command *command; /* last redirect in command->redirects list */ struct redir_struct *pending_redirect; + o_string word; #if !BB_MMU o_string as_string; #endif + smallint is_assignment; /* 0:maybe, 1:yes, 2:no, 3:keyword */ #if HAS_KEYWORDS smallint ctx_res_w; smallint ctx_inverted; /* "! cmd | cmd" */ @@ -717,6 +711,13 @@ struct parse_context { struct parse_context *stack; #endif }; +enum { + MAYBE_ASSIGNMENT = 0, + DEFINITELY_ASSIGNMENT = 1, + NOT_ASSIGNMENT = 2, + /* Not an assignment, but next word may be: "if v=xyz cmd;" */ + WORD_IS_KEYWORD = 3, +}; /* On program start, environ points to initial environment. * putenv adds new pointers into it, unsetenv removes them. @@ -3671,6 +3672,8 @@ static void done_pipe(struct parse_context *ctx, pipe_style type) static void initialize_context(struct parse_context *ctx) { memset(ctx, 0, sizeof(*ctx)); + if (MAYBE_ASSIGNMENT != 0) + ctx->is_assignment = MAYBE_ASSIGNMENT; ctx->pipe = ctx->list_head = new_pipe(); /* Create the memory for command, roughly: * ctx->pipe->cmds = new struct command; @@ -3752,7 +3755,7 @@ static const struct reserved_combo* match_reserved_word(o_string *word) } /* Return NULL: not a keyword, else: keyword */ -static const struct reserved_combo* reserved_word(o_string *word, struct parse_context *ctx) +static const struct reserved_combo* reserved_word(struct parse_context *ctx) { # if ENABLE_HUSH_CASE static const struct reserved_combo reserved_match = { @@ -3761,9 +3764,9 @@ static const struct reserved_combo* reserved_word(o_string *word, struct parse_c # endif const struct reserved_combo *r; - if (word->has_quoted_part) + if (ctx->word.has_quoted_part) return 0; - r = match_reserved_word(word); + r = match_reserved_word(&ctx->word); if (!r) return r; /* NULL */ @@ -3790,7 +3793,7 @@ static const struct reserved_combo* reserved_word(o_string *word, struct parse_c initialize_context(ctx); ctx->stack = old; } else if (/*ctx->ctx_res_w == RES_NONE ||*/ !(ctx->old_flag & (1 << r->res))) { - syntax_error_at(word->data); + syntax_error_at(ctx->word.data); ctx->ctx_res_w = RES_SNTX; return r; } else { @@ -3803,8 +3806,8 @@ static const struct reserved_combo* reserved_word(o_string *word, struct parse_c ctx->ctx_res_w = r->res; ctx->old_flag = r->flag; - word->o_assignment = r->assignment_flag; - debug_printf_parse("word->o_assignment='%s'\n", assignment_flag[word->o_assignment]); + ctx->is_assignment = r->assignment_flag; + debug_printf_parse("ctx->is_assignment='%s'\n", assignment_flag[ctx->is_assignment]); if (ctx->old_flag & FLAG_END) { struct parse_context *old; @@ -3850,12 +3853,12 @@ static const struct reserved_combo* reserved_word(o_string *word, struct parse_c * Normal return is 0. Syntax errors return 1. * Note: on return, word is reset, but not o_free'd! */ -static int done_word(o_string *word, struct parse_context *ctx) +static int done_word(struct parse_context *ctx) { struct command *command = ctx->command; - debug_printf_parse("done_word entered: '%s' %p\n", word->data, command); - if (word->length == 0 && !word->has_quoted_part) { + debug_printf_parse("done_word entered: '%s' %p\n", ctx->word.data, command); + if (ctx->word.length == 0 && !ctx->word.has_quoted_part) { debug_printf_parse("done_word return 0: true null, ignored\n"); return 0; } @@ -3885,7 +3888,7 @@ static int done_word(o_string *word, struct parse_context *ctx) // <pending_redirect->rd_filename = xstrdup(word->data); + ctx->pending_redirect->rd_filename = xstrdup(ctx->word.data); /* Cater for >\file case: * >\a creates file a; >\\a, >"\a", >"\\a" create file \a * Same with heredocs: @@ -3894,17 +3897,17 @@ static int done_word(o_string *word, struct parse_context *ctx) if (ctx->pending_redirect->rd_type == REDIRECT_HEREDOC) { unbackslash(ctx->pending_redirect->rd_filename); /* Is it <<"HEREDOC"? */ - if (word->has_quoted_part) { + if (ctx->word.has_quoted_part) { ctx->pending_redirect->rd_dup |= HEREDOC_QUOTED; } } - debug_printf_parse("word stored in rd_filename: '%s'\n", word->data); + debug_printf_parse("word stored in rd_filename: '%s'\n", ctx->word.data); ctx->pending_redirect = NULL; } else { #if HAS_KEYWORDS # if ENABLE_HUSH_CASE if (ctx->ctx_dsemicolon - && strcmp(word->data, "esac") != 0 /* not "... pattern) cmd;; esac" */ + && strcmp(ctx->word.data, "esac") != 0 /* not "... pattern) cmd;; esac" */ ) { /* already done when ctx_dsemicolon was set to 1: */ /* ctx->ctx_res_w = RES_MATCH; */ @@ -3921,7 +3924,7 @@ static int done_word(o_string *word, struct parse_context *ctx) # endif ) { const struct reserved_combo *reserved; - reserved = reserved_word(word, ctx); + reserved = reserved_word(ctx); debug_printf_parse("checking for reserved-ness: %d\n", !!reserved); if (reserved) { # if ENABLE_HUSH_LINENO_VAR @@ -3940,7 +3943,7 @@ static int done_word(o_string *word, struct parse_context *ctx) done_pipe(ctx, PIPE_SEQ); } # endif - o_reset_to_empty_unquoted(word); + o_reset_to_empty_unquoted(&ctx->word); debug_printf_parse("done_word return %d\n", (ctx->ctx_res_w == RES_SNTX)); return (ctx->ctx_res_w == RES_SNTX); @@ -3948,7 +3951,7 @@ static int done_word(o_string *word, struct parse_context *ctx) # if defined(CMD_SINGLEWORD_NOGLOB) if (0 # if BASH_TEST2 - || strcmp(word->data, "[[") == 0 + || strcmp(ctx->word.data, "[[") == 0 # endif /* In bash, local/export/readonly are special, args * are assignments and therefore expansion of them @@ -3965,9 +3968,9 @@ static int done_word(o_string *word, struct parse_context *ctx) * $ "export" i=`echo 'aaa bbb'`; echo "$i" * aaa */ - IF_HUSH_LOCAL( || strcmp(word->data, "local") == 0) - IF_HUSH_EXPORT( || strcmp(word->data, "export") == 0) - IF_HUSH_READONLY( || strcmp(word->data, "readonly") == 0) + IF_HUSH_LOCAL( || strcmp(ctx->word.data, "local") == 0) + IF_HUSH_EXPORT( || strcmp(ctx->word.data, "export") == 0) + IF_HUSH_READONLY(|| strcmp(ctx->word.data, "readonly") == 0) ) { command->cmd_type = CMD_SINGLEWORD_NOGLOB; } @@ -3978,7 +3981,7 @@ static int done_word(o_string *word, struct parse_context *ctx) if (command->group) { /* "{ echo foo; } echo bar" - bad */ - syntax_error_at(word->data); + syntax_error_at(ctx->word.data); debug_printf_parse("done_word return 1: syntax error, " "groups and arglists don't mix\n"); return 1; @@ -3986,26 +3989,26 @@ static int done_word(o_string *word, struct parse_context *ctx) /* If this word wasn't an assignment, next ones definitely * can't be assignments. Even if they look like ones. */ - if (word->o_assignment != DEFINITELY_ASSIGNMENT - && word->o_assignment != WORD_IS_KEYWORD + if (ctx->is_assignment != DEFINITELY_ASSIGNMENT + && ctx->is_assignment != WORD_IS_KEYWORD ) { - word->o_assignment = NOT_ASSIGNMENT; + ctx->is_assignment = NOT_ASSIGNMENT; } else { - if (word->o_assignment == DEFINITELY_ASSIGNMENT) { + if (ctx->is_assignment == DEFINITELY_ASSIGNMENT) { command->assignment_cnt++; debug_printf_parse("++assignment_cnt=%d\n", command->assignment_cnt); } - debug_printf_parse("word->o_assignment was:'%s'\n", assignment_flag[word->o_assignment]); - word->o_assignment = MAYBE_ASSIGNMENT; + debug_printf_parse("ctx->is_assignment was:'%s'\n", assignment_flag[ctx->is_assignment]); + ctx->is_assignment = MAYBE_ASSIGNMENT; } - debug_printf_parse("word->o_assignment='%s'\n", assignment_flag[word->o_assignment]); - command->argv = add_string_to_strings(command->argv, xstrdup(word->data)); + debug_printf_parse("ctx->is_assignment='%s'\n", assignment_flag[ctx->is_assignment]); + command->argv = add_string_to_strings(command->argv, xstrdup(ctx->word.data)); debug_print_strings("word appended to argv", command->argv); } #if ENABLE_HUSH_LOOPS if (ctx->ctx_res_w == RES_FOR) { - if (word->has_quoted_part + if (ctx->word.has_quoted_part || !is_well_formed_var_name(command->argv[0], '\0') ) { /* bash says just "not a valid identifier" */ @@ -4026,7 +4029,7 @@ static int done_word(o_string *word, struct parse_context *ctx) } #endif - o_reset_to_empty_unquoted(word); + o_reset_to_empty_unquoted(&ctx->word); debug_printf_parse("done_word return 0\n"); return 0; @@ -4310,14 +4313,10 @@ static struct pipe *parse_stream(char **pstring, int end_trigger); -#if !ENABLE_HUSH_FUNCTIONS -#define parse_group(dest, ctx, input, ch) \ - parse_group(ctx, input, ch) -#endif -static int parse_group(o_string *dest, struct parse_context *ctx, +static int parse_group(struct parse_context *ctx, struct in_str *input, int ch) { - /* dest contains characters seen prior to ( or {. + /* ctx->word contains characters seen prior to ( or {. * Typically it's empty, but for function defs, * it contains function name (without '()'). */ #if BB_MMU @@ -4331,9 +4330,9 @@ static int parse_group(o_string *dest, struct parse_context *ctx, debug_printf_parse("parse_group entered\n"); #if ENABLE_HUSH_FUNCTIONS - if (ch == '(' && !dest->has_quoted_part) { - if (dest->length) - if (done_word(dest, ctx)) + if (ch == '(' && !ctx->word.has_quoted_part) { + if (ctx->word.length) + if (done_word(ctx)) return 1; if (!command->argv) goto skip; /* (... */ @@ -4365,8 +4364,8 @@ static int parse_group(o_string *dest, struct parse_context *ctx, #if 0 /* Prevented by caller */ if (command->argv /* word [word]{... */ - || dest->length /* word{... */ - || dest->has_quoted_part /* ""{... */ + || ctx->word.length /* word{... */ + || ctx->word.has_quoted_part /* ""{... */ ) { syntax_error(NULL); debug_printf_parse("parse_group return 1: " @@ -4972,29 +4971,28 @@ static struct pipe *parse_stream(char **pstring, int end_trigger) { struct parse_context ctx; - o_string dest = NULL_O_STRING; int heredoc_cnt; /* Single-quote triggers a bypass of the main loop until its mate is - * found. When recursing, quote state is passed in via dest->o_expflags. + * found. When recursing, quote state is passed in via ctx.word.o_expflags. */ debug_printf_parse("parse_stream entered, end_trigger='%c'\n", end_trigger ? end_trigger : 'X'); debug_enter(); - /* If very first arg is "" or '', dest.data may end up NULL. - * Preventing this: */ - o_addchr(&dest, '\0'); - dest.length = 0; + initialize_context(&ctx); + + /* If very first arg is "" or '', ctx.word.data may end up NULL. + * Preventing this: + */ + o_addchr(&ctx.word, '\0'); + ctx.word.length = 0; /* We used to separate words on $IFS here. This was wrong. * $IFS is used only for word splitting when $var is expanded, * here we should use blank chars as separators, not $IFS */ - if (MAYBE_ASSIGNMENT != 0) - dest.o_assignment = MAYBE_ASSIGNMENT; - initialize_context(&ctx); heredoc_cnt = 0; while (1) { const char *is_blank; @@ -5006,7 +5004,7 @@ static struct pipe *parse_stream(char **pstring, ch = i_getch(input); debug_printf_parse(": ch=%c (%d) escape=%d\n", - ch, ch, !!(dest.o_expflags & EXP_FLAG_ESC_GLOB_CHARS)); + ch, ch, !!(ctx.word.o_expflags & EXP_FLAG_ESC_GLOB_CHARS)); if (ch == EOF) { struct pipe *pi; @@ -5023,10 +5021,10 @@ static struct pipe *parse_stream(char **pstring, goto parse_error; } - if (done_word(&dest, &ctx)) { + if (done_word(&ctx)) { goto parse_error; } - o_free(&dest); + o_free(&ctx.word); done_pipe(&ctx, PIPE_SEQ); pi = ctx.list_head; /* If we got nothing... */ @@ -5066,8 +5064,8 @@ static struct pipe *parse_stream(char **pstring, SPECIAL_VAR_SYMBOL_STR; /* Are { and } special here? */ if (ctx.command->argv /* word [word]{... - non-special */ - || dest.length /* word{... - non-special */ - || dest.has_quoted_part /* ""{... - non-special */ + || ctx.word.length /* word{... - non-special */ + || ctx.word.has_quoted_part /* ""{... - non-special */ || (next != ';' /* }; - special */ && next != ')' /* }) - special */ && next != '(' /* {( - special */ @@ -5084,14 +5082,14 @@ static struct pipe *parse_stream(char **pstring, if (!is_special && !is_blank) { /* ordinary char */ ordinary_char: - o_addQchr(&dest, ch); - if ((dest.o_assignment == MAYBE_ASSIGNMENT - || dest.o_assignment == WORD_IS_KEYWORD) + o_addQchr(&ctx.word, ch); + if ((ctx.is_assignment == MAYBE_ASSIGNMENT + || ctx.is_assignment == WORD_IS_KEYWORD) && ch == '=' - && is_well_formed_var_name(dest.data, '=') + && is_well_formed_var_name(ctx.word.data, '=') ) { - dest.o_assignment = DEFINITELY_ASSIGNMENT; - debug_printf_parse("dest.o_assignment='%s'\n", assignment_flag[dest.o_assignment]); + ctx.is_assignment = DEFINITELY_ASSIGNMENT; + debug_printf_parse("ctx.is_assignment='%s'\n", assignment_flag[ctx.is_assignment]); } continue; } @@ -5113,7 +5111,7 @@ static struct pipe *parse_stream(char **pstring, } /* ch == last eaten whitespace char */ #endif - if (done_word(&dest, &ctx)) { + if (done_word(&ctx)) { goto parse_error; } if (ch == '\n') { @@ -5123,7 +5121,7 @@ static struct pipe *parse_stream(char **pstring, * "case ... in word) ..." */ if (IS_NULL_CMD(ctx.command) - && dest.length == 0 && !dest.has_quoted_part + && ctx.word.length == 0 && !ctx.word.has_quoted_part ) { /* This newline can be ignored. But... * Without check #1, interactive shell @@ -5158,8 +5156,8 @@ static struct pipe *parse_stream(char **pstring, } heredoc_cnt = 0; } - dest.o_assignment = MAYBE_ASSIGNMENT; - debug_printf_parse("dest.o_assignment='%s'\n", assignment_flag[dest.o_assignment]); + ctx.is_assignment = MAYBE_ASSIGNMENT; + debug_printf_parse("ctx.is_assignment='%s'\n", assignment_flag[ctx.is_assignment]); ch = ';'; /* note: if (is_blank) continue; * will still trigger for us */ @@ -5171,8 +5169,8 @@ static struct pipe *parse_stream(char **pstring, * Pathological example: { ""}; } should exec "}" cmd */ if (ch == '}') { - if (dest.length != 0 /* word} */ - || dest.has_quoted_part /* ""} */ + if (ctx.word.length != 0 /* word} */ + || ctx.word.has_quoted_part /* ""} */ ) { goto ordinary_char; } @@ -5201,7 +5199,7 @@ static struct pipe *parse_stream(char **pstring, #if ENABLE_HUSH_CASE && (ch != ')' || ctx.ctx_res_w != RES_MATCH - || (!dest.has_quoted_part && strcmp(dest.data, "esac") == 0) + || (!ctx.word.has_quoted_part && strcmp(ctx.word.data, "esac") == 0) ) #endif ) { @@ -5218,17 +5216,17 @@ static struct pipe *parse_stream(char **pstring, syntax_error_unterm_str("here document"); goto parse_error; } - if (done_word(&dest, &ctx)) { + if (done_word(&ctx)) { goto parse_error; } done_pipe(&ctx, PIPE_SEQ); - dest.o_assignment = MAYBE_ASSIGNMENT; - debug_printf_parse("dest.o_assignment='%s'\n", assignment_flag[dest.o_assignment]); + ctx.is_assignment = MAYBE_ASSIGNMENT; + debug_printf_parse("ctx.is_assignment='%s'\n", assignment_flag[ctx.is_assignment]); /* Do we sit outside of any if's, loops or case's? */ if (!HAS_KEYWORDS IF_HAS_KEYWORDS(|| (ctx.ctx_res_w == RES_NONE && ctx.old_flag == 0)) ) { - o_free(&dest); + o_free(&ctx.word); #if !BB_MMU debug_printf_parse("as_string2 '%s'\n", ctx.as_string.data); if (pstring) @@ -5257,8 +5255,8 @@ static struct pipe *parse_stream(char **pstring, * an assignment. a=1 2>z b=2: b=2 is still assignment */ switch (ch) { case '>': - redir_fd = redirect_opt_num(&dest); - if (done_word(&dest, &ctx)) { + redir_fd = redirect_opt_num(&ctx.word); + if (done_word(&ctx)) { goto parse_error; } redir_style = REDIRECT_OVERWRITE; @@ -5279,8 +5277,8 @@ static struct pipe *parse_stream(char **pstring, goto parse_error; continue; /* back to top of while (1) */ case '<': - redir_fd = redirect_opt_num(&dest); - if (done_word(&dest, &ctx)) { + redir_fd = redirect_opt_num(&ctx.word); + if (done_word(&ctx)) { goto parse_error; } redir_style = REDIRECT_INPUT; @@ -5307,7 +5305,7 @@ static struct pipe *parse_stream(char **pstring, goto parse_error; continue; /* back to top of while (1) */ case '#': - if (dest.length == 0 && !dest.has_quoted_part) { + if (ctx.word.length == 0 && !ctx.word.has_quoted_part) { /* skip "#comment" */ /* note: we do not add it to &ctx.as_string */ /* TODO: in bash: @@ -5342,14 +5340,14 @@ static struct pipe *parse_stream(char **pstring, break; } - if (dest.o_assignment == MAYBE_ASSIGNMENT + if (ctx.is_assignment == MAYBE_ASSIGNMENT /* check that we are not in word in "a=1 2>word b=1": */ && !ctx.pending_redirect ) { /* ch is a special char and thus this word * cannot be an assignment */ - dest.o_assignment = NOT_ASSIGNMENT; - debug_printf_parse("dest.o_assignment='%s'\n", assignment_flag[dest.o_assignment]); + ctx.is_assignment = NOT_ASSIGNMENT; + debug_printf_parse("ctx.is_assignment='%s'\n", assignment_flag[ctx.is_assignment]); } /* Note: nommu_addchr(&ctx.as_string, ch) is already done */ @@ -5357,12 +5355,12 @@ static struct pipe *parse_stream(char **pstring, switch (ch) { case SPECIAL_VAR_SYMBOL: /* Convert raw ^C to corresponding special variable reference */ - o_addchr(&dest, SPECIAL_VAR_SYMBOL); - o_addchr(&dest, SPECIAL_VAR_QUOTED_SVS); + o_addchr(&ctx.word, SPECIAL_VAR_SYMBOL); + o_addchr(&ctx.word, SPECIAL_VAR_QUOTED_SVS); /* fall through */ case '#': /* non-comment #: "echo a#b" etc */ - o_addchr(&dest, ch); + o_addchr(&ctx.word, ch); break; case '\\': if (next == EOF) { @@ -5371,29 +5369,29 @@ static struct pipe *parse_stream(char **pstring, } ch = i_getch(input); /* note: ch != '\n' (that case does not reach this place) */ - o_addchr(&dest, '\\'); + o_addchr(&ctx.word, '\\'); /*nommu_addchr(&ctx.as_string, '\\'); - already done */ - o_addchr(&dest, ch); + o_addchr(&ctx.word, ch); nommu_addchr(&ctx.as_string, ch); /* Example: echo Hello \2>file * we need to know that word 2 is quoted */ - dest.has_quoted_part = 1; + ctx.word.has_quoted_part = 1; break; case '$': - if (!parse_dollar(&ctx.as_string, &dest, input, /*quote_mask:*/ 0)) { + if (!parse_dollar(&ctx.as_string, &ctx.word, input, /*quote_mask:*/ 0)) { debug_printf_parse("parse_stream parse error: " "parse_dollar returned 0 (error)\n"); goto parse_error; } break; case '\'': - dest.has_quoted_part = 1; + ctx.word.has_quoted_part = 1; if (next == '\'' && !ctx.pending_redirect) { insert_empty_quoted_str_marker: nommu_addchr(&ctx.as_string, next); i_getch(input); /* eat second ' */ - o_addchr(&dest, SPECIAL_VAR_SYMBOL); - o_addchr(&dest, SPECIAL_VAR_SYMBOL); + o_addchr(&ctx.word, SPECIAL_VAR_SYMBOL); + o_addchr(&ctx.word, SPECIAL_VAR_SYMBOL); } else { while (1) { ch = i_getch(input); @@ -5406,38 +5404,38 @@ static struct pipe *parse_stream(char **pstring, break; if (ch == SPECIAL_VAR_SYMBOL) { /* Convert raw ^C to corresponding special variable reference */ - o_addchr(&dest, SPECIAL_VAR_SYMBOL); - o_addchr(&dest, SPECIAL_VAR_QUOTED_SVS); + o_addchr(&ctx.word, SPECIAL_VAR_SYMBOL); + o_addchr(&ctx.word, SPECIAL_VAR_QUOTED_SVS); } - o_addqchr(&dest, ch); + o_addqchr(&ctx.word, ch); } } break; case '"': - dest.has_quoted_part = 1; + ctx.word.has_quoted_part = 1; if (next == '"' && !ctx.pending_redirect) goto insert_empty_quoted_str_marker; - if (dest.o_assignment == NOT_ASSIGNMENT) - dest.o_expflags |= EXP_FLAG_ESC_GLOB_CHARS; - if (!encode_string(&ctx.as_string, &dest, input, '"', /*process_bkslash:*/ 1)) + if (ctx.is_assignment == NOT_ASSIGNMENT) + ctx.word.o_expflags |= EXP_FLAG_ESC_GLOB_CHARS; + if (!encode_string(&ctx.as_string, &ctx.word, input, '"', /*process_bkslash:*/ 1)) goto parse_error; - dest.o_expflags &= ~EXP_FLAG_ESC_GLOB_CHARS; + ctx.word.o_expflags &= ~EXP_FLAG_ESC_GLOB_CHARS; break; #if ENABLE_HUSH_TICK case '`': { USE_FOR_NOMMU(unsigned pos;) - o_addchr(&dest, SPECIAL_VAR_SYMBOL); - o_addchr(&dest, '`'); - USE_FOR_NOMMU(pos = dest.length;) - if (!add_till_backquote(&dest, input, /*in_dquote:*/ 0)) + o_addchr(&ctx.word, SPECIAL_VAR_SYMBOL); + o_addchr(&ctx.word, '`'); + USE_FOR_NOMMU(pos = ctx.word.length;) + if (!add_till_backquote(&ctx.word, input, /*in_dquote:*/ 0)) goto parse_error; # if !BB_MMU - o_addstr(&ctx.as_string, dest.data + pos); + o_addstr(&ctx.as_string, ctx.word.data + pos); o_addchr(&ctx.as_string, '`'); # endif - o_addchr(&dest, SPECIAL_VAR_SYMBOL); - //debug_printf_subst("SUBST RES3 '%s'\n", dest.data + pos); + o_addchr(&ctx.word, SPECIAL_VAR_SYMBOL); + //debug_printf_subst("SUBST RES3 '%s'\n", ctx.word.data + pos); break; } #endif @@ -5445,7 +5443,7 @@ static struct pipe *parse_stream(char **pstring, #if ENABLE_HUSH_CASE case_semi: #endif - if (done_word(&dest, &ctx)) { + if (done_word(&ctx)) { goto parse_error; } done_pipe(&ctx, PIPE_SEQ); @@ -5468,11 +5466,11 @@ static struct pipe *parse_stream(char **pstring, new_cmd: /* We just finished a cmd. New one may start * with an assignment */ - dest.o_assignment = MAYBE_ASSIGNMENT; - debug_printf_parse("dest.o_assignment='%s'\n", assignment_flag[dest.o_assignment]); + ctx.is_assignment = MAYBE_ASSIGNMENT; + debug_printf_parse("ctx.is_assignment='%s'\n", assignment_flag[ctx.is_assignment]); break; case '&': - if (done_word(&dest, &ctx)) { + if (done_word(&ctx)) { goto parse_error; } if (next == '\\') @@ -5486,7 +5484,7 @@ static struct pipe *parse_stream(char **pstring, } goto new_cmd; case '|': - if (done_word(&dest, &ctx)) { + if (done_word(&ctx)) { goto parse_error; } #if ENABLE_HUSH_CASE @@ -5511,14 +5509,14 @@ static struct pipe *parse_stream(char **pstring, /* "case... in [(]word)..." - skip '(' */ if (ctx.ctx_res_w == RES_MATCH && ctx.command->argv == NULL /* not (word|(... */ - && dest.length == 0 /* not word(... */ - && dest.has_quoted_part == 0 /* not ""(... */ + && ctx.word.length == 0 /* not word(... */ + && ctx.word.has_quoted_part == 0 /* not ""(... */ ) { continue; } #endif case '{': - if (parse_group(&dest, &ctx, input, ch) != 0) { + if (parse_group(&ctx, input, ch) != 0) { goto parse_error; } goto new_cmd; @@ -5575,7 +5573,7 @@ static struct pipe *parse_stream(char **pstring, IF_HAS_KEYWORDS(pctx = p2;) } while (HAS_KEYWORDS && pctx); - o_free(&dest); + o_free(&ctx.word); #if !BB_MMU if (pstring) *pstring = NULL;