diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2018-04-10 03:22:10 +0200 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2018-04-10 03:22:10 +0200 |
commit | 09b7a7ec0ea5ef602ff543dad1a90b6174a4f1c8 (patch) | |
tree | b8b2e44a90f7a7558d6697956f4679a4f22c8d78 /shell | |
parent | e93031e6dced47e8f5a86408b4aa3f89aef647c7 (diff) | |
download | busybox-w32-09b7a7ec0ea5ef602ff543dad1a90b6174a4f1c8.tar.gz busybox-w32-09b7a7ec0ea5ef602ff543dad1a90b6174a4f1c8.tar.bz2 busybox-w32-09b7a7ec0ea5ef602ff543dad1a90b6174a4f1c8.zip |
hush: put "current word" structure into parsing context
function old new delta
done_word 790 767 -23
parse_stream 3018 2919 -99
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 0/2 up/down: 0/-122) Total: -122 bytes
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
Diffstat (limited to 'shell')
-rw-r--r-- | shell/hush.c | 242 |
1 files changed, 120 insertions, 122 deletions
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 { | |||
522 | * possibly empty one: word"", wo''rd etc. */ | 522 | * possibly empty one: word"", wo''rd etc. */ |
523 | smallint has_quoted_part; | 523 | smallint has_quoted_part; |
524 | smallint has_empty_slot; | 524 | smallint has_empty_slot; |
525 | smallint o_assignment; /* 0:maybe, 1:yes, 2:no */ | ||
526 | } o_string; | 525 | } o_string; |
527 | enum { | 526 | enum { |
528 | EXP_FLAG_SINGLEWORD = 0x80, /* must be 0x80 */ | 527 | EXP_FLAG_SINGLEWORD = 0x80, /* must be 0x80 */ |
@@ -531,13 +530,6 @@ enum { | |||
531 | * by prepending \ to *, ?, [, \ */ | 530 | * by prepending \ to *, ?, [, \ */ |
532 | EXP_FLAG_ESC_GLOB_CHARS = 0x1, | 531 | EXP_FLAG_ESC_GLOB_CHARS = 0x1, |
533 | }; | 532 | }; |
534 | enum { | ||
535 | MAYBE_ASSIGNMENT = 0, | ||
536 | DEFINITELY_ASSIGNMENT = 1, | ||
537 | NOT_ASSIGNMENT = 2, | ||
538 | /* Not an assignment, but next word may be: "if v=xyz cmd;" */ | ||
539 | WORD_IS_KEYWORD = 3, | ||
540 | }; | ||
541 | /* Used for initialization: o_string foo = NULL_O_STRING; */ | 533 | /* Used for initialization: o_string foo = NULL_O_STRING; */ |
542 | #define NULL_O_STRING { NULL } | 534 | #define NULL_O_STRING { NULL } |
543 | 535 | ||
@@ -694,9 +686,11 @@ struct parse_context { | |||
694 | struct command *command; | 686 | struct command *command; |
695 | /* last redirect in command->redirects list */ | 687 | /* last redirect in command->redirects list */ |
696 | struct redir_struct *pending_redirect; | 688 | struct redir_struct *pending_redirect; |
689 | o_string word; | ||
697 | #if !BB_MMU | 690 | #if !BB_MMU |
698 | o_string as_string; | 691 | o_string as_string; |
699 | #endif | 692 | #endif |
693 | smallint is_assignment; /* 0:maybe, 1:yes, 2:no, 3:keyword */ | ||
700 | #if HAS_KEYWORDS | 694 | #if HAS_KEYWORDS |
701 | smallint ctx_res_w; | 695 | smallint ctx_res_w; |
702 | smallint ctx_inverted; /* "! cmd | cmd" */ | 696 | smallint ctx_inverted; /* "! cmd | cmd" */ |
@@ -717,6 +711,13 @@ struct parse_context { | |||
717 | struct parse_context *stack; | 711 | struct parse_context *stack; |
718 | #endif | 712 | #endif |
719 | }; | 713 | }; |
714 | enum { | ||
715 | MAYBE_ASSIGNMENT = 0, | ||
716 | DEFINITELY_ASSIGNMENT = 1, | ||
717 | NOT_ASSIGNMENT = 2, | ||
718 | /* Not an assignment, but next word may be: "if v=xyz cmd;" */ | ||
719 | WORD_IS_KEYWORD = 3, | ||
720 | }; | ||
720 | 721 | ||
721 | /* On program start, environ points to initial environment. | 722 | /* On program start, environ points to initial environment. |
722 | * putenv adds new pointers into it, unsetenv removes them. | 723 | * putenv adds new pointers into it, unsetenv removes them. |
@@ -3671,6 +3672,8 @@ static void done_pipe(struct parse_context *ctx, pipe_style type) | |||
3671 | static void initialize_context(struct parse_context *ctx) | 3672 | static void initialize_context(struct parse_context *ctx) |
3672 | { | 3673 | { |
3673 | memset(ctx, 0, sizeof(*ctx)); | 3674 | memset(ctx, 0, sizeof(*ctx)); |
3675 | if (MAYBE_ASSIGNMENT != 0) | ||
3676 | ctx->is_assignment = MAYBE_ASSIGNMENT; | ||
3674 | ctx->pipe = ctx->list_head = new_pipe(); | 3677 | ctx->pipe = ctx->list_head = new_pipe(); |
3675 | /* Create the memory for command, roughly: | 3678 | /* Create the memory for command, roughly: |
3676 | * ctx->pipe->cmds = new struct command; | 3679 | * ctx->pipe->cmds = new struct command; |
@@ -3752,7 +3755,7 @@ static const struct reserved_combo* match_reserved_word(o_string *word) | |||
3752 | } | 3755 | } |
3753 | /* Return NULL: not a keyword, else: keyword | 3756 | /* Return NULL: not a keyword, else: keyword |
3754 | */ | 3757 | */ |
3755 | static const struct reserved_combo* reserved_word(o_string *word, struct parse_context *ctx) | 3758 | static const struct reserved_combo* reserved_word(struct parse_context *ctx) |
3756 | { | 3759 | { |
3757 | # if ENABLE_HUSH_CASE | 3760 | # if ENABLE_HUSH_CASE |
3758 | static const struct reserved_combo reserved_match = { | 3761 | static const struct reserved_combo reserved_match = { |
@@ -3761,9 +3764,9 @@ static const struct reserved_combo* reserved_word(o_string *word, struct parse_c | |||
3761 | # endif | 3764 | # endif |
3762 | const struct reserved_combo *r; | 3765 | const struct reserved_combo *r; |
3763 | 3766 | ||
3764 | if (word->has_quoted_part) | 3767 | if (ctx->word.has_quoted_part) |
3765 | return 0; | 3768 | return 0; |
3766 | r = match_reserved_word(word); | 3769 | r = match_reserved_word(&ctx->word); |
3767 | if (!r) | 3770 | if (!r) |
3768 | return r; /* NULL */ | 3771 | return r; /* NULL */ |
3769 | 3772 | ||
@@ -3790,7 +3793,7 @@ static const struct reserved_combo* reserved_word(o_string *word, struct parse_c | |||
3790 | initialize_context(ctx); | 3793 | initialize_context(ctx); |
3791 | ctx->stack = old; | 3794 | ctx->stack = old; |
3792 | } else if (/*ctx->ctx_res_w == RES_NONE ||*/ !(ctx->old_flag & (1 << r->res))) { | 3795 | } else if (/*ctx->ctx_res_w == RES_NONE ||*/ !(ctx->old_flag & (1 << r->res))) { |
3793 | syntax_error_at(word->data); | 3796 | syntax_error_at(ctx->word.data); |
3794 | ctx->ctx_res_w = RES_SNTX; | 3797 | ctx->ctx_res_w = RES_SNTX; |
3795 | return r; | 3798 | return r; |
3796 | } else { | 3799 | } else { |
@@ -3803,8 +3806,8 @@ static const struct reserved_combo* reserved_word(o_string *word, struct parse_c | |||
3803 | 3806 | ||
3804 | ctx->ctx_res_w = r->res; | 3807 | ctx->ctx_res_w = r->res; |
3805 | ctx->old_flag = r->flag; | 3808 | ctx->old_flag = r->flag; |
3806 | word->o_assignment = r->assignment_flag; | 3809 | ctx->is_assignment = r->assignment_flag; |
3807 | debug_printf_parse("word->o_assignment='%s'\n", assignment_flag[word->o_assignment]); | 3810 | debug_printf_parse("ctx->is_assignment='%s'\n", assignment_flag[ctx->is_assignment]); |
3808 | 3811 | ||
3809 | if (ctx->old_flag & FLAG_END) { | 3812 | if (ctx->old_flag & FLAG_END) { |
3810 | struct parse_context *old; | 3813 | struct parse_context *old; |
@@ -3850,12 +3853,12 @@ static const struct reserved_combo* reserved_word(o_string *word, struct parse_c | |||
3850 | * Normal return is 0. Syntax errors return 1. | 3853 | * Normal return is 0. Syntax errors return 1. |
3851 | * Note: on return, word is reset, but not o_free'd! | 3854 | * Note: on return, word is reset, but not o_free'd! |
3852 | */ | 3855 | */ |
3853 | static int done_word(o_string *word, struct parse_context *ctx) | 3856 | static int done_word(struct parse_context *ctx) |
3854 | { | 3857 | { |
3855 | struct command *command = ctx->command; | 3858 | struct command *command = ctx->command; |
3856 | 3859 | ||
3857 | debug_printf_parse("done_word entered: '%s' %p\n", word->data, command); | 3860 | debug_printf_parse("done_word entered: '%s' %p\n", ctx->word.data, command); |
3858 | if (word->length == 0 && !word->has_quoted_part) { | 3861 | if (ctx->word.length == 0 && !ctx->word.has_quoted_part) { |
3859 | debug_printf_parse("done_word return 0: true null, ignored\n"); | 3862 | debug_printf_parse("done_word return 0: true null, ignored\n"); |
3860 | return 0; | 3863 | return 0; |
3861 | } | 3864 | } |
@@ -3885,7 +3888,7 @@ static int done_word(o_string *word, struct parse_context *ctx) | |||
3885 | // <<EOF$((1)) | 3888 | // <<EOF$((1)) |
3886 | // <<EOF`true` [this case also makes heredoc "quoted", a-la <<"EOF". Probably bash-4.3.43 bug] | 3889 | // <<EOF`true` [this case also makes heredoc "quoted", a-la <<"EOF". Probably bash-4.3.43 bug] |
3887 | 3890 | ||
3888 | ctx->pending_redirect->rd_filename = xstrdup(word->data); | 3891 | ctx->pending_redirect->rd_filename = xstrdup(ctx->word.data); |
3889 | /* Cater for >\file case: | 3892 | /* Cater for >\file case: |
3890 | * >\a creates file a; >\\a, >"\a", >"\\a" create file \a | 3893 | * >\a creates file a; >\\a, >"\a", >"\\a" create file \a |
3891 | * Same with heredocs: | 3894 | * Same with heredocs: |
@@ -3894,17 +3897,17 @@ static int done_word(o_string *word, struct parse_context *ctx) | |||
3894 | if (ctx->pending_redirect->rd_type == REDIRECT_HEREDOC) { | 3897 | if (ctx->pending_redirect->rd_type == REDIRECT_HEREDOC) { |
3895 | unbackslash(ctx->pending_redirect->rd_filename); | 3898 | unbackslash(ctx->pending_redirect->rd_filename); |
3896 | /* Is it <<"HEREDOC"? */ | 3899 | /* Is it <<"HEREDOC"? */ |
3897 | if (word->has_quoted_part) { | 3900 | if (ctx->word.has_quoted_part) { |
3898 | ctx->pending_redirect->rd_dup |= HEREDOC_QUOTED; | 3901 | ctx->pending_redirect->rd_dup |= HEREDOC_QUOTED; |
3899 | } | 3902 | } |
3900 | } | 3903 | } |
3901 | debug_printf_parse("word stored in rd_filename: '%s'\n", word->data); | 3904 | debug_printf_parse("word stored in rd_filename: '%s'\n", ctx->word.data); |
3902 | ctx->pending_redirect = NULL; | 3905 | ctx->pending_redirect = NULL; |
3903 | } else { | 3906 | } else { |
3904 | #if HAS_KEYWORDS | 3907 | #if HAS_KEYWORDS |
3905 | # if ENABLE_HUSH_CASE | 3908 | # if ENABLE_HUSH_CASE |
3906 | if (ctx->ctx_dsemicolon | 3909 | if (ctx->ctx_dsemicolon |
3907 | && strcmp(word->data, "esac") != 0 /* not "... pattern) cmd;; esac" */ | 3910 | && strcmp(ctx->word.data, "esac") != 0 /* not "... pattern) cmd;; esac" */ |
3908 | ) { | 3911 | ) { |
3909 | /* already done when ctx_dsemicolon was set to 1: */ | 3912 | /* already done when ctx_dsemicolon was set to 1: */ |
3910 | /* ctx->ctx_res_w = RES_MATCH; */ | 3913 | /* ctx->ctx_res_w = RES_MATCH; */ |
@@ -3921,7 +3924,7 @@ static int done_word(o_string *word, struct parse_context *ctx) | |||
3921 | # endif | 3924 | # endif |
3922 | ) { | 3925 | ) { |
3923 | const struct reserved_combo *reserved; | 3926 | const struct reserved_combo *reserved; |
3924 | reserved = reserved_word(word, ctx); | 3927 | reserved = reserved_word(ctx); |
3925 | debug_printf_parse("checking for reserved-ness: %d\n", !!reserved); | 3928 | debug_printf_parse("checking for reserved-ness: %d\n", !!reserved); |
3926 | if (reserved) { | 3929 | if (reserved) { |
3927 | # if ENABLE_HUSH_LINENO_VAR | 3930 | # if ENABLE_HUSH_LINENO_VAR |
@@ -3940,7 +3943,7 @@ static int done_word(o_string *word, struct parse_context *ctx) | |||
3940 | done_pipe(ctx, PIPE_SEQ); | 3943 | done_pipe(ctx, PIPE_SEQ); |
3941 | } | 3944 | } |
3942 | # endif | 3945 | # endif |
3943 | o_reset_to_empty_unquoted(word); | 3946 | o_reset_to_empty_unquoted(&ctx->word); |
3944 | debug_printf_parse("done_word return %d\n", | 3947 | debug_printf_parse("done_word return %d\n", |
3945 | (ctx->ctx_res_w == RES_SNTX)); | 3948 | (ctx->ctx_res_w == RES_SNTX)); |
3946 | return (ctx->ctx_res_w == RES_SNTX); | 3949 | return (ctx->ctx_res_w == RES_SNTX); |
@@ -3948,7 +3951,7 @@ static int done_word(o_string *word, struct parse_context *ctx) | |||
3948 | # if defined(CMD_SINGLEWORD_NOGLOB) | 3951 | # if defined(CMD_SINGLEWORD_NOGLOB) |
3949 | if (0 | 3952 | if (0 |
3950 | # if BASH_TEST2 | 3953 | # if BASH_TEST2 |
3951 | || strcmp(word->data, "[[") == 0 | 3954 | || strcmp(ctx->word.data, "[[") == 0 |
3952 | # endif | 3955 | # endif |
3953 | /* In bash, local/export/readonly are special, args | 3956 | /* In bash, local/export/readonly are special, args |
3954 | * are assignments and therefore expansion of them | 3957 | * are assignments and therefore expansion of them |
@@ -3965,9 +3968,9 @@ static int done_word(o_string *word, struct parse_context *ctx) | |||
3965 | * $ "export" i=`echo 'aaa bbb'`; echo "$i" | 3968 | * $ "export" i=`echo 'aaa bbb'`; echo "$i" |
3966 | * aaa | 3969 | * aaa |
3967 | */ | 3970 | */ |
3968 | IF_HUSH_LOCAL( || strcmp(word->data, "local") == 0) | 3971 | IF_HUSH_LOCAL( || strcmp(ctx->word.data, "local") == 0) |
3969 | IF_HUSH_EXPORT( || strcmp(word->data, "export") == 0) | 3972 | IF_HUSH_EXPORT( || strcmp(ctx->word.data, "export") == 0) |
3970 | IF_HUSH_READONLY( || strcmp(word->data, "readonly") == 0) | 3973 | IF_HUSH_READONLY(|| strcmp(ctx->word.data, "readonly") == 0) |
3971 | ) { | 3974 | ) { |
3972 | command->cmd_type = CMD_SINGLEWORD_NOGLOB; | 3975 | command->cmd_type = CMD_SINGLEWORD_NOGLOB; |
3973 | } | 3976 | } |
@@ -3978,7 +3981,7 @@ static int done_word(o_string *word, struct parse_context *ctx) | |||
3978 | 3981 | ||
3979 | if (command->group) { | 3982 | if (command->group) { |
3980 | /* "{ echo foo; } echo bar" - bad */ | 3983 | /* "{ echo foo; } echo bar" - bad */ |
3981 | syntax_error_at(word->data); | 3984 | syntax_error_at(ctx->word.data); |
3982 | debug_printf_parse("done_word return 1: syntax error, " | 3985 | debug_printf_parse("done_word return 1: syntax error, " |
3983 | "groups and arglists don't mix\n"); | 3986 | "groups and arglists don't mix\n"); |
3984 | return 1; | 3987 | return 1; |
@@ -3986,26 +3989,26 @@ static int done_word(o_string *word, struct parse_context *ctx) | |||
3986 | 3989 | ||
3987 | /* If this word wasn't an assignment, next ones definitely | 3990 | /* If this word wasn't an assignment, next ones definitely |
3988 | * can't be assignments. Even if they look like ones. */ | 3991 | * can't be assignments. Even if they look like ones. */ |
3989 | if (word->o_assignment != DEFINITELY_ASSIGNMENT | 3992 | if (ctx->is_assignment != DEFINITELY_ASSIGNMENT |
3990 | && word->o_assignment != WORD_IS_KEYWORD | 3993 | && ctx->is_assignment != WORD_IS_KEYWORD |
3991 | ) { | 3994 | ) { |
3992 | word->o_assignment = NOT_ASSIGNMENT; | 3995 | ctx->is_assignment = NOT_ASSIGNMENT; |
3993 | } else { | 3996 | } else { |
3994 | if (word->o_assignment == DEFINITELY_ASSIGNMENT) { | 3997 | if (ctx->is_assignment == DEFINITELY_ASSIGNMENT) { |
3995 | command->assignment_cnt++; | 3998 | command->assignment_cnt++; |
3996 | debug_printf_parse("++assignment_cnt=%d\n", command->assignment_cnt); | 3999 | debug_printf_parse("++assignment_cnt=%d\n", command->assignment_cnt); |
3997 | } | 4000 | } |
3998 | debug_printf_parse("word->o_assignment was:'%s'\n", assignment_flag[word->o_assignment]); | 4001 | debug_printf_parse("ctx->is_assignment was:'%s'\n", assignment_flag[ctx->is_assignment]); |
3999 | word->o_assignment = MAYBE_ASSIGNMENT; | 4002 | ctx->is_assignment = MAYBE_ASSIGNMENT; |
4000 | } | 4003 | } |
4001 | debug_printf_parse("word->o_assignment='%s'\n", assignment_flag[word->o_assignment]); | 4004 | debug_printf_parse("ctx->is_assignment='%s'\n", assignment_flag[ctx->is_assignment]); |
4002 | command->argv = add_string_to_strings(command->argv, xstrdup(word->data)); | 4005 | command->argv = add_string_to_strings(command->argv, xstrdup(ctx->word.data)); |
4003 | debug_print_strings("word appended to argv", command->argv); | 4006 | debug_print_strings("word appended to argv", command->argv); |
4004 | } | 4007 | } |
4005 | 4008 | ||
4006 | #if ENABLE_HUSH_LOOPS | 4009 | #if ENABLE_HUSH_LOOPS |
4007 | if (ctx->ctx_res_w == RES_FOR) { | 4010 | if (ctx->ctx_res_w == RES_FOR) { |
4008 | if (word->has_quoted_part | 4011 | if (ctx->word.has_quoted_part |
4009 | || !is_well_formed_var_name(command->argv[0], '\0') | 4012 | || !is_well_formed_var_name(command->argv[0], '\0') |
4010 | ) { | 4013 | ) { |
4011 | /* bash says just "not a valid identifier" */ | 4014 | /* bash says just "not a valid identifier" */ |
@@ -4026,7 +4029,7 @@ static int done_word(o_string *word, struct parse_context *ctx) | |||
4026 | } | 4029 | } |
4027 | #endif | 4030 | #endif |
4028 | 4031 | ||
4029 | o_reset_to_empty_unquoted(word); | 4032 | o_reset_to_empty_unquoted(&ctx->word); |
4030 | 4033 | ||
4031 | debug_printf_parse("done_word return 0\n"); | 4034 | debug_printf_parse("done_word return 0\n"); |
4032 | return 0; | 4035 | return 0; |
@@ -4310,14 +4313,10 @@ static struct pipe *parse_stream(char **pstring, | |||
4310 | int end_trigger); | 4313 | int end_trigger); |
4311 | 4314 | ||
4312 | 4315 | ||
4313 | #if !ENABLE_HUSH_FUNCTIONS | 4316 | static int parse_group(struct parse_context *ctx, |
4314 | #define parse_group(dest, ctx, input, ch) \ | ||
4315 | parse_group(ctx, input, ch) | ||
4316 | #endif | ||
4317 | static int parse_group(o_string *dest, struct parse_context *ctx, | ||
4318 | struct in_str *input, int ch) | 4317 | struct in_str *input, int ch) |
4319 | { | 4318 | { |
4320 | /* dest contains characters seen prior to ( or {. | 4319 | /* ctx->word contains characters seen prior to ( or {. |
4321 | * Typically it's empty, but for function defs, | 4320 | * Typically it's empty, but for function defs, |
4322 | * it contains function name (without '()'). */ | 4321 | * it contains function name (without '()'). */ |
4323 | #if BB_MMU | 4322 | #if BB_MMU |
@@ -4331,9 +4330,9 @@ static int parse_group(o_string *dest, struct parse_context *ctx, | |||
4331 | 4330 | ||
4332 | debug_printf_parse("parse_group entered\n"); | 4331 | debug_printf_parse("parse_group entered\n"); |
4333 | #if ENABLE_HUSH_FUNCTIONS | 4332 | #if ENABLE_HUSH_FUNCTIONS |
4334 | if (ch == '(' && !dest->has_quoted_part) { | 4333 | if (ch == '(' && !ctx->word.has_quoted_part) { |
4335 | if (dest->length) | 4334 | if (ctx->word.length) |
4336 | if (done_word(dest, ctx)) | 4335 | if (done_word(ctx)) |
4337 | return 1; | 4336 | return 1; |
4338 | if (!command->argv) | 4337 | if (!command->argv) |
4339 | goto skip; /* (... */ | 4338 | goto skip; /* (... */ |
@@ -4365,8 +4364,8 @@ static int parse_group(o_string *dest, struct parse_context *ctx, | |||
4365 | 4364 | ||
4366 | #if 0 /* Prevented by caller */ | 4365 | #if 0 /* Prevented by caller */ |
4367 | if (command->argv /* word [word]{... */ | 4366 | if (command->argv /* word [word]{... */ |
4368 | || dest->length /* word{... */ | 4367 | || ctx->word.length /* word{... */ |
4369 | || dest->has_quoted_part /* ""{... */ | 4368 | || ctx->word.has_quoted_part /* ""{... */ |
4370 | ) { | 4369 | ) { |
4371 | syntax_error(NULL); | 4370 | syntax_error(NULL); |
4372 | debug_printf_parse("parse_group return 1: " | 4371 | debug_printf_parse("parse_group return 1: " |
@@ -4972,29 +4971,28 @@ static struct pipe *parse_stream(char **pstring, | |||
4972 | int end_trigger) | 4971 | int end_trigger) |
4973 | { | 4972 | { |
4974 | struct parse_context ctx; | 4973 | struct parse_context ctx; |
4975 | o_string dest = NULL_O_STRING; | ||
4976 | int heredoc_cnt; | 4974 | int heredoc_cnt; |
4977 | 4975 | ||
4978 | /* Single-quote triggers a bypass of the main loop until its mate is | 4976 | /* Single-quote triggers a bypass of the main loop until its mate is |
4979 | * found. When recursing, quote state is passed in via dest->o_expflags. | 4977 | * found. When recursing, quote state is passed in via ctx.word.o_expflags. |
4980 | */ | 4978 | */ |
4981 | debug_printf_parse("parse_stream entered, end_trigger='%c'\n", | 4979 | debug_printf_parse("parse_stream entered, end_trigger='%c'\n", |
4982 | end_trigger ? end_trigger : 'X'); | 4980 | end_trigger ? end_trigger : 'X'); |
4983 | debug_enter(); | 4981 | debug_enter(); |
4984 | 4982 | ||
4985 | /* If very first arg is "" or '', dest.data may end up NULL. | 4983 | initialize_context(&ctx); |
4986 | * Preventing this: */ | 4984 | |
4987 | o_addchr(&dest, '\0'); | 4985 | /* If very first arg is "" or '', ctx.word.data may end up NULL. |
4988 | dest.length = 0; | 4986 | * Preventing this: |
4987 | */ | ||
4988 | o_addchr(&ctx.word, '\0'); | ||
4989 | ctx.word.length = 0; | ||
4989 | 4990 | ||
4990 | /* We used to separate words on $IFS here. This was wrong. | 4991 | /* We used to separate words on $IFS here. This was wrong. |
4991 | * $IFS is used only for word splitting when $var is expanded, | 4992 | * $IFS is used only for word splitting when $var is expanded, |
4992 | * here we should use blank chars as separators, not $IFS | 4993 | * here we should use blank chars as separators, not $IFS |
4993 | */ | 4994 | */ |
4994 | 4995 | ||
4995 | if (MAYBE_ASSIGNMENT != 0) | ||
4996 | dest.o_assignment = MAYBE_ASSIGNMENT; | ||
4997 | initialize_context(&ctx); | ||
4998 | heredoc_cnt = 0; | 4996 | heredoc_cnt = 0; |
4999 | while (1) { | 4997 | while (1) { |
5000 | const char *is_blank; | 4998 | const char *is_blank; |
@@ -5006,7 +5004,7 @@ static struct pipe *parse_stream(char **pstring, | |||
5006 | 5004 | ||
5007 | ch = i_getch(input); | 5005 | ch = i_getch(input); |
5008 | debug_printf_parse(": ch=%c (%d) escape=%d\n", | 5006 | debug_printf_parse(": ch=%c (%d) escape=%d\n", |
5009 | ch, ch, !!(dest.o_expflags & EXP_FLAG_ESC_GLOB_CHARS)); | 5007 | ch, ch, !!(ctx.word.o_expflags & EXP_FLAG_ESC_GLOB_CHARS)); |
5010 | if (ch == EOF) { | 5008 | if (ch == EOF) { |
5011 | struct pipe *pi; | 5009 | struct pipe *pi; |
5012 | 5010 | ||
@@ -5023,10 +5021,10 @@ static struct pipe *parse_stream(char **pstring, | |||
5023 | goto parse_error; | 5021 | goto parse_error; |
5024 | } | 5022 | } |
5025 | 5023 | ||
5026 | if (done_word(&dest, &ctx)) { | 5024 | if (done_word(&ctx)) { |
5027 | goto parse_error; | 5025 | goto parse_error; |
5028 | } | 5026 | } |
5029 | o_free(&dest); | 5027 | o_free(&ctx.word); |
5030 | done_pipe(&ctx, PIPE_SEQ); | 5028 | done_pipe(&ctx, PIPE_SEQ); |
5031 | pi = ctx.list_head; | 5029 | pi = ctx.list_head; |
5032 | /* If we got nothing... */ | 5030 | /* If we got nothing... */ |
@@ -5066,8 +5064,8 @@ static struct pipe *parse_stream(char **pstring, | |||
5066 | SPECIAL_VAR_SYMBOL_STR; | 5064 | SPECIAL_VAR_SYMBOL_STR; |
5067 | /* Are { and } special here? */ | 5065 | /* Are { and } special here? */ |
5068 | if (ctx.command->argv /* word [word]{... - non-special */ | 5066 | if (ctx.command->argv /* word [word]{... - non-special */ |
5069 | || dest.length /* word{... - non-special */ | 5067 | || ctx.word.length /* word{... - non-special */ |
5070 | || dest.has_quoted_part /* ""{... - non-special */ | 5068 | || ctx.word.has_quoted_part /* ""{... - non-special */ |
5071 | || (next != ';' /* }; - special */ | 5069 | || (next != ';' /* }; - special */ |
5072 | && next != ')' /* }) - special */ | 5070 | && next != ')' /* }) - special */ |
5073 | && next != '(' /* {( - special */ | 5071 | && next != '(' /* {( - special */ |
@@ -5084,14 +5082,14 @@ static struct pipe *parse_stream(char **pstring, | |||
5084 | 5082 | ||
5085 | if (!is_special && !is_blank) { /* ordinary char */ | 5083 | if (!is_special && !is_blank) { /* ordinary char */ |
5086 | ordinary_char: | 5084 | ordinary_char: |
5087 | o_addQchr(&dest, ch); | 5085 | o_addQchr(&ctx.word, ch); |
5088 | if ((dest.o_assignment == MAYBE_ASSIGNMENT | 5086 | if ((ctx.is_assignment == MAYBE_ASSIGNMENT |
5089 | || dest.o_assignment == WORD_IS_KEYWORD) | 5087 | || ctx.is_assignment == WORD_IS_KEYWORD) |
5090 | && ch == '=' | 5088 | && ch == '=' |
5091 | && is_well_formed_var_name(dest.data, '=') | 5089 | && is_well_formed_var_name(ctx.word.data, '=') |
5092 | ) { | 5090 | ) { |
5093 | dest.o_assignment = DEFINITELY_ASSIGNMENT; | 5091 | ctx.is_assignment = DEFINITELY_ASSIGNMENT; |
5094 | debug_printf_parse("dest.o_assignment='%s'\n", assignment_flag[dest.o_assignment]); | 5092 | debug_printf_parse("ctx.is_assignment='%s'\n", assignment_flag[ctx.is_assignment]); |
5095 | } | 5093 | } |
5096 | continue; | 5094 | continue; |
5097 | } | 5095 | } |
@@ -5113,7 +5111,7 @@ static struct pipe *parse_stream(char **pstring, | |||
5113 | } | 5111 | } |
5114 | /* ch == last eaten whitespace char */ | 5112 | /* ch == last eaten whitespace char */ |
5115 | #endif | 5113 | #endif |
5116 | if (done_word(&dest, &ctx)) { | 5114 | if (done_word(&ctx)) { |
5117 | goto parse_error; | 5115 | goto parse_error; |
5118 | } | 5116 | } |
5119 | if (ch == '\n') { | 5117 | if (ch == '\n') { |
@@ -5123,7 +5121,7 @@ static struct pipe *parse_stream(char **pstring, | |||
5123 | * "case ... in <newline> word) ..." | 5121 | * "case ... in <newline> word) ..." |
5124 | */ | 5122 | */ |
5125 | if (IS_NULL_CMD(ctx.command) | 5123 | if (IS_NULL_CMD(ctx.command) |
5126 | && dest.length == 0 && !dest.has_quoted_part | 5124 | && ctx.word.length == 0 && !ctx.word.has_quoted_part |
5127 | ) { | 5125 | ) { |
5128 | /* This newline can be ignored. But... | 5126 | /* This newline can be ignored. But... |
5129 | * Without check #1, interactive shell | 5127 | * Without check #1, interactive shell |
@@ -5158,8 +5156,8 @@ static struct pipe *parse_stream(char **pstring, | |||
5158 | } | 5156 | } |
5159 | heredoc_cnt = 0; | 5157 | heredoc_cnt = 0; |
5160 | } | 5158 | } |
5161 | dest.o_assignment = MAYBE_ASSIGNMENT; | 5159 | ctx.is_assignment = MAYBE_ASSIGNMENT; |
5162 | debug_printf_parse("dest.o_assignment='%s'\n", assignment_flag[dest.o_assignment]); | 5160 | debug_printf_parse("ctx.is_assignment='%s'\n", assignment_flag[ctx.is_assignment]); |
5163 | ch = ';'; | 5161 | ch = ';'; |
5164 | /* note: if (is_blank) continue; | 5162 | /* note: if (is_blank) continue; |
5165 | * will still trigger for us */ | 5163 | * will still trigger for us */ |
@@ -5171,8 +5169,8 @@ static struct pipe *parse_stream(char **pstring, | |||
5171 | * Pathological example: { ""}; } should exec "}" cmd | 5169 | * Pathological example: { ""}; } should exec "}" cmd |
5172 | */ | 5170 | */ |
5173 | if (ch == '}') { | 5171 | if (ch == '}') { |
5174 | if (dest.length != 0 /* word} */ | 5172 | if (ctx.word.length != 0 /* word} */ |
5175 | || dest.has_quoted_part /* ""} */ | 5173 | || ctx.word.has_quoted_part /* ""} */ |
5176 | ) { | 5174 | ) { |
5177 | goto ordinary_char; | 5175 | goto ordinary_char; |
5178 | } | 5176 | } |
@@ -5201,7 +5199,7 @@ static struct pipe *parse_stream(char **pstring, | |||
5201 | #if ENABLE_HUSH_CASE | 5199 | #if ENABLE_HUSH_CASE |
5202 | && (ch != ')' | 5200 | && (ch != ')' |
5203 | || ctx.ctx_res_w != RES_MATCH | 5201 | || ctx.ctx_res_w != RES_MATCH |
5204 | || (!dest.has_quoted_part && strcmp(dest.data, "esac") == 0) | 5202 | || (!ctx.word.has_quoted_part && strcmp(ctx.word.data, "esac") == 0) |
5205 | ) | 5203 | ) |
5206 | #endif | 5204 | #endif |
5207 | ) { | 5205 | ) { |
@@ -5218,17 +5216,17 @@ static struct pipe *parse_stream(char **pstring, | |||
5218 | syntax_error_unterm_str("here document"); | 5216 | syntax_error_unterm_str("here document"); |
5219 | goto parse_error; | 5217 | goto parse_error; |
5220 | } | 5218 | } |
5221 | if (done_word(&dest, &ctx)) { | 5219 | if (done_word(&ctx)) { |
5222 | goto parse_error; | 5220 | goto parse_error; |
5223 | } | 5221 | } |
5224 | done_pipe(&ctx, PIPE_SEQ); | 5222 | done_pipe(&ctx, PIPE_SEQ); |
5225 | dest.o_assignment = MAYBE_ASSIGNMENT; | 5223 | ctx.is_assignment = MAYBE_ASSIGNMENT; |
5226 | debug_printf_parse("dest.o_assignment='%s'\n", assignment_flag[dest.o_assignment]); | 5224 | debug_printf_parse("ctx.is_assignment='%s'\n", assignment_flag[ctx.is_assignment]); |
5227 | /* Do we sit outside of any if's, loops or case's? */ | 5225 | /* Do we sit outside of any if's, loops or case's? */ |
5228 | if (!HAS_KEYWORDS | 5226 | if (!HAS_KEYWORDS |
5229 | IF_HAS_KEYWORDS(|| (ctx.ctx_res_w == RES_NONE && ctx.old_flag == 0)) | 5227 | IF_HAS_KEYWORDS(|| (ctx.ctx_res_w == RES_NONE && ctx.old_flag == 0)) |
5230 | ) { | 5228 | ) { |
5231 | o_free(&dest); | 5229 | o_free(&ctx.word); |
5232 | #if !BB_MMU | 5230 | #if !BB_MMU |
5233 | debug_printf_parse("as_string2 '%s'\n", ctx.as_string.data); | 5231 | debug_printf_parse("as_string2 '%s'\n", ctx.as_string.data); |
5234 | if (pstring) | 5232 | if (pstring) |
@@ -5257,8 +5255,8 @@ static struct pipe *parse_stream(char **pstring, | |||
5257 | * an assignment. a=1 2>z b=2: b=2 is still assignment */ | 5255 | * an assignment. a=1 2>z b=2: b=2 is still assignment */ |
5258 | switch (ch) { | 5256 | switch (ch) { |
5259 | case '>': | 5257 | case '>': |
5260 | redir_fd = redirect_opt_num(&dest); | 5258 | redir_fd = redirect_opt_num(&ctx.word); |
5261 | if (done_word(&dest, &ctx)) { | 5259 | if (done_word(&ctx)) { |
5262 | goto parse_error; | 5260 | goto parse_error; |
5263 | } | 5261 | } |
5264 | redir_style = REDIRECT_OVERWRITE; | 5262 | redir_style = REDIRECT_OVERWRITE; |
@@ -5279,8 +5277,8 @@ static struct pipe *parse_stream(char **pstring, | |||
5279 | goto parse_error; | 5277 | goto parse_error; |
5280 | continue; /* back to top of while (1) */ | 5278 | continue; /* back to top of while (1) */ |
5281 | case '<': | 5279 | case '<': |
5282 | redir_fd = redirect_opt_num(&dest); | 5280 | redir_fd = redirect_opt_num(&ctx.word); |
5283 | if (done_word(&dest, &ctx)) { | 5281 | if (done_word(&ctx)) { |
5284 | goto parse_error; | 5282 | goto parse_error; |
5285 | } | 5283 | } |
5286 | redir_style = REDIRECT_INPUT; | 5284 | redir_style = REDIRECT_INPUT; |
@@ -5307,7 +5305,7 @@ static struct pipe *parse_stream(char **pstring, | |||
5307 | goto parse_error; | 5305 | goto parse_error; |
5308 | continue; /* back to top of while (1) */ | 5306 | continue; /* back to top of while (1) */ |
5309 | case '#': | 5307 | case '#': |
5310 | if (dest.length == 0 && !dest.has_quoted_part) { | 5308 | if (ctx.word.length == 0 && !ctx.word.has_quoted_part) { |
5311 | /* skip "#comment" */ | 5309 | /* skip "#comment" */ |
5312 | /* note: we do not add it to &ctx.as_string */ | 5310 | /* note: we do not add it to &ctx.as_string */ |
5313 | /* TODO: in bash: | 5311 | /* TODO: in bash: |
@@ -5342,14 +5340,14 @@ static struct pipe *parse_stream(char **pstring, | |||
5342 | break; | 5340 | break; |
5343 | } | 5341 | } |
5344 | 5342 | ||
5345 | if (dest.o_assignment == MAYBE_ASSIGNMENT | 5343 | if (ctx.is_assignment == MAYBE_ASSIGNMENT |
5346 | /* check that we are not in word in "a=1 2>word b=1": */ | 5344 | /* check that we are not in word in "a=1 2>word b=1": */ |
5347 | && !ctx.pending_redirect | 5345 | && !ctx.pending_redirect |
5348 | ) { | 5346 | ) { |
5349 | /* ch is a special char and thus this word | 5347 | /* ch is a special char and thus this word |
5350 | * cannot be an assignment */ | 5348 | * cannot be an assignment */ |
5351 | dest.o_assignment = NOT_ASSIGNMENT; | 5349 | ctx.is_assignment = NOT_ASSIGNMENT; |
5352 | debug_printf_parse("dest.o_assignment='%s'\n", assignment_flag[dest.o_assignment]); | 5350 | debug_printf_parse("ctx.is_assignment='%s'\n", assignment_flag[ctx.is_assignment]); |
5353 | } | 5351 | } |
5354 | 5352 | ||
5355 | /* Note: nommu_addchr(&ctx.as_string, ch) is already done */ | 5353 | /* Note: nommu_addchr(&ctx.as_string, ch) is already done */ |
@@ -5357,12 +5355,12 @@ static struct pipe *parse_stream(char **pstring, | |||
5357 | switch (ch) { | 5355 | switch (ch) { |
5358 | case SPECIAL_VAR_SYMBOL: | 5356 | case SPECIAL_VAR_SYMBOL: |
5359 | /* Convert raw ^C to corresponding special variable reference */ | 5357 | /* Convert raw ^C to corresponding special variable reference */ |
5360 | o_addchr(&dest, SPECIAL_VAR_SYMBOL); | 5358 | o_addchr(&ctx.word, SPECIAL_VAR_SYMBOL); |
5361 | o_addchr(&dest, SPECIAL_VAR_QUOTED_SVS); | 5359 | o_addchr(&ctx.word, SPECIAL_VAR_QUOTED_SVS); |
5362 | /* fall through */ | 5360 | /* fall through */ |
5363 | case '#': | 5361 | case '#': |
5364 | /* non-comment #: "echo a#b" etc */ | 5362 | /* non-comment #: "echo a#b" etc */ |
5365 | o_addchr(&dest, ch); | 5363 | o_addchr(&ctx.word, ch); |
5366 | break; | 5364 | break; |
5367 | case '\\': | 5365 | case '\\': |
5368 | if (next == EOF) { | 5366 | if (next == EOF) { |
@@ -5371,29 +5369,29 @@ static struct pipe *parse_stream(char **pstring, | |||
5371 | } | 5369 | } |
5372 | ch = i_getch(input); | 5370 | ch = i_getch(input); |
5373 | /* note: ch != '\n' (that case does not reach this place) */ | 5371 | /* note: ch != '\n' (that case does not reach this place) */ |
5374 | o_addchr(&dest, '\\'); | 5372 | o_addchr(&ctx.word, '\\'); |
5375 | /*nommu_addchr(&ctx.as_string, '\\'); - already done */ | 5373 | /*nommu_addchr(&ctx.as_string, '\\'); - already done */ |
5376 | o_addchr(&dest, ch); | 5374 | o_addchr(&ctx.word, ch); |
5377 | nommu_addchr(&ctx.as_string, ch); | 5375 | nommu_addchr(&ctx.as_string, ch); |
5378 | /* Example: echo Hello \2>file | 5376 | /* Example: echo Hello \2>file |
5379 | * we need to know that word 2 is quoted */ | 5377 | * we need to know that word 2 is quoted */ |
5380 | dest.has_quoted_part = 1; | 5378 | ctx.word.has_quoted_part = 1; |
5381 | break; | 5379 | break; |
5382 | case '$': | 5380 | case '$': |
5383 | if (!parse_dollar(&ctx.as_string, &dest, input, /*quote_mask:*/ 0)) { | 5381 | if (!parse_dollar(&ctx.as_string, &ctx.word, input, /*quote_mask:*/ 0)) { |
5384 | debug_printf_parse("parse_stream parse error: " | 5382 | debug_printf_parse("parse_stream parse error: " |
5385 | "parse_dollar returned 0 (error)\n"); | 5383 | "parse_dollar returned 0 (error)\n"); |
5386 | goto parse_error; | 5384 | goto parse_error; |
5387 | } | 5385 | } |
5388 | break; | 5386 | break; |
5389 | case '\'': | 5387 | case '\'': |
5390 | dest.has_quoted_part = 1; | 5388 | ctx.word.has_quoted_part = 1; |
5391 | if (next == '\'' && !ctx.pending_redirect) { | 5389 | if (next == '\'' && !ctx.pending_redirect) { |
5392 | insert_empty_quoted_str_marker: | 5390 | insert_empty_quoted_str_marker: |
5393 | nommu_addchr(&ctx.as_string, next); | 5391 | nommu_addchr(&ctx.as_string, next); |
5394 | i_getch(input); /* eat second ' */ | 5392 | i_getch(input); /* eat second ' */ |
5395 | o_addchr(&dest, SPECIAL_VAR_SYMBOL); | 5393 | o_addchr(&ctx.word, SPECIAL_VAR_SYMBOL); |
5396 | o_addchr(&dest, SPECIAL_VAR_SYMBOL); | 5394 | o_addchr(&ctx.word, SPECIAL_VAR_SYMBOL); |
5397 | } else { | 5395 | } else { |
5398 | while (1) { | 5396 | while (1) { |
5399 | ch = i_getch(input); | 5397 | ch = i_getch(input); |
@@ -5406,38 +5404,38 @@ static struct pipe *parse_stream(char **pstring, | |||
5406 | break; | 5404 | break; |
5407 | if (ch == SPECIAL_VAR_SYMBOL) { | 5405 | if (ch == SPECIAL_VAR_SYMBOL) { |
5408 | /* Convert raw ^C to corresponding special variable reference */ | 5406 | /* Convert raw ^C to corresponding special variable reference */ |
5409 | o_addchr(&dest, SPECIAL_VAR_SYMBOL); | 5407 | o_addchr(&ctx.word, SPECIAL_VAR_SYMBOL); |
5410 | o_addchr(&dest, SPECIAL_VAR_QUOTED_SVS); | 5408 | o_addchr(&ctx.word, SPECIAL_VAR_QUOTED_SVS); |
5411 | } | 5409 | } |
5412 | o_addqchr(&dest, ch); | 5410 | o_addqchr(&ctx.word, ch); |
5413 | } | 5411 | } |
5414 | } | 5412 | } |
5415 | break; | 5413 | break; |
5416 | case '"': | 5414 | case '"': |
5417 | dest.has_quoted_part = 1; | 5415 | ctx.word.has_quoted_part = 1; |
5418 | if (next == '"' && !ctx.pending_redirect) | 5416 | if (next == '"' && !ctx.pending_redirect) |
5419 | goto insert_empty_quoted_str_marker; | 5417 | goto insert_empty_quoted_str_marker; |
5420 | if (dest.o_assignment == NOT_ASSIGNMENT) | 5418 | if (ctx.is_assignment == NOT_ASSIGNMENT) |
5421 | dest.o_expflags |= EXP_FLAG_ESC_GLOB_CHARS; | 5419 | ctx.word.o_expflags |= EXP_FLAG_ESC_GLOB_CHARS; |
5422 | if (!encode_string(&ctx.as_string, &dest, input, '"', /*process_bkslash:*/ 1)) | 5420 | if (!encode_string(&ctx.as_string, &ctx.word, input, '"', /*process_bkslash:*/ 1)) |
5423 | goto parse_error; | 5421 | goto parse_error; |
5424 | dest.o_expflags &= ~EXP_FLAG_ESC_GLOB_CHARS; | 5422 | ctx.word.o_expflags &= ~EXP_FLAG_ESC_GLOB_CHARS; |
5425 | break; | 5423 | break; |
5426 | #if ENABLE_HUSH_TICK | 5424 | #if ENABLE_HUSH_TICK |
5427 | case '`': { | 5425 | case '`': { |
5428 | USE_FOR_NOMMU(unsigned pos;) | 5426 | USE_FOR_NOMMU(unsigned pos;) |
5429 | 5427 | ||
5430 | o_addchr(&dest, SPECIAL_VAR_SYMBOL); | 5428 | o_addchr(&ctx.word, SPECIAL_VAR_SYMBOL); |
5431 | o_addchr(&dest, '`'); | 5429 | o_addchr(&ctx.word, '`'); |
5432 | USE_FOR_NOMMU(pos = dest.length;) | 5430 | USE_FOR_NOMMU(pos = ctx.word.length;) |
5433 | if (!add_till_backquote(&dest, input, /*in_dquote:*/ 0)) | 5431 | if (!add_till_backquote(&ctx.word, input, /*in_dquote:*/ 0)) |
5434 | goto parse_error; | 5432 | goto parse_error; |
5435 | # if !BB_MMU | 5433 | # if !BB_MMU |
5436 | o_addstr(&ctx.as_string, dest.data + pos); | 5434 | o_addstr(&ctx.as_string, ctx.word.data + pos); |
5437 | o_addchr(&ctx.as_string, '`'); | 5435 | o_addchr(&ctx.as_string, '`'); |
5438 | # endif | 5436 | # endif |
5439 | o_addchr(&dest, SPECIAL_VAR_SYMBOL); | 5437 | o_addchr(&ctx.word, SPECIAL_VAR_SYMBOL); |
5440 | //debug_printf_subst("SUBST RES3 '%s'\n", dest.data + pos); | 5438 | //debug_printf_subst("SUBST RES3 '%s'\n", ctx.word.data + pos); |
5441 | break; | 5439 | break; |
5442 | } | 5440 | } |
5443 | #endif | 5441 | #endif |
@@ -5445,7 +5443,7 @@ static struct pipe *parse_stream(char **pstring, | |||
5445 | #if ENABLE_HUSH_CASE | 5443 | #if ENABLE_HUSH_CASE |
5446 | case_semi: | 5444 | case_semi: |
5447 | #endif | 5445 | #endif |
5448 | if (done_word(&dest, &ctx)) { | 5446 | if (done_word(&ctx)) { |
5449 | goto parse_error; | 5447 | goto parse_error; |
5450 | } | 5448 | } |
5451 | done_pipe(&ctx, PIPE_SEQ); | 5449 | done_pipe(&ctx, PIPE_SEQ); |
@@ -5468,11 +5466,11 @@ static struct pipe *parse_stream(char **pstring, | |||
5468 | new_cmd: | 5466 | new_cmd: |
5469 | /* We just finished a cmd. New one may start | 5467 | /* We just finished a cmd. New one may start |
5470 | * with an assignment */ | 5468 | * with an assignment */ |
5471 | dest.o_assignment = MAYBE_ASSIGNMENT; | 5469 | ctx.is_assignment = MAYBE_ASSIGNMENT; |
5472 | debug_printf_parse("dest.o_assignment='%s'\n", assignment_flag[dest.o_assignment]); | 5470 | debug_printf_parse("ctx.is_assignment='%s'\n", assignment_flag[ctx.is_assignment]); |
5473 | break; | 5471 | break; |
5474 | case '&': | 5472 | case '&': |
5475 | if (done_word(&dest, &ctx)) { | 5473 | if (done_word(&ctx)) { |
5476 | goto parse_error; | 5474 | goto parse_error; |
5477 | } | 5475 | } |
5478 | if (next == '\\') | 5476 | if (next == '\\') |
@@ -5486,7 +5484,7 @@ static struct pipe *parse_stream(char **pstring, | |||
5486 | } | 5484 | } |
5487 | goto new_cmd; | 5485 | goto new_cmd; |
5488 | case '|': | 5486 | case '|': |
5489 | if (done_word(&dest, &ctx)) { | 5487 | if (done_word(&ctx)) { |
5490 | goto parse_error; | 5488 | goto parse_error; |
5491 | } | 5489 | } |
5492 | #if ENABLE_HUSH_CASE | 5490 | #if ENABLE_HUSH_CASE |
@@ -5511,14 +5509,14 @@ static struct pipe *parse_stream(char **pstring, | |||
5511 | /* "case... in [(]word)..." - skip '(' */ | 5509 | /* "case... in [(]word)..." - skip '(' */ |
5512 | if (ctx.ctx_res_w == RES_MATCH | 5510 | if (ctx.ctx_res_w == RES_MATCH |
5513 | && ctx.command->argv == NULL /* not (word|(... */ | 5511 | && ctx.command->argv == NULL /* not (word|(... */ |
5514 | && dest.length == 0 /* not word(... */ | 5512 | && ctx.word.length == 0 /* not word(... */ |
5515 | && dest.has_quoted_part == 0 /* not ""(... */ | 5513 | && ctx.word.has_quoted_part == 0 /* not ""(... */ |
5516 | ) { | 5514 | ) { |
5517 | continue; | 5515 | continue; |
5518 | } | 5516 | } |
5519 | #endif | 5517 | #endif |
5520 | case '{': | 5518 | case '{': |
5521 | if (parse_group(&dest, &ctx, input, ch) != 0) { | 5519 | if (parse_group(&ctx, input, ch) != 0) { |
5522 | goto parse_error; | 5520 | goto parse_error; |
5523 | } | 5521 | } |
5524 | goto new_cmd; | 5522 | goto new_cmd; |
@@ -5575,7 +5573,7 @@ static struct pipe *parse_stream(char **pstring, | |||
5575 | IF_HAS_KEYWORDS(pctx = p2;) | 5573 | IF_HAS_KEYWORDS(pctx = p2;) |
5576 | } while (HAS_KEYWORDS && pctx); | 5574 | } while (HAS_KEYWORDS && pctx); |
5577 | 5575 | ||
5578 | o_free(&dest); | 5576 | o_free(&ctx.word); |
5579 | #if !BB_MMU | 5577 | #if !BB_MMU |
5580 | if (pstring) | 5578 | if (pstring) |
5581 | *pstring = NULL; | 5579 | *pstring = NULL; |