aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2008-07-14 06:29:38 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2008-07-14 06:29:38 +0000
commit395ae452165a607c6b5bc4623225516044619616 (patch)
tree00ceff4dcd3fc4604d9252003cf45dfb6cfbedc1
parent17f02e79f407ff2311255981c191a1bf8b3a7ae0 (diff)
downloadbusybox-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.c34
-rw-r--r--shell/hush_doc.txt77
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 @@
12008-07-14
2
3 Command parsing
4
5Command parsing results in "pipe" structures. "Pipe" structure
6does not always correspond to what sh language calls "pipe",
7it also controls execution of if, while, etc statements.
8
9struct 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
17Blocks of commands { pipe; pipe; } and (pipe; pipe) are represented
18as one pipe struct with one progs[0] element which is a "group" -
19struct child_prog can contain a list of pipes. Sometimes these
20"groups" are created implicitly, e.g. every control
21statement (if, while, etc) sits inside its own "pipe" struct).
22
23res_word controls statement execution. Examples:
24
25"echo Hello" -
26pipe 0 res_word=NONE followup=SEQ prog[0] 'echo' 'Hello'
27pipe 1 res_word=NONE followup=1 SEQ
28
29"echo foo || echo bar" -
30pipe 0 res_word=NONE followup=OR prog[0] 'echo' 'foo'
31pipe 1 res_word=NONE followup=SEQ prog[0] 'echo' 'bar'
32pipe 2 res_word=NONE followup=SEQ
33
34"if true; then echo Hello; true; fi" -
35res_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)
42pipe 1 res_word=NONE followup=SEQ
43
44"if true; then { echo Hello; true; }; fi" -
45pipe 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)
54pipe 1 res_word=NONE followup=1 SEQ
55
56"for v in a b; do echo $v; true; done" -
57pipe 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)
65pipe 1 res_word=NONE followup=SEQ
66
67Note how "THEN" and "DO" does not just mark the first pipe,
68it "sticks" to all pipes in the body. This is used when
69hush executes parsed pipes.
70
71Dummy trailing pipes with no commands are artifacts of imperfect
72parsing algorithm - done_pipe() appends new pipe struct beforehand
73and last one ends up empty and unused.
74
75
762008-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 */