diff options
author | Denis Vlasenko <vda.linux@googlemail.com> | 2007-05-03 22:45:39 +0000 |
---|---|---|
committer | Denis Vlasenko <vda.linux@googlemail.com> | 2007-05-03 22:45:39 +0000 |
commit | e725bfe6e01505f0480dd1bd357209d3a2e72bb7 (patch) | |
tree | 3e128376a43debb087230efdd9bd73fb7a7f3be0 /shell/hush.c | |
parent | f2fffd0014edff7f791fc2a5b27147bb0628d7e6 (diff) | |
download | busybox-w32-e725bfe6e01505f0480dd1bd357209d3a2e72bb7.tar.gz busybox-w32-e725bfe6e01505f0480dd1bd357209d3a2e72bb7.tar.bz2 busybox-w32-e725bfe6e01505f0480dd1bd357209d3a2e72bb7.zip |
hush: fix "true | exit 3; echo $?" bug
Diffstat (limited to '')
-rw-r--r-- | shell/hush.c | 138 |
1 files changed, 92 insertions, 46 deletions
diff --git a/shell/hush.c b/shell/hush.c index f3be78547..4d5e41244 100644 --- a/shell/hush.c +++ b/shell/hush.c | |||
@@ -89,6 +89,7 @@ | |||
89 | /* Finer-grained debug switch */ | 89 | /* Finer-grained debug switch */ |
90 | #define debug_printf_jobs(...) do {} while (0) | 90 | #define debug_printf_jobs(...) do {} while (0) |
91 | #define debug_printf_exec(...) do {} while (0) | 91 | #define debug_printf_exec(...) do {} while (0) |
92 | #define debug_printf_parse(...) do {} while (0) | ||
92 | 93 | ||
93 | 94 | ||
94 | #ifndef debug_printf | 95 | #ifndef debug_printf |
@@ -111,6 +112,10 @@ static const char *indenter(int i) | |||
111 | #define debug_printf_exec(...) fprintf(stderr, __VA_ARGS__) | 112 | #define debug_printf_exec(...) fprintf(stderr, __VA_ARGS__) |
112 | #endif | 113 | #endif |
113 | 114 | ||
115 | #ifndef debug_printf_parse | ||
116 | #define debug_printf_parse(...) fprintf(stderr, __VA_ARGS__) | ||
117 | #endif | ||
118 | |||
114 | 119 | ||
115 | #if !ENABLE_HUSH_INTERACTIVE | 120 | #if !ENABLE_HUSH_INTERACTIVE |
116 | #undef ENABLE_FEATURE_EDITING | 121 | #undef ENABLE_FEATURE_EDITING |
@@ -259,8 +264,14 @@ static int last_return_code; | |||
259 | extern char **environ; /* This is in <unistd.h>, but protected with __USE_GNU */ | 264 | extern char **environ; /* This is in <unistd.h>, but protected with __USE_GNU */ |
260 | 265 | ||
261 | /* "globals" within this file */ | 266 | /* "globals" within this file */ |
262 | static const char *ifs; | 267 | enum { |
268 | MAP_ORDINARY = 0, | ||
269 | MAP_FLOWTROUGH_IF_QUOTED = 1, | ||
270 | MAP_IFS_IF_UNQUOTED = 2, /* flow through if quoted too */ | ||
271 | MAP_NEVER_FLOWTROUGH = 3, | ||
272 | }; | ||
263 | static unsigned char map[256]; | 273 | static unsigned char map[256]; |
274 | static const char *ifs; | ||
264 | static int fake_mode; | 275 | static int fake_mode; |
265 | static struct close_me *close_me_head; | 276 | static struct close_me *close_me_head; |
266 | static const char *cwd; | 277 | static const char *cwd; |
@@ -390,13 +401,13 @@ static int done_pipe(struct p_context *ctx, pipe_style type); | |||
390 | /* primary string parsing: */ | 401 | /* primary string parsing: */ |
391 | static int redirect_dup_num(struct in_str *input); | 402 | static int redirect_dup_num(struct in_str *input); |
392 | static int redirect_opt_num(o_string *o); | 403 | static int redirect_opt_num(o_string *o); |
393 | static int process_command_subs(o_string *dest, struct p_context *ctx, struct in_str *input, int subst_end); | 404 | static int process_command_subs(o_string *dest, struct p_context *ctx, struct in_str *input, const char *subst_end); |
394 | static int parse_group(o_string *dest, struct p_context *ctx, struct in_str *input, int ch); | 405 | static int parse_group(o_string *dest, struct p_context *ctx, struct in_str *input, int ch); |
395 | static const char *lookup_param(const char *src); | 406 | static const char *lookup_param(const char *src); |
396 | static char *make_string(char **inp); | 407 | static char *make_string(char **inp); |
397 | static int handle_dollar(o_string *dest, struct p_context *ctx, struct in_str *input); | 408 | static int handle_dollar(o_string *dest, struct p_context *ctx, struct in_str *input); |
398 | static int parse_string(o_string *dest, struct p_context *ctx, const char *src); | 409 | static int parse_string(o_string *dest, struct p_context *ctx, const char *src); |
399 | static int parse_stream(o_string *dest, struct p_context *ctx, struct in_str *input0, int end_trigger); | 410 | static int parse_stream(o_string *dest, struct p_context *ctx, struct in_str *input0, const char *end_trigger); |
400 | /* setup: */ | 411 | /* setup: */ |
401 | static int parse_stream_outer(struct in_str *inp, int flag); | 412 | static int parse_stream_outer(struct in_str *inp, int flag); |
402 | static int parse_string_outer(const char *s, int flag); | 413 | static int parse_string_outer(const char *s, int flag); |
@@ -1977,8 +1988,9 @@ static int run_list_real(struct pipe *pi) | |||
1977 | { | 1988 | { |
1978 | rcode = checkjobs(pi); | 1989 | rcode = checkjobs(pi); |
1979 | } | 1990 | } |
1980 | debug_printf("checkjobs returned %d\n", rcode); | 1991 | debug_printf_exec("checkjobs returned %d\n", rcode); |
1981 | } | 1992 | } |
1993 | debug_printf_exec("setting last_return_code=%d\n", rcode); | ||
1982 | last_return_code = rcode; | 1994 | last_return_code = rcode; |
1983 | pi->num_progs = save_num_progs; /* restore number of programs */ | 1995 | pi->num_progs = save_num_progs; /* restore number of programs */ |
1984 | if (rmode == RES_IF || rmode == RES_ELIF) | 1996 | if (rmode == RES_IF || rmode == RES_ELIF) |
@@ -2519,7 +2531,7 @@ static int reserved_word(o_string *dest, struct p_context *ctx) | |||
2519 | return 0; | 2531 | return 0; |
2520 | } | 2532 | } |
2521 | 2533 | ||
2522 | /* normal return is 0. | 2534 | /* Normal return is 0. |
2523 | * Syntax or xglob errors return 1. */ | 2535 | * Syntax or xglob errors return 1. */ |
2524 | static int done_word(o_string *dest, struct p_context *ctx) | 2536 | static int done_word(o_string *dest, struct p_context *ctx) |
2525 | { | 2537 | { |
@@ -2527,9 +2539,9 @@ static int done_word(o_string *dest, struct p_context *ctx) | |||
2527 | glob_t *glob_target; | 2539 | glob_t *glob_target; |
2528 | int gr, flags = 0; | 2540 | int gr, flags = 0; |
2529 | 2541 | ||
2530 | debug_printf("done_word: %s %p\n", dest->data, child); | 2542 | debug_printf_parse("done_word: '%s' %p\n", dest->data, child); |
2531 | if (dest->length == 0 && !dest->nonnull) { | 2543 | if (dest->length == 0 && !dest->nonnull) { |
2532 | debug_printf(" true null, ignored\n"); | 2544 | debug_printf_parse("done_word return 0: true null, ignored\n"); |
2533 | return 0; | 2545 | return 0; |
2534 | } | 2546 | } |
2535 | if (ctx->pending_redirect) { | 2547 | if (ctx->pending_redirect) { |
@@ -2537,24 +2549,31 @@ static int done_word(o_string *dest, struct p_context *ctx) | |||
2537 | } else { | 2549 | } else { |
2538 | if (child->group) { | 2550 | if (child->group) { |
2539 | syntax(); | 2551 | syntax(); |
2540 | return 1; /* syntax error, groups and arglists don't mix */ | 2552 | debug_printf_parse("done_word return 1: syntax error, groups and arglists don't mix\n"); |
2553 | return 1; | ||
2541 | } | 2554 | } |
2542 | if (!child->argv && (ctx->type & FLAG_PARSE_SEMICOLON)) { | 2555 | if (!child->argv && (ctx->type & FLAG_PARSE_SEMICOLON)) { |
2543 | debug_printf("checking %s for reserved-ness\n", dest->data); | 2556 | debug_printf_parse(": checking %s for reserved-ness\n", dest->data); |
2544 | if (reserved_word(dest, ctx)) | 2557 | if (reserved_word(dest, ctx)) { |
2558 | debug_printf_parse("done_word return %d\n", (ctx->w == RES_SNTX)); | ||
2545 | return (ctx->w == RES_SNTX); | 2559 | return (ctx->w == RES_SNTX); |
2560 | } | ||
2546 | } | 2561 | } |
2547 | glob_target = &child->glob_result; | 2562 | glob_target = &child->glob_result; |
2548 | if (child->argv) flags |= GLOB_APPEND; | 2563 | if (child->argv) flags |= GLOB_APPEND; |
2549 | } | 2564 | } |
2550 | gr = xglob(dest, flags, glob_target); | 2565 | gr = xglob(dest, flags, glob_target); |
2551 | if (gr != 0) return 1; | 2566 | if (gr != 0) { |
2567 | debug_printf_parse("done_word return 1: xglob returned %d\n", gr); | ||
2568 | return 1; | ||
2569 | } | ||
2552 | 2570 | ||
2553 | b_reset(dest); | 2571 | b_reset(dest); |
2554 | if (ctx->pending_redirect) { | 2572 | if (ctx->pending_redirect) { |
2555 | ctx->pending_redirect = NULL; | 2573 | ctx->pending_redirect = NULL; |
2556 | if (glob_target->gl_pathc != 1) { | 2574 | if (glob_target->gl_pathc != 1) { |
2557 | bb_error_msg("ambiguous redirect"); | 2575 | bb_error_msg("ambiguous redirect"); |
2576 | debug_printf_parse("done_word return 1: ambiguous redirect\n"); | ||
2558 | return 1; | 2577 | return 1; |
2559 | } | 2578 | } |
2560 | } else { | 2579 | } else { |
@@ -2564,6 +2583,7 @@ static int done_word(o_string *dest, struct p_context *ctx) | |||
2564 | done_word(dest, ctx); | 2583 | done_word(dest, ctx); |
2565 | done_pipe(ctx, PIPE_SEQ); | 2584 | done_pipe(ctx, PIPE_SEQ); |
2566 | } | 2585 | } |
2586 | debug_printf_parse("done_word return 0\n"); | ||
2567 | return 0; | 2587 | return 0; |
2568 | } | 2588 | } |
2569 | 2589 | ||
@@ -2614,7 +2634,7 @@ static int done_pipe(struct p_context *ctx, pipe_style type) | |||
2614 | { | 2634 | { |
2615 | struct pipe *new_p; | 2635 | struct pipe *new_p; |
2616 | done_command(ctx); /* implicit closure of previous command */ | 2636 | done_command(ctx); /* implicit closure of previous command */ |
2617 | debug_printf("done_pipe, type %d\n", type); | 2637 | debug_printf_parse("done_pipe, type %d\n", type); |
2618 | ctx->pipe->followup = type; | 2638 | ctx->pipe->followup = type; |
2619 | ctx->pipe->r_mode = ctx->w; | 2639 | ctx->pipe->r_mode = ctx->w; |
2620 | new_p = new_pipe(); | 2640 | new_p = new_pipe(); |
@@ -2710,7 +2730,8 @@ static FILE *generate_stream_from_list(struct pipe *head) | |||
2710 | 2730 | ||
2711 | /* this version hacked for testing purposes */ | 2731 | /* this version hacked for testing purposes */ |
2712 | /* return code is exit status of the process that is run. */ | 2732 | /* return code is exit status of the process that is run. */ |
2713 | static int process_command_subs(o_string *dest, struct p_context *ctx, struct in_str *input, int subst_end) | 2733 | static int process_command_subs(o_string *dest, struct p_context *ctx, |
2734 | struct in_str *input, const char *subst_end) | ||
2714 | { | 2735 | { |
2715 | int retcode; | 2736 | int retcode; |
2716 | o_string result = NULL_O_STRING; | 2737 | o_string result = NULL_O_STRING; |
@@ -2732,7 +2753,7 @@ static int process_command_subs(o_string *dest, struct p_context *ctx, struct in | |||
2732 | setup_file_in_str(&pipe_str, p); | 2753 | setup_file_in_str(&pipe_str, p); |
2733 | 2754 | ||
2734 | /* now send results of command back into original context */ | 2755 | /* now send results of command back into original context */ |
2735 | retcode = parse_stream(dest, ctx, &pipe_str, '\0'); | 2756 | retcode = parse_stream(dest, ctx, &pipe_str, NULL); |
2736 | /* XXX In case of a syntax error, should we try to kill the child? | 2757 | /* XXX In case of a syntax error, should we try to kill the child? |
2737 | * That would be tough to do right, so just read until EOF. */ | 2758 | * That would be tough to do right, so just read until EOF. */ |
2738 | if (retcode == 1) { | 2759 | if (retcode == 1) { |
@@ -2757,21 +2778,25 @@ static int process_command_subs(o_string *dest, struct p_context *ctx, struct in | |||
2757 | static int parse_group(o_string *dest, struct p_context *ctx, | 2778 | static int parse_group(o_string *dest, struct p_context *ctx, |
2758 | struct in_str *input, int ch) | 2779 | struct in_str *input, int ch) |
2759 | { | 2780 | { |
2760 | int rcode, endch = 0; | 2781 | int rcode; |
2782 | const char *endch = NULL; | ||
2761 | struct p_context sub; | 2783 | struct p_context sub; |
2762 | struct child_prog *child = ctx->child; | 2784 | struct child_prog *child = ctx->child; |
2785 | |||
2786 | debug_printf_parse("parse_group entered\n"); | ||
2763 | if (child->argv) { | 2787 | if (child->argv) { |
2764 | syntax(); | 2788 | syntax(); |
2765 | return 1; /* syntax error, groups and arglists don't mix */ | 2789 | debug_printf_parse("parse_group return 1: syntax error, groups and arglists don't mix\n"); |
2790 | return 1; | ||
2766 | } | 2791 | } |
2767 | initialize_context(&sub); | 2792 | initialize_context(&sub); |
2768 | switch (ch) { | 2793 | switch (ch) { |
2769 | case '(': | 2794 | case '(': |
2770 | endch = ')'; | 2795 | endch = ")"; |
2771 | child->subshell = 1; | 2796 | child->subshell = 1; |
2772 | break; | 2797 | break; |
2773 | case '{': | 2798 | case '{': |
2774 | endch = '}'; | 2799 | endch = "}"; |
2775 | break; | 2800 | break; |
2776 | default: | 2801 | default: |
2777 | syntax(); /* really logic error */ | 2802 | syntax(); /* really logic error */ |
@@ -2780,6 +2805,8 @@ static int parse_group(o_string *dest, struct p_context *ctx, | |||
2780 | done_word(dest, &sub); /* finish off the final word in the subcontext */ | 2805 | done_word(dest, &sub); /* finish off the final word in the subcontext */ |
2781 | done_pipe(&sub, PIPE_SEQ); /* and the final command there, too */ | 2806 | done_pipe(&sub, PIPE_SEQ); /* and the final command there, too */ |
2782 | child->group = sub.list_head; | 2807 | child->group = sub.list_head; |
2808 | |||
2809 | debug_printf_parse("parse_group return %d\n", rcode); | ||
2783 | return rcode; | 2810 | return rcode; |
2784 | /* child remains "open", available for possible redirects */ | 2811 | /* child remains "open", available for possible redirects */ |
2785 | } | 2812 | } |
@@ -2880,7 +2907,7 @@ static int handle_dollar(o_string *dest, struct p_context *ctx, struct in_str *i | |||
2880 | break; | 2907 | break; |
2881 | case '(': | 2908 | case '(': |
2882 | b_getch(input); | 2909 | b_getch(input); |
2883 | process_command_subs(dest, ctx, input, ')'); | 2910 | process_command_subs(dest, ctx, input, ")"); |
2884 | break; | 2911 | break; |
2885 | case '*': | 2912 | case '*': |
2886 | sep[0] = ifs[0]; | 2913 | sep[0] = ifs[0]; |
@@ -2913,12 +2940,12 @@ static int parse_string(o_string *dest, struct p_context *ctx, const char *src) | |||
2913 | { | 2940 | { |
2914 | struct in_str foo; | 2941 | struct in_str foo; |
2915 | setup_string_in_str(&foo, src); | 2942 | setup_string_in_str(&foo, src); |
2916 | return parse_stream(dest, ctx, &foo, '\0'); | 2943 | return parse_stream(dest, ctx, &foo, NULL); |
2917 | } | 2944 | } |
2918 | 2945 | ||
2919 | /* return code is 0 for normal exit, 1 for syntax error */ | 2946 | /* return code is 0 for normal exit, 1 for syntax error */ |
2920 | static int parse_stream(o_string *dest, struct p_context *ctx, | 2947 | static int parse_stream(o_string *dest, struct p_context *ctx, |
2921 | struct in_str *input, int end_trigger) | 2948 | struct in_str *input, const char *end_trigger) |
2922 | { | 2949 | { |
2923 | int ch, m; | 2950 | int ch, m; |
2924 | int redir_fd; | 2951 | int redir_fd; |
@@ -2929,30 +2956,38 @@ static int parse_stream(o_string *dest, struct p_context *ctx, | |||
2929 | * A single-quote triggers a bypass of the main loop until its mate is | 2956 | * A single-quote triggers a bypass of the main loop until its mate is |
2930 | * found. When recursing, quote state is passed in via dest->quote. */ | 2957 | * found. When recursing, quote state is passed in via dest->quote. */ |
2931 | 2958 | ||
2932 | debug_printf("parse_stream, end_trigger=%d\n", end_trigger); | 2959 | debug_printf_parse("parse_stream entered, end_trigger='%s'\n", end_trigger); |
2960 | |||
2933 | while ((ch = b_getch(input)) != EOF) { | 2961 | while ((ch = b_getch(input)) != EOF) { |
2934 | m = map[ch]; | 2962 | m = map[ch]; |
2935 | next = (ch == '\n') ? 0 : b_peek(input); | 2963 | next = (ch == '\n') ? 0 : b_peek(input); |
2936 | debug_printf("parse_stream: ch=%c (%d) m=%d quote=%d\n", | 2964 | debug_printf_parse(": ch=%c (%d) m=%d quote=%d\n", |
2937 | ch, ch, m, dest->quote); | 2965 | ch, ch, m, dest->quote); |
2938 | if (m == 0 || ((m == 1 || m == 2) && dest->quote)) { | 2966 | if (m == MAP_ORDINARY |
2967 | || (m != MAP_NEVER_FLOWTROUGH && dest->quote) | ||
2968 | ) { | ||
2939 | b_addqchr(dest, ch, dest->quote); | 2969 | b_addqchr(dest, ch, dest->quote); |
2940 | continue; | 2970 | continue; |
2941 | } | 2971 | } |
2942 | if (m == 2) { /* unquoted IFS */ | 2972 | if (m == MAP_IFS_IF_UNQUOTED) { |
2943 | if (done_word(dest, ctx)) { | 2973 | if (done_word(dest, ctx)) { |
2974 | debug_printf_parse("parse_stream return 1\n"); | ||
2944 | return 1; | 2975 | return 1; |
2945 | } | 2976 | } |
2946 | /* If we aren't performing a substitution, treat a newline as a | 2977 | /* If we aren't performing a substitution, treat |
2947 | * command separator. */ | 2978 | * a newline as a command separator. |
2948 | if (end_trigger != '\0' && ch == '\n') | 2979 | * [why we don't handle it exactly like ';'? --vda] */ |
2980 | if (end_trigger && ch == '\n') { | ||
2949 | done_pipe(ctx, PIPE_SEQ); | 2981 | done_pipe(ctx, PIPE_SEQ); |
2982 | } | ||
2950 | } | 2983 | } |
2951 | if (ch == end_trigger && !dest->quote && ctx->w == RES_NONE) { | 2984 | if ((end_trigger && strchr(end_trigger, ch)) |
2952 | debug_printf("leaving parse_stream (triggered)\n"); | 2985 | && !dest->quote && ctx->w == RES_NONE |
2986 | ) { | ||
2987 | debug_printf_parse("parse_stream return 0\n"); | ||
2953 | return 0; | 2988 | return 0; |
2954 | } | 2989 | } |
2955 | if (m == 2) | 2990 | if (m == MAP_IFS_IF_UNQUOTED) |
2956 | continue; | 2991 | continue; |
2957 | switch (ch) { | 2992 | switch (ch) { |
2958 | case '#': | 2993 | case '#': |
@@ -2970,13 +3005,17 @@ static int parse_stream(o_string *dest, struct p_context *ctx, | |||
2970 | case '\\': | 3005 | case '\\': |
2971 | if (next == EOF) { | 3006 | if (next == EOF) { |
2972 | syntax(); | 3007 | syntax(); |
3008 | debug_printf_parse("parse_stream return 1\n"); | ||
2973 | return 1; | 3009 | return 1; |
2974 | } | 3010 | } |
2975 | b_addqchr(dest, '\\', dest->quote); | 3011 | b_addqchr(dest, '\\', dest->quote); |
2976 | b_addqchr(dest, b_getch(input), dest->quote); | 3012 | b_addqchr(dest, b_getch(input), dest->quote); |
2977 | break; | 3013 | break; |
2978 | case '$': | 3014 | case '$': |
2979 | if (handle_dollar(dest, ctx, input) != 0) return 1; | 3015 | if (handle_dollar(dest, ctx, input) != 0) { |
3016 | debug_printf_parse("parse_stream return 1: handle_dollar returned non-0\n"); | ||
3017 | return 1; | ||
3018 | } | ||
2980 | break; | 3019 | break; |
2981 | case '\'': | 3020 | case '\'': |
2982 | dest->nonnull = 1; | 3021 | dest->nonnull = 1; |
@@ -2988,6 +3027,7 @@ static int parse_stream(o_string *dest, struct p_context *ctx, | |||
2988 | } | 3027 | } |
2989 | if (ch == EOF) { | 3028 | if (ch == EOF) { |
2990 | syntax(); | 3029 | syntax(); |
3030 | debug_printf_parse("parse_stream return 1\n"); | ||
2991 | return 1; | 3031 | return 1; |
2992 | } | 3032 | } |
2993 | break; | 3033 | break; |
@@ -2996,7 +3036,7 @@ static int parse_stream(o_string *dest, struct p_context *ctx, | |||
2996 | dest->quote = !dest->quote; | 3036 | dest->quote = !dest->quote; |
2997 | break; | 3037 | break; |
2998 | case '`': | 3038 | case '`': |
2999 | process_command_subs(dest, ctx, input, '`'); | 3039 | process_command_subs(dest, ctx, input, "`"); |
3000 | break; | 3040 | break; |
3001 | case '>': | 3041 | case '>': |
3002 | redir_fd = redirect_opt_num(dest); | 3042 | redir_fd = redirect_opt_num(dest); |
@@ -3007,6 +3047,7 @@ static int parse_stream(o_string *dest, struct p_context *ctx, | |||
3007 | b_getch(input); | 3047 | b_getch(input); |
3008 | } else if (next == '(') { | 3048 | } else if (next == '(') { |
3009 | syntax(); /* until we support >(list) Process Substitution */ | 3049 | syntax(); /* until we support >(list) Process Substitution */ |
3050 | debug_printf_parse("parse_stream return 1: >(process) not supported\n"); | ||
3010 | return 1; | 3051 | return 1; |
3011 | } | 3052 | } |
3012 | setup_redirect(ctx, redir_fd, redir_style, input); | 3053 | setup_redirect(ctx, redir_fd, redir_style, input); |
@@ -3023,6 +3064,7 @@ static int parse_stream(o_string *dest, struct p_context *ctx, | |||
3023 | b_getch(input); | 3064 | b_getch(input); |
3024 | } else if (next == '(') { | 3065 | } else if (next == '(') { |
3025 | syntax(); /* until we support <(list) Process Substitution */ | 3066 | syntax(); /* until we support <(list) Process Substitution */ |
3067 | debug_printf_parse("parse_stream return 1: <(process) not supported\n"); | ||
3026 | return 1; | 3068 | return 1; |
3027 | } | 3069 | } |
3028 | setup_redirect(ctx, redir_fd, redir_style, input); | 3070 | setup_redirect(ctx, redir_fd, redir_style, input); |
@@ -3054,28 +3096,32 @@ static int parse_stream(o_string *dest, struct p_context *ctx, | |||
3054 | break; | 3096 | break; |
3055 | case '(': | 3097 | case '(': |
3056 | case '{': | 3098 | case '{': |
3057 | if (parse_group(dest, ctx, input, ch) != 0) | 3099 | if (parse_group(dest, ctx, input, ch) != 0) { |
3100 | debug_printf_parse("parse_stream return 1: parse_group returned non-0\n"); | ||
3058 | return 1; | 3101 | return 1; |
3102 | } | ||
3059 | break; | 3103 | break; |
3060 | case ')': | 3104 | case ')': |
3061 | case '}': | 3105 | case '}': |
3062 | syntax(); /* Proper use of this character caught by end_trigger */ | 3106 | syntax(); /* Proper use of this character is caught by end_trigger */ |
3107 | debug_printf_parse("parse_stream return 1: unexpected '}'\n"); | ||
3063 | return 1; | 3108 | return 1; |
3064 | default: | 3109 | default: |
3065 | syntax(); /* this is really an internal logic error */ | 3110 | syntax(); /* this is really an internal logic error */ |
3111 | debug_printf_parse("parse_stream return 1: internal logic error\n"); | ||
3066 | return 1; | 3112 | return 1; |
3067 | } | 3113 | } |
3068 | } | 3114 | } |
3069 | /* complain if quote? No, maybe we just finished a command substitution | 3115 | /* Complain if quote? No, maybe we just finished a command substitution |
3070 | * that was quoted. Example: | 3116 | * that was quoted. Example: |
3071 | * $ echo "`cat foo` plus more" | 3117 | * $ echo "`cat foo` plus more" |
3072 | * and we just got the EOF generated by the subshell that ran "cat foo" | 3118 | * and we just got the EOF generated by the subshell that ran "cat foo" |
3073 | * The only real complaint is if we got an EOF when end_trigger != '\0', | 3119 | * The only real complaint is if we got an EOF when end_trigger != NULL, |
3074 | * that is, we were really supposed to get end_trigger, and never got | 3120 | * that is, we were really supposed to get end_trigger, and never got |
3075 | * one before the EOF. Can't use the standard "syntax error" return code, | 3121 | * one before the EOF. Can't use the standard "syntax error" return code, |
3076 | * so that parse_stream_outer can distinguish the EOF and exit smoothly. */ | 3122 | * so that parse_stream_outer can distinguish the EOF and exit smoothly. */ |
3077 | debug_printf("leaving parse_stream (EOF)\n"); | 3123 | debug_printf_parse("parse_stream return -%d\n", end_trigger != NULL); |
3078 | if (end_trigger != '\0') | 3124 | if (end_trigger) |
3079 | return -1; | 3125 | return -1; |
3080 | return 0; | 3126 | return 0; |
3081 | } | 3127 | } |
@@ -3097,17 +3143,17 @@ static void update_ifs_map(void) | |||
3097 | * The map[] array only really needs two bits each, and on most machines | 3143 | * The map[] array only really needs two bits each, and on most machines |
3098 | * that would be faster because of the reduced L1 cache footprint. | 3144 | * that would be faster because of the reduced L1 cache footprint. |
3099 | */ | 3145 | */ |
3100 | memset(map, 0, sizeof(map)); /* most characters flow through always */ | 3146 | memset(map, MAP_ORDINARY, sizeof(map)); /* most chars flow through always */ |
3101 | mapset("\\$'\"`", 3); /* never flow through */ | 3147 | mapset("\\$'\"`", MAP_NEVER_FLOWTROUGH); |
3102 | mapset("<>;&|(){}#", 1); /* flow through if quoted */ | 3148 | mapset("<>;&|(){}#", MAP_FLOWTROUGH_IF_QUOTED); |
3103 | mapset(ifs, 2); /* also flow through if quoted */ | 3149 | mapset(ifs, MAP_IFS_IF_UNQUOTED); /* also flow through if quoted */ |
3104 | } | 3150 | } |
3105 | 3151 | ||
3106 | /* most recursion does not come through here, the exception is | 3152 | /* most recursion does not come through here, the exception is |
3107 | * from builtin_source() */ | 3153 | * from builtin_source() */ |
3108 | static int parse_stream_outer(struct in_str *inp, int flag) | 3154 | static int parse_stream_outer(struct in_str *inp, int flag) |
3109 | { | 3155 | { |
3110 | // FIXME: 'true | exit 3; echo $?' is parsed as a whole, | 3156 | // FIXME: '{ true | exit 3; echo $? }' is parsed as a whole, |
3111 | // as a result $? is replaced by 0, not 3! | 3157 | // as a result $? is replaced by 0, not 3! |
3112 | // Need to stop & execute stuff at ';', not parse till EOL! | 3158 | // Need to stop & execute stuff at ';', not parse till EOL! |
3113 | 3159 | ||
@@ -3119,11 +3165,11 @@ static int parse_stream_outer(struct in_str *inp, int flag) | |||
3119 | initialize_context(&ctx); | 3165 | initialize_context(&ctx); |
3120 | update_ifs_map(); | 3166 | update_ifs_map(); |
3121 | if (!(flag & FLAG_PARSE_SEMICOLON) || (flag & FLAG_REPARSING)) | 3167 | if (!(flag & FLAG_PARSE_SEMICOLON) || (flag & FLAG_REPARSING)) |
3122 | mapset(";$&|", 0); | 3168 | mapset(";$&|", MAP_ORDINARY); |
3123 | #if ENABLE_HUSH_INTERACTIVE | 3169 | #if ENABLE_HUSH_INTERACTIVE |
3124 | inp->promptmode = 1; | 3170 | inp->promptmode = 1; |
3125 | #endif | 3171 | #endif |
3126 | rcode = parse_stream(&temp, &ctx, inp, '\n'); | 3172 | rcode = parse_stream(&temp, &ctx, inp, ";\n"); |
3127 | if (rcode != 1 && ctx.old_flag != 0) { | 3173 | if (rcode != 1 && ctx.old_flag != 0) { |
3128 | syntax(); | 3174 | syntax(); |
3129 | } | 3175 | } |