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 /shell | |
| 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.
Diffstat (limited to 'shell')
| -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 | ||
