blob: c68dc2416be089ccf482f9701e04a06435e0d92e [file] [log] [blame]
Denis Vlasenko395ae452008-07-14 06:29:38 +000012008-07-14
2
3 Command parsing
4
Denis Vlasenkobcb25532008-07-28 23:04:34 +00005Command parsing results in a list of "pipe" structures.
6This list correspond not only to usual "pipe1 || pipe2 && pipe3"
7lists, but it also controls execution of if, while, etc statements.
8Every such statement is a list for hush. List consists of pipes.
Denis Vlasenko395ae452008-07-14 06:29:38 +00009
10struct pipe fields:
11 smallint res_word - "none" for normal commands,
12 "if" for if condition etc
13 struct child_prog progs[] - array of commands in pipe
14 smallint followup - how this pipe is related to next: is it
15 "pipe; pipe", "pipe & pipe" "pipe && pipe",
16 "pipe || pipe"?
17
18Blocks of commands { pipe; pipe; } and (pipe; pipe) are represented
19as one pipe struct with one progs[0] element which is a "group" -
20struct child_prog can contain a list of pipes. Sometimes these
21"groups" are created implicitly, e.g. every control
Denis Vlasenkobcb25532008-07-28 23:04:34 +000022statement (if, while, etc) sits inside its own group.
Denis Vlasenko395ae452008-07-14 06:29:38 +000023
24res_word controls statement execution. Examples:
25
26"echo Hello" -
27pipe 0 res_word=NONE followup=SEQ prog[0] 'echo' 'Hello'
Denis Vlasenko38c89212008-07-28 00:06:02 +000028pipe 1 res_word=NONE followup=SEQ
Denis Vlasenko395ae452008-07-14 06:29:38 +000029
30"echo foo || echo bar" -
31pipe 0 res_word=NONE followup=OR prog[0] 'echo' 'foo'
32pipe 1 res_word=NONE followup=SEQ prog[0] 'echo' 'bar'
33pipe 2 res_word=NONE followup=SEQ
34
35"if true; then echo Hello; true; fi" -
36res_word=NONE followup=SEQ
37 prog 0 group {}:
38 pipe 0 res_word=IF followup=SEQ prog[0] 'true'
39 pipe 1 res_word=THEN followup=SEQ prog[0] 'echo' 'Hello'
40 pipe 2 res_word=THEN followup=SEQ prog[0] 'true'
41 pipe 3 res_word=FI followup=SEQ
42 pipe 4 res_word=NONE followup=(null)
43pipe 1 res_word=NONE followup=SEQ
44
Denis Vlasenkobcb25532008-07-28 23:04:34 +000045Above you see that if is a list, and it sits in a {} group
46implicitly created by hush. Also note two THEN res_word's -
47it is explained below.
48
Denis Vlasenko395ae452008-07-14 06:29:38 +000049"if true; then { echo Hello; true; }; fi" -
50pipe 0 res_word=NONE followup=SEQ
51 prog 0 group {}:
52 pipe 0 res_word=IF followup=SEQ prog[0] 'true'
53 pipe 1 res_word=THEN followup=SEQ
54 prog 0 group {}:
55 pipe 0 res_word=NONE followup=SEQ prog[0] 'echo' 'Hello'
56 pipe 1 res_word=NONE followup=SEQ prog[0] 'true'
57 pipe 2 res_word=NONE followup=SEQ
58 pipe 2 res_word=NONE followup=(null)
Denis Vlasenko38c89212008-07-28 00:06:02 +000059pipe 1 res_word=NONE followup=SEQ
Denis Vlasenko395ae452008-07-14 06:29:38 +000060
61"for v in a b; do echo $v; true; done" -
62pipe 0 res_word=NONE followup=SEQ
63 prog 0 group {}:
64 pipe 0 res_word=FOR followup=SEQ prog[0] 'v'
65 pipe 1 res_word=IN followup=SEQ prog[0] 'a' 'b'
66 pipe 2 res_word=DO followup=SEQ prog[0] 'echo' '$v'
67 pipe 3 res_word=DO followup=SEQ prog[0] 'true'
68 pipe 4 res_word=DONE followup=SEQ
69 pipe 5 res_word=NONE followup=(null)
70pipe 1 res_word=NONE followup=SEQ
71
72Note how "THEN" and "DO" does not just mark the first pipe,
73it "sticks" to all pipes in the body. This is used when
74hush executes parsed pipes.
75
76Dummy trailing pipes with no commands are artifacts of imperfect
77parsing algorithm - done_pipe() appends new pipe struct beforehand
78and last one ends up empty and unused.
79
Denis Vlasenko757361f2008-07-14 08:26:47 +000080"for" and "case" statements (ab)use progs[] to keep their data
81instead of argv vector progs[] usually do. "for" keyword is forcing
82pipe termination after first word, which makes hush see
83"for v in..." as "for v; in...". "case" keyword does the same.
84Other judiciuosly placed hacks make hush see
85"case word in a) cmd1;; b) cmd2;; esac" as if it was
86"case word; match a; cmd; match b; cmd2; esac"
87("match" is a fictitious keyword here):
88
89"case word in a) cmd1;; b) cmd2; esac" -
90pipe 0 res_word=NONE followup=1 SEQ
91 prog 0 group {}:
92 pipe 0 res_word=CASE followup=SEQ prog[0] 'word'
93 pipe 1 res_word=MATCH followup=SEQ prog[0] 'a'
94 pipe 2 res_word=CASEI followup=SEQ prog[0] 'cmd1'
95 pipe 3 res_word=MATCH followup=SEQ prog[0] 'b'
96 pipe 4 res_word=CASEI followup=SEQ prog[0] 'cmd2'
97 pipe 5 res_word=CASEI followup=SEQ prog[0] 'cmd3'
98 pipe 6 res_word=ESAC followup=SEQ
99 pipe 7 res_word=NONE followup=(null)
Denis Vlasenko38c89212008-07-28 00:06:02 +0000100pipe 1 res_word=NONE followup=SEQ
Denis Vlasenko757361f2008-07-14 08:26:47 +0000101
Denis Vlasenko395ae452008-07-14 06:29:38 +0000102
1032008-01
104
Denis Vlasenko757361f2008-07-14 08:26:47 +0000105 Command execution
Denis Vlasenko05743d72008-02-10 12:10:08 +0000106
107/* callsite: process_command_subs */
108generate_stream_from_list(struct pipe *head) - handles `cmds`
109 create UNIX pipe
110 [v]fork
111 child:
112 redirect pipe output to stdout
113 _exit(run_list(head)); /* leaks memory */
114 parent:
115 return UNIX pipe's output fd
116 /* head is freed by the caller */
117
118/* callsite: parse_and_run_stream */
119run_and_free_list(struct pipe *)
120 run_list(struct pipe *)
121 free_pipe_list(struct pipe *)
122
123/* callsites: generate_stream_from_list, run_and_free_list, pseudo_exec, run_pipe */
124run_list(struct pipe *) - handles "cmd; cmd2 && cmd3", while/for/do loops
125 run_pipe - for every pipe in list
126
127/* callsite: run_list */
128run_pipe - runs "cmd1 | cmd2 | cmd3 [&]"
Denis Vlasenko0ef240d2008-02-10 16:00:30 +0000129 run_list - used if only one cmd and it is of the form "{cmds;}"
Denis Vlasenko05743d72008-02-10 12:10:08 +0000130 forks for every cmd if more than one cmd or if & is there
131 pseudo_exec - runs each "cmdN" (handles builtins etc)
132
Denis Vlasenko0ef240d2008-02-10 16:00:30 +0000133/* callsite: run_pipe */
Denis Vlasenko05743d72008-02-10 12:10:08 +0000134pseudo_exec - runs "cmd" (handles builtins etc)
135 exec - execs external programs
136 run_list - used if cmdN is "(cmds)" or "{cmds;}"
137 /* problem: putenv's malloced strings into environ -
138 ** with vfork they will leak into parent process
139 */
140 /* problem with ENABLE_FEATURE_SH_STANDALONE:
141 ** run_applet_no_and_exit(a, argv) uses exit - this can interfere
142 ** with vfork - switch to _exit there?
143 */