aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2008-07-06 10:01:13 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2008-07-06 10:01:13 +0000
commit733e3fbc2fb6eb0195cbcc02724d186b1b820df6 (patch)
tree81ba6758a3b20c84b56e42473d427368b9180c0d
parentd48e81f0cda73aca49cd852212a62e879cf35b86 (diff)
downloadbusybox-w32-733e3fbc2fb6eb0195cbcc02724d186b1b820df6.tar.gz
busybox-w32-733e3fbc2fb6eb0195cbcc02724d186b1b820df6.tar.bz2
busybox-w32-733e3fbc2fb6eb0195cbcc02724d186b1b820df6.zip
hush: support "for if in do done then; do echo $if; done" case
function old new delta done_pipe 83 95 +12 parse_stream 1758 1764 +6 done_word 674 647 -27 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 2/1 up/down: 18/-27) Total: -9 bytes
-rw-r--r--shell/hush.c59
-rw-r--r--shell/hush_test/hush-misc/for_with_keywords.right4
-rwxr-xr-xshell/hush_test/hush-misc/for_with_keywords.tests2
3 files changed, 41 insertions, 24 deletions
diff --git a/shell/hush.c b/shell/hush.c
index f38f3752b..c71ddb14f 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -1344,7 +1344,7 @@ static int setup_redirects(struct child_prog *prog, int squirrel[])
1344 if (redir->dup == -1) { 1344 if (redir->dup == -1) {
1345 char *p; 1345 char *p;
1346 mode = redir_table[redir->rd_type].mode; 1346 mode = redir_table[redir->rd_type].mode;
1347//TODO: check redir to names like '\\' 1347//TODO: check redir for names like '\\'
1348 p = expand_string_to_string(redir->rd_filename); 1348 p = expand_string_to_string(redir->rd_filename);
1349 openfd = open_or_warn(p, mode); 1349 openfd = open_or_warn(p, mode);
1350 free(p); 1350 free(p);
@@ -2854,17 +2854,7 @@ static int reserved_word(const o_string *word, struct p_context *ctx)
2854 continue; 2854 continue;
2855 debug_printf("found reserved word %s, res %d\n", r->literal, r->res); 2855 debug_printf("found reserved word %s, res %d\n", r->literal, r->res);
2856 if (r->flag == 0) { /* '!' */ 2856 if (r->flag == 0) { /* '!' */
2857#if ENABLE_HUSH_LOOPS 2857 if (ctx->ctx_inverted) { /* bash doesn't accept '! ! true' */
2858 if (ctx->ctx_res_w == RES_IN) {
2859 /* 'for a in ! a b c; ...' - ! isn't a keyword here */
2860 break;
2861 }
2862#endif
2863 if (ctx->ctx_inverted /* bash doesn't accept '! ! true' */
2864#if ENABLE_HUSH_LOOPS
2865 || ctx->ctx_res_w == RES_FOR /* example: 'for ! a' */
2866#endif
2867 ) {
2868 syntax(NULL); 2858 syntax(NULL);
2869 IF_HAS_KEYWORDS(ctx->ctx_res_w = RES_SNTX;) 2859 IF_HAS_KEYWORDS(ctx->ctx_res_w = RES_SNTX;)
2870 } 2860 }
@@ -2885,7 +2875,7 @@ static int reserved_word(const o_string *word, struct p_context *ctx)
2885 *new = *ctx; /* physical copy */ 2875 *new = *ctx; /* physical copy */
2886 initialize_context(ctx); 2876 initialize_context(ctx);
2887 ctx->stack = new; 2877 ctx->stack = new;
2888 } else if (ctx->ctx_res_w == RES_NONE || !(ctx->old_flag & (1 << r->res))) { 2878 } else if (/*ctx->ctx_res_w == RES_NONE ||*/ !(ctx->old_flag & (1 << r->res))) {
2889 syntax(NULL); 2879 syntax(NULL);
2890 ctx->ctx_res_w = RES_SNTX; 2880 ctx->ctx_res_w = RES_SNTX;
2891 return 1; 2881 return 1;
@@ -2940,7 +2930,10 @@ static int done_word(o_string *word, struct p_context *ctx)
2940 return 1; 2930 return 1;
2941 } 2931 }
2942#if HAS_KEYWORDS 2932#if HAS_KEYWORDS
2943 if (!child->argv) { /* if it's the first word... */ 2933 if (!child->argv /* if it's the first word... */
2934 && ctx->ctx_res_w != RES_FOR /* ...not after FOR or IN */
2935 && ctx->ctx_res_w != RES_IN
2936 ) {
2944 debug_printf_parse(": checking '%s' for reserved-ness\n", word->data); 2937 debug_printf_parse(": checking '%s' for reserved-ness\n", word->data);
2945 if (reserved_word(word, ctx)) { 2938 if (reserved_word(word, ctx)) {
2946 o_reset(word); 2939 o_reset(word);
@@ -2953,9 +2946,9 @@ static int done_word(o_string *word, struct p_context *ctx)
2953 if (word->nonnull /* word had "xx" or 'xx' at least as part of it. */ 2946 if (word->nonnull /* word had "xx" or 'xx' at least as part of it. */
2954 /* optimization: and if it's ("" or '') or ($v... or `cmd`...): */ 2947 /* optimization: and if it's ("" or '') or ($v... or `cmd`...): */
2955 && (word->data[0] == '\0' || word->data[0] == SPECIAL_VAR_SYMBOL) 2948 && (word->data[0] == '\0' || word->data[0] == SPECIAL_VAR_SYMBOL)
2956 /* (otherwise it's "abc".... and is already safe) */ 2949 /* (otherwise it's known to be not empty and is already safe) */
2957 ) { 2950 ) {
2958 /* but exclude "$@" - it expands to no word despite "" */ 2951 /* exclude "$@" - it can expand to no word despite "" */
2959 char *p = word->data; 2952 char *p = word->data;
2960 while (p[0] == SPECIAL_VAR_SYMBOL 2953 while (p[0] == SPECIAL_VAR_SYMBOL
2961 && (p[1] & 0x7f) == '@' 2954 && (p[1] & 0x7f) == '@'
@@ -2964,7 +2957,9 @@ static int done_word(o_string *word, struct p_context *ctx)
2964 p += 3; 2957 p += 3;
2965 } 2958 }
2966 if (p == word->data || p[0] != '\0') { 2959 if (p == word->data || p[0] != '\0') {
2967 /* Insert "empty variable" reference, this makes 2960 /* saw no "$@", or not only "$@" but some
2961 * real text is there too */
2962 /* insert "empty variable" reference, this makes
2968 * e.g. "", $empty"" etc to not disappear */ 2963 * e.g. "", $empty"" etc to not disappear */
2969 o_addchr(word, SPECIAL_VAR_SYMBOL); 2964 o_addchr(word, SPECIAL_VAR_SYMBOL);
2970 o_addchr(word, SPECIAL_VAR_SYMBOL); 2965 o_addchr(word, SPECIAL_VAR_SYMBOL);
@@ -2979,8 +2974,13 @@ static int done_word(o_string *word, struct p_context *ctx)
2979 2974
2980#if ENABLE_HUSH_LOOPS 2975#if ENABLE_HUSH_LOOPS
2981 /* Force FOR to have just one word (variable name) */ 2976 /* Force FOR to have just one word (variable name) */
2982 if (ctx->ctx_res_w == RES_FOR) 2977 /* NB: basically, this makes hush see "for v in ..." syntax as if
2978 * as it is "for v; in ...". FOR and IN become two pipe structs
2979 * in parse tree. */
2980 if (ctx->ctx_res_w == RES_FOR) {
2981//TODO: check that child->argv[0] is a valid variable name!
2983 done_pipe(ctx, PIPE_SEQ); 2982 done_pipe(ctx, PIPE_SEQ);
2983 }
2984#endif 2984#endif
2985 debug_printf_parse("done_word return 0\n"); 2985 debug_printf_parse("done_word return 0\n");
2986 return 0; 2986 return 0;
@@ -3030,19 +3030,28 @@ static void done_pipe(struct p_context *ctx, pipe_style type)
3030 debug_printf_parse("done_pipe entered, followup %d\n", type); 3030 debug_printf_parse("done_pipe entered, followup %d\n", type);
3031 not_null = done_command(ctx); /* implicit closure of previous command */ 3031 not_null = done_command(ctx); /* implicit closure of previous command */
3032 ctx->pipe->followup = type; 3032 ctx->pipe->followup = type;
3033 IF_HAS_KEYWORDS(ctx->pipe->res_word = ctx->ctx_res_w;)
3034 IF_HAS_KEYWORDS(ctx->pipe->pi_inverted = ctx->ctx_inverted;) 3033 IF_HAS_KEYWORDS(ctx->pipe->pi_inverted = ctx->ctx_inverted;)
3035 IF_HAS_KEYWORDS(ctx->ctx_inverted = 0;) 3034 IF_HAS_KEYWORDS(ctx->ctx_inverted = 0;)
3035 IF_HAS_KEYWORDS(ctx->pipe->res_word = ctx->ctx_res_w;)
3036 /* Without this check, even just <enter> on command line generates 3036 /* Without this check, even just <enter> on command line generates
3037 * tree of three NOPs (!). Which is harmless but annoying. 3037 * tree of three NOPs (!). Which is harmless but annoying.
3038 * IOW: it is safe to do it unconditionally. 3038 * IOW: it is safe to do it unconditionally.
3039 * RES_IN case is for "for a in; do ..." (empty IN set) 3039 * RES_NONE case is for "for a in; do ..." (empty IN set)
3040 * to work. */ 3040 * to work, possibly other cases too. */
3041 if (not_null USE_HUSH_LOOPS(|| ctx->pipe->res_word == RES_IN)) { 3041 if (not_null IF_HAS_KEYWORDS(|| ctx->ctx_res_w != RES_NONE)) {
3042 struct pipe *new_p = new_pipe(); 3042 struct pipe *new_p = new_pipe();
3043 ctx->pipe->next = new_p; 3043 ctx->pipe->next = new_p;
3044 ctx->pipe = new_p; 3044 ctx->pipe = new_p;
3045 ctx->child = NULL; /* needed! */ 3045 ctx->child = NULL; /* needed! */
3046 /* RES_IF, RES_WHILE etc are "sticky" -
3047 * they remain set for commands inside if/while.
3048 * This is used to control execution.
3049 * RES_FOR and RES_IN are NOT sticky (needed to support
3050 * cases where variable or value happens to match a keyword):
3051 */
3052 if (ctx->ctx_res_w == RES_FOR
3053 || ctx->ctx_res_w == RES_IN)
3054 ctx->ctx_res_w = RES_NONE;
3046 /* Create the memory for child, roughly: 3055 /* Create the memory for child, roughly:
3047 * ctx->pipe->progs = new struct child_prog; 3056 * ctx->pipe->progs = new struct child_prog;
3048 * ctx->pipe->progs[0].family = ctx->pipe; 3057 * ctx->pipe->progs[0].family = ctx->pipe;
@@ -3444,7 +3453,7 @@ static int handle_dollar(o_string *dest, struct in_str *input)
3444 return 0; 3453 return 0;
3445} 3454}
3446 3455
3447/* Scan input, call done_word() whenever full IFS delemited word was seen. 3456/* Scan input, call done_word() whenever full IFS delimited word was seen.
3448 * call done_pipe if '\n' was seen (and end_trigger != NULL) 3457 * call done_pipe if '\n' was seen (and end_trigger != NULL)
3449 * Return if (non-quoted) char in end_trigger was seen; or on parse error. */ 3458 * Return if (non-quoted) char in end_trigger was seen; or on parse error. */
3450/* Return code is 0 if end_trigger char is met, 3459/* Return code is 0 if end_trigger char is met,
@@ -3517,7 +3526,9 @@ static int parse_stream(o_string *dest, struct p_context *ctx,
3517//err chk? 3526//err chk?
3518 done_pipe(ctx, PIPE_SEQ); 3527 done_pipe(ctx, PIPE_SEQ);
3519 } 3528 }
3520 if (!HAS_KEYWORDS IF_HAS_KEYWORDS(|| ctx->ctx_res_w == RES_NONE)) { 3529 if (!HAS_KEYWORDS
3530 IF_HAS_KEYWORDS(|| (ctx->ctx_res_w == RES_NONE && ctx->old_flag == 0))
3531 ) {
3521 debug_printf_parse("parse_stream return 0: end_trigger char found\n"); 3532 debug_printf_parse("parse_stream return 0: end_trigger char found\n");
3522 return 0; 3533 return 0;
3523 } 3534 }
diff --git a/shell/hush_test/hush-misc/for_with_keywords.right b/shell/hush_test/hush-misc/for_with_keywords.right
new file mode 100644
index 000000000..eb04e9af9
--- /dev/null
+++ b/shell/hush_test/hush-misc/for_with_keywords.right
@@ -0,0 +1,4 @@
1do
2done
3then
4OK: 0
diff --git a/shell/hush_test/hush-misc/for_with_keywords.tests b/shell/hush_test/hush-misc/for_with_keywords.tests
new file mode 100755
index 000000000..a8b8e4264
--- /dev/null
+++ b/shell/hush_test/hush-misc/for_with_keywords.tests
@@ -0,0 +1,2 @@
1for if in do done then; do echo $if; done
2echo OK: $?