diff options
author | Denis Vlasenko <vda.linux@googlemail.com> | 2007-05-05 15:10:52 +0000 |
---|---|---|
committer | Denis Vlasenko <vda.linux@googlemail.com> | 2007-05-05 15:10:52 +0000 |
commit | a6c467f6d134f1fb906806f4cf3b6ca401b6a616 (patch) | |
tree | da2697fd1fc7fc1f71b0f4dc83a6c8d7fd4532bf /shell/hush.c | |
parent | 734e5ebc93a4ed325173119211559f6942e651c4 (diff) | |
download | busybox-w32-a6c467f6d134f1fb906806f4cf3b6ca401b6a616.tar.gz busybox-w32-a6c467f6d134f1fb906806f4cf3b6ca401b6a616.tar.bz2 busybox-w32-a6c467f6d134f1fb906806f4cf3b6ca401b6a616.zip |
hush: preparatory patch for removing extra empty pipes generation
in parse stage. No real code change here.
Diffstat (limited to 'shell/hush.c')
-rw-r--r-- | shell/hush.c | 170 |
1 files changed, 90 insertions, 80 deletions
diff --git a/shell/hush.c b/shell/hush.c index 78531e864..eb6f37f15 100644 --- a/shell/hush.c +++ b/shell/hush.c | |||
@@ -125,10 +125,10 @@ static const char *indenter(int i) | |||
125 | #define ENABLE_FEATURE_EDITING_FANCY_PROMPT 0 | 125 | #define ENABLE_FEATURE_EDITING_FANCY_PROMPT 0 |
126 | #endif | 126 | #endif |
127 | 127 | ||
128 | #define SPECIAL_VAR_SYMBOL 03 | 128 | #define SPECIAL_VAR_SYMBOL 3 |
129 | #define FLAG_EXIT_FROM_LOOP 1 | 129 | #define FLAG_EXIT_FROM_LOOP 1 |
130 | #define FLAG_PARSE_SEMICOLON (1 << 1) /* symbol ';' is special for parser */ | 130 | #define FLAG_PARSE_SEMICOLON (1 << 1) /* symbol ';' is special for parser */ |
131 | #define FLAG_REPARSING (1 << 2) /* >=2nd pass */ | 131 | #define FLAG_REPARSING (1 << 2) /* >= 2nd pass */ |
132 | 132 | ||
133 | typedef enum { | 133 | typedef enum { |
134 | REDIRECT_INPUT = 1, | 134 | REDIRECT_INPUT = 1, |
@@ -199,10 +199,10 @@ struct p_context { | |||
199 | struct pipe *list_head; | 199 | struct pipe *list_head; |
200 | struct pipe *pipe; | 200 | struct pipe *pipe; |
201 | struct redir_struct *pending_redirect; | 201 | struct redir_struct *pending_redirect; |
202 | reserved_style w; | 202 | reserved_style res_w; |
203 | int old_flag; /* for figuring out valid reserved words */ | 203 | int old_flag; /* for figuring out valid reserved words */ |
204 | struct p_context *stack; | 204 | struct p_context *stack; |
205 | int type; /* define type of parser : ";$" common or special symbol */ | 205 | int parse_type; /* define type of parser : ";$" common or special symbol */ |
206 | /* How about quoting status? */ | 206 | /* How about quoting status? */ |
207 | }; | 207 | }; |
208 | 208 | ||
@@ -410,8 +410,8 @@ static int handle_dollar(o_string *dest, struct p_context *ctx, struct in_str *i | |||
410 | static int parse_string(o_string *dest, struct p_context *ctx, const char *src); | 410 | static int parse_string(o_string *dest, struct p_context *ctx, const char *src); |
411 | static int parse_stream(o_string *dest, struct p_context *ctx, struct in_str *input0, const char *end_trigger); | 411 | static int parse_stream(o_string *dest, struct p_context *ctx, struct in_str *input0, const char *end_trigger); |
412 | /* setup: */ | 412 | /* setup: */ |
413 | static int parse_stream_outer(struct in_str *inp, int flag); | 413 | static int parse_stream_outer(struct in_str *inp, int parse_flag); |
414 | static int parse_string_outer(const char *s, int flag); | 414 | static int parse_string_outer(const char *s, int parse_flag); |
415 | static int parse_file_outer(FILE *f); | 415 | static int parse_file_outer(FILE *f); |
416 | /* job management: */ | 416 | /* job management: */ |
417 | static int checkjobs(struct pipe* fg_pipe); | 417 | static int checkjobs(struct pipe* fg_pipe); |
@@ -1854,23 +1854,24 @@ static void debug_print_tree(struct pipe *pi, int lvl) | |||
1854 | }; | 1854 | }; |
1855 | 1855 | ||
1856 | int pin, prn; | 1856 | int pin, prn; |
1857 | char **argv; | ||
1858 | pin = 0; | 1857 | pin = 0; |
1859 | while (pi) { | 1858 | while (pi) { |
1860 | fprintf(stderr, "%*spipe %d r_mode=%s followup=%d %s\n", lvl*2, "", | 1859 | fprintf(stderr, "%*spipe %d r_mode=%s followup=%d %s\n", lvl*2, "", |
1861 | pin, RES[pi->r_mode], pi->followup, PIPE[pi->followup]); | 1860 | pin, RES[pi->r_mode], pi->followup, PIPE[pi->followup]); |
1862 | prn = 0; | 1861 | prn = 0; |
1863 | while (prn < pi->num_progs) { | 1862 | while (prn < pi->num_progs) { |
1863 | struct child_prog *child = &pi->progs[prn]; | ||
1864 | char **argv = child->argv; | ||
1865 | |||
1864 | fprintf(stderr, "%*s prog %d", lvl*2, "", prn); | 1866 | fprintf(stderr, "%*s prog %d", lvl*2, "", prn); |
1865 | if (pi->progs[prn].group) { | 1867 | if (child->group) { |
1866 | fprintf(stderr, " group %s: (argv=%p)\n", | 1868 | fprintf(stderr, " group %s: (argv=%p)\n", |
1867 | (pi->subshell ? "()" : "{}"), | 1869 | (child->subshell ? "()" : "{}"), |
1868 | pi->progs[prn].argv); | 1870 | argv); |
1869 | debug_print_tree(pi->progs[prn].group, lvl+1); | 1871 | debug_print_tree(child->group, lvl+1); |
1870 | prn++; | 1872 | prn++; |
1871 | continue; | 1873 | continue; |
1872 | } | 1874 | } |
1873 | argv = pi->progs[prn].argv; | ||
1874 | if (argv) while (*argv) { | 1875 | if (argv) while (*argv) { |
1875 | fprintf(stderr, " '%s'", *argv); | 1876 | fprintf(stderr, " '%s'", *argv); |
1876 | argv++; | 1877 | argv++; |
@@ -1901,7 +1902,7 @@ static int run_list_real(struct pipe *pi) | |||
1901 | int flag_rep = 0; | 1902 | int flag_rep = 0; |
1902 | int save_num_progs; | 1903 | int save_num_progs; |
1903 | int flag_skip = 1; | 1904 | int flag_skip = 1; |
1904 | int rcode = 0; /* probaly for gcc only */ | 1905 | int rcode = 0; /* probably for gcc only */ |
1905 | int flag_restore = 0; | 1906 | int flag_restore = 0; |
1906 | int if_code = 0, next_if_code = 0; /* need double-buffer to handle elif */ | 1907 | int if_code = 0, next_if_code = 0; /* need double-buffer to handle elif */ |
1907 | reserved_style rmode, skip_more_in_this_rmode = RES_XXXX; | 1908 | reserved_style rmode, skip_more_in_this_rmode = RES_XXXX; |
@@ -1968,17 +1969,15 @@ static int run_list_real(struct pipe *pi) | |||
1968 | } | 1969 | } |
1969 | #endif | 1970 | #endif |
1970 | 1971 | ||
1971 | for (; pi; pi = (flag_restore != 0) ? rpipe : pi->next) { | 1972 | for (; pi; pi = flag_restore ? rpipe : pi->next) { |
1972 | if (pi->r_mode == RES_WHILE || pi->r_mode == RES_UNTIL | 1973 | rmode = pi->r_mode; |
1973 | || pi->r_mode == RES_FOR | 1974 | if (rmode == RES_WHILE || rmode == RES_UNTIL || rmode == RES_FOR) { |
1974 | ) { | ||
1975 | flag_restore = 0; | 1975 | flag_restore = 0; |
1976 | if (!rpipe) { | 1976 | if (!rpipe) { |
1977 | flag_rep = 0; | 1977 | flag_rep = 0; |
1978 | rpipe = pi; | 1978 | rpipe = pi; |
1979 | } | 1979 | } |
1980 | } | 1980 | } |
1981 | rmode = pi->r_mode; | ||
1982 | debug_printf_exec(": rmode=%d if_code=%d next_if_code=%d skip_more=%d\n", | 1981 | debug_printf_exec(": rmode=%d if_code=%d next_if_code=%d skip_more=%d\n", |
1983 | rmode, if_code, next_if_code, skip_more_in_this_rmode); | 1982 | rmode, if_code, next_if_code, skip_more_in_this_rmode); |
1984 | if (rmode == skip_more_in_this_rmode && flag_skip) { | 1983 | if (rmode == skip_more_in_this_rmode && flag_skip) { |
@@ -2535,7 +2534,7 @@ static void initialize_context(struct p_context *ctx) | |||
2535 | ctx->child = NULL; | 2534 | ctx->child = NULL; |
2536 | ctx->list_head = new_pipe(); | 2535 | ctx->list_head = new_pipe(); |
2537 | ctx->pipe = ctx->list_head; | 2536 | ctx->pipe = ctx->list_head; |
2538 | ctx->w = RES_NONE; | 2537 | ctx->res_w = RES_NONE; |
2539 | ctx->stack = NULL; | 2538 | ctx->stack = NULL; |
2540 | ctx->old_flag = 0; | 2539 | ctx->old_flag = 0; |
2541 | done_command(ctx); /* creates the memory for working child */ | 2540 | done_command(ctx); /* creates the memory for working child */ |
@@ -2574,29 +2573,29 @@ static int reserved_word(o_string *dest, struct p_context *ctx) | |||
2574 | enum { NRES = sizeof(reserved_list)/sizeof(reserved_list[0]) }; | 2573 | enum { NRES = sizeof(reserved_list)/sizeof(reserved_list[0]) }; |
2575 | const struct reserved_combo *r; | 2574 | const struct reserved_combo *r; |
2576 | 2575 | ||
2577 | for (r = reserved_list; r < reserved_list+NRES; r++) { | 2576 | for (r = reserved_list; r < reserved_list + NRES; r++) { |
2578 | if (strcmp(dest->data, r->literal) == 0) { | 2577 | if (strcmp(dest->data, r->literal) == 0) { |
2579 | debug_printf("found reserved word %s, code %d\n", r->literal, r->code); | 2578 | debug_printf("found reserved word %s, code %d\n", r->literal, r->code); |
2580 | if (r->flag & FLAG_START) { | 2579 | if (r->flag & FLAG_START) { |
2581 | struct p_context *new = xmalloc(sizeof(struct p_context)); | 2580 | struct p_context *new = xmalloc(sizeof(struct p_context)); |
2582 | debug_printf("push stack\n"); | 2581 | debug_printf("push stack\n"); |
2583 | if (ctx->w == RES_IN || ctx->w == RES_FOR) { | 2582 | if (ctx->res_w == RES_IN || ctx->res_w == RES_FOR) { |
2584 | syntax(); | 2583 | syntax(); |
2585 | free(new); | 2584 | free(new); |
2586 | ctx->w = RES_SNTX; | 2585 | ctx->res_w = RES_SNTX; |
2587 | b_reset(dest); | 2586 | b_reset(dest); |
2588 | return 1; | 2587 | return 1; |
2589 | } | 2588 | } |
2590 | *new = *ctx; /* physical copy */ | 2589 | *new = *ctx; /* physical copy */ |
2591 | initialize_context(ctx); | 2590 | initialize_context(ctx); |
2592 | ctx->stack = new; | 2591 | ctx->stack = new; |
2593 | } else if (ctx->w == RES_NONE || !(ctx->old_flag & (1 << r->code))) { | 2592 | } else if (ctx->res_w == RES_NONE || !(ctx->old_flag & (1 << r->code))) { |
2594 | syntax(); | 2593 | syntax(); |
2595 | ctx->w = RES_SNTX; | 2594 | ctx->res_w = RES_SNTX; |
2596 | b_reset(dest); | 2595 | b_reset(dest); |
2597 | return 1; | 2596 | return 1; |
2598 | } | 2597 | } |
2599 | ctx->w = r->code; | 2598 | ctx->res_w = r->code; |
2600 | ctx->old_flag = r->flag; | 2599 | ctx->old_flag = r->flag; |
2601 | if (ctx->old_flag & FLAG_END) { | 2600 | if (ctx->old_flag & FLAG_END) { |
2602 | struct p_context *old; | 2601 | struct p_context *old; |
@@ -2623,7 +2622,7 @@ static int done_word(o_string *dest, struct p_context *ctx) | |||
2623 | glob_t *glob_target; | 2622 | glob_t *glob_target; |
2624 | int gr, flags = 0; | 2623 | int gr, flags = 0; |
2625 | 2624 | ||
2626 | debug_printf_parse("done_word: '%s' %p\n", dest->data, child); | 2625 | debug_printf_parse("done_word entered: '%s' %p\n", dest->data, child); |
2627 | if (dest->length == 0 && !dest->nonnull) { | 2626 | if (dest->length == 0 && !dest->nonnull) { |
2628 | debug_printf_parse("done_word return 0: true null, ignored\n"); | 2627 | debug_printf_parse("done_word return 0: true null, ignored\n"); |
2629 | return 0; | 2628 | return 0; |
@@ -2636,15 +2635,16 @@ static int done_word(o_string *dest, struct p_context *ctx) | |||
2636 | debug_printf_parse("done_word return 1: syntax error, groups and arglists don't mix\n"); | 2635 | debug_printf_parse("done_word return 1: syntax error, groups and arglists don't mix\n"); |
2637 | return 1; | 2636 | return 1; |
2638 | } | 2637 | } |
2639 | if (!child->argv && (ctx->type & FLAG_PARSE_SEMICOLON)) { | 2638 | if (!child->argv && (ctx->parse_type & FLAG_PARSE_SEMICOLON)) { |
2640 | debug_printf_parse(": checking %s for reserved-ness\n", dest->data); | 2639 | debug_printf_parse(": checking '%s' for reserved-ness\n", dest->data); |
2641 | if (reserved_word(dest, ctx)) { | 2640 | if (reserved_word(dest, ctx)) { |
2642 | debug_printf_parse("done_word return %d\n", (ctx->w == RES_SNTX)); | 2641 | debug_printf_parse("done_word return %d\n", (ctx->res_w == RES_SNTX)); |
2643 | return (ctx->w == RES_SNTX); | 2642 | return (ctx->res_w == RES_SNTX); |
2644 | } | 2643 | } |
2645 | } | 2644 | } |
2646 | glob_target = &child->glob_result; | 2645 | glob_target = &child->glob_result; |
2647 | if (child->argv) flags |= GLOB_APPEND; | 2646 | if (child->argv) |
2647 | flags |= GLOB_APPEND; | ||
2648 | } | 2648 | } |
2649 | gr = xglob(dest, flags, glob_target); | 2649 | gr = xglob(dest, flags, glob_target); |
2650 | if (gr != 0) { | 2650 | if (gr != 0) { |
@@ -2663,7 +2663,7 @@ static int done_word(o_string *dest, struct p_context *ctx) | |||
2663 | } else { | 2663 | } else { |
2664 | child->argv = glob_target->gl_pathv; | 2664 | child->argv = glob_target->gl_pathv; |
2665 | } | 2665 | } |
2666 | if (ctx->w == RES_FOR) { | 2666 | if (ctx->res_w == RES_FOR) { |
2667 | done_word(dest, ctx); | 2667 | done_word(dest, ctx); |
2668 | done_pipe(ctx, PIPE_SEQ); | 2668 | done_pipe(ctx, PIPE_SEQ); |
2669 | } | 2669 | } |
@@ -2676,56 +2676,63 @@ static int done_word(o_string *dest, struct p_context *ctx) | |||
2676 | static int done_command(struct p_context *ctx) | 2676 | static int done_command(struct p_context *ctx) |
2677 | { | 2677 | { |
2678 | /* The child is really already in the pipe structure, so | 2678 | /* The child is really already in the pipe structure, so |
2679 | * advance the pipe counter and make a new, null child. | 2679 | * advance the pipe counter and make a new, null child. */ |
2680 | * Only real trickiness here is that the uncommitted | ||
2681 | * child structure, to which ctx->child points, is not | ||
2682 | * counted in pi->num_progs. */ | ||
2683 | struct pipe *pi = ctx->pipe; | 2680 | struct pipe *pi = ctx->pipe; |
2684 | struct child_prog *prog = ctx->child; | 2681 | struct child_prog *child = ctx->child; |
2685 | 2682 | ||
2686 | if (prog && prog->group == NULL | 2683 | if (child) { |
2687 | && prog->argv == NULL | 2684 | if (child->group == NULL |
2688 | && prog->redirects == NULL | 2685 | && child->argv == NULL |
2689 | ) { | 2686 | && child->redirects == NULL |
2690 | debug_printf("done_command: skipping null command\n"); | 2687 | ) { |
2691 | return 0; | 2688 | debug_printf_parse("done_command: skipping null command\n"); |
2692 | } | 2689 | return 0; |
2693 | if (prog) { | 2690 | } |
2694 | pi->num_progs++; | 2691 | pi->num_progs++; |
2695 | debug_printf("done_command: num_progs incremented to %d\n", pi->num_progs); | 2692 | debug_printf_parse("done_command: ++num_progs=%d\n", pi->num_progs); |
2696 | } else { | 2693 | } else { |
2697 | debug_printf("done_command: initializing\n"); | 2694 | debug_printf_parse("done_command: initializing, num_progs=%d\n", pi->num_progs); |
2698 | } | 2695 | } |
2699 | pi->progs = xrealloc(pi->progs, sizeof(*pi->progs) * (pi->num_progs+1)); | ||
2700 | |||
2701 | prog = pi->progs + pi->num_progs; | ||
2702 | memset(prog, 0, sizeof(*prog)); | ||
2703 | /*prog->redirects = NULL;*/ | ||
2704 | /*prog->argv = NULL; */ | ||
2705 | /*prog->is_stopped = 0;*/ | ||
2706 | /*prog->group = NULL;*/ | ||
2707 | /*prog->glob_result.gl_pathv = NULL;*/ | ||
2708 | prog->family = pi; | ||
2709 | /*prog->sp = 0;*/ | ||
2710 | ctx->child = prog; | ||
2711 | prog->type = ctx->type; | ||
2712 | 2696 | ||
2697 | /* Only real trickiness here is that the uncommitted | ||
2698 | * child structure is not counted in pi->num_progs. */ | ||
2699 | pi->progs = xrealloc(pi->progs, sizeof(*pi->progs) * (pi->num_progs+1)); | ||
2700 | child = &pi->progs[pi->num_progs]; | ||
2701 | |||
2702 | memset(child, 0, sizeof(*child)); | ||
2703 | /*child->redirects = NULL;*/ | ||
2704 | /*child->argv = NULL;*/ | ||
2705 | /*child->is_stopped = 0;*/ | ||
2706 | /*child->group = NULL;*/ | ||
2707 | /*child->glob_result.gl_pathv = NULL;*/ | ||
2708 | child->family = pi; | ||
2709 | /*child->sp = 0;*/ | ||
2710 | child->type = ctx->parse_type; | ||
2711 | |||
2712 | ctx->child = child; | ||
2713 | /* but ctx->pipe and ctx->list_head remain unchanged */ | 2713 | /* but ctx->pipe and ctx->list_head remain unchanged */ |
2714 | |||
2714 | return 0; | 2715 | return 0; |
2715 | } | 2716 | } |
2716 | 2717 | ||
2717 | static int done_pipe(struct p_context *ctx, pipe_style type) | 2718 | static int done_pipe(struct p_context *ctx, pipe_style type) |
2718 | { | 2719 | { |
2719 | struct pipe *new_p; | 2720 | struct pipe *new_p; |
2721 | |||
2722 | debug_printf_parse("done_pipe entered, followup %d\n", type); | ||
2720 | done_command(ctx); /* implicit closure of previous command */ | 2723 | done_command(ctx); /* implicit closure of previous command */ |
2721 | debug_printf_parse("done_pipe, type %d\n", type); | ||
2722 | ctx->pipe->followup = type; | 2724 | ctx->pipe->followup = type; |
2723 | ctx->pipe->r_mode = ctx->w; | 2725 | ctx->pipe->r_mode = ctx->res_w; |
2724 | new_p = new_pipe(); | 2726 | new_p = new_pipe(); |
2725 | ctx->pipe->next = new_p; | 2727 | ctx->pipe->next = new_p; |
2726 | ctx->pipe = new_p; | 2728 | ctx->pipe = new_p; |
2727 | ctx->child = NULL; | 2729 | ctx->child = NULL; |
2730 | // TODO: even just <enter> on command line basically generates | ||
2731 | // tree of three NOPs (!). | ||
2732 | // Can we detect that previous done_command have seen "skipping null command" | ||
2733 | // condition and NOT create new pipe here? | ||
2728 | done_command(ctx); /* set up new pipe to accept commands */ | 2734 | done_command(ctx); /* set up new pipe to accept commands */ |
2735 | debug_printf_parse("done_pipe return 0\n"); | ||
2729 | return 0; | 2736 | return 0; |
2730 | } | 2737 | } |
2731 | 2738 | ||
@@ -3055,7 +3062,7 @@ static int parse_stream(o_string *dest, struct p_context *ctx, | |||
3055 | } | 3062 | } |
3056 | if (m == MAP_IFS_IF_UNQUOTED) { | 3063 | if (m == MAP_IFS_IF_UNQUOTED) { |
3057 | if (done_word(dest, ctx)) { | 3064 | if (done_word(dest, ctx)) { |
3058 | debug_printf_parse("parse_stream return 1\n"); | 3065 | debug_printf_parse("parse_stream return 1: done_word!=0\n"); |
3059 | return 1; | 3066 | return 1; |
3060 | } | 3067 | } |
3061 | /* If we aren't performing a substitution, treat | 3068 | /* If we aren't performing a substitution, treat |
@@ -3066,9 +3073,9 @@ static int parse_stream(o_string *dest, struct p_context *ctx, | |||
3066 | } | 3073 | } |
3067 | } | 3074 | } |
3068 | if ((end_trigger && strchr(end_trigger, ch)) | 3075 | if ((end_trigger && strchr(end_trigger, ch)) |
3069 | && !dest->quote && ctx->w == RES_NONE | 3076 | && !dest->quote && ctx->res_w == RES_NONE |
3070 | ) { | 3077 | ) { |
3071 | debug_printf_parse("parse_stream return 0\n"); | 3078 | debug_printf_parse("parse_stream return 0: end_trigger char found\n"); |
3072 | return 0; | 3079 | return 0; |
3073 | } | 3080 | } |
3074 | if (m == MAP_IFS_IF_UNQUOTED) | 3081 | if (m == MAP_IFS_IF_UNQUOTED) |
@@ -3089,7 +3096,7 @@ static int parse_stream(o_string *dest, struct p_context *ctx, | |||
3089 | case '\\': | 3096 | case '\\': |
3090 | if (next == EOF) { | 3097 | if (next == EOF) { |
3091 | syntax(); | 3098 | syntax(); |
3092 | debug_printf_parse("parse_stream return 1\n"); | 3099 | debug_printf_parse("parse_stream return 1: \\<eof>\n"); |
3093 | return 1; | 3100 | return 1; |
3094 | } | 3101 | } |
3095 | b_addqchr(dest, '\\', dest->quote); | 3102 | b_addqchr(dest, '\\', dest->quote); |
@@ -3111,7 +3118,7 @@ static int parse_stream(o_string *dest, struct p_context *ctx, | |||
3111 | } | 3118 | } |
3112 | if (ch == EOF) { | 3119 | if (ch == EOF) { |
3113 | syntax(); | 3120 | syntax(); |
3114 | debug_printf_parse("parse_stream return 1\n"); | 3121 | debug_printf_parse("parse_stream return 1: unterminated '\n"); |
3115 | return 1; | 3122 | return 1; |
3116 | } | 3123 | } |
3117 | break; | 3124 | break; |
@@ -3204,7 +3211,7 @@ static int parse_stream(o_string *dest, struct p_context *ctx, | |||
3204 | * that is, we were really supposed to get end_trigger, and never got | 3211 | * that is, we were really supposed to get end_trigger, and never got |
3205 | * one before the EOF. Can't use the standard "syntax error" return code, | 3212 | * one before the EOF. Can't use the standard "syntax error" return code, |
3206 | * so that parse_stream_outer can distinguish the EOF and exit smoothly. */ | 3213 | * so that parse_stream_outer can distinguish the EOF and exit smoothly. */ |
3207 | debug_printf_parse("parse_stream return -%d\n", end_trigger != NULL); | 3214 | debug_printf_parse("parse_stream return %d\n", -(end_trigger != NULL)); |
3208 | if (end_trigger) | 3215 | if (end_trigger) |
3209 | return -1; | 3216 | return -1; |
3210 | return 0; | 3217 | return 0; |
@@ -3220,7 +3227,8 @@ static void update_ifs_map(void) | |||
3220 | { | 3227 | { |
3221 | /* char *ifs and char map[256] are both globals. */ | 3228 | /* char *ifs and char map[256] are both globals. */ |
3222 | ifs = getenv("IFS"); | 3229 | ifs = getenv("IFS"); |
3223 | if (ifs == NULL) ifs = " \t\n"; | 3230 | if (ifs == NULL) |
3231 | ifs = " \t\n"; | ||
3224 | /* Precompute a list of 'flow through' behavior so it can be treated | 3232 | /* Precompute a list of 'flow through' behavior so it can be treated |
3225 | * quickly up front. Computation is necessary because of IFS. | 3233 | * quickly up front. Computation is necessary because of IFS. |
3226 | * Special case handling of IFS == " \t\n" is not implemented. | 3234 | * Special case handling of IFS == " \t\n" is not implemented. |
@@ -3235,24 +3243,26 @@ static void update_ifs_map(void) | |||
3235 | 3243 | ||
3236 | /* most recursion does not come through here, the exception is | 3244 | /* most recursion does not come through here, the exception is |
3237 | * from builtin_source() */ | 3245 | * from builtin_source() */ |
3238 | static int parse_stream_outer(struct in_str *inp, int flag) | 3246 | static int parse_stream_outer(struct in_str *inp, int parse_flag) |
3239 | { | 3247 | { |
3240 | // FIXME: '{ true | exit 3; echo $? }' is parsed as a whole, | 3248 | // FIXME: '{ true | exit 3; echo $? }' is parsed as a whole, |
3241 | // as a result $? is replaced by 0, not 3! | 3249 | // as a result $? is replaced by 0, not 3! |
3242 | // Need to stop & execute stuff at ';', not parse till EOL! | ||
3243 | 3250 | ||
3244 | struct p_context ctx; | 3251 | struct p_context ctx; |
3245 | o_string temp = NULL_O_STRING; | 3252 | o_string temp = NULL_O_STRING; |
3246 | int rcode; | 3253 | int rcode; |
3247 | do { | 3254 | do { |
3248 | ctx.type = flag; | 3255 | ctx.parse_type = parse_flag; |
3249 | initialize_context(&ctx); | 3256 | initialize_context(&ctx); |
3250 | update_ifs_map(); | 3257 | update_ifs_map(); |
3251 | if (!(flag & FLAG_PARSE_SEMICOLON) || (flag & FLAG_REPARSING)) | 3258 | if (!(parse_flag & FLAG_PARSE_SEMICOLON) || (parse_flag & FLAG_REPARSING)) |
3252 | mapset(";$&|", MAP_ORDINARY); | 3259 | mapset(";$&|", MAP_ORDINARY); |
3253 | #if ENABLE_HUSH_INTERACTIVE | 3260 | #if ENABLE_HUSH_INTERACTIVE |
3254 | inp->promptmode = 1; | 3261 | inp->promptmode = 1; |
3255 | #endif | 3262 | #endif |
3263 | /* We will stop & execute after each ';' or '\n'. | ||
3264 | * Example: "sleep 9999; echo TEST" + ctrl-C: | ||
3265 | * TEST should be printed */ | ||
3256 | rcode = parse_stream(&temp, &ctx, inp, ";\n"); | 3266 | rcode = parse_stream(&temp, &ctx, inp, ";\n"); |
3257 | if (rcode != 1 && ctx.old_flag != 0) { | 3267 | if (rcode != 1 && ctx.old_flag != 0) { |
3258 | syntax(); | 3268 | syntax(); |
@@ -3274,15 +3284,15 @@ static int parse_stream_outer(struct in_str *inp, int flag) | |||
3274 | free_pipe_list(ctx.list_head, 0); | 3284 | free_pipe_list(ctx.list_head, 0); |
3275 | } | 3285 | } |
3276 | b_free(&temp); | 3286 | b_free(&temp); |
3277 | } while (rcode != -1 && !(flag & FLAG_EXIT_FROM_LOOP)); /* loop on syntax errors, return on EOF */ | 3287 | } while (rcode != -1 && !(parse_flag & FLAG_EXIT_FROM_LOOP)); /* loop on syntax errors, return on EOF */ |
3278 | return 0; | 3288 | return 0; |
3279 | } | 3289 | } |
3280 | 3290 | ||
3281 | static int parse_string_outer(const char *s, int flag) | 3291 | static int parse_string_outer(const char *s, int parse_flag) |
3282 | { | 3292 | { |
3283 | struct in_str input; | 3293 | struct in_str input; |
3284 | setup_string_in_str(&input, s); | 3294 | setup_string_in_str(&input, s); |
3285 | return parse_stream_outer(&input, flag); | 3295 | return parse_stream_outer(&input, parse_flag); |
3286 | } | 3296 | } |
3287 | 3297 | ||
3288 | static int parse_file_outer(FILE *f) | 3298 | static int parse_file_outer(FILE *f) |
@@ -3303,7 +3313,7 @@ static void setup_job_control(void) | |||
3303 | pid_t shell_pgrp; | 3313 | pid_t shell_pgrp; |
3304 | 3314 | ||
3305 | saved_task_pgrp = shell_pgrp = getpgrp(); | 3315 | saved_task_pgrp = shell_pgrp = getpgrp(); |
3306 | debug_printf("saved_task_pgrp=%d\n", saved_task_pgrp); | 3316 | debug_printf_jobs("saved_task_pgrp=%d\n", saved_task_pgrp); |
3307 | fcntl(interactive_fd, F_SETFD, FD_CLOEXEC); | 3317 | fcntl(interactive_fd, F_SETFD, FD_CLOEXEC); |
3308 | 3318 | ||
3309 | /* If we were ran as 'hush &', | 3319 | /* If we were ran as 'hush &', |
@@ -3319,7 +3329,7 @@ static void setup_job_control(void) | |||
3319 | set_misc_sighandler(SIG_IGN); | 3329 | set_misc_sighandler(SIG_IGN); |
3320 | //huh? signal(SIGCHLD, SIG_IGN); | 3330 | //huh? signal(SIGCHLD, SIG_IGN); |
3321 | 3331 | ||
3322 | /* We _must_ restore tty pgrp fatal signals */ | 3332 | /* We _must_ restore tty pgrp on fatal signals */ |
3323 | set_fatal_sighandler(sigexit); | 3333 | set_fatal_sighandler(sigexit); |
3324 | 3334 | ||
3325 | /* Put ourselves in our own process group. */ | 3335 | /* Put ourselves in our own process group. */ |