diff options
author | Denis Vlasenko <vda.linux@googlemail.com> | 2009-04-10 00:20:58 +0000 |
---|---|---|
committer | Denis Vlasenko <vda.linux@googlemail.com> | 2009-04-10 00:20:58 +0000 |
commit | c96865f4458f357df41eeea73d456e15755b51f4 (patch) | |
tree | 2ff83e9aa8062a05aea94c9b576af5f5c8870b55 | |
parent | e05f9286a943eb74bdcdead86c016e6c8cc5c082 (diff) | |
download | busybox-w32-c96865f4458f357df41eeea73d456e15755b51f4.tar.gz busybox-w32-c96865f4458f357df41eeea73d456e15755b51f4.tar.bz2 busybox-w32-c96865f4458f357df41eeea73d456e15755b51f4.zip |
hush: readability improvements.
fix some more obscure bugs.
a new redir4.tests is known to fail.
-rw-r--r-- | shell/hush.c | 216 | ||||
-rw-r--r-- | shell/hush_test/hush-misc/redir1.right | 2 | ||||
-rwxr-xr-x | shell/hush_test/hush-misc/redir1.tests | 6 | ||||
-rw-r--r-- | shell/hush_test/hush-misc/redir4.right | 25 | ||||
-rwxr-xr-x | shell/hush_test/hush-misc/redir4.tests | 80 |
5 files changed, 232 insertions, 97 deletions
diff --git a/shell/hush.c b/shell/hush.c index ac2410c48..21590adfb 100644 --- a/shell/hush.c +++ b/shell/hush.c | |||
@@ -341,7 +341,11 @@ typedef enum redir_type { | |||
341 | REDIRECT_HEREDOC = 4, | 341 | REDIRECT_HEREDOC = 4, |
342 | REDIRECT_IO = 5, | 342 | REDIRECT_IO = 5, |
343 | REDIRECT_HEREDOC2 = 6, /* REDIRECT_HEREDOC after heredoc is loaded */ | 343 | REDIRECT_HEREDOC2 = 6, /* REDIRECT_HEREDOC after heredoc is loaded */ |
344 | REDIRFD_CLOSE = -3, | 344 | |
345 | REDIRFD_CLOSE = -3, | ||
346 | REDIRFD_SYNTAX_ERR = -2, | ||
347 | REDIRFD_TO_FILE = -1, /* otherwise, rd_fd if redirected to rd_dup */ | ||
348 | |||
345 | HEREDOC_SKIPTABS = 1, | 349 | HEREDOC_SKIPTABS = 1, |
346 | HEREDOC_QUOTED = 2, | 350 | HEREDOC_QUOTED = 2, |
347 | } redir_type; | 351 | } redir_type; |
@@ -2427,6 +2431,7 @@ static int setup_redirects(struct command *prog, int squirrel[]) | |||
2427 | 2431 | ||
2428 | for (redir = prog->redirects; redir; redir = redir->next) { | 2432 | for (redir = prog->redirects; redir; redir = redir->next) { |
2429 | if (redir->rd_type == REDIRECT_HEREDOC2) { | 2433 | if (redir->rd_type == REDIRECT_HEREDOC2) { |
2434 | /* rd_fd<<HERE case */ | ||
2430 | if (squirrel && redir->rd_fd < 3) { | 2435 | if (squirrel && redir->rd_fd < 3) { |
2431 | squirrel[redir->rd_fd] = dup(redir->rd_fd); | 2436 | squirrel[redir->rd_fd] = dup(redir->rd_fd); |
2432 | } | 2437 | } |
@@ -2438,15 +2443,16 @@ static int setup_redirects(struct command *prog, int squirrel[]) | |||
2438 | continue; | 2443 | continue; |
2439 | } | 2444 | } |
2440 | 2445 | ||
2441 | if (redir->rd_dup == -1) { | 2446 | if (redir->rd_dup == REDIRFD_TO_FILE) { |
2447 | /* rd_fd<*>file case (<*> is <,>,>>,<>) */ | ||
2442 | char *p; | 2448 | char *p; |
2443 | if (redir->rd_filename == NULL) { | 2449 | if (redir->rd_filename == NULL) { |
2444 | /* Something went wrong in the parse. | 2450 | /* Something went wrong in the parse. |
2445 | * Pretend it didn't happen */ | 2451 | * Pretend it didn't happen */ |
2452 | bb_error_msg("bug in redirect parse"); | ||
2446 | continue; | 2453 | continue; |
2447 | } | 2454 | } |
2448 | mode = redir_table[redir->rd_type].mode; | 2455 | mode = redir_table[redir->rd_type].mode; |
2449 | //TODO: check redir for names like '\\' | ||
2450 | p = expand_string_to_string(redir->rd_filename); | 2456 | p = expand_string_to_string(redir->rd_filename); |
2451 | openfd = open_or_warn(p, mode); | 2457 | openfd = open_or_warn(p, mode); |
2452 | free(p); | 2458 | free(p); |
@@ -2457,6 +2463,7 @@ static int setup_redirects(struct command *prog, int squirrel[]) | |||
2457 | return 1; | 2463 | return 1; |
2458 | } | 2464 | } |
2459 | } else { | 2465 | } else { |
2466 | /* rd_fd<*>rd_dup or rd_fd<*>- cases */ | ||
2460 | openfd = redir->rd_dup; | 2467 | openfd = redir->rd_dup; |
2461 | } | 2468 | } |
2462 | 2469 | ||
@@ -2469,7 +2476,7 @@ static int setup_redirects(struct command *prog, int squirrel[]) | |||
2469 | close(redir->rd_fd); | 2476 | close(redir->rd_fd); |
2470 | } else { | 2477 | } else { |
2471 | xdup2(openfd, redir->rd_fd); | 2478 | xdup2(openfd, redir->rd_fd); |
2472 | if (redir->rd_dup == -1) | 2479 | if (redir->rd_dup == REDIRFD_TO_FILE) |
2473 | close(openfd); | 2480 | close(openfd); |
2474 | } | 2481 | } |
2475 | } | 2482 | } |
@@ -3963,17 +3970,6 @@ static int done_word(o_string *word, struct parse_context *ctx) | |||
3963 | debug_printf_parse("done_word return 0: true null, ignored\n"); | 3970 | debug_printf_parse("done_word return 0: true null, ignored\n"); |
3964 | return 0; | 3971 | return 0; |
3965 | } | 3972 | } |
3966 | /* If this word wasn't an assignment, next ones definitely | ||
3967 | * can't be assignments. Even if they look like ones. */ | ||
3968 | if (word->o_assignment != DEFINITELY_ASSIGNMENT | ||
3969 | && word->o_assignment != WORD_IS_KEYWORD | ||
3970 | ) { | ||
3971 | word->o_assignment = NOT_ASSIGNMENT; | ||
3972 | } else { | ||
3973 | if (word->o_assignment == DEFINITELY_ASSIGNMENT) | ||
3974 | command->assignment_cnt++; | ||
3975 | word->o_assignment = MAYBE_ASSIGNMENT; | ||
3976 | } | ||
3977 | 3973 | ||
3978 | if (ctx->pending_redirect) { | 3974 | if (ctx->pending_redirect) { |
3979 | /* We do not glob in e.g. >*.tmp case. bash seems to glob here | 3975 | /* We do not glob in e.g. >*.tmp case. bash seems to glob here |
@@ -3989,29 +3985,47 @@ static int done_word(o_string *word, struct parse_context *ctx) | |||
3989 | * the expansion would result in one word." | 3985 | * the expansion would result in one word." |
3990 | */ | 3986 | */ |
3991 | ctx->pending_redirect->rd_filename = xstrdup(word->data); | 3987 | ctx->pending_redirect->rd_filename = xstrdup(word->data); |
3988 | /* Cater for >\file case: | ||
3989 | * >\a creates file a; >\\a, >"\a", >"\\a" create file \a | ||
3990 | * Same with heredocs: | ||
3991 | * for <<\H delim is H; <<\\H, <<"\H", <<"\\H" - \H | ||
3992 | */ | ||
3993 | unbackslash(ctx->pending_redirect->rd_filename); | ||
3994 | /* Is it <<"HEREDOC"? */ | ||
3992 | if (ctx->pending_redirect->rd_type == REDIRECT_HEREDOC | 3995 | if (ctx->pending_redirect->rd_type == REDIRECT_HEREDOC |
3993 | && word->o_quoted | 3996 | && word->o_quoted |
3994 | ) { | 3997 | ) { |
3995 | ctx->pending_redirect->rd_dup |= HEREDOC_QUOTED; | 3998 | ctx->pending_redirect->rd_dup |= HEREDOC_QUOTED; |
3996 | } | 3999 | } |
3997 | word->o_assignment = NOT_ASSIGNMENT; | ||
3998 | debug_printf_parse("word stored in rd_filename: '%s'\n", word->data); | 4000 | debug_printf_parse("word stored in rd_filename: '%s'\n", word->data); |
3999 | } else { | 4001 | } else { |
4000 | /* "{ echo foo; } echo bar" - bad */ | 4002 | /* If this word wasn't an assignment, next ones definitely |
4001 | /* NB: bash allows e.g.: | 4003 | * can't be assignments. Even if they look like ones. */ |
4002 | * if true; then { echo foo; } fi | 4004 | if (word->o_assignment != DEFINITELY_ASSIGNMENT |
4003 | * while if false; then false; fi do break; done | 4005 | && word->o_assignment != WORD_IS_KEYWORD |
4004 | * and disallows: | 4006 | ) { |
4005 | * while if false; then false; fi; do; break; done | 4007 | word->o_assignment = NOT_ASSIGNMENT; |
4006 | * TODO? */ | 4008 | } else { |
4009 | if (word->o_assignment == DEFINITELY_ASSIGNMENT) | ||
4010 | command->assignment_cnt++; | ||
4011 | word->o_assignment = MAYBE_ASSIGNMENT; | ||
4012 | } | ||
4013 | |||
4007 | if (command->group) { | 4014 | if (command->group) { |
4015 | /* "{ echo foo; } echo bar" - bad */ | ||
4016 | /* NB: bash allows e.g.: | ||
4017 | * if true; then { echo foo; } fi | ||
4018 | * while if false; then false; fi do break; done | ||
4019 | * and disallows: | ||
4020 | * while if false; then false; fi; do; break; done | ||
4021 | * TODO? */ | ||
4008 | syntax_error_at(word->data); | 4022 | syntax_error_at(word->data); |
4009 | debug_printf_parse("done_word return 1: syntax error, " | 4023 | debug_printf_parse("done_word return 1: syntax error, " |
4010 | "groups and arglists don't mix\n"); | 4024 | "groups and arglists don't mix\n"); |
4011 | return 1; | 4025 | return 1; |
4012 | } | 4026 | } |
4013 | #if HAS_KEYWORDS | 4027 | #if HAS_KEYWORDS |
4014 | #if ENABLE_HUSH_CASE | 4028 | # if ENABLE_HUSH_CASE |
4015 | if (ctx->ctx_dsemicolon | 4029 | if (ctx->ctx_dsemicolon |
4016 | && strcmp(word->data, "esac") != 0 /* not "... pattern) cmd;; esac" */ | 4030 | && strcmp(word->data, "esac") != 0 /* not "... pattern) cmd;; esac" */ |
4017 | ) { | 4031 | ) { |
@@ -4019,12 +4033,12 @@ static int done_word(o_string *word, struct parse_context *ctx) | |||
4019 | /* ctx->ctx_res_w = RES_MATCH; */ | 4033 | /* ctx->ctx_res_w = RES_MATCH; */ |
4020 | ctx->ctx_dsemicolon = 0; | 4034 | ctx->ctx_dsemicolon = 0; |
4021 | } else | 4035 | } else |
4022 | #endif | 4036 | # endif |
4023 | if (!command->argv /* if it's the first word... */ | 4037 | if (!command->argv /* if it's the first word... */ |
4024 | #if ENABLE_HUSH_LOOPS | 4038 | # if ENABLE_HUSH_LOOPS |
4025 | && ctx->ctx_res_w != RES_FOR /* ...not after FOR or IN */ | 4039 | && ctx->ctx_res_w != RES_FOR /* ...not after FOR or IN */ |
4026 | && ctx->ctx_res_w != RES_IN | 4040 | && ctx->ctx_res_w != RES_IN |
4027 | #endif | 4041 | # endif |
4028 | ) { | 4042 | ) { |
4029 | debug_printf_parse(": checking '%s' for reserved-ness\n", word->data); | 4043 | debug_printf_parse(": checking '%s' for reserved-ness\n", word->data); |
4030 | if (reserved_word(word, ctx)) { | 4044 | if (reserved_word(word, ctx)) { |
@@ -4090,20 +4104,23 @@ static int done_word(o_string *word, struct parse_context *ctx) | |||
4090 | 4104 | ||
4091 | /* Peek ahead in the input to find out if we have a "&n" construct, | 4105 | /* Peek ahead in the input to find out if we have a "&n" construct, |
4092 | * as in "2>&1", that represents duplicating a file descriptor. | 4106 | * as in "2>&1", that represents duplicating a file descriptor. |
4093 | * Return: REDIRFD_CLOSE (-3) if >&- "close fd" construct is seen, | 4107 | * Return: |
4094 | * -2 (syntax error), -1 if no & was seen, or the number found. | 4108 | * REDIRFD_CLOSE if >&- "close fd" construct is seen, |
4109 | * REDIRFD_SYNTAX_ERR if syntax error, | ||
4110 | * REDIRFD_TO_FILE if no & was seen, | ||
4111 | * or the number found. | ||
4095 | */ | 4112 | */ |
4096 | #if BB_MMU | 4113 | #if BB_MMU |
4097 | #define redirect_dup_num(as_string, input) \ | 4114 | #define parse_redir_right_fd(as_string, input) \ |
4098 | redirect_dup_num(input) | 4115 | parse_redir_right_fd(input) |
4099 | #endif | 4116 | #endif |
4100 | static int redirect_dup_num(o_string *as_string, struct in_str *input) | 4117 | static int parse_redir_right_fd(o_string *as_string, struct in_str *input) |
4101 | { | 4118 | { |
4102 | int ch, d, ok; | 4119 | int ch, d, ok; |
4103 | 4120 | ||
4104 | ch = i_peek(input); | 4121 | ch = i_peek(input); |
4105 | if (ch != '&') | 4122 | if (ch != '&') |
4106 | return -1; | 4123 | return REDIRFD_TO_FILE; |
4107 | 4124 | ||
4108 | ch = i_getch(input); /* get the & */ | 4125 | ch = i_getch(input); /* get the & */ |
4109 | nommu_addchr(as_string, ch); | 4126 | nommu_addchr(as_string, ch); |
@@ -4127,10 +4144,10 @@ static int redirect_dup_num(o_string *as_string, struct in_str *input) | |||
4127 | //TODO: this is the place to catch ">&file" bashism (redirect both fd 1 and 2) | 4144 | //TODO: this is the place to catch ">&file" bashism (redirect both fd 1 and 2) |
4128 | 4145 | ||
4129 | bb_error_msg("ambiguous redirect"); | 4146 | bb_error_msg("ambiguous redirect"); |
4130 | return -2; | 4147 | return REDIRFD_SYNTAX_ERR; |
4131 | } | 4148 | } |
4132 | 4149 | ||
4133 | /* Return code is 0 normally, 1 if a syntax error is detected | 4150 | /* Return code is 0 normal, 1 if a syntax error is detected |
4134 | */ | 4151 | */ |
4135 | static int parse_redirect(struct parse_context *ctx, | 4152 | static int parse_redirect(struct parse_context *ctx, |
4136 | int fd, | 4153 | int fd, |
@@ -4142,12 +4159,12 @@ static int parse_redirect(struct parse_context *ctx, | |||
4142 | struct redir_struct **redirp; | 4159 | struct redir_struct **redirp; |
4143 | int dup_num; | 4160 | int dup_num; |
4144 | 4161 | ||
4145 | dup_num = -1; | 4162 | dup_num = REDIRFD_TO_FILE; |
4146 | if (style != REDIRECT_HEREDOC) { | 4163 | if (style != REDIRECT_HEREDOC) { |
4147 | /* Check for a '2>&1' type redirect */ | 4164 | /* Check for a '>&1' type redirect */ |
4148 | dup_num = redirect_dup_num(&ctx->as_string, input); | 4165 | dup_num = parse_redir_right_fd(&ctx->as_string, input); |
4149 | if (dup_num == -2) | 4166 | if (dup_num == REDIRFD_SYNTAX_ERR) |
4150 | return 1; /* syntax error */ | 4167 | return 1; |
4151 | } else { | 4168 | } else { |
4152 | int ch = i_peek(input); | 4169 | int ch = i_peek(input); |
4153 | dup_num = (ch == '-'); /* HEREDOC_SKIPTABS bit is 1 */ | 4170 | dup_num = (ch == '-'); /* HEREDOC_SKIPTABS bit is 1 */ |
@@ -4158,7 +4175,7 @@ static int parse_redirect(struct parse_context *ctx, | |||
4158 | } | 4175 | } |
4159 | } | 4176 | } |
4160 | 4177 | ||
4161 | if (style == REDIRECT_OVERWRITE && dup_num == -1) { | 4178 | if (style == REDIRECT_OVERWRITE && dup_num == REDIRFD_TO_FILE) { |
4162 | int ch = i_peek(input); | 4179 | int ch = i_peek(input); |
4163 | if (ch == '|') { | 4180 | if (ch == '|') { |
4164 | /* >|FILE redirect ("clobbering" >). | 4181 | /* >|FILE redirect ("clobbering" >). |
@@ -4185,7 +4202,7 @@ static int parse_redirect(struct parse_context *ctx, | |||
4185 | redir_table[style].descrip); | 4202 | redir_table[style].descrip); |
4186 | 4203 | ||
4187 | redir->rd_dup = dup_num; | 4204 | redir->rd_dup = dup_num; |
4188 | if (style != REDIRECT_HEREDOC && dup_num != -1) { | 4205 | if (style != REDIRECT_HEREDOC && dup_num != REDIRFD_TO_FILE) { |
4189 | /* Erik had a check here that the file descriptor in question | 4206 | /* Erik had a check here that the file descriptor in question |
4190 | * is legit; I postpone that to "run time" | 4207 | * is legit; I postpone that to "run time" |
4191 | * A "-" representation of "close me" shows up as a -3 here */ | 4208 | * A "-" representation of "close me" shows up as a -3 here */ |
@@ -4862,9 +4879,6 @@ static int parse_stream_dquoted(o_string *as_string, | |||
4862 | * only when followed by one of the following characters: | 4879 | * only when followed by one of the following characters: |
4863 | * $, `, ", \, or <newline>. A double quote may be quoted | 4880 | * $, `, ", \, or <newline>. A double quote may be quoted |
4864 | * within double quotes by preceding it with a backslash. | 4881 | * within double quotes by preceding it with a backslash. |
4865 | * If enabled, history expansion will be performed unless | ||
4866 | * an ! appearing in double quotes is escaped using | ||
4867 | * a backslash. The backslash preceding the ! is not removed." | ||
4868 | */ | 4882 | */ |
4869 | if (strchr("$`\"\\", next) != NULL) { | 4883 | if (strchr("$`\"\\", next) != NULL) { |
4870 | o_addqchr(dest, i_getch(input)); | 4884 | o_addqchr(dest, i_getch(input)); |
@@ -5081,17 +5095,71 @@ static struct pipe *parse_stream(char **pstring, | |||
5081 | if (is_ifs) | 5095 | if (is_ifs) |
5082 | continue; | 5096 | continue; |
5083 | 5097 | ||
5084 | if (dest.o_assignment == MAYBE_ASSIGNMENT) { | ||
5085 | /* ch is a special char and thus this word | ||
5086 | * cannot be an assignment */ | ||
5087 | dest.o_assignment = NOT_ASSIGNMENT; | ||
5088 | } | ||
5089 | |||
5090 | next = '\0'; | 5098 | next = '\0'; |
5091 | if (ch != '\n') { | 5099 | if (ch != '\n') { |
5092 | next = i_peek(input); | 5100 | next = i_peek(input); |
5093 | } | 5101 | } |
5094 | 5102 | ||
5103 | /* Catch <, > before deciding whether this word is | ||
5104 | * an assignment. a=1 2>z b=2: b=2 is still assignment */ | ||
5105 | switch (ch) { | ||
5106 | case '>': | ||
5107 | redir_fd = redirect_opt_num(&dest); | ||
5108 | if (done_word(&dest, &ctx)) { | ||
5109 | goto parse_error; | ||
5110 | } | ||
5111 | redir_style = REDIRECT_OVERWRITE; | ||
5112 | if (next == '>') { | ||
5113 | redir_style = REDIRECT_APPEND; | ||
5114 | ch = i_getch(input); | ||
5115 | nommu_addchr(&ctx.as_string, ch); | ||
5116 | } | ||
5117 | #if 0 | ||
5118 | else if (next == '(') { | ||
5119 | syntax_error(">(process) not supported"); | ||
5120 | goto parse_error; | ||
5121 | } | ||
5122 | #endif | ||
5123 | if (parse_redirect(&ctx, redir_fd, redir_style, input)) | ||
5124 | goto parse_error; | ||
5125 | continue; /* back to top of while (1) */ | ||
5126 | case '<': | ||
5127 | redir_fd = redirect_opt_num(&dest); | ||
5128 | if (done_word(&dest, &ctx)) { | ||
5129 | goto parse_error; | ||
5130 | } | ||
5131 | redir_style = REDIRECT_INPUT; | ||
5132 | if (next == '<') { | ||
5133 | redir_style = REDIRECT_HEREDOC; | ||
5134 | heredoc_cnt++; | ||
5135 | debug_printf_parse("++heredoc_cnt=%d\n", heredoc_cnt); | ||
5136 | ch = i_getch(input); | ||
5137 | nommu_addchr(&ctx.as_string, ch); | ||
5138 | } else if (next == '>') { | ||
5139 | redir_style = REDIRECT_IO; | ||
5140 | ch = i_getch(input); | ||
5141 | nommu_addchr(&ctx.as_string, ch); | ||
5142 | } | ||
5143 | #if 0 | ||
5144 | else if (next == '(') { | ||
5145 | syntax_error("<(process) not supported"); | ||
5146 | goto parse_error; | ||
5147 | } | ||
5148 | #endif | ||
5149 | if (parse_redirect(&ctx, redir_fd, redir_style, input)) | ||
5150 | goto parse_error; | ||
5151 | continue; /* back to top of while (1) */ | ||
5152 | } | ||
5153 | |||
5154 | if (dest.o_assignment == MAYBE_ASSIGNMENT | ||
5155 | /* check that we are not in word in "a=1 2>word b=1": */ | ||
5156 | && !ctx.pending_redirect | ||
5157 | ) { | ||
5158 | /* ch is a special char and thus this word | ||
5159 | * cannot be an assignment */ | ||
5160 | dest.o_assignment = NOT_ASSIGNMENT; | ||
5161 | } | ||
5162 | |||
5095 | switch (ch) { | 5163 | switch (ch) { |
5096 | case '#': | 5164 | case '#': |
5097 | if (dest.length == 0) { | 5165 | if (dest.length == 0) { |
@@ -5171,52 +5239,6 @@ static struct pipe *parse_stream(char **pstring, | |||
5171 | break; | 5239 | break; |
5172 | } | 5240 | } |
5173 | #endif | 5241 | #endif |
5174 | case '>': | ||
5175 | redir_fd = redirect_opt_num(&dest); | ||
5176 | if (done_word(&dest, &ctx)) { | ||
5177 | goto parse_error; | ||
5178 | } | ||
5179 | redir_style = REDIRECT_OVERWRITE; | ||
5180 | if (next == '>') { | ||
5181 | redir_style = REDIRECT_APPEND; | ||
5182 | ch = i_getch(input); | ||
5183 | nommu_addchr(&ctx.as_string, ch); | ||
5184 | } | ||
5185 | #if 0 | ||
5186 | else if (next == '(') { | ||
5187 | syntax_error(">(process) not supported"); | ||
5188 | goto parse_error; | ||
5189 | } | ||
5190 | #endif | ||
5191 | if (parse_redirect(&ctx, redir_fd, redir_style, input)) | ||
5192 | goto parse_error; | ||
5193 | break; | ||
5194 | case '<': | ||
5195 | redir_fd = redirect_opt_num(&dest); | ||
5196 | if (done_word(&dest, &ctx)) { | ||
5197 | goto parse_error; | ||
5198 | } | ||
5199 | redir_style = REDIRECT_INPUT; | ||
5200 | if (next == '<') { | ||
5201 | redir_style = REDIRECT_HEREDOC; | ||
5202 | heredoc_cnt++; | ||
5203 | debug_printf_parse("++heredoc_cnt=%d\n", heredoc_cnt); | ||
5204 | ch = i_getch(input); | ||
5205 | nommu_addchr(&ctx.as_string, ch); | ||
5206 | } else if (next == '>') { | ||
5207 | redir_style = REDIRECT_IO; | ||
5208 | ch = i_getch(input); | ||
5209 | nommu_addchr(&ctx.as_string, ch); | ||
5210 | } | ||
5211 | #if 0 | ||
5212 | else if (next == '(') { | ||
5213 | syntax_error("<(process) not supported"); | ||
5214 | goto parse_error; | ||
5215 | } | ||
5216 | #endif | ||
5217 | if (parse_redirect(&ctx, redir_fd, redir_style, input)) | ||
5218 | goto parse_error; | ||
5219 | break; | ||
5220 | case ';': | 5242 | case ';': |
5221 | #if ENABLE_HUSH_CASE | 5243 | #if ENABLE_HUSH_CASE |
5222 | case_semi: | 5244 | case_semi: |
diff --git a/shell/hush_test/hush-misc/redir1.right b/shell/hush_test/hush-misc/redir1.right index ac90b4a0a..15515d1af 100644 --- a/shell/hush_test/hush-misc/redir1.right +++ b/shell/hush_test/hush-misc/redir1.right | |||
@@ -1,3 +1,5 @@ | |||
1 | Test 0: var:ok | ||
2 | File created:ok | ||
1 | Test 1: var:ok | 3 | Test 1: var:ok |
2 | File created:ok | 4 | File created:ok |
3 | Test 2: var:ok | 5 | Test 2: var:ok |
diff --git a/shell/hush_test/hush-misc/redir1.tests b/shell/hush_test/hush-misc/redir1.tests index 7e204514c..70e9e17f0 100755 --- a/shell/hush_test/hush-misc/redir1.tests +++ b/shell/hush_test/hush-misc/redir1.tests | |||
@@ -1,5 +1,11 @@ | |||
1 | rm shell_test_$$ 2>/dev/null | 1 | rm shell_test_$$ 2>/dev/null |
2 | var=bad | 2 | var=bad |
3 | >shell_test_$$ var=ok | ||
4 | echo "Test 0: var:$var" | ||
5 | test -f shell_test_$$ && echo "File created:ok" | ||
6 | |||
7 | rm shell_test_$$ 2>/dev/null | ||
8 | var=bad | ||
3 | var=ok >shell_test_$$ | 9 | var=ok >shell_test_$$ |
4 | echo "Test 1: var:$var" | 10 | echo "Test 1: var:$var" |
5 | test -f shell_test_$$ && echo "File created:ok" | 11 | test -f shell_test_$$ && echo "File created:ok" |
diff --git a/shell/hush_test/hush-misc/redir4.right b/shell/hush_test/hush-misc/redir4.right new file mode 100644 index 000000000..ada6c2d85 --- /dev/null +++ b/shell/hush_test/hush-misc/redir4.right | |||
@@ -0,0 +1,25 @@ | |||
1 | shell_test | ||
2 | \shell_test | ||
3 | \shell_test | ||
4 | \shell_test | ||
5 | Here1 | ||
6 | Ok1 | ||
7 | Here2 | ||
8 | Ok2 | ||
9 | Here3 | ||
10 | Ok3 | ||
11 | Here4 | ||
12 | Ok4 | ||
13 | How with variable refs | ||
14 | shell_test_1 | ||
15 | \shell_test_1 | ||
16 | \shell_test_1 | ||
17 | \shell_test_1 | ||
18 | Here1 | ||
19 | Ok1 | ||
20 | Here2 | ||
21 | Ok2 | ||
22 | Here3 | ||
23 | Ok3 | ||
24 | Here4 | ||
25 | Ok4 | ||
diff --git a/shell/hush_test/hush-misc/redir4.tests b/shell/hush_test/hush-misc/redir4.tests new file mode 100755 index 000000000..ac2a44166 --- /dev/null +++ b/shell/hush_test/hush-misc/redir4.tests | |||
@@ -0,0 +1,80 @@ | |||
1 | rm *shell_test* 2>/dev/null | ||
2 | |||
3 | >\shell_test | ||
4 | echo *shell_test* | ||
5 | rm *shell_test* | ||
6 | |||
7 | >\\shell_test | ||
8 | echo *shell_test* | ||
9 | rm *shell_test* | ||
10 | |||
11 | >"\shell_test" | ||
12 | echo *shell_test* | ||
13 | rm *shell_test* | ||
14 | |||
15 | >"\\shell_test" | ||
16 | echo *shell_test* | ||
17 | rm *shell_test* | ||
18 | |||
19 | |||
20 | cat <<\shell_test | ||
21 | Here1 | ||
22 | shell_test | ||
23 | echo Ok1 | ||
24 | |||
25 | cat <<\\shell_test | ||
26 | Here2 | ||
27 | \shell_test | ||
28 | echo Ok2 | ||
29 | |||
30 | cat <<"\shell_test" | ||
31 | Here3 | ||
32 | \shell_test | ||
33 | echo Ok3 | ||
34 | |||
35 | cat <<"\\shell_test" | ||
36 | Here4 | ||
37 | \shell_test | ||
38 | echo Ok4 | ||
39 | |||
40 | |||
41 | echo How with variable refs | ||
42 | i=1 | ||
43 | |||
44 | |||
45 | >\shell_test_$i | ||
46 | echo *shell_test* | ||
47 | rm *shell_test* | ||
48 | |||
49 | >\\shell_test_$i | ||
50 | echo *shell_test* | ||
51 | rm *shell_test* | ||
52 | |||
53 | >"\shell_test_$i" | ||
54 | echo *shell_test* | ||
55 | rm *shell_test* | ||
56 | |||
57 | >"\\shell_test_$i" | ||
58 | echo *shell_test* | ||
59 | rm *shell_test* | ||
60 | |||
61 | |||
62 | cat <<\shell_test_$i | ||
63 | Here1 | ||
64 | shell_test_$i | ||
65 | echo Ok1 | ||
66 | |||
67 | cat <<\\shell_test_$i | ||
68 | Here2 | ||
69 | \shell_test_$i | ||
70 | echo Ok2 | ||
71 | |||
72 | cat <<"\shell_test_$i" | ||
73 | Here3 | ||
74 | \shell_test_$i | ||
75 | echo Ok3 | ||
76 | |||
77 | cat <<"\\shell_test_$i" | ||
78 | Here4 | ||
79 | \shell_test_$i | ||
80 | echo Ok4 | ||