aboutsummaryrefslogtreecommitdiff
path: root/shell
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2018-04-10 03:22:10 +0200
committerDenys Vlasenko <vda.linux@googlemail.com>2018-04-10 03:22:10 +0200
commit09b7a7ec0ea5ef602ff543dad1a90b6174a4f1c8 (patch)
treeb8b2e44a90f7a7558d6697956f4679a4f22c8d78 /shell
parente93031e6dced47e8f5a86408b4aa3f89aef647c7 (diff)
downloadbusybox-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.c242
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;
527enum { 526enum {
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};
534enum {
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};
714enum {
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)
3671static void initialize_context(struct parse_context *ctx) 3672static 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 */
3755static const struct reserved_combo* reserved_word(o_string *word, struct parse_context *ctx) 3758static 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 */
3853static int done_word(o_string *word, struct parse_context *ctx) 3856static 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 4316static int parse_group(struct parse_context *ctx,
4314#define parse_group(dest, ctx, input, ch) \
4315 parse_group(ctx, input, ch)
4316#endif
4317static 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;