summaryrefslogtreecommitdiff
path: root/shell/hush.c
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2007-05-03 22:45:39 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2007-05-03 22:45:39 +0000
commite725bfe6e01505f0480dd1bd357209d3a2e72bb7 (patch)
tree3e128376a43debb087230efdd9bd73fb7a7f3be0 /shell/hush.c
parentf2fffd0014edff7f791fc2a5b27147bb0628d7e6 (diff)
downloadbusybox-w32-e725bfe6e01505f0480dd1bd357209d3a2e72bb7.tar.gz
busybox-w32-e725bfe6e01505f0480dd1bd357209d3a2e72bb7.tar.bz2
busybox-w32-e725bfe6e01505f0480dd1bd357209d3a2e72bb7.zip
hush: fix "true | exit 3; echo $?" bug
Diffstat (limited to 'shell/hush.c')
-rw-r--r--shell/hush.c138
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;
259extern char **environ; /* This is in <unistd.h>, but protected with __USE_GNU */ 264extern char **environ; /* This is in <unistd.h>, but protected with __USE_GNU */
260 265
261/* "globals" within this file */ 266/* "globals" within this file */
262static const char *ifs; 267enum {
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};
263static unsigned char map[256]; 273static unsigned char map[256];
274static const char *ifs;
264static int fake_mode; 275static int fake_mode;
265static struct close_me *close_me_head; 276static struct close_me *close_me_head;
266static const char *cwd; 277static 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: */
391static int redirect_dup_num(struct in_str *input); 402static int redirect_dup_num(struct in_str *input);
392static int redirect_opt_num(o_string *o); 403static int redirect_opt_num(o_string *o);
393static int process_command_subs(o_string *dest, struct p_context *ctx, struct in_str *input, int subst_end); 404static int process_command_subs(o_string *dest, struct p_context *ctx, struct in_str *input, const char *subst_end);
394static int parse_group(o_string *dest, struct p_context *ctx, struct in_str *input, int ch); 405static int parse_group(o_string *dest, struct p_context *ctx, struct in_str *input, int ch);
395static const char *lookup_param(const char *src); 406static const char *lookup_param(const char *src);
396static char *make_string(char **inp); 407static char *make_string(char **inp);
397static int handle_dollar(o_string *dest, struct p_context *ctx, struct in_str *input); 408static int handle_dollar(o_string *dest, struct p_context *ctx, struct in_str *input);
398static int parse_string(o_string *dest, struct p_context *ctx, const char *src); 409static int parse_string(o_string *dest, struct p_context *ctx, const char *src);
399static int parse_stream(o_string *dest, struct p_context *ctx, struct in_str *input0, int end_trigger); 410static int parse_stream(o_string *dest, struct p_context *ctx, struct in_str *input0, const char *end_trigger);
400/* setup: */ 411/* setup: */
401static int parse_stream_outer(struct in_str *inp, int flag); 412static int parse_stream_outer(struct in_str *inp, int flag);
402static int parse_string_outer(const char *s, int flag); 413static 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. */
2524static int done_word(o_string *dest, struct p_context *ctx) 2536static 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. */
2713static int process_command_subs(o_string *dest, struct p_context *ctx, struct in_str *input, int subst_end) 2733static 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
2757static int parse_group(o_string *dest, struct p_context *ctx, 2778static 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 */
2920static int parse_stream(o_string *dest, struct p_context *ctx, 2947static 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() */
3108static int parse_stream_outer(struct in_str *inp, int flag) 3154static 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 }