hush: put "current word" structure into parsing context
No binary (build failed)
—
(log yok)
| @@ -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) | |
| // <<EOF$((1)) | |
| // <<EOF`true` [this case also makes heredoc "quoted", a-la <<"EOF". Probably bash-4.3.43 bug] | |
| - | 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 <newline> 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; | |