39f7dcee5f59b567f82c6e6ca0063d3df3df7738
[oweals/busybox.git] / shell / hush_doc.txt
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=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=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 "for" and "case" statements (ab)use progs[] to keep their data
76 instead of argv vector progs[] usually do. "for" keyword is forcing
77 pipe termination after first word, which makes hush see
78 "for v in..." as "for v; in...". "case" keyword does the same.
79 Other judiciuosly placed hacks make hush see
80 "case word in a) cmd1;; b) cmd2;; esac" as if it was
81 "case word; match a; cmd; match b; cmd2; esac"
82 ("match" is a fictitious keyword here):
83
84 "case word in a) cmd1;; b) cmd2; esac" -
85 pipe 0 res_word=NONE followup=1 SEQ
86  prog 0 group {}:
87   pipe 0 res_word=CASE followup=SEQ prog[0] 'word'
88   pipe 1 res_word=MATCH followup=SEQ prog[0] 'a'
89   pipe 2 res_word=CASEI followup=SEQ prog[0] 'cmd1'
90   pipe 3 res_word=MATCH followup=SEQ prog[0] 'b'
91   pipe 4 res_word=CASEI followup=SEQ prog[0] 'cmd2'
92   pipe 5 res_word=CASEI followup=SEQ prog[0] 'cmd3'
93   pipe 6 res_word=ESAC followup=SEQ
94   pipe 7 res_word=NONE followup=(null)
95 pipe 1 res_word=NONE followup=SEQ
96
97
98 2008-01
99
100         Command execution
101
102 /* callsite: process_command_subs */
103 generate_stream_from_list(struct pipe *head) - handles `cmds`
104   create UNIX pipe
105   [v]fork
106   child:
107   redirect pipe output to stdout
108   _exit(run_list(head));   /* leaks memory */
109   parent:
110   return UNIX pipe's output fd
111   /* head is freed by the caller */
112
113 /* callsite: parse_and_run_stream */
114 run_and_free_list(struct pipe *)
115   run_list(struct pipe *)
116   free_pipe_list(struct pipe *)
117
118 /* callsites: generate_stream_from_list, run_and_free_list, pseudo_exec, run_pipe */
119 run_list(struct pipe *) - handles "cmd; cmd2 && cmd3", while/for/do loops
120   run_pipe - for every pipe in list
121
122 /* callsite: run_list */
123 run_pipe - runs "cmd1 | cmd2 | cmd3 [&]"
124   run_list - used if only one cmd and it is of the form "{cmds;}"
125   forks for every cmd if more than one cmd or if & is there
126   pseudo_exec - runs each "cmdN" (handles builtins etc)
127
128 /* callsite: run_pipe */
129 pseudo_exec - runs "cmd" (handles builtins etc)
130   exec - execs external programs
131   run_list - used if cmdN is "(cmds)" or "{cmds;}"
132   /* problem: putenv's malloced strings into environ -
133   ** with vfork they will leak into parent process
134   */
135   /* problem with ENABLE_FEATURE_SH_STANDALONE:
136   ** run_applet_no_and_exit(a, argv) uses exit - this can interfere
137   ** with vfork - switch to _exit there?
138   */