diff options
author | Denis Vlasenko <vda.linux@googlemail.com> | 2008-07-14 06:29:38 +0000 |
---|---|---|
committer | Denis Vlasenko <vda.linux@googlemail.com> | 2008-07-14 06:29:38 +0000 |
commit | 395ae452165a607c6b5bc4623225516044619616 (patch) | |
tree | 00ceff4dcd3fc4604d9252003cf45dfb6cfbedc1 | |
parent | 17f02e79f407ff2311255981c191a1bf8b3a7ae0 (diff) | |
download | busybox-w32-395ae452165a607c6b5bc4623225516044619616.tar.gz busybox-w32-395ae452165a607c6b5bc4623225516044619616.tar.bz2 busybox-w32-395ae452165a607c6b5bc4623225516044619616.zip |
hush: delete unused field in struct child.
reinstate needed check for invalid syntax.
document command parsing in hush_doc.txt.
-rw-r--r-- | shell/hush.c | 34 | ||||
-rw-r--r-- | shell/hush_doc.txt | 77 |
2 files changed, 95 insertions, 16 deletions
diff --git a/shell/hush.c b/shell/hush.c index 47e53f8c1..db608018c 100644 --- a/shell/hush.c +++ b/shell/hush.c | |||
@@ -322,7 +322,6 @@ struct child_prog { | |||
322 | char **argv; /* program name and arguments */ | 322 | char **argv; /* program name and arguments */ |
323 | struct pipe *group; /* if non-NULL, first in group or subshell */ | 323 | struct pipe *group; /* if non-NULL, first in group or subshell */ |
324 | struct redir_struct *redirects; /* I/O redirections */ | 324 | struct redir_struct *redirects; /* I/O redirections */ |
325 | struct pipe *family; /* pointer back to the child's parent pipe */ | ||
326 | }; | 325 | }; |
327 | /* argv vector may contain variable references (^Cvar^C, ^C0^C etc) | 326 | /* argv vector may contain variable references (^Cvar^C, ^C0^C etc) |
328 | * and on execution these are substituted with their values. | 327 | * and on execution these are substituted with their values. |
@@ -2830,7 +2829,6 @@ static void initialize_context(struct p_context *ctx) | |||
2830 | ctx->pipe = ctx->list_head = new_pipe(); | 2829 | ctx->pipe = ctx->list_head = new_pipe(); |
2831 | /* Create the memory for child, roughly: | 2830 | /* Create the memory for child, roughly: |
2832 | * ctx->pipe->progs = new struct child_prog; | 2831 | * ctx->pipe->progs = new struct child_prog; |
2833 | * ctx->pipe->progs[0].family = ctx->pipe; | ||
2834 | * ctx->child = &ctx->pipe->progs[0]; | 2832 | * ctx->child = &ctx->pipe->progs[0]; |
2835 | */ | 2833 | */ |
2836 | done_command(ctx); | 2834 | done_command(ctx); |
@@ -2960,6 +2958,7 @@ static int done_word(o_string *word, struct p_context *ctx) | |||
2960 | { | 2958 | { |
2961 | struct child_prog *child = ctx->child; | 2959 | struct child_prog *child = ctx->child; |
2962 | 2960 | ||
2961 | debug_printf_parse("done_word entered: '%s' %p\n", word->data, child); | ||
2963 | /* If this word wasn't an assignment, next ones definitely | 2962 | /* If this word wasn't an assignment, next ones definitely |
2964 | * can't be assignments. Even if they look like ones. */ | 2963 | * can't be assignments. Even if they look like ones. */ |
2965 | if (word->o_assignment != DEFINITELY_ASSIGNMENT) { | 2964 | if (word->o_assignment != DEFINITELY_ASSIGNMENT) { |
@@ -2967,8 +2966,6 @@ static int done_word(o_string *word, struct p_context *ctx) | |||
2967 | } else { | 2966 | } else { |
2968 | word->o_assignment = MAYBE_ASSIGNMENT; | 2967 | word->o_assignment = MAYBE_ASSIGNMENT; |
2969 | } | 2968 | } |
2970 | |||
2971 | debug_printf_parse("done_word entered: '%s' %p\n", word->data, child); | ||
2972 | if (word->length == 0 && word->nonnull == 0) { | 2969 | if (word->length == 0 && word->nonnull == 0) { |
2973 | debug_printf_parse("done_word return 0: true null, ignored\n"); | 2970 | debug_printf_parse("done_word return 0: true null, ignored\n"); |
2974 | return 0; | 2971 | return 0; |
@@ -2980,15 +2977,17 @@ static int done_word(o_string *word, struct p_context *ctx) | |||
2980 | word->o_assignment = NOT_ASSIGNMENT; | 2977 | word->o_assignment = NOT_ASSIGNMENT; |
2981 | debug_printf("word stored in rd_filename: '%s'\n", word->data); | 2978 | debug_printf("word stored in rd_filename: '%s'\n", word->data); |
2982 | } else { | 2979 | } else { |
2983 | // if (child->group) { /* TODO: example how to trigger? */ | 2980 | /* "{ echo foo; } echo bar" - bad */ |
2984 | // syntax(NULL); | 2981 | /* NB: bash allows e.g. "if true; then { echo foo; } fi". TODO? */ |
2985 | // debug_printf_parse("done_word return 1: syntax error, groups and arglists don't mix\n"); | 2982 | if (child->group) { |
2986 | // return 1; | 2983 | syntax(NULL); |
2987 | // } | 2984 | debug_printf_parse("done_word return 1: syntax error, groups and arglists don't mix\n"); |
2985 | return 1; | ||
2986 | } | ||
2988 | #if HAS_KEYWORDS | 2987 | #if HAS_KEYWORDS |
2989 | #if ENABLE_HUSH_CASE | 2988 | #if ENABLE_HUSH_CASE |
2990 | if (ctx->ctx_dsemicolon) { | 2989 | if (ctx->ctx_dsemicolon) { |
2991 | /* already done when ctx_dsemicolon was set to 1 */ | 2990 | /* already done when ctx_dsemicolon was set to 1: */ |
2992 | /* ctx->ctx_res_w = RES_MATCH; */ | 2991 | /* ctx->ctx_res_w = RES_MATCH; */ |
2993 | ctx->ctx_dsemicolon = 0; | 2992 | ctx->ctx_dsemicolon = 0; |
2994 | } else | 2993 | } else |
@@ -3085,9 +3084,7 @@ static int done_command(struct p_context *ctx) | |||
3085 | * child structure is not counted in pi->num_progs. */ | 3084 | * child structure is not counted in pi->num_progs. */ |
3086 | pi->progs = xrealloc(pi->progs, sizeof(*pi->progs) * (pi->num_progs+1)); | 3085 | pi->progs = xrealloc(pi->progs, sizeof(*pi->progs) * (pi->num_progs+1)); |
3087 | child = &pi->progs[pi->num_progs]; | 3086 | child = &pi->progs[pi->num_progs]; |
3088 | |||
3089 | memset(child, 0, sizeof(*child)); | 3087 | memset(child, 0, sizeof(*child)); |
3090 | child->family = pi; | ||
3091 | 3088 | ||
3092 | ctx->child = child; | 3089 | ctx->child = child; |
3093 | /* but ctx->pipe and ctx->list_head remain unchanged */ | 3090 | /* but ctx->pipe and ctx->list_head remain unchanged */ |
@@ -3100,22 +3097,28 @@ static void done_pipe(struct p_context *ctx, pipe_style type) | |||
3100 | int not_null; | 3097 | int not_null; |
3101 | 3098 | ||
3102 | debug_printf_parse("done_pipe entered, followup %d\n", type); | 3099 | debug_printf_parse("done_pipe entered, followup %d\n", type); |
3103 | not_null = done_command(ctx); /* implicit closure of previous command */ | 3100 | /* Close previous command */ |
3101 | not_null = done_command(ctx); | ||
3104 | ctx->pipe->followup = type; | 3102 | ctx->pipe->followup = type; |
3105 | IF_HAS_KEYWORDS(ctx->pipe->pi_inverted = ctx->ctx_inverted;) | 3103 | IF_HAS_KEYWORDS(ctx->pipe->pi_inverted = ctx->ctx_inverted;) |
3106 | IF_HAS_KEYWORDS(ctx->ctx_inverted = 0;) | 3104 | IF_HAS_KEYWORDS(ctx->ctx_inverted = 0;) |
3107 | IF_HAS_KEYWORDS(ctx->pipe->res_word = ctx->ctx_res_w;) | 3105 | IF_HAS_KEYWORDS(ctx->pipe->res_word = ctx->ctx_res_w;) |
3106 | |||
3108 | /* Without this check, even just <enter> on command line generates | 3107 | /* Without this check, even just <enter> on command line generates |
3109 | * tree of three NOPs (!). Which is harmless but annoying. | 3108 | * tree of three NOPs (!). Which is harmless but annoying. |
3110 | * IOW: it is safe to do it unconditionally. | 3109 | * IOW: it is safe to do it unconditionally. |
3111 | * RES_NONE case is for "for a in; do ..." (empty IN set) | 3110 | * RES_NONE case is for "for a in; do ..." (empty IN set) |
3112 | * to work, possibly other cases too. */ | 3111 | * to work, possibly other cases too. */ |
3113 | if (not_null IF_HAS_KEYWORDS(|| ctx->ctx_res_w != RES_NONE)) { | 3112 | if (not_null IF_HAS_KEYWORDS(|| ctx->ctx_res_w != RES_NONE)) { |
3114 | struct pipe *new_p = new_pipe(); | 3113 | struct pipe *new_p; |
3114 | debug_printf_parse("done_pipe: adding new pipe: " | ||
3115 | " not_null:%d ctx->ctx_res_w:%d\n", | ||
3116 | not_null, ctx->ctx_res_w); | ||
3117 | new_p = new_pipe(); | ||
3115 | ctx->pipe->next = new_p; | 3118 | ctx->pipe->next = new_p; |
3116 | ctx->pipe = new_p; | 3119 | ctx->pipe = new_p; |
3117 | ctx->child = NULL; /* needed! */ | 3120 | ctx->child = NULL; /* needed! */ |
3118 | /* RES_IF, RES_WHILE etc are "sticky" - | 3121 | /* RES_THEN, RES_DO etc are "sticky" - |
3119 | * they remain set for commands inside if/while. | 3122 | * they remain set for commands inside if/while. |
3120 | * This is used to control execution. | 3123 | * This is used to control execution. |
3121 | * RES_FOR and RES_IN are NOT sticky (needed to support | 3124 | * RES_FOR and RES_IN are NOT sticky (needed to support |
@@ -3132,7 +3135,6 @@ static void done_pipe(struct p_context *ctx, pipe_style type) | |||
3132 | #endif | 3135 | #endif |
3133 | /* Create the memory for child, roughly: | 3136 | /* Create the memory for child, roughly: |
3134 | * ctx->pipe->progs = new struct child_prog; | 3137 | * ctx->pipe->progs = new struct child_prog; |
3135 | * ctx->pipe->progs[0].family = ctx->pipe; | ||
3136 | * ctx->child = &ctx->pipe->progs[0]; | 3138 | * ctx->child = &ctx->pipe->progs[0]; |
3137 | */ | 3139 | */ |
3138 | done_command(ctx); | 3140 | done_command(ctx); |
diff --git a/shell/hush_doc.txt b/shell/hush_doc.txt index 973fe44c5..ec5dd00f2 100644 --- a/shell/hush_doc.txt +++ b/shell/hush_doc.txt | |||
@@ -1,3 +1,80 @@ | |||
1 | 2008-07-14 | ||
2 | |||
3 | Command parsing | ||
4 | |||
5 | Command parsing results in "pipe" structures. "Pipe" structure | ||
6 | does not always correspond to what sh language calls "pipe", | ||
7 | it also controls execution of if, while, etc statements. | ||
8 | |||
9 | struct pipe fields: | ||
10 | smallint res_word - "none" for normal commands, | ||
11 | "if" for if condition etc | ||
12 | struct child_prog progs[] - array of commands in pipe | ||
13 | smallint followup - how this pipe is related to next: is it | ||
14 | "pipe; pipe", "pipe & pipe" "pipe && pipe", | ||
15 | "pipe || pipe"? | ||
16 | |||
17 | Blocks of commands { pipe; pipe; } and (pipe; pipe) are represented | ||
18 | as one pipe struct with one progs[0] element which is a "group" - | ||
19 | struct child_prog can contain a list of pipes. Sometimes these | ||
20 | "groups" are created implicitly, e.g. every control | ||
21 | statement (if, while, etc) sits inside its own "pipe" struct). | ||
22 | |||
23 | res_word controls statement execution. Examples: | ||
24 | |||
25 | "echo Hello" - | ||
26 | pipe 0 res_word=NONE followup=SEQ prog[0] 'echo' 'Hello' | ||
27 | pipe 1 res_word=NONE followup=1 SEQ | ||
28 | |||
29 | "echo foo || echo bar" - | ||
30 | pipe 0 res_word=NONE followup=OR prog[0] 'echo' 'foo' | ||
31 | pipe 1 res_word=NONE followup=SEQ prog[0] 'echo' 'bar' | ||
32 | pipe 2 res_word=NONE followup=SEQ | ||
33 | |||
34 | "if true; then echo Hello; true; fi" - | ||
35 | res_word=NONE followup=SEQ | ||
36 | prog 0 group {}: | ||
37 | pipe 0 res_word=IF followup=SEQ prog[0] 'true' | ||
38 | pipe 1 res_word=THEN followup=SEQ prog[0] 'echo' 'Hello' | ||
39 | pipe 2 res_word=THEN followup=SEQ prog[0] 'true' | ||
40 | pipe 3 res_word=FI followup=SEQ | ||
41 | pipe 4 res_word=NONE followup=(null) | ||
42 | pipe 1 res_word=NONE followup=SEQ | ||
43 | |||
44 | "if true; then { echo Hello; true; }; fi" - | ||
45 | pipe 0 res_word=NONE followup=SEQ | ||
46 | prog 0 group {}: | ||
47 | pipe 0 res_word=IF followup=SEQ prog[0] 'true' | ||
48 | pipe 1 res_word=THEN followup=SEQ | ||
49 | prog 0 group {}: | ||
50 | pipe 0 res_word=NONE followup=SEQ prog[0] 'echo' 'Hello' | ||
51 | pipe 1 res_word=NONE followup=SEQ prog[0] 'true' | ||
52 | pipe 2 res_word=NONE followup=SEQ | ||
53 | pipe 2 res_word=NONE followup=(null) | ||
54 | pipe 1 res_word=NONE followup=1 SEQ | ||
55 | |||
56 | "for v in a b; do echo $v; true; done" - | ||
57 | pipe 0 res_word=NONE followup=SEQ | ||
58 | prog 0 group {}: | ||
59 | pipe 0 res_word=FOR followup=SEQ prog[0] 'v' | ||
60 | pipe 1 res_word=IN followup=SEQ prog[0] 'a' 'b' | ||
61 | pipe 2 res_word=DO followup=SEQ prog[0] 'echo' '$v' | ||
62 | pipe 3 res_word=DO followup=SEQ prog[0] 'true' | ||
63 | pipe 4 res_word=DONE followup=SEQ | ||
64 | pipe 5 res_word=NONE followup=(null) | ||
65 | pipe 1 res_word=NONE followup=SEQ | ||
66 | |||
67 | Note how "THEN" and "DO" does not just mark the first pipe, | ||
68 | it "sticks" to all pipes in the body. This is used when | ||
69 | hush executes parsed pipes. | ||
70 | |||
71 | Dummy trailing pipes with no commands are artifacts of imperfect | ||
72 | parsing algorithm - done_pipe() appends new pipe struct beforehand | ||
73 | and last one ends up empty and unused. | ||
74 | |||
75 | |||
76 | 2008-01 | ||
77 | |||
1 | This is how hush runs commands: | 78 | This is how hush runs commands: |
2 | 79 | ||
3 | /* callsite: process_command_subs */ | 80 | /* callsite: process_command_subs */ |