xref: /aosp_15_r20/external/toybox/toys/pending/sh.c (revision cf5a6c84e2b8763fc1a7db14496fd4742913b199)
1*cf5a6c84SAndroid Build Coastguard Worker /* sh.c - toybox shell
2*cf5a6c84SAndroid Build Coastguard Worker  *
3*cf5a6c84SAndroid Build Coastguard Worker  * Copyright 2006 Rob Landley <[email protected]>
4*cf5a6c84SAndroid Build Coastguard Worker  *
5*cf5a6c84SAndroid Build Coastguard Worker  * This shell aims for bash compatibility. The bash man page is at:
6*cf5a6c84SAndroid Build Coastguard Worker  * http://man7.org/linux/man-pages/man1/bash.1.html
7*cf5a6c84SAndroid Build Coastguard Worker  *
8*cf5a6c84SAndroid Build Coastguard Worker  * The POSIX-2008/SUSv4 shell spec is at:
9*cf5a6c84SAndroid Build Coastguard Worker  * http://opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html
10*cf5a6c84SAndroid Build Coastguard Worker  * and http://opengroup.org/onlinepubs/9699919799/utilities/sh.html
11*cf5a6c84SAndroid Build Coastguard Worker  *
12*cf5a6c84SAndroid Build Coastguard Worker  * deviations from posix: don't care about $LANG or $LC_ALL
13*cf5a6c84SAndroid Build Coastguard Worker  * deviations from bash:
14*cf5a6c84SAndroid Build Coastguard Worker  *   redirect+expansion in one pass so we can't report errors between them.
15*cf5a6c84SAndroid Build Coastguard Worker  *   Trailing redirects error at runtime, not parse time.
16*cf5a6c84SAndroid Build Coastguard Worker 
17*cf5a6c84SAndroid Build Coastguard Worker  * builtins: alias bg command fc fg getopts jobs newgrp read umask unalias wait
18*cf5a6c84SAndroid Build Coastguard Worker  *          disown suspend source pushd popd dirs logout times trap cd hash exit
19*cf5a6c84SAndroid Build Coastguard Worker  *           unset local export readonly set : . let history declare ulimit type
20*cf5a6c84SAndroid Build Coastguard Worker  * "special" builtins: break continue eval exec return shift
21*cf5a6c84SAndroid Build Coastguard Worker  * external with extra shell behavior: kill pwd time test
22*cf5a6c84SAndroid Build Coastguard Worker 
23*cf5a6c84SAndroid Build Coastguard Worker  * * ? [ # ~ = % [[ ]] function select exit label:
24*cf5a6c84SAndroid Build Coastguard Worker 
25*cf5a6c84SAndroid Build Coastguard Worker  * TODO: case, wildcard +(*|?), job control (find_plus_minus), ${x//}, $(())
26*cf5a6c84SAndroid Build Coastguard Worker 
27*cf5a6c84SAndroid Build Coastguard Worker  * TODO: support case in $() because $(case a in a) ;; ; esac) stops at first )
28*cf5a6c84SAndroid Build Coastguard Worker  * TODO: test exit from "trap EXIT" doesn't recurse
29*cf5a6c84SAndroid Build Coastguard Worker  * TODO: ! history expansion
30*cf5a6c84SAndroid Build Coastguard Worker  * TODO: getuid() vs geteuid()
31*cf5a6c84SAndroid Build Coastguard Worker  * TODO: test that $PS1 color changes work without stupid \[ \] hack
32*cf5a6c84SAndroid Build Coastguard Worker  * TODO: Handle embedded NUL bytes in the command line? (When/how?)
33*cf5a6c84SAndroid Build Coastguard Worker  * TODO: set -e -o pipefail, shopt -s nullglob
34*cf5a6c84SAndroid Build Coastguard Worker  * TODO: utf8 isspace
35*cf5a6c84SAndroid Build Coastguard Worker  *
36*cf5a6c84SAndroid Build Coastguard Worker  * bash man page:
37*cf5a6c84SAndroid Build Coastguard Worker  * control operators || & && ; ;; ;& ;;& ( ) | |& <newline>
38*cf5a6c84SAndroid Build Coastguard Worker  * reserved words
39*cf5a6c84SAndroid Build Coastguard Worker  *   ! case  coproc  do done elif else esac fi for  function  if  in  select
40*cf5a6c84SAndroid Build Coastguard Worker  *   then until while { } time [[ ]]
41*cf5a6c84SAndroid Build Coastguard Worker  *
42*cf5a6c84SAndroid Build Coastguard Worker  * Flow control statements:
43*cf5a6c84SAndroid Build Coastguard Worker  *
44*cf5a6c84SAndroid Build Coastguard Worker  * if/then/elif/else/fi, for select while until/do/done, case/esac,
45*cf5a6c84SAndroid Build Coastguard Worker  * {/}, [[/]], (/), function assignment
46*cf5a6c84SAndroid Build Coastguard Worker 
47*cf5a6c84SAndroid Build Coastguard Worker USE_SH(NEWTOY(break, ">1", TOYFLAG_NOFORK))
48*cf5a6c84SAndroid Build Coastguard Worker USE_SH(NEWTOY(cd, ">1LP[-LP]", TOYFLAG_NOFORK))
49*cf5a6c84SAndroid Build Coastguard Worker USE_SH(NEWTOY(continue, ">1", TOYFLAG_NOFORK))
50*cf5a6c84SAndroid Build Coastguard Worker USE_SH(NEWTOY(declare, "pAailunxr", TOYFLAG_NOFORK))
51*cf5a6c84SAndroid Build Coastguard Worker  // TODO tpgfF
52*cf5a6c84SAndroid Build Coastguard Worker USE_SH(NEWTOY(eval, 0, TOYFLAG_NOFORK))
53*cf5a6c84SAndroid Build Coastguard Worker USE_SH(NEWTOY(exec, "^cla:", TOYFLAG_NOFORK))
54*cf5a6c84SAndroid Build Coastguard Worker USE_SH(NEWTOY(exit, 0, TOYFLAG_NOFORK))
55*cf5a6c84SAndroid Build Coastguard Worker USE_SH(NEWTOY(export, "np", TOYFLAG_NOFORK))
56*cf5a6c84SAndroid Build Coastguard Worker USE_SH(NEWTOY(jobs, "lnprs", TOYFLAG_NOFORK))
57*cf5a6c84SAndroid Build Coastguard Worker USE_SH(NEWTOY(local, 0, TOYFLAG_NOFORK))
58*cf5a6c84SAndroid Build Coastguard Worker USE_SH(NEWTOY(return, ">1", TOYFLAG_NOFORK))
59*cf5a6c84SAndroid Build Coastguard Worker USE_SH(NEWTOY(set, 0, TOYFLAG_NOFORK))
60*cf5a6c84SAndroid Build Coastguard Worker USE_SH(NEWTOY(shift, ">1", TOYFLAG_NOFORK))
61*cf5a6c84SAndroid Build Coastguard Worker USE_SH(NEWTOY(source, "<1", TOYFLAG_NOFORK))
62*cf5a6c84SAndroid Build Coastguard Worker USE_SH(OLDTOY(., source, TOYFLAG_NOFORK))
63*cf5a6c84SAndroid Build Coastguard Worker USE_SH(NEWTOY(unset, "fvn[!fv]", TOYFLAG_NOFORK))
64*cf5a6c84SAndroid Build Coastguard Worker USE_SH(NEWTOY(wait, "n", TOYFLAG_NOFORK))
65*cf5a6c84SAndroid Build Coastguard Worker 
66*cf5a6c84SAndroid Build Coastguard Worker USE_SH(NEWTOY(sh, "0^(noediting)(noprofile)(norc)sc:i", TOYFLAG_BIN))
67*cf5a6c84SAndroid Build Coastguard Worker USE_SH(OLDTOY(toysh, sh, TOYFLAG_BIN))
68*cf5a6c84SAndroid Build Coastguard Worker USE_SH(OLDTOY(bash, sh, TOYFLAG_BIN))
69*cf5a6c84SAndroid Build Coastguard Worker // Login lies in argv[0], so add some aliases to catch that
70*cf5a6c84SAndroid Build Coastguard Worker USE_SH(OLDTOY(-sh, sh, 0))
71*cf5a6c84SAndroid Build Coastguard Worker USE_SH(OLDTOY(-toysh, sh, 0))
72*cf5a6c84SAndroid Build Coastguard Worker USE_SH(OLDTOY(-bash, sh, 0))
73*cf5a6c84SAndroid Build Coastguard Worker 
74*cf5a6c84SAndroid Build Coastguard Worker config SH
75*cf5a6c84SAndroid Build Coastguard Worker   bool "sh (toysh)"
76*cf5a6c84SAndroid Build Coastguard Worker   default n
77*cf5a6c84SAndroid Build Coastguard Worker   help
78*cf5a6c84SAndroid Build Coastguard Worker     usage: sh [-c command] [script]
79*cf5a6c84SAndroid Build Coastguard Worker 
80*cf5a6c84SAndroid Build Coastguard Worker     Command shell.  Runs a shell script, or reads input interactively
81*cf5a6c84SAndroid Build Coastguard Worker     and responds to it. Roughly compatible with "bash". Run "help" for
82*cf5a6c84SAndroid Build Coastguard Worker     list of built-in commands.
83*cf5a6c84SAndroid Build Coastguard Worker 
84*cf5a6c84SAndroid Build Coastguard Worker     -c	command line to execute
85*cf5a6c84SAndroid Build Coastguard Worker     -i	interactive mode (default when STDIN is a tty)
86*cf5a6c84SAndroid Build Coastguard Worker     -s	don't run script (args set $* parameters but read commands from stdin)
87*cf5a6c84SAndroid Build Coastguard Worker 
88*cf5a6c84SAndroid Build Coastguard Worker     Command shells parse each line of input (prompting when interactive), perform
89*cf5a6c84SAndroid Build Coastguard Worker     variable expansion and redirection, execute commands (spawning child processes
90*cf5a6c84SAndroid Build Coastguard Worker     and background jobs), and perform flow control based on the return code.
91*cf5a6c84SAndroid Build Coastguard Worker 
92*cf5a6c84SAndroid Build Coastguard Worker     Parsing:
93*cf5a6c84SAndroid Build Coastguard Worker       syntax errors
94*cf5a6c84SAndroid Build Coastguard Worker 
95*cf5a6c84SAndroid Build Coastguard Worker     Interactive prompts:
96*cf5a6c84SAndroid Build Coastguard Worker       line continuation
97*cf5a6c84SAndroid Build Coastguard Worker 
98*cf5a6c84SAndroid Build Coastguard Worker     Variable expansion:
99*cf5a6c84SAndroid Build Coastguard Worker       Note: can cause syntax errors at runtime
100*cf5a6c84SAndroid Build Coastguard Worker 
101*cf5a6c84SAndroid Build Coastguard Worker     Redirection:
102*cf5a6c84SAndroid Build Coastguard Worker       HERE documents (parsing)
103*cf5a6c84SAndroid Build Coastguard Worker       Pipelines (flow control and job control)
104*cf5a6c84SAndroid Build Coastguard Worker 
105*cf5a6c84SAndroid Build Coastguard Worker     Running commands:
106*cf5a6c84SAndroid Build Coastguard Worker       process state
107*cf5a6c84SAndroid Build Coastguard Worker       builtins
108*cf5a6c84SAndroid Build Coastguard Worker         cd [[ ]] (( ))
109*cf5a6c84SAndroid Build Coastguard Worker         ! : [ # TODO: help for these?
110*cf5a6c84SAndroid Build Coastguard Worker         true false help echo kill printf pwd test
111*cf5a6c84SAndroid Build Coastguard Worker       child processes
112*cf5a6c84SAndroid Build Coastguard Worker 
113*cf5a6c84SAndroid Build Coastguard Worker     Job control:
114*cf5a6c84SAndroid Build Coastguard Worker       &    Background process
115*cf5a6c84SAndroid Build Coastguard Worker       Ctrl-C kill process
116*cf5a6c84SAndroid Build Coastguard Worker       Ctrl-Z suspend process
117*cf5a6c84SAndroid Build Coastguard Worker       bg fg jobs kill
118*cf5a6c84SAndroid Build Coastguard Worker 
119*cf5a6c84SAndroid Build Coastguard Worker     Flow control:
120*cf5a6c84SAndroid Build Coastguard Worker     ;    End statement (same as newline)
121*cf5a6c84SAndroid Build Coastguard Worker     &    Background process (returns true unless syntax error)
122*cf5a6c84SAndroid Build Coastguard Worker     &&   If this fails, next command fails without running
123*cf5a6c84SAndroid Build Coastguard Worker     ||   If this succeeds, next command succeeds without running
124*cf5a6c84SAndroid Build Coastguard Worker     |    Pipelines! (Can of worms...)
125*cf5a6c84SAndroid Build Coastguard Worker     for {name [in...]}|((;;)) do; BODY; done
126*cf5a6c84SAndroid Build Coastguard Worker     if TEST; then BODY; fi
127*cf5a6c84SAndroid Build Coastguard Worker     while TEST; do BODY; done
128*cf5a6c84SAndroid Build Coastguard Worker     case a in X);; esac
129*cf5a6c84SAndroid Build Coastguard Worker     [[ TEST ]]
130*cf5a6c84SAndroid Build Coastguard Worker     ((MATH))
131*cf5a6c84SAndroid Build Coastguard Worker 
132*cf5a6c84SAndroid Build Coastguard Worker     Job control:
133*cf5a6c84SAndroid Build Coastguard Worker     &    Background process
134*cf5a6c84SAndroid Build Coastguard Worker     Ctrl-C kill process
135*cf5a6c84SAndroid Build Coastguard Worker     Ctrl-Z suspend process
136*cf5a6c84SAndroid Build Coastguard Worker     bg fg jobs kill
137*cf5a6c84SAndroid Build Coastguard Worker 
138*cf5a6c84SAndroid Build Coastguard Worker # These are here for the help text, they're not selectable and control nothing
139*cf5a6c84SAndroid Build Coastguard Worker config BREAK
140*cf5a6c84SAndroid Build Coastguard Worker   bool
141*cf5a6c84SAndroid Build Coastguard Worker   default n
142*cf5a6c84SAndroid Build Coastguard Worker   depends on SH
143*cf5a6c84SAndroid Build Coastguard Worker   help
144*cf5a6c84SAndroid Build Coastguard Worker     usage: break [N]
145*cf5a6c84SAndroid Build Coastguard Worker 
146*cf5a6c84SAndroid Build Coastguard Worker     End N levels of for/while/until loop immediately (default 1).
147*cf5a6c84SAndroid Build Coastguard Worker 
148*cf5a6c84SAndroid Build Coastguard Worker config CD
149*cf5a6c84SAndroid Build Coastguard Worker   bool
150*cf5a6c84SAndroid Build Coastguard Worker   default n
151*cf5a6c84SAndroid Build Coastguard Worker   depends on SH
152*cf5a6c84SAndroid Build Coastguard Worker   help
153*cf5a6c84SAndroid Build Coastguard Worker     usage: cd [-PL] [-] [path]
154*cf5a6c84SAndroid Build Coastguard Worker 
155*cf5a6c84SAndroid Build Coastguard Worker     Change current directory. With no arguments, go $HOME. Sets $OLDPWD to
156*cf5a6c84SAndroid Build Coastguard Worker     previous directory: cd - to return to $OLDPWD.
157*cf5a6c84SAndroid Build Coastguard Worker 
158*cf5a6c84SAndroid Build Coastguard Worker     -P	Physical path: resolve symlinks in path
159*cf5a6c84SAndroid Build Coastguard Worker     -L	Local path: .. trims directories off $PWD (default)
160*cf5a6c84SAndroid Build Coastguard Worker 
161*cf5a6c84SAndroid Build Coastguard Worker config CONTINUE
162*cf5a6c84SAndroid Build Coastguard Worker   bool
163*cf5a6c84SAndroid Build Coastguard Worker   default n
164*cf5a6c84SAndroid Build Coastguard Worker   depends on SH
165*cf5a6c84SAndroid Build Coastguard Worker   help
166*cf5a6c84SAndroid Build Coastguard Worker     usage: continue [N]
167*cf5a6c84SAndroid Build Coastguard Worker 
168*cf5a6c84SAndroid Build Coastguard Worker     Start next entry in for/while/until loop (or Nth outer loop, default 1).
169*cf5a6c84SAndroid Build Coastguard Worker 
170*cf5a6c84SAndroid Build Coastguard Worker config DECLARE
171*cf5a6c84SAndroid Build Coastguard Worker   bool
172*cf5a6c84SAndroid Build Coastguard Worker   default n
173*cf5a6c84SAndroid Build Coastguard Worker   depends on SH
174*cf5a6c84SAndroid Build Coastguard Worker   help
175*cf5a6c84SAndroid Build Coastguard Worker     usage: declare [-pAailunxr] [NAME...]
176*cf5a6c84SAndroid Build Coastguard Worker 
177*cf5a6c84SAndroid Build Coastguard Worker     Set or print variable attributes and values.
178*cf5a6c84SAndroid Build Coastguard Worker 
179*cf5a6c84SAndroid Build Coastguard Worker     -p	Print variables instead of setting
180*cf5a6c84SAndroid Build Coastguard Worker     -A	Associative array
181*cf5a6c84SAndroid Build Coastguard Worker     -a	Indexed array
182*cf5a6c84SAndroid Build Coastguard Worker     -i	Integer
183*cf5a6c84SAndroid Build Coastguard Worker     -l	Lower case
184*cf5a6c84SAndroid Build Coastguard Worker     -n	Name reference (symlink)
185*cf5a6c84SAndroid Build Coastguard Worker     -r	Readonly
186*cf5a6c84SAndroid Build Coastguard Worker     -u	Uppercase
187*cf5a6c84SAndroid Build Coastguard Worker     -x	Export
188*cf5a6c84SAndroid Build Coastguard Worker 
189*cf5a6c84SAndroid Build Coastguard Worker config EXIT
190*cf5a6c84SAndroid Build Coastguard Worker   bool
191*cf5a6c84SAndroid Build Coastguard Worker   default n
192*cf5a6c84SAndroid Build Coastguard Worker   depends on SH
193*cf5a6c84SAndroid Build Coastguard Worker   help
194*cf5a6c84SAndroid Build Coastguard Worker     usage: exit [status]
195*cf5a6c84SAndroid Build Coastguard Worker 
196*cf5a6c84SAndroid Build Coastguard Worker     Exit shell.  If no return value supplied on command line, use value
197*cf5a6c84SAndroid Build Coastguard Worker     of most recent command, or 0 if none.
198*cf5a6c84SAndroid Build Coastguard Worker 
199*cf5a6c84SAndroid Build Coastguard Worker config SET
200*cf5a6c84SAndroid Build Coastguard Worker   bool
201*cf5a6c84SAndroid Build Coastguard Worker   default n
202*cf5a6c84SAndroid Build Coastguard Worker   depends on SH
203*cf5a6c84SAndroid Build Coastguard Worker   help
204*cf5a6c84SAndroid Build Coastguard Worker     usage: set [+a] [+o OPTION] [VAR...]
205*cf5a6c84SAndroid Build Coastguard Worker 
206*cf5a6c84SAndroid Build Coastguard Worker     Set variables and shell attributes. Use + to disable and - to enable.
207*cf5a6c84SAndroid Build Coastguard Worker     NAME=VALUE arguments assign to the variable, any leftovers set $1, $2...
208*cf5a6c84SAndroid Build Coastguard Worker     With no arguments, prints current variables.
209*cf5a6c84SAndroid Build Coastguard Worker 
210*cf5a6c84SAndroid Build Coastguard Worker     -f	NAME is a function
211*cf5a6c84SAndroid Build Coastguard Worker     -v	NAME is a variable
212*cf5a6c84SAndroid Build Coastguard Worker     -n	don't follow name reference
213*cf5a6c84SAndroid Build Coastguard Worker 
214*cf5a6c84SAndroid Build Coastguard Worker     OPTIONs:
215*cf5a6c84SAndroid Build Coastguard Worker       history - enable command history
216*cf5a6c84SAndroid Build Coastguard Worker 
217*cf5a6c84SAndroid Build Coastguard Worker config UNSET
218*cf5a6c84SAndroid Build Coastguard Worker   bool
219*cf5a6c84SAndroid Build Coastguard Worker   default n
220*cf5a6c84SAndroid Build Coastguard Worker   depends on SH
221*cf5a6c84SAndroid Build Coastguard Worker   help
222*cf5a6c84SAndroid Build Coastguard Worker     usage: unset [-fvn] NAME...
223*cf5a6c84SAndroid Build Coastguard Worker 
224*cf5a6c84SAndroid Build Coastguard Worker     -f	NAME is a function
225*cf5a6c84SAndroid Build Coastguard Worker     -v	NAME is a variable
226*cf5a6c84SAndroid Build Coastguard Worker     -n	dereference NAME and unset that
227*cf5a6c84SAndroid Build Coastguard Worker 
228*cf5a6c84SAndroid Build Coastguard Worker config EVAL
229*cf5a6c84SAndroid Build Coastguard Worker   bool
230*cf5a6c84SAndroid Build Coastguard Worker   default n
231*cf5a6c84SAndroid Build Coastguard Worker   depends on SH
232*cf5a6c84SAndroid Build Coastguard Worker   help
233*cf5a6c84SAndroid Build Coastguard Worker     usage: eval COMMAND...
234*cf5a6c84SAndroid Build Coastguard Worker 
235*cf5a6c84SAndroid Build Coastguard Worker     Execute (combined) arguments as a shell command.
236*cf5a6c84SAndroid Build Coastguard Worker 
237*cf5a6c84SAndroid Build Coastguard Worker config EXEC
238*cf5a6c84SAndroid Build Coastguard Worker   bool
239*cf5a6c84SAndroid Build Coastguard Worker   default n
240*cf5a6c84SAndroid Build Coastguard Worker   depends on SH
241*cf5a6c84SAndroid Build Coastguard Worker   help
242*cf5a6c84SAndroid Build Coastguard Worker     usage: exec [-cl] [-a NAME] COMMAND...
243*cf5a6c84SAndroid Build Coastguard Worker 
244*cf5a6c84SAndroid Build Coastguard Worker     -a	set argv[0] to NAME
245*cf5a6c84SAndroid Build Coastguard Worker     -c	clear environment
246*cf5a6c84SAndroid Build Coastguard Worker     -l	prepend - to argv[0]
247*cf5a6c84SAndroid Build Coastguard Worker 
248*cf5a6c84SAndroid Build Coastguard Worker config EXPORT
249*cf5a6c84SAndroid Build Coastguard Worker   bool
250*cf5a6c84SAndroid Build Coastguard Worker   default n
251*cf5a6c84SAndroid Build Coastguard Worker   depends on SH
252*cf5a6c84SAndroid Build Coastguard Worker   help
253*cf5a6c84SAndroid Build Coastguard Worker     usage: export [-n] [NAME[=VALUE]...]
254*cf5a6c84SAndroid Build Coastguard Worker 
255*cf5a6c84SAndroid Build Coastguard Worker     Make variables available to child processes. NAME exports existing local
256*cf5a6c84SAndroid Build Coastguard Worker     variable(s), NAME=VALUE sets and exports.
257*cf5a6c84SAndroid Build Coastguard Worker 
258*cf5a6c84SAndroid Build Coastguard Worker     -n	Unexport. Turn listed variable(s) into local variables.
259*cf5a6c84SAndroid Build Coastguard Worker 
260*cf5a6c84SAndroid Build Coastguard Worker     With no arguments list exported variables/attributes as "declare" statements.
261*cf5a6c84SAndroid Build Coastguard Worker 
262*cf5a6c84SAndroid Build Coastguard Worker config JOBS
263*cf5a6c84SAndroid Build Coastguard Worker   bool
264*cf5a6c84SAndroid Build Coastguard Worker   default n
265*cf5a6c84SAndroid Build Coastguard Worker   depends on SH
266*cf5a6c84SAndroid Build Coastguard Worker   help
267*cf5a6c84SAndroid Build Coastguard Worker     usage: jobs [-lnprs] [%JOB | -x COMMAND...]
268*cf5a6c84SAndroid Build Coastguard Worker 
269*cf5a6c84SAndroid Build Coastguard Worker     List running/stopped background jobs.
270*cf5a6c84SAndroid Build Coastguard Worker 
271*cf5a6c84SAndroid Build Coastguard Worker     -l Include process ID in list
272*cf5a6c84SAndroid Build Coastguard Worker     -n Show only new/changed processes
273*cf5a6c84SAndroid Build Coastguard Worker     -p Show process IDs only
274*cf5a6c84SAndroid Build Coastguard Worker     -r Show running processes
275*cf5a6c84SAndroid Build Coastguard Worker     -s Show stopped processes
276*cf5a6c84SAndroid Build Coastguard Worker 
277*cf5a6c84SAndroid Build Coastguard Worker config LOCAL
278*cf5a6c84SAndroid Build Coastguard Worker   bool
279*cf5a6c84SAndroid Build Coastguard Worker   default n
280*cf5a6c84SAndroid Build Coastguard Worker   depends on SH
281*cf5a6c84SAndroid Build Coastguard Worker   help
282*cf5a6c84SAndroid Build Coastguard Worker     usage: local [NAME[=VALUE]...]
283*cf5a6c84SAndroid Build Coastguard Worker 
284*cf5a6c84SAndroid Build Coastguard Worker     Create a local variable that lasts until return from this function.
285*cf5a6c84SAndroid Build Coastguard Worker     With no arguments lists local variables in current function context.
286*cf5a6c84SAndroid Build Coastguard Worker     TODO: implement "declare" options.
287*cf5a6c84SAndroid Build Coastguard Worker 
288*cf5a6c84SAndroid Build Coastguard Worker config RETURN
289*cf5a6c84SAndroid Build Coastguard Worker   bool
290*cf5a6c84SAndroid Build Coastguard Worker   default n
291*cf5a6c84SAndroid Build Coastguard Worker   depends on SH
292*cf5a6c84SAndroid Build Coastguard Worker   help
293*cf5a6c84SAndroid Build Coastguard Worker     usage: return [#]
294*cf5a6c84SAndroid Build Coastguard Worker 
295*cf5a6c84SAndroid Build Coastguard Worker     Return from function/source with specified value or last command's exit val.
296*cf5a6c84SAndroid Build Coastguard Worker 
297*cf5a6c84SAndroid Build Coastguard Worker config SHIFT
298*cf5a6c84SAndroid Build Coastguard Worker   bool
299*cf5a6c84SAndroid Build Coastguard Worker   default n
300*cf5a6c84SAndroid Build Coastguard Worker   depends on SH
301*cf5a6c84SAndroid Build Coastguard Worker   help
302*cf5a6c84SAndroid Build Coastguard Worker     usage: shift [N]
303*cf5a6c84SAndroid Build Coastguard Worker 
304*cf5a6c84SAndroid Build Coastguard Worker     Skip N (default 1) positional parameters, moving $1 and friends along the list.
305*cf5a6c84SAndroid Build Coastguard Worker     Does not affect $0.
306*cf5a6c84SAndroid Build Coastguard Worker 
307*cf5a6c84SAndroid Build Coastguard Worker config SOURCE
308*cf5a6c84SAndroid Build Coastguard Worker   bool
309*cf5a6c84SAndroid Build Coastguard Worker   default n
310*cf5a6c84SAndroid Build Coastguard Worker   depends on SH
311*cf5a6c84SAndroid Build Coastguard Worker   help
312*cf5a6c84SAndroid Build Coastguard Worker     usage: source FILE [ARGS...]
313*cf5a6c84SAndroid Build Coastguard Worker 
314*cf5a6c84SAndroid Build Coastguard Worker     Read FILE and execute commands. Any ARGS become positional parameters.
315*cf5a6c84SAndroid Build Coastguard Worker 
316*cf5a6c84SAndroid Build Coastguard Worker config WAIT
317*cf5a6c84SAndroid Build Coastguard Worker   bool
318*cf5a6c84SAndroid Build Coastguard Worker   default n
319*cf5a6c84SAndroid Build Coastguard Worker   depends on SH
320*cf5a6c84SAndroid Build Coastguard Worker   help
321*cf5a6c84SAndroid Build Coastguard Worker     usage: wait [-n] [ID...]
322*cf5a6c84SAndroid Build Coastguard Worker 
323*cf5a6c84SAndroid Build Coastguard Worker     Wait for background processes to exit, returning its exit code.
324*cf5a6c84SAndroid Build Coastguard Worker     ID can be PID or job, with no IDs waits for all backgrounded processes.
325*cf5a6c84SAndroid Build Coastguard Worker 
326*cf5a6c84SAndroid Build Coastguard Worker     -n	Wait for next process to exit
327*cf5a6c84SAndroid Build Coastguard Worker */
328*cf5a6c84SAndroid Build Coastguard Worker 
329*cf5a6c84SAndroid Build Coastguard Worker #define FOR_sh
330*cf5a6c84SAndroid Build Coastguard Worker #include "toys.h"
331*cf5a6c84SAndroid Build Coastguard Worker 
332*cf5a6c84SAndroid Build Coastguard Worker GLOBALS(
333*cf5a6c84SAndroid Build Coastguard Worker   union {
334*cf5a6c84SAndroid Build Coastguard Worker     struct {
335*cf5a6c84SAndroid Build Coastguard Worker       char *c;
336*cf5a6c84SAndroid Build Coastguard Worker     } sh;
337*cf5a6c84SAndroid Build Coastguard Worker     struct {
338*cf5a6c84SAndroid Build Coastguard Worker       char *a;
339*cf5a6c84SAndroid Build Coastguard Worker     } exec;
340*cf5a6c84SAndroid Build Coastguard Worker   };
341*cf5a6c84SAndroid Build Coastguard Worker 
342*cf5a6c84SAndroid Build Coastguard Worker   // keep SECONDS here: used to work around compiler limitation in run_command()
343*cf5a6c84SAndroid Build Coastguard Worker   long long SECONDS;
344*cf5a6c84SAndroid Build Coastguard Worker   char *isexec, *wcpat;
345*cf5a6c84SAndroid Build Coastguard Worker   unsigned options, jobcnt, LINENO;
346*cf5a6c84SAndroid Build Coastguard Worker   int hfd, pid, bangpid, srclvl, recursion, recfile[50+200*CFG_TOYBOX_FORK];
347*cf5a6c84SAndroid Build Coastguard Worker 
348*cf5a6c84SAndroid Build Coastguard Worker   // Callable function array
349*cf5a6c84SAndroid Build Coastguard Worker   struct sh_function {
350*cf5a6c84SAndroid Build Coastguard Worker     char *name;
351*cf5a6c84SAndroid Build Coastguard Worker     struct sh_pipeline {  // pipeline segments: linked list of arg w/metadata
352*cf5a6c84SAndroid Build Coastguard Worker       struct sh_pipeline *next, *prev, *end;
353*cf5a6c84SAndroid Build Coastguard Worker       int count, here, type, lineno;
354*cf5a6c84SAndroid Build Coastguard Worker       struct sh_arg {
355*cf5a6c84SAndroid Build Coastguard Worker         char **v;
356*cf5a6c84SAndroid Build Coastguard Worker         int c;
357*cf5a6c84SAndroid Build Coastguard Worker       } arg[1];
358*cf5a6c84SAndroid Build Coastguard Worker     } *pipeline;
359*cf5a6c84SAndroid Build Coastguard Worker     unsigned long refcount;
360*cf5a6c84SAndroid Build Coastguard Worker   } **functions;
361*cf5a6c84SAndroid Build Coastguard Worker   long funcslen;
362*cf5a6c84SAndroid Build Coastguard Worker 
363*cf5a6c84SAndroid Build Coastguard Worker   // runtime function call stack
364*cf5a6c84SAndroid Build Coastguard Worker   struct sh_fcall {
365*cf5a6c84SAndroid Build Coastguard Worker     struct sh_fcall *next, *prev;
366*cf5a6c84SAndroid Build Coastguard Worker 
367*cf5a6c84SAndroid Build Coastguard Worker     // This dlist in reverse order: TT.ff current function, TT.ff->prev globals
368*cf5a6c84SAndroid Build Coastguard Worker     struct sh_vars {
369*cf5a6c84SAndroid Build Coastguard Worker       long flags;
370*cf5a6c84SAndroid Build Coastguard Worker       char *str;
371*cf5a6c84SAndroid Build Coastguard Worker     } *vars;
372*cf5a6c84SAndroid Build Coastguard Worker     long varslen, varscap, shift, oldlineno;
373*cf5a6c84SAndroid Build Coastguard Worker 
374*cf5a6c84SAndroid Build Coastguard Worker     struct sh_function *func; // TODO wire this up
375*cf5a6c84SAndroid Build Coastguard Worker     struct sh_pipeline *pl;
376*cf5a6c84SAndroid Build Coastguard Worker     char *ifs, *omnom;
377*cf5a6c84SAndroid Build Coastguard Worker     struct sh_arg arg;
378*cf5a6c84SAndroid Build Coastguard Worker     struct arg_list *delete;
379*cf5a6c84SAndroid Build Coastguard Worker 
380*cf5a6c84SAndroid Build Coastguard Worker     // Runtime stack of nested if/else/fi and for/do/done contexts.
381*cf5a6c84SAndroid Build Coastguard Worker     struct sh_blockstack {
382*cf5a6c84SAndroid Build Coastguard Worker       struct sh_blockstack *next;
383*cf5a6c84SAndroid Build Coastguard Worker       struct sh_pipeline *start, *middle;
384*cf5a6c84SAndroid Build Coastguard Worker       struct sh_process *pp;       // list of processes piping in to us
385*cf5a6c84SAndroid Build Coastguard Worker       int run, loop, *urd, pout, pipe;
386*cf5a6c84SAndroid Build Coastguard Worker       struct sh_arg farg;          // for/select arg stack, case wildcard deck
387*cf5a6c84SAndroid Build Coastguard Worker       struct arg_list *fdelete;    // farg's cleanup list
388*cf5a6c84SAndroid Build Coastguard Worker       char *fvar;                  // for/select's iteration variable name
389*cf5a6c84SAndroid Build Coastguard Worker     } *blk;
390*cf5a6c84SAndroid Build Coastguard Worker   } *ff;
391*cf5a6c84SAndroid Build Coastguard Worker 
392*cf5a6c84SAndroid Build Coastguard Worker // TODO ctrl-Z suspend should stop script
393*cf5a6c84SAndroid Build Coastguard Worker   struct sh_process {
394*cf5a6c84SAndroid Build Coastguard Worker     struct sh_process *next, *prev; // | && ||
395*cf5a6c84SAndroid Build Coastguard Worker     struct arg_list *delete;   // expanded strings
396*cf5a6c84SAndroid Build Coastguard Worker     // undo redirects, a=b at start, child PID, exit status, has !, job #
397*cf5a6c84SAndroid Build Coastguard Worker     int *urd, envlen, pid, exit, flags, job, dash;
398*cf5a6c84SAndroid Build Coastguard Worker     long long when; // when job backgrounded/suspended
399*cf5a6c84SAndroid Build Coastguard Worker     struct sh_arg *raw, arg;
400*cf5a6c84SAndroid Build Coastguard Worker   } *pp; // currently running process
401*cf5a6c84SAndroid Build Coastguard Worker 
402*cf5a6c84SAndroid Build Coastguard Worker   // job list, command line for $*, scratch space for do_wildcard_files()
403*cf5a6c84SAndroid Build Coastguard Worker   struct sh_arg jobs, *wcdeck;
404*cf5a6c84SAndroid Build Coastguard Worker   FILE *script;
405*cf5a6c84SAndroid Build Coastguard Worker )
406*cf5a6c84SAndroid Build Coastguard Worker 
407*cf5a6c84SAndroid Build Coastguard Worker // Prototype because $($($(blah))) nests, leading to run->parse->run loop
408*cf5a6c84SAndroid Build Coastguard Worker int do_source(char *name, FILE *ff);
409*cf5a6c84SAndroid Build Coastguard Worker // functions contain pipelines contain functions: prototype because loop
410*cf5a6c84SAndroid Build Coastguard Worker static void free_pipeline(void *pipeline);
411*cf5a6c84SAndroid Build Coastguard Worker // recalculate needs to get/set variables, but setvar_found calls recalculate
412*cf5a6c84SAndroid Build Coastguard Worker static struct sh_vars *setvar(char *str);
413*cf5a6c84SAndroid Build Coastguard Worker 
414*cf5a6c84SAndroid Build Coastguard Worker // ordered for greedy matching, so >&; becomes >& ; not > &;
415*cf5a6c84SAndroid Build Coastguard Worker // making these const means I need to typecast the const away later to
416*cf5a6c84SAndroid Build Coastguard Worker // avoid endless warnings.
417*cf5a6c84SAndroid Build Coastguard Worker static const char *redirectors[] = {"<<<", "<<-", "<<", "<&", "<>", "<", ">>",
418*cf5a6c84SAndroid Build Coastguard Worker   ">&", ">|", ">", "&>>", "&>", 0};
419*cf5a6c84SAndroid Build Coastguard Worker 
420*cf5a6c84SAndroid Build Coastguard Worker // The order of these has to match the string in set_main()
421*cf5a6c84SAndroid Build Coastguard Worker #define OPT_B	0x100
422*cf5a6c84SAndroid Build Coastguard Worker #define OPT_C	0x200
423*cf5a6c84SAndroid Build Coastguard Worker #define OPT_x	0x400
424*cf5a6c84SAndroid Build Coastguard Worker #define OPT_u	0x800
425*cf5a6c84SAndroid Build Coastguard Worker 
426*cf5a6c84SAndroid Build Coastguard Worker // only export $PWD and $OLDPWD on first cd
427*cf5a6c84SAndroid Build Coastguard Worker #define OPT_cd  0x80000000
428*cf5a6c84SAndroid Build Coastguard Worker 
429*cf5a6c84SAndroid Build Coastguard Worker // struct sh_process->flags
430*cf5a6c84SAndroid Build Coastguard Worker #define PFLAG_NOT    1
431*cf5a6c84SAndroid Build Coastguard Worker 
syntax_err(char * s)432*cf5a6c84SAndroid Build Coastguard Worker static void syntax_err(char *s)
433*cf5a6c84SAndroid Build Coastguard Worker {
434*cf5a6c84SAndroid Build Coastguard Worker   struct sh_fcall *ff = TT.ff;
435*cf5a6c84SAndroid Build Coastguard Worker // TODO: script@line only for script not interactive.
436*cf5a6c84SAndroid Build Coastguard Worker   for (ff = TT.ff; ff != TT.ff->prev; ff = ff->next) if (ff->omnom) break;
437*cf5a6c84SAndroid Build Coastguard Worker   error_msg("syntax error '%s'@%u: %s", ff->omnom ? : "-c", TT.LINENO, s);
438*cf5a6c84SAndroid Build Coastguard Worker   toys.exitval = 2;
439*cf5a6c84SAndroid Build Coastguard Worker   if (!(TT.options&FLAG_i)) xexit();
440*cf5a6c84SAndroid Build Coastguard Worker }
441*cf5a6c84SAndroid Build Coastguard Worker 
debug_show_fds()442*cf5a6c84SAndroid Build Coastguard Worker void debug_show_fds()
443*cf5a6c84SAndroid Build Coastguard Worker {
444*cf5a6c84SAndroid Build Coastguard Worker   int x = 0, fd = open("/proc/self/fd", O_RDONLY);
445*cf5a6c84SAndroid Build Coastguard Worker   DIR *X = fdopendir(fd);
446*cf5a6c84SAndroid Build Coastguard Worker   struct dirent *DE;
447*cf5a6c84SAndroid Build Coastguard Worker   char *s, *ss = 0, buf[4096], *sss = buf;
448*cf5a6c84SAndroid Build Coastguard Worker 
449*cf5a6c84SAndroid Build Coastguard Worker   if (!X) return;
450*cf5a6c84SAndroid Build Coastguard Worker   for (; (DE = readdir(X));) {
451*cf5a6c84SAndroid Build Coastguard Worker     if (atoi(DE->d_name) == fd) continue;
452*cf5a6c84SAndroid Build Coastguard Worker     s = xreadlink(ss = xmprintf("/proc/self/fd/%s", DE->d_name));
453*cf5a6c84SAndroid Build Coastguard Worker     if (s && *s != '.') sss += sprintf(sss, ", %s=%s"+2*!x++, DE->d_name, s);
454*cf5a6c84SAndroid Build Coastguard Worker     free(s); free(ss);
455*cf5a6c84SAndroid Build Coastguard Worker   }
456*cf5a6c84SAndroid Build Coastguard Worker   *sss = 0;
457*cf5a6c84SAndroid Build Coastguard Worker   dprintf(2, "%d fd:%s\n", getpid(), buf);
458*cf5a6c84SAndroid Build Coastguard Worker   closedir(X);
459*cf5a6c84SAndroid Build Coastguard Worker }
460*cf5a6c84SAndroid Build Coastguard Worker 
nospace(char ** ss)461*cf5a6c84SAndroid Build Coastguard Worker static char **nospace(char **ss)
462*cf5a6c84SAndroid Build Coastguard Worker {
463*cf5a6c84SAndroid Build Coastguard Worker   while (isspace(**ss)) ++*ss;
464*cf5a6c84SAndroid Build Coastguard Worker 
465*cf5a6c84SAndroid Build Coastguard Worker   return ss;
466*cf5a6c84SAndroid Build Coastguard Worker }
467*cf5a6c84SAndroid Build Coastguard Worker 
468*cf5a6c84SAndroid Build Coastguard Worker // append to array with null terminator and realloc as necessary
arg_add(struct sh_arg * arg,char * data)469*cf5a6c84SAndroid Build Coastguard Worker static void arg_add(struct sh_arg *arg, char *data)
470*cf5a6c84SAndroid Build Coastguard Worker {
471*cf5a6c84SAndroid Build Coastguard Worker   // expand with stride 32. Micro-optimization: don't realloc empty stack
472*cf5a6c84SAndroid Build Coastguard Worker   if (!(arg->c&31) && (arg->c || !arg->v))
473*cf5a6c84SAndroid Build Coastguard Worker     arg->v = xrealloc(arg->v, sizeof(char *)*(arg->c+33));
474*cf5a6c84SAndroid Build Coastguard Worker   arg->v[arg->c++] = data;
475*cf5a6c84SAndroid Build Coastguard Worker   arg->v[arg->c] = 0;
476*cf5a6c84SAndroid Build Coastguard Worker }
477*cf5a6c84SAndroid Build Coastguard Worker 
478*cf5a6c84SAndroid Build Coastguard Worker // add argument to an arg_list
push_arg(struct arg_list ** list,void * arg)479*cf5a6c84SAndroid Build Coastguard Worker static void *push_arg(struct arg_list **list, void *arg)
480*cf5a6c84SAndroid Build Coastguard Worker {
481*cf5a6c84SAndroid Build Coastguard Worker   struct arg_list *al;
482*cf5a6c84SAndroid Build Coastguard Worker 
483*cf5a6c84SAndroid Build Coastguard Worker   if (list) {
484*cf5a6c84SAndroid Build Coastguard Worker     al = xmalloc(sizeof(struct arg_list));
485*cf5a6c84SAndroid Build Coastguard Worker     al->next = *list;
486*cf5a6c84SAndroid Build Coastguard Worker     al->arg = arg;
487*cf5a6c84SAndroid Build Coastguard Worker     *list = al;
488*cf5a6c84SAndroid Build Coastguard Worker   }
489*cf5a6c84SAndroid Build Coastguard Worker 
490*cf5a6c84SAndroid Build Coastguard Worker   return arg;
491*cf5a6c84SAndroid Build Coastguard Worker }
492*cf5a6c84SAndroid Build Coastguard Worker 
arg_add_del(struct sh_arg * arg,char * data,struct arg_list ** delete)493*cf5a6c84SAndroid Build Coastguard Worker static void arg_add_del(struct sh_arg *arg, char *data,struct arg_list **delete)
494*cf5a6c84SAndroid Build Coastguard Worker {
495*cf5a6c84SAndroid Build Coastguard Worker   arg_add(arg, push_arg(delete, data));
496*cf5a6c84SAndroid Build Coastguard Worker }
497*cf5a6c84SAndroid Build Coastguard Worker 
498*cf5a6c84SAndroid Build Coastguard Worker // Assign one variable from malloced key=val string, returns var struct
499*cf5a6c84SAndroid Build Coastguard Worker // TODO implement remaining types
500*cf5a6c84SAndroid Build Coastguard Worker #define VAR_NOFREE    (1<<10)
501*cf5a6c84SAndroid Build Coastguard Worker #define VAR_WHITEOUT  (1<<9)
502*cf5a6c84SAndroid Build Coastguard Worker #define VAR_DICT      (1<<8)
503*cf5a6c84SAndroid Build Coastguard Worker #define VAR_ARRAY     (1<<7)
504*cf5a6c84SAndroid Build Coastguard Worker #define VAR_INT       (1<<6)
505*cf5a6c84SAndroid Build Coastguard Worker #define VAR_TOLOWER   (1<<5)
506*cf5a6c84SAndroid Build Coastguard Worker #define VAR_TOUPPER   (1<<4)
507*cf5a6c84SAndroid Build Coastguard Worker #define VAR_NAMEREF   (1<<3)
508*cf5a6c84SAndroid Build Coastguard Worker #define VAR_EXPORT    (1<<2)
509*cf5a6c84SAndroid Build Coastguard Worker #define VAR_READONLY  (1<<1)
510*cf5a6c84SAndroid Build Coastguard Worker #define VAR_MAGIC     (1<<0)
511*cf5a6c84SAndroid Build Coastguard Worker 
512*cf5a6c84SAndroid Build Coastguard Worker // return length of valid variable name
varend(char * s)513*cf5a6c84SAndroid Build Coastguard Worker static char *varend(char *s)
514*cf5a6c84SAndroid Build Coastguard Worker {
515*cf5a6c84SAndroid Build Coastguard Worker   if (isdigit(*s)) return s;
516*cf5a6c84SAndroid Build Coastguard Worker   while (*s>' ' && (*s=='_' || !ispunct(*s))) s++;
517*cf5a6c84SAndroid Build Coastguard Worker 
518*cf5a6c84SAndroid Build Coastguard Worker   return s;
519*cf5a6c84SAndroid Build Coastguard Worker }
520*cf5a6c84SAndroid Build Coastguard Worker 
521*cf5a6c84SAndroid Build Coastguard Worker // TODO: this has to handle VAR_NAMEREF, but return dangling symlink
522*cf5a6c84SAndroid Build Coastguard Worker // Also, unset -n, also "local ISLINK" to parent var.
523*cf5a6c84SAndroid Build Coastguard Worker // Return sh_vars * or 0 if not found.
524*cf5a6c84SAndroid Build Coastguard Worker // Sets *pff to function (only if found), only returns whiteouts if pff not NULL
findvar(char * name,struct sh_fcall ** pff)525*cf5a6c84SAndroid Build Coastguard Worker static struct sh_vars *findvar(char *name, struct sh_fcall **pff)
526*cf5a6c84SAndroid Build Coastguard Worker {
527*cf5a6c84SAndroid Build Coastguard Worker   int len = varend(name)-name;
528*cf5a6c84SAndroid Build Coastguard Worker   struct sh_fcall *ff = TT.ff;
529*cf5a6c84SAndroid Build Coastguard Worker 
530*cf5a6c84SAndroid Build Coastguard Worker   // advance through locals to global context, ignoring whiteouts
531*cf5a6c84SAndroid Build Coastguard Worker   if (len) do {
532*cf5a6c84SAndroid Build Coastguard Worker     struct sh_vars *var = ff->vars+ff->varslen;
533*cf5a6c84SAndroid Build Coastguard Worker 
534*cf5a6c84SAndroid Build Coastguard Worker     if (var) while (var--!=ff->vars) {
535*cf5a6c84SAndroid Build Coastguard Worker       if (strncmp(var->str, name, len) || var->str[len]!='=') continue;
536*cf5a6c84SAndroid Build Coastguard Worker       if (pff) *pff = ff;
537*cf5a6c84SAndroid Build Coastguard Worker       else if (var->flags&VAR_WHITEOUT) return 0;
538*cf5a6c84SAndroid Build Coastguard Worker 
539*cf5a6c84SAndroid Build Coastguard Worker       return var;
540*cf5a6c84SAndroid Build Coastguard Worker     }
541*cf5a6c84SAndroid Build Coastguard Worker   } while ((ff = ff->next)!=TT.ff);
542*cf5a6c84SAndroid Build Coastguard Worker 
543*cf5a6c84SAndroid Build Coastguard Worker   return 0;
544*cf5a6c84SAndroid Build Coastguard Worker }
545*cf5a6c84SAndroid Build Coastguard Worker 
546*cf5a6c84SAndroid Build Coastguard Worker // get value of variable starting at s.
getvar(char * s)547*cf5a6c84SAndroid Build Coastguard Worker static char *getvar(char *s)
548*cf5a6c84SAndroid Build Coastguard Worker {
549*cf5a6c84SAndroid Build Coastguard Worker   struct sh_vars *var = findvar(s, 0);
550*cf5a6c84SAndroid Build Coastguard Worker 
551*cf5a6c84SAndroid Build Coastguard Worker   if (!var) return 0;
552*cf5a6c84SAndroid Build Coastguard Worker 
553*cf5a6c84SAndroid Build Coastguard Worker   if (var->flags & VAR_MAGIC) {
554*cf5a6c84SAndroid Build Coastguard Worker     char c = *var->str;
555*cf5a6c84SAndroid Build Coastguard Worker 
556*cf5a6c84SAndroid Build Coastguard Worker     if (c == 'S') sprintf(toybuf, "%lld", (millitime()-TT.SECONDS)/1000);
557*cf5a6c84SAndroid Build Coastguard Worker     else if (c == 'R') sprintf(toybuf, "%ld", random()&((1<<16)-1));
558*cf5a6c84SAndroid Build Coastguard Worker     else if (c == 'L') sprintf(toybuf, "%u", TT.ff->pl->lineno);
559*cf5a6c84SAndroid Build Coastguard Worker     else if (c == 'G') sprintf(toybuf, "TODO: GROUPS");
560*cf5a6c84SAndroid Build Coastguard Worker     else if (c == 'B') sprintf(toybuf, "%d", getpid());
561*cf5a6c84SAndroid Build Coastguard Worker     else if (c == 'E') {
562*cf5a6c84SAndroid Build Coastguard Worker       struct timespec ts;
563*cf5a6c84SAndroid Build Coastguard Worker 
564*cf5a6c84SAndroid Build Coastguard Worker       clock_gettime(CLOCK_REALTIME, &ts);
565*cf5a6c84SAndroid Build Coastguard Worker       sprintf(toybuf, "%lld%c%06ld", (long long)ts.tv_sec, (s[5]=='R')*'.',
566*cf5a6c84SAndroid Build Coastguard Worker               ts.tv_nsec/1000);
567*cf5a6c84SAndroid Build Coastguard Worker     }
568*cf5a6c84SAndroid Build Coastguard Worker 
569*cf5a6c84SAndroid Build Coastguard Worker     return toybuf;
570*cf5a6c84SAndroid Build Coastguard Worker   }
571*cf5a6c84SAndroid Build Coastguard Worker 
572*cf5a6c84SAndroid Build Coastguard Worker   return varend(var->str)+1;
573*cf5a6c84SAndroid Build Coastguard Worker }
574*cf5a6c84SAndroid Build Coastguard Worker 
575*cf5a6c84SAndroid Build Coastguard Worker // Append variable to ff->vars, returning *struct. Does not check duplicates.
addvar(char * s,struct sh_fcall * ff)576*cf5a6c84SAndroid Build Coastguard Worker static struct sh_vars *addvar(char *s, struct sh_fcall *ff)
577*cf5a6c84SAndroid Build Coastguard Worker {
578*cf5a6c84SAndroid Build Coastguard Worker   if (ff->varslen == ff->varscap) {
579*cf5a6c84SAndroid Build Coastguard Worker     ff->varscap += 32;
580*cf5a6c84SAndroid Build Coastguard Worker     ff->vars = xrealloc(ff->vars, (ff->varscap)*sizeof(*ff->vars));
581*cf5a6c84SAndroid Build Coastguard Worker   }
582*cf5a6c84SAndroid Build Coastguard Worker   if (!s) return ff->vars;
583*cf5a6c84SAndroid Build Coastguard Worker   ff->vars[ff->varslen].flags = 0;
584*cf5a6c84SAndroid Build Coastguard Worker   ff->vars[ff->varslen].str = s;
585*cf5a6c84SAndroid Build Coastguard Worker 
586*cf5a6c84SAndroid Build Coastguard Worker   return ff->vars+ff->varslen++;
587*cf5a6c84SAndroid Build Coastguard Worker }
588*cf5a6c84SAndroid Build Coastguard Worker 
589*cf5a6c84SAndroid Build Coastguard Worker // Recursively calculate string into dd, returns 0 if failed, ss = error point
590*cf5a6c84SAndroid Build Coastguard Worker // Recursion resolves operators of lower priority level to a value
591*cf5a6c84SAndroid Build Coastguard Worker // Loops through operators at same priority
592*cf5a6c84SAndroid Build Coastguard Worker #define NO_ASSIGN 128
recalculate(long long * dd,char ** ss,int lvl)593*cf5a6c84SAndroid Build Coastguard Worker static int recalculate(long long *dd, char **ss, int lvl)
594*cf5a6c84SAndroid Build Coastguard Worker {
595*cf5a6c84SAndroid Build Coastguard Worker   long long ee, ff;
596*cf5a6c84SAndroid Build Coastguard Worker   char *var = 0, *val, cc = **nospace(ss);
597*cf5a6c84SAndroid Build Coastguard Worker   int ii, noa = lvl&NO_ASSIGN;
598*cf5a6c84SAndroid Build Coastguard Worker   lvl &= NO_ASSIGN-1;
599*cf5a6c84SAndroid Build Coastguard Worker 
600*cf5a6c84SAndroid Build Coastguard Worker   // Unary prefixes can only occur at the start of a parse context
601*cf5a6c84SAndroid Build Coastguard Worker   if (cc=='!' || cc=='~') {
602*cf5a6c84SAndroid Build Coastguard Worker     ++*ss;
603*cf5a6c84SAndroid Build Coastguard Worker     if (!recalculate(dd, ss, noa|15)) return 0;
604*cf5a6c84SAndroid Build Coastguard Worker     *dd = (cc=='!') ? !*dd : ~*dd;
605*cf5a6c84SAndroid Build Coastguard Worker   } else if (cc=='+' || cc=='-') {
606*cf5a6c84SAndroid Build Coastguard Worker     // Is this actually preincrement/decrement? (Requires assignable var.)
607*cf5a6c84SAndroid Build Coastguard Worker     if (*++*ss==cc) {
608*cf5a6c84SAndroid Build Coastguard Worker       val = (*ss)++;
609*cf5a6c84SAndroid Build Coastguard Worker       nospace(ss);
610*cf5a6c84SAndroid Build Coastguard Worker       if (*ss==(var = varend(*ss))) {
611*cf5a6c84SAndroid Build Coastguard Worker         *ss = val;
612*cf5a6c84SAndroid Build Coastguard Worker         var = 0;
613*cf5a6c84SAndroid Build Coastguard Worker       }
614*cf5a6c84SAndroid Build Coastguard Worker     }
615*cf5a6c84SAndroid Build Coastguard Worker     if (!var) {
616*cf5a6c84SAndroid Build Coastguard Worker       if (!recalculate(dd, ss, noa|15)) return 0;
617*cf5a6c84SAndroid Build Coastguard Worker       if (cc=='-') *dd = -*dd;
618*cf5a6c84SAndroid Build Coastguard Worker     }
619*cf5a6c84SAndroid Build Coastguard Worker   } else if (cc=='(') {
620*cf5a6c84SAndroid Build Coastguard Worker     ++*ss;
621*cf5a6c84SAndroid Build Coastguard Worker     if (!recalculate(dd, ss, noa|1)) return 0;
622*cf5a6c84SAndroid Build Coastguard Worker     if (**ss!=')') return 0;
623*cf5a6c84SAndroid Build Coastguard Worker     else ++*ss;
624*cf5a6c84SAndroid Build Coastguard Worker   } else if (isdigit(cc)) {
625*cf5a6c84SAndroid Build Coastguard Worker     *dd = strtoll(*ss, ss, 0);
626*cf5a6c84SAndroid Build Coastguard Worker     if (**ss=='#') {
627*cf5a6c84SAndroid Build Coastguard Worker       if (!*++*ss || isspace(**ss) || ispunct(**ss)) return 0;
628*cf5a6c84SAndroid Build Coastguard Worker       *dd = strtoll(val = *ss, ss, *dd);
629*cf5a6c84SAndroid Build Coastguard Worker       if (val == *ss) return 0;
630*cf5a6c84SAndroid Build Coastguard Worker     }
631*cf5a6c84SAndroid Build Coastguard Worker   } else if ((var = varend(*ss))==*ss) {
632*cf5a6c84SAndroid Build Coastguard Worker     // At lvl 0 "" is ok, anything higher needs a non-empty equation
633*cf5a6c84SAndroid Build Coastguard Worker     if (lvl || (cc && cc!=')')) return 0;
634*cf5a6c84SAndroid Build Coastguard Worker     *dd = 0;
635*cf5a6c84SAndroid Build Coastguard Worker 
636*cf5a6c84SAndroid Build Coastguard Worker     return 1;
637*cf5a6c84SAndroid Build Coastguard Worker   }
638*cf5a6c84SAndroid Build Coastguard Worker 
639*cf5a6c84SAndroid Build Coastguard Worker   // If we got a variable, evaluate its contents to set *dd
640*cf5a6c84SAndroid Build Coastguard Worker   if (var) {
641*cf5a6c84SAndroid Build Coastguard Worker     // Recursively evaluate, catching x=y; y=x; echo $((x))
642*cf5a6c84SAndroid Build Coastguard Worker     TT.recfile[TT.recursion++] = 0;
643*cf5a6c84SAndroid Build Coastguard Worker     if (TT.recursion == ARRAY_LEN(TT.recfile)) {
644*cf5a6c84SAndroid Build Coastguard Worker       perror_msg("recursive occlusion");
645*cf5a6c84SAndroid Build Coastguard Worker       --TT.recursion;
646*cf5a6c84SAndroid Build Coastguard Worker 
647*cf5a6c84SAndroid Build Coastguard Worker       return 0;
648*cf5a6c84SAndroid Build Coastguard Worker     }
649*cf5a6c84SAndroid Build Coastguard Worker     val = getvar(var = *ss) ? : "";
650*cf5a6c84SAndroid Build Coastguard Worker     ii = recalculate(dd, &val, noa);
651*cf5a6c84SAndroid Build Coastguard Worker     TT.recursion--;
652*cf5a6c84SAndroid Build Coastguard Worker     if (!ii) return 0;
653*cf5a6c84SAndroid Build Coastguard Worker     if (*val) {
654*cf5a6c84SAndroid Build Coastguard Worker       perror_msg("bad math: %s @ %d", var, (int)(val-var));
655*cf5a6c84SAndroid Build Coastguard Worker 
656*cf5a6c84SAndroid Build Coastguard Worker       return 0;
657*cf5a6c84SAndroid Build Coastguard Worker     }
658*cf5a6c84SAndroid Build Coastguard Worker     val = *ss = varend(var);
659*cf5a6c84SAndroid Build Coastguard Worker 
660*cf5a6c84SAndroid Build Coastguard Worker     // Operators that assign to a varible must be adjacent to one:
661*cf5a6c84SAndroid Build Coastguard Worker 
662*cf5a6c84SAndroid Build Coastguard Worker     // Handle preincrement/predecrement (only gets here if var set before else)
663*cf5a6c84SAndroid Build Coastguard Worker     if (cc=='+' || cc=='-') {
664*cf5a6c84SAndroid Build Coastguard Worker       if (cc=='+') ee = ++*dd;
665*cf5a6c84SAndroid Build Coastguard Worker       else ee = --*dd;
666*cf5a6c84SAndroid Build Coastguard Worker     } else cc = 0;
667*cf5a6c84SAndroid Build Coastguard Worker 
668*cf5a6c84SAndroid Build Coastguard Worker     // handle postinc/postdec
669*cf5a6c84SAndroid Build Coastguard Worker     if ((**nospace(ss)=='+' || **ss=='-') && (*ss)[1]==**ss) {
670*cf5a6c84SAndroid Build Coastguard Worker       ee = ((cc = **ss)=='+') ? 1+*dd : -1+*dd;
671*cf5a6c84SAndroid Build Coastguard Worker       *ss += 2;
672*cf5a6c84SAndroid Build Coastguard Worker 
673*cf5a6c84SAndroid Build Coastguard Worker     // Assignment operators: = *= /= %= += -= <<= >>= &= ^= |=
674*cf5a6c84SAndroid Build Coastguard Worker     } else if (lvl<=2 && (*ss)[ii = (-1 != stridx("*/%+-", **ss))
675*cf5a6c84SAndroid Build Coastguard Worker                +2*!smemcmp(*ss, "<<", 2)+2*!smemcmp(*ss, ">>", 2)]=='=')
676*cf5a6c84SAndroid Build Coastguard Worker     {
677*cf5a6c84SAndroid Build Coastguard Worker       // TODO: assignments are lower priority BUT must go after variable,
678*cf5a6c84SAndroid Build Coastguard Worker       // come up with precedence checking tests?
679*cf5a6c84SAndroid Build Coastguard Worker       cc = **ss;
680*cf5a6c84SAndroid Build Coastguard Worker       *ss += ii+1;
681*cf5a6c84SAndroid Build Coastguard Worker       if (!recalculate(&ee, ss, noa|1)) return 0; // TODO lvl instead of 1?
682*cf5a6c84SAndroid Build Coastguard Worker       if (cc=='*') *dd *= ee;
683*cf5a6c84SAndroid Build Coastguard Worker       else if (cc=='+') *dd += ee;
684*cf5a6c84SAndroid Build Coastguard Worker       else if (cc=='-') *dd -= ee;
685*cf5a6c84SAndroid Build Coastguard Worker       else if (cc=='<') *dd <<= ee;
686*cf5a6c84SAndroid Build Coastguard Worker       else if (cc=='>') *dd >>= ee;
687*cf5a6c84SAndroid Build Coastguard Worker       else if (cc=='&') *dd &= ee;
688*cf5a6c84SAndroid Build Coastguard Worker       else if (cc=='^') *dd ^= ee;
689*cf5a6c84SAndroid Build Coastguard Worker       else if (cc=='|') *dd |= ee;
690*cf5a6c84SAndroid Build Coastguard Worker       else if (!cc) *dd = ee;
691*cf5a6c84SAndroid Build Coastguard Worker       else if (!ee) {
692*cf5a6c84SAndroid Build Coastguard Worker         perror_msg("%c0", cc);
693*cf5a6c84SAndroid Build Coastguard Worker 
694*cf5a6c84SAndroid Build Coastguard Worker         return 0;
695*cf5a6c84SAndroid Build Coastguard Worker       } else if (cc=='/') *dd /= ee;
696*cf5a6c84SAndroid Build Coastguard Worker       else if (cc=='%') *dd %= ee;
697*cf5a6c84SAndroid Build Coastguard Worker       ee = *dd;
698*cf5a6c84SAndroid Build Coastguard Worker     }
699*cf5a6c84SAndroid Build Coastguard Worker     if (cc && !noa) setvar(xmprintf("%.*s=%lld", (int)(val-var), var, ee));
700*cf5a6c84SAndroid Build Coastguard Worker   }
701*cf5a6c84SAndroid Build Coastguard Worker 
702*cf5a6c84SAndroid Build Coastguard Worker   // x**y binds first
703*cf5a6c84SAndroid Build Coastguard Worker   if (lvl<=14) while (strstart(nospace(ss), "**")) {
704*cf5a6c84SAndroid Build Coastguard Worker     if (!recalculate(&ee, ss, noa|15)) return 0;
705*cf5a6c84SAndroid Build Coastguard Worker     if (ee<0) perror_msg("** < 0");
706*cf5a6c84SAndroid Build Coastguard Worker     for (ff = *dd, *dd = 1; ee; ee--) *dd *= ff;
707*cf5a6c84SAndroid Build Coastguard Worker   }
708*cf5a6c84SAndroid Build Coastguard Worker 
709*cf5a6c84SAndroid Build Coastguard Worker   // w*x/y%z bind next
710*cf5a6c84SAndroid Build Coastguard Worker   if (lvl<=13) while ((cc = **nospace(ss)) && strchr("*/%", cc)) {
711*cf5a6c84SAndroid Build Coastguard Worker     ++*ss;
712*cf5a6c84SAndroid Build Coastguard Worker     if (!recalculate(&ee, ss, noa|14)) return 0;
713*cf5a6c84SAndroid Build Coastguard Worker     if (cc=='*') *dd *= ee;
714*cf5a6c84SAndroid Build Coastguard Worker     else if (!ee) {
715*cf5a6c84SAndroid Build Coastguard Worker       perror_msg("%c0", cc);
716*cf5a6c84SAndroid Build Coastguard Worker 
717*cf5a6c84SAndroid Build Coastguard Worker       return 0;
718*cf5a6c84SAndroid Build Coastguard Worker     } else if (cc=='%') *dd %= ee;
719*cf5a6c84SAndroid Build Coastguard Worker     else *dd /= ee;
720*cf5a6c84SAndroid Build Coastguard Worker   }
721*cf5a6c84SAndroid Build Coastguard Worker 
722*cf5a6c84SAndroid Build Coastguard Worker   // x+y-z
723*cf5a6c84SAndroid Build Coastguard Worker   if (lvl<=12) while ((cc = **nospace(ss)) && strchr("+-", cc)) {
724*cf5a6c84SAndroid Build Coastguard Worker     ++*ss;
725*cf5a6c84SAndroid Build Coastguard Worker     if (!recalculate(&ee, ss, noa|13)) return 0;
726*cf5a6c84SAndroid Build Coastguard Worker     if (cc=='+') *dd += ee;
727*cf5a6c84SAndroid Build Coastguard Worker     else *dd -= ee;
728*cf5a6c84SAndroid Build Coastguard Worker   }
729*cf5a6c84SAndroid Build Coastguard Worker 
730*cf5a6c84SAndroid Build Coastguard Worker   // x<<y >>
731*cf5a6c84SAndroid Build Coastguard Worker 
732*cf5a6c84SAndroid Build Coastguard Worker   if (lvl<=11) while ((cc = **nospace(ss)) && strchr("<>", cc) && cc==(*ss)[1]){
733*cf5a6c84SAndroid Build Coastguard Worker     *ss += 2;
734*cf5a6c84SAndroid Build Coastguard Worker     if (!recalculate(&ee, ss, noa|12)) return 0;
735*cf5a6c84SAndroid Build Coastguard Worker     if (cc == '<') *dd <<= ee;
736*cf5a6c84SAndroid Build Coastguard Worker     else *dd >>= ee;
737*cf5a6c84SAndroid Build Coastguard Worker   }
738*cf5a6c84SAndroid Build Coastguard Worker 
739*cf5a6c84SAndroid Build Coastguard Worker   // x<y <= > >=
740*cf5a6c84SAndroid Build Coastguard Worker   if (lvl<=10) while ((cc = **nospace(ss)) && strchr("<>", cc)) {
741*cf5a6c84SAndroid Build Coastguard Worker     if ((ii = *++*ss=='=')) ++*ss;
742*cf5a6c84SAndroid Build Coastguard Worker     if (!recalculate(&ee, ss, noa|11)) return 0;
743*cf5a6c84SAndroid Build Coastguard Worker     if (cc=='<') *dd = ii ? (*dd<=ee) : (*dd<ee);
744*cf5a6c84SAndroid Build Coastguard Worker     else *dd = ii ? (*dd>=ee) : (*dd>ee);
745*cf5a6c84SAndroid Build Coastguard Worker   }
746*cf5a6c84SAndroid Build Coastguard Worker 
747*cf5a6c84SAndroid Build Coastguard Worker   if (lvl<=9) while ((cc = **nospace(ss)) && strchr("=!", cc) && (*ss)[1]=='='){
748*cf5a6c84SAndroid Build Coastguard Worker     *ss += 2;
749*cf5a6c84SAndroid Build Coastguard Worker     if (!recalculate(&ee, ss, noa|10)) return 0;
750*cf5a6c84SAndroid Build Coastguard Worker     *dd = (cc=='!') ? *dd != ee : *dd == ee;
751*cf5a6c84SAndroid Build Coastguard Worker   }
752*cf5a6c84SAndroid Build Coastguard Worker 
753*cf5a6c84SAndroid Build Coastguard Worker   if (lvl<=8) while (**nospace(ss)=='&' && (*ss)[1]!='&') {
754*cf5a6c84SAndroid Build Coastguard Worker     ++*ss;
755*cf5a6c84SAndroid Build Coastguard Worker     if (!recalculate(&ee, ss, noa|9)) return 0;
756*cf5a6c84SAndroid Build Coastguard Worker     *dd &= ee;
757*cf5a6c84SAndroid Build Coastguard Worker   }
758*cf5a6c84SAndroid Build Coastguard Worker 
759*cf5a6c84SAndroid Build Coastguard Worker   if (lvl<=7) while (**nospace(ss)=='^') {
760*cf5a6c84SAndroid Build Coastguard Worker     ++*ss;
761*cf5a6c84SAndroid Build Coastguard Worker     if (!recalculate(&ee, ss, noa|8)) return 0;
762*cf5a6c84SAndroid Build Coastguard Worker     *dd ^= ee;
763*cf5a6c84SAndroid Build Coastguard Worker   }
764*cf5a6c84SAndroid Build Coastguard Worker 
765*cf5a6c84SAndroid Build Coastguard Worker   if (lvl<=6) while (**nospace(ss)=='|' && (*ss)[1]!='|') {
766*cf5a6c84SAndroid Build Coastguard Worker     ++*ss;
767*cf5a6c84SAndroid Build Coastguard Worker     if (!recalculate(&ee, ss, noa|7)) return 0;
768*cf5a6c84SAndroid Build Coastguard Worker     *dd |= ee;
769*cf5a6c84SAndroid Build Coastguard Worker   }
770*cf5a6c84SAndroid Build Coastguard Worker 
771*cf5a6c84SAndroid Build Coastguard Worker   if (lvl<=5) while (strstart(nospace(ss), "&&")) {
772*cf5a6c84SAndroid Build Coastguard Worker     if (!recalculate(&ee, ss, noa|6|NO_ASSIGN*!*dd)) return 0;
773*cf5a6c84SAndroid Build Coastguard Worker     *dd = *dd && ee;
774*cf5a6c84SAndroid Build Coastguard Worker   }
775*cf5a6c84SAndroid Build Coastguard Worker 
776*cf5a6c84SAndroid Build Coastguard Worker   if (lvl<=4) while (strstart(nospace(ss), "||")) {
777*cf5a6c84SAndroid Build Coastguard Worker     if (!recalculate(&ee, ss, noa|5|NO_ASSIGN*!!*dd)) return 0;
778*cf5a6c84SAndroid Build Coastguard Worker     *dd = *dd || ee;
779*cf5a6c84SAndroid Build Coastguard Worker   }
780*cf5a6c84SAndroid Build Coastguard Worker 
781*cf5a6c84SAndroid Build Coastguard Worker   // ? : slightly weird: recurses with lower priority instead of looping
782*cf5a6c84SAndroid Build Coastguard Worker   // because a ? b ? c : d ? e : f : g == a ? (b ? c : (d ? e : f) : g)
783*cf5a6c84SAndroid Build Coastguard Worker   if (lvl<=3) if (**nospace(ss)=='?') {
784*cf5a6c84SAndroid Build Coastguard Worker     ++*ss;
785*cf5a6c84SAndroid Build Coastguard Worker     if (**nospace(ss)==':' && *dd) ee = *dd;
786*cf5a6c84SAndroid Build Coastguard Worker     else if (!recalculate(&ee, ss, noa|1|NO_ASSIGN*!*dd) || **nospace(ss)!=':')
787*cf5a6c84SAndroid Build Coastguard Worker       return 0;
788*cf5a6c84SAndroid Build Coastguard Worker     ++*ss;
789*cf5a6c84SAndroid Build Coastguard Worker     if (!recalculate(&ff, ss, noa|1|NO_ASSIGN*!!*dd)) return 0;
790*cf5a6c84SAndroid Build Coastguard Worker     *dd = *dd ? ee : ff;
791*cf5a6c84SAndroid Build Coastguard Worker   }
792*cf5a6c84SAndroid Build Coastguard Worker 
793*cf5a6c84SAndroid Build Coastguard Worker   // lvl<=2 assignment would go here, but handled above because variable
794*cf5a6c84SAndroid Build Coastguard Worker 
795*cf5a6c84SAndroid Build Coastguard Worker   // , (slightly weird, replaces dd instead of modifying it via ee/ff)
796*cf5a6c84SAndroid Build Coastguard Worker   if (lvl<=1) while (**nospace(ss)==',') {
797*cf5a6c84SAndroid Build Coastguard Worker     ++*ss;
798*cf5a6c84SAndroid Build Coastguard Worker     if (!recalculate(dd, ss, noa|2)) return 0;
799*cf5a6c84SAndroid Build Coastguard Worker   }
800*cf5a6c84SAndroid Build Coastguard Worker 
801*cf5a6c84SAndroid Build Coastguard Worker   return 1;
802*cf5a6c84SAndroid Build Coastguard Worker }
803*cf5a6c84SAndroid Build Coastguard Worker 
804*cf5a6c84SAndroid Build Coastguard Worker // Return length of utf8 char @s fitting in len, writing value into *cc
getutf8(char * s,int len,int * cc)805*cf5a6c84SAndroid Build Coastguard Worker static int getutf8(char *s, int len, int *cc)
806*cf5a6c84SAndroid Build Coastguard Worker {
807*cf5a6c84SAndroid Build Coastguard Worker   unsigned wc;
808*cf5a6c84SAndroid Build Coastguard Worker 
809*cf5a6c84SAndroid Build Coastguard Worker   if (len<0) wc = len = 0;
810*cf5a6c84SAndroid Build Coastguard Worker   else if (1>(len = utf8towc(&wc, s, len))) wc = *s, len = 1;
811*cf5a6c84SAndroid Build Coastguard Worker   if (cc) *cc = wc;
812*cf5a6c84SAndroid Build Coastguard Worker 
813*cf5a6c84SAndroid Build Coastguard Worker   return len;
814*cf5a6c84SAndroid Build Coastguard Worker }
815*cf5a6c84SAndroid Build Coastguard Worker 
816*cf5a6c84SAndroid Build Coastguard Worker // utf8 strchr: return wide char matched at wc from chrs, or 0 if not matched
817*cf5a6c84SAndroid Build Coastguard Worker // if len, save length of next wc (whether or not it's in list)
utf8chr(char * wc,char * chrs,int * len)818*cf5a6c84SAndroid Build Coastguard Worker static int utf8chr(char *wc, char *chrs, int *len)
819*cf5a6c84SAndroid Build Coastguard Worker {
820*cf5a6c84SAndroid Build Coastguard Worker   unsigned wc1, wc2;
821*cf5a6c84SAndroid Build Coastguard Worker   int ll;
822*cf5a6c84SAndroid Build Coastguard Worker 
823*cf5a6c84SAndroid Build Coastguard Worker   if (len) *len = 1;
824*cf5a6c84SAndroid Build Coastguard Worker   if (!*wc) return 0;
825*cf5a6c84SAndroid Build Coastguard Worker   if (0<(ll = utf8towc(&wc1, wc, 99))) {
826*cf5a6c84SAndroid Build Coastguard Worker     if (len) *len = ll;
827*cf5a6c84SAndroid Build Coastguard Worker     while (*chrs) {
828*cf5a6c84SAndroid Build Coastguard Worker       if(1>(ll = utf8towc(&wc2, chrs, 99))) chrs++;
829*cf5a6c84SAndroid Build Coastguard Worker       else {
830*cf5a6c84SAndroid Build Coastguard Worker         if (wc1 == wc2) return wc1;
831*cf5a6c84SAndroid Build Coastguard Worker         chrs += ll;
832*cf5a6c84SAndroid Build Coastguard Worker       }
833*cf5a6c84SAndroid Build Coastguard Worker     }
834*cf5a6c84SAndroid Build Coastguard Worker   }
835*cf5a6c84SAndroid Build Coastguard Worker 
836*cf5a6c84SAndroid Build Coastguard Worker   return 0;
837*cf5a6c84SAndroid Build Coastguard Worker }
838*cf5a6c84SAndroid Build Coastguard Worker 
839*cf5a6c84SAndroid Build Coastguard Worker // does this entire string match one of the strings in try[]
anystr(char * s,char ** try)840*cf5a6c84SAndroid Build Coastguard Worker static int anystr(char *s, char **try)
841*cf5a6c84SAndroid Build Coastguard Worker {
842*cf5a6c84SAndroid Build Coastguard Worker   while (*try) if (!strcmp(s, *try++)) return 1;
843*cf5a6c84SAndroid Build Coastguard Worker 
844*cf5a6c84SAndroid Build Coastguard Worker   return 0;
845*cf5a6c84SAndroid Build Coastguard Worker }
846*cf5a6c84SAndroid Build Coastguard Worker 
847*cf5a6c84SAndroid Build Coastguard Worker // Update $IFS cache in function call stack after variable assignment
cache_ifs(char * s,struct sh_fcall * ff)848*cf5a6c84SAndroid Build Coastguard Worker static void cache_ifs(char *s, struct sh_fcall *ff)
849*cf5a6c84SAndroid Build Coastguard Worker {
850*cf5a6c84SAndroid Build Coastguard Worker   if (strstart(&s, "IFS="))
851*cf5a6c84SAndroid Build Coastguard Worker     do ff->ifs = s; while ((ff = ff->next) != TT.ff->prev);
852*cf5a6c84SAndroid Build Coastguard Worker }
853*cf5a6c84SAndroid Build Coastguard Worker 
854*cf5a6c84SAndroid Build Coastguard Worker // declare -aAilnrux
855*cf5a6c84SAndroid Build Coastguard Worker // ft
856*cf5a6c84SAndroid Build Coastguard Worker // TODO VAR_ARRAY VAR_DICT
857*cf5a6c84SAndroid Build Coastguard Worker 
858*cf5a6c84SAndroid Build Coastguard Worker // Assign new name=value string for existing variable. s takes x=y or x+=y
setvar_found(char * s,int freeable,struct sh_vars * var)859*cf5a6c84SAndroid Build Coastguard Worker static struct sh_vars *setvar_found(char *s, int freeable, struct sh_vars *var)
860*cf5a6c84SAndroid Build Coastguard Worker {
861*cf5a6c84SAndroid Build Coastguard Worker   char *ss, *sss, *sd, buf[24];
862*cf5a6c84SAndroid Build Coastguard Worker   long ii, jj, kk, flags = var->flags&~VAR_WHITEOUT;
863*cf5a6c84SAndroid Build Coastguard Worker   long long ll;
864*cf5a6c84SAndroid Build Coastguard Worker   int cc, vlen = varend(s)-s;
865*cf5a6c84SAndroid Build Coastguard Worker 
866*cf5a6c84SAndroid Build Coastguard Worker   if (flags&VAR_READONLY) {
867*cf5a6c84SAndroid Build Coastguard Worker     error_msg("%.*s: read only", vlen, s);
868*cf5a6c84SAndroid Build Coastguard Worker     goto bad;
869*cf5a6c84SAndroid Build Coastguard Worker   }
870*cf5a6c84SAndroid Build Coastguard Worker 
871*cf5a6c84SAndroid Build Coastguard Worker   // If += has no old value (addvar placeholder or empty old var) yank the +
872*cf5a6c84SAndroid Build Coastguard Worker   if (s[vlen]=='+' && (var->str==s || !strchr(var->str, '=')[1])) {
873*cf5a6c84SAndroid Build Coastguard Worker     ss = xmprintf("%.*s%s", vlen, s, s+vlen+1);
874*cf5a6c84SAndroid Build Coastguard Worker     if (var->str==s) {
875*cf5a6c84SAndroid Build Coastguard Worker       if (!freeable++) var->flags |= VAR_NOFREE;
876*cf5a6c84SAndroid Build Coastguard Worker     } else if (freeable++) free(s);
877*cf5a6c84SAndroid Build Coastguard Worker     s = ss;
878*cf5a6c84SAndroid Build Coastguard Worker   }
879*cf5a6c84SAndroid Build Coastguard Worker 
880*cf5a6c84SAndroid Build Coastguard Worker   // Handle VAR_NAMEREF mismatch by replacing name
881*cf5a6c84SAndroid Build Coastguard Worker   if (strncmp(var->str, s, vlen)) {
882*cf5a6c84SAndroid Build Coastguard Worker     ss = s+vlen+(s[vlen]=='+')+1;
883*cf5a6c84SAndroid Build Coastguard Worker     ss = xmprintf("%.*s%s", (vlen = varend(var->str)-var->str)+1, var->str, ss);
884*cf5a6c84SAndroid Build Coastguard Worker     if (freeable++) free(s);
885*cf5a6c84SAndroid Build Coastguard Worker     s = ss;
886*cf5a6c84SAndroid Build Coastguard Worker   }
887*cf5a6c84SAndroid Build Coastguard Worker 
888*cf5a6c84SAndroid Build Coastguard Worker   // utf8 aware case conversion, two pass (measure, allocate, convert) because
889*cf5a6c84SAndroid Build Coastguard Worker   // unicode IS stupid enough for upper/lower case to be different utf8 byte
890*cf5a6c84SAndroid Build Coastguard Worker   // lengths, for example lowercase of U+023a (c8 ba) is U+2c65 (e2 b1 a5)
891*cf5a6c84SAndroid Build Coastguard Worker   if (flags&(VAR_TOUPPER|VAR_TOLOWER)) {
892*cf5a6c84SAndroid Build Coastguard Worker     for (jj = kk = 0, sss = 0; jj<2; jj++, sss = sd = xmalloc(vlen+kk+2)) {
893*cf5a6c84SAndroid Build Coastguard Worker       sd = jj ? stpncpy(sss, s, vlen+1) : (void *)&sss;
894*cf5a6c84SAndroid Build Coastguard Worker       for (ss = s+vlen+1; (ii = getutf8(ss, 4, &cc)); ss += ii) {
895*cf5a6c84SAndroid Build Coastguard Worker         kk += wctoutf8(sd, (flags&VAR_TOUPPER) ? towupper(cc) : towlower(cc));
896*cf5a6c84SAndroid Build Coastguard Worker         if (jj) {
897*cf5a6c84SAndroid Build Coastguard Worker           sd += kk;
898*cf5a6c84SAndroid Build Coastguard Worker           kk = 0;
899*cf5a6c84SAndroid Build Coastguard Worker         }
900*cf5a6c84SAndroid Build Coastguard Worker       }
901*cf5a6c84SAndroid Build Coastguard Worker     }
902*cf5a6c84SAndroid Build Coastguard Worker     *sd = 0;
903*cf5a6c84SAndroid Build Coastguard Worker     if (freeable++) free(s);
904*cf5a6c84SAndroid Build Coastguard Worker     s = sss;
905*cf5a6c84SAndroid Build Coastguard Worker   }
906*cf5a6c84SAndroid Build Coastguard Worker 
907*cf5a6c84SAndroid Build Coastguard Worker   // integer variables treat += differently
908*cf5a6c84SAndroid Build Coastguard Worker   ss = s+vlen+(s[vlen]=='+')+1;
909*cf5a6c84SAndroid Build Coastguard Worker   if (flags&VAR_INT) {
910*cf5a6c84SAndroid Build Coastguard Worker     sd = ss;
911*cf5a6c84SAndroid Build Coastguard Worker     if (!recalculate(&ll, &sd, 0) || *sd) {
912*cf5a6c84SAndroid Build Coastguard Worker       perror_msg("bad math: %s @ %d", ss, (int)(sd-ss));
913*cf5a6c84SAndroid Build Coastguard Worker 
914*cf5a6c84SAndroid Build Coastguard Worker       goto bad;
915*cf5a6c84SAndroid Build Coastguard Worker     }
916*cf5a6c84SAndroid Build Coastguard Worker 
917*cf5a6c84SAndroid Build Coastguard Worker     sprintf(buf, "%lld", ll);
918*cf5a6c84SAndroid Build Coastguard Worker     if (flags&VAR_MAGIC) {
919*cf5a6c84SAndroid Build Coastguard Worker       if (*s == 'S') {
920*cf5a6c84SAndroid Build Coastguard Worker         ll *= 1000;
921*cf5a6c84SAndroid Build Coastguard Worker         TT.SECONDS = (s[vlen]=='+') ? TT.SECONDS+ll : millitime()-ll;
922*cf5a6c84SAndroid Build Coastguard Worker       } else if (*s == 'R') srandom(ll);
923*cf5a6c84SAndroid Build Coastguard Worker       if (freeable) free(s);
924*cf5a6c84SAndroid Build Coastguard Worker 
925*cf5a6c84SAndroid Build Coastguard Worker       // magic can't be whiteout or nofree, and keeps old string
926*cf5a6c84SAndroid Build Coastguard Worker       return var;
927*cf5a6c84SAndroid Build Coastguard Worker     } else if (s[vlen]=='+' || strcmp(buf, ss)) {
928*cf5a6c84SAndroid Build Coastguard Worker       if (s[vlen]=='+') ll += atoll(strchr(var->str, '=')+1);
929*cf5a6c84SAndroid Build Coastguard Worker       ss = xmprintf("%.*s=%lld", vlen, s, ll);
930*cf5a6c84SAndroid Build Coastguard Worker       if (freeable++) free(s);
931*cf5a6c84SAndroid Build Coastguard Worker       s = ss;
932*cf5a6c84SAndroid Build Coastguard Worker     }
933*cf5a6c84SAndroid Build Coastguard Worker   } else if (s[vlen]=='+' && !(flags&VAR_MAGIC)) {
934*cf5a6c84SAndroid Build Coastguard Worker     ss = xmprintf("%s%s", var->str, ss);
935*cf5a6c84SAndroid Build Coastguard Worker     if (freeable++) free(s);
936*cf5a6c84SAndroid Build Coastguard Worker     s = ss;
937*cf5a6c84SAndroid Build Coastguard Worker   }
938*cf5a6c84SAndroid Build Coastguard Worker 
939*cf5a6c84SAndroid Build Coastguard Worker   // Replace old string with new one, adjusting nofree status
940*cf5a6c84SAndroid Build Coastguard Worker   if (flags&VAR_NOFREE) flags ^= VAR_NOFREE;
941*cf5a6c84SAndroid Build Coastguard Worker   else free(var->str);
942*cf5a6c84SAndroid Build Coastguard Worker   if (!freeable) flags |= VAR_NOFREE;
943*cf5a6c84SAndroid Build Coastguard Worker   var->str = s;
944*cf5a6c84SAndroid Build Coastguard Worker   var->flags = flags;
945*cf5a6c84SAndroid Build Coastguard Worker 
946*cf5a6c84SAndroid Build Coastguard Worker   return var;
947*cf5a6c84SAndroid Build Coastguard Worker bad:
948*cf5a6c84SAndroid Build Coastguard Worker   if (freeable) free(s);
949*cf5a6c84SAndroid Build Coastguard Worker 
950*cf5a6c84SAndroid Build Coastguard Worker   return 0;
951*cf5a6c84SAndroid Build Coastguard Worker }
952*cf5a6c84SAndroid Build Coastguard Worker 
953*cf5a6c84SAndroid Build Coastguard Worker // Creates new variables (local or global) and handles +=
954*cf5a6c84SAndroid Build Coastguard Worker // returns 0 on error, else sh_vars of new entry. Adds at ff if not found.
setvar_long(char * s,int freeable,struct sh_fcall * ff)955*cf5a6c84SAndroid Build Coastguard Worker static struct sh_vars *setvar_long(char *s, int freeable, struct sh_fcall *ff)
956*cf5a6c84SAndroid Build Coastguard Worker {
957*cf5a6c84SAndroid Build Coastguard Worker   struct sh_vars *vv = 0, *was;
958*cf5a6c84SAndroid Build Coastguard Worker   char *ss;
959*cf5a6c84SAndroid Build Coastguard Worker 
960*cf5a6c84SAndroid Build Coastguard Worker   if (!s) return 0;
961*cf5a6c84SAndroid Build Coastguard Worker   ss = varend(s);
962*cf5a6c84SAndroid Build Coastguard Worker   if (ss[*ss=='+']!='=') {
963*cf5a6c84SAndroid Build Coastguard Worker     error_msg("bad setvar %s\n", s);
964*cf5a6c84SAndroid Build Coastguard Worker     if (freeable) free(s);
965*cf5a6c84SAndroid Build Coastguard Worker 
966*cf5a6c84SAndroid Build Coastguard Worker     return 0;
967*cf5a6c84SAndroid Build Coastguard Worker   }
968*cf5a6c84SAndroid Build Coastguard Worker 
969*cf5a6c84SAndroid Build Coastguard Worker   // Add if necessary, set value, and remove again if we added but set failed
970*cf5a6c84SAndroid Build Coastguard Worker   if (!(was = vv = findvar(s, &ff))) (vv = addvar(s, ff))->flags = VAR_NOFREE;
971*cf5a6c84SAndroid Build Coastguard Worker   if (!setvar_found(s, freeable, vv)) {
972*cf5a6c84SAndroid Build Coastguard Worker     if (!was) memmove(vv, vv+1, sizeof(ff->vars)*(--ff->varslen-(vv-ff->vars)));
973*cf5a6c84SAndroid Build Coastguard Worker 
974*cf5a6c84SAndroid Build Coastguard Worker     return 0;
975*cf5a6c84SAndroid Build Coastguard Worker   }
976*cf5a6c84SAndroid Build Coastguard Worker   cache_ifs(vv->str, ff);
977*cf5a6c84SAndroid Build Coastguard Worker 
978*cf5a6c84SAndroid Build Coastguard Worker   return vv;
979*cf5a6c84SAndroid Build Coastguard Worker }
980*cf5a6c84SAndroid Build Coastguard Worker 
981*cf5a6c84SAndroid Build Coastguard Worker // Set variable via a malloced "name=value" (or "name+=value") string.
982*cf5a6c84SAndroid Build Coastguard Worker // Returns sh_vars * or 0 for failure (readonly, etc)
setvar(char * str)983*cf5a6c84SAndroid Build Coastguard Worker static struct sh_vars *setvar(char *str)
984*cf5a6c84SAndroid Build Coastguard Worker {
985*cf5a6c84SAndroid Build Coastguard Worker   return setvar_long(str, 1, TT.ff->prev);
986*cf5a6c84SAndroid Build Coastguard Worker }
987*cf5a6c84SAndroid Build Coastguard Worker 
988*cf5a6c84SAndroid Build Coastguard Worker 
989*cf5a6c84SAndroid Build Coastguard Worker // returns whether variable found (whiteout doesn't count)
unsetvar(char * name)990*cf5a6c84SAndroid Build Coastguard Worker static int unsetvar(char *name)
991*cf5a6c84SAndroid Build Coastguard Worker {
992*cf5a6c84SAndroid Build Coastguard Worker   struct sh_fcall *ff;
993*cf5a6c84SAndroid Build Coastguard Worker   struct sh_vars *var = findvar(name, &ff);
994*cf5a6c84SAndroid Build Coastguard Worker   int len = varend(name)-name;
995*cf5a6c84SAndroid Build Coastguard Worker 
996*cf5a6c84SAndroid Build Coastguard Worker   if (!var || (var->flags&VAR_WHITEOUT)) return 0;
997*cf5a6c84SAndroid Build Coastguard Worker   if (var->flags&VAR_READONLY) error_msg("readonly %.*s", len, name);
998*cf5a6c84SAndroid Build Coastguard Worker   else {
999*cf5a6c84SAndroid Build Coastguard Worker     // turn local into whiteout
1000*cf5a6c84SAndroid Build Coastguard Worker     if (ff != TT.ff->prev) {
1001*cf5a6c84SAndroid Build Coastguard Worker       var->flags = VAR_WHITEOUT;
1002*cf5a6c84SAndroid Build Coastguard Worker       if (!(var->flags&VAR_NOFREE))
1003*cf5a6c84SAndroid Build Coastguard Worker         (var->str = xrealloc(var->str, len+2))[len+1] = 0;
1004*cf5a6c84SAndroid Build Coastguard Worker     // free from global context
1005*cf5a6c84SAndroid Build Coastguard Worker     } else {
1006*cf5a6c84SAndroid Build Coastguard Worker       if (!(var->flags&VAR_NOFREE)) free(var->str);
1007*cf5a6c84SAndroid Build Coastguard Worker       memmove(var, var+1, sizeof(ff->vars)*(ff->varslen-- -(var-ff->vars)));
1008*cf5a6c84SAndroid Build Coastguard Worker     }
1009*cf5a6c84SAndroid Build Coastguard Worker     if (!strcmp(name, "IFS"))
1010*cf5a6c84SAndroid Build Coastguard Worker       do ff->ifs = " \t\n"; while ((ff = ff->next) != TT.ff->prev);
1011*cf5a6c84SAndroid Build Coastguard Worker   }
1012*cf5a6c84SAndroid Build Coastguard Worker 
1013*cf5a6c84SAndroid Build Coastguard Worker   return 1;
1014*cf5a6c84SAndroid Build Coastguard Worker }
1015*cf5a6c84SAndroid Build Coastguard Worker 
setvarval(char * name,char * val)1016*cf5a6c84SAndroid Build Coastguard Worker static struct sh_vars *setvarval(char *name, char *val)
1017*cf5a6c84SAndroid Build Coastguard Worker {
1018*cf5a6c84SAndroid Build Coastguard Worker   return setvar(xmprintf("%s=%s", name, val));
1019*cf5a6c84SAndroid Build Coastguard Worker }
1020*cf5a6c84SAndroid Build Coastguard Worker 
1021*cf5a6c84SAndroid Build Coastguard Worker // TODO: keep variable arrays sorted for binary search
1022*cf5a6c84SAndroid Build Coastguard Worker 
1023*cf5a6c84SAndroid Build Coastguard Worker // create array of variables visible in current function.
visible_vars(void)1024*cf5a6c84SAndroid Build Coastguard Worker static struct sh_vars **visible_vars(void)
1025*cf5a6c84SAndroid Build Coastguard Worker {
1026*cf5a6c84SAndroid Build Coastguard Worker   struct sh_arg arg;
1027*cf5a6c84SAndroid Build Coastguard Worker   struct sh_fcall *ff;
1028*cf5a6c84SAndroid Build Coastguard Worker   struct sh_vars *vv;
1029*cf5a6c84SAndroid Build Coastguard Worker   unsigned ii, jj, len;
1030*cf5a6c84SAndroid Build Coastguard Worker 
1031*cf5a6c84SAndroid Build Coastguard Worker   arg.c = 0;
1032*cf5a6c84SAndroid Build Coastguard Worker   arg.v = 0;
1033*cf5a6c84SAndroid Build Coastguard Worker 
1034*cf5a6c84SAndroid Build Coastguard Worker   // Find non-duplicate entries: TODO, sort and binary search
1035*cf5a6c84SAndroid Build Coastguard Worker   for (ff = TT.ff; ; ff = ff->next) {
1036*cf5a6c84SAndroid Build Coastguard Worker     if (ff->vars) for (ii = ff->varslen; ii--;) {
1037*cf5a6c84SAndroid Build Coastguard Worker       vv = ff->vars+ii;
1038*cf5a6c84SAndroid Build Coastguard Worker       len = 1+(varend(vv->str)-vv->str);
1039*cf5a6c84SAndroid Build Coastguard Worker       for (jj = 0; ;jj++) {
1040*cf5a6c84SAndroid Build Coastguard Worker         if (jj == arg.c) arg_add(&arg, (void *)vv);
1041*cf5a6c84SAndroid Build Coastguard Worker         else if (strncmp(arg.v[jj], vv->str, len)) continue;
1042*cf5a6c84SAndroid Build Coastguard Worker 
1043*cf5a6c84SAndroid Build Coastguard Worker         break;
1044*cf5a6c84SAndroid Build Coastguard Worker       }
1045*cf5a6c84SAndroid Build Coastguard Worker     }
1046*cf5a6c84SAndroid Build Coastguard Worker     if (ff->next == TT.ff) break;
1047*cf5a6c84SAndroid Build Coastguard Worker   }
1048*cf5a6c84SAndroid Build Coastguard Worker 
1049*cf5a6c84SAndroid Build Coastguard Worker   return (void *)arg.v;
1050*cf5a6c84SAndroid Build Coastguard Worker }
1051*cf5a6c84SAndroid Build Coastguard Worker 
1052*cf5a6c84SAndroid Build Coastguard Worker // malloc declare -x "escaped string"
declarep(struct sh_vars * var)1053*cf5a6c84SAndroid Build Coastguard Worker static char *declarep(struct sh_vars *var)
1054*cf5a6c84SAndroid Build Coastguard Worker {
1055*cf5a6c84SAndroid Build Coastguard Worker   char *types = "rxnuliaA", *esc = "$\"\\`", *in, flags[16], *out = flags, *ss;
1056*cf5a6c84SAndroid Build Coastguard Worker   int len;
1057*cf5a6c84SAndroid Build Coastguard Worker 
1058*cf5a6c84SAndroid Build Coastguard Worker   for (len = 0; types[len]; len++) if (var->flags&(2<<len)) *out++ = types[len];
1059*cf5a6c84SAndroid Build Coastguard Worker   if (out==flags) *out++ = '-';
1060*cf5a6c84SAndroid Build Coastguard Worker   *out = 0;
1061*cf5a6c84SAndroid Build Coastguard Worker   len = out-flags;
1062*cf5a6c84SAndroid Build Coastguard Worker 
1063*cf5a6c84SAndroid Build Coastguard Worker   for (in = var->str; *in; in++) len += !!strchr(esc, *in);
1064*cf5a6c84SAndroid Build Coastguard Worker   len += in-var->str;
1065*cf5a6c84SAndroid Build Coastguard Worker   ss = xmalloc(len+15);
1066*cf5a6c84SAndroid Build Coastguard Worker 
1067*cf5a6c84SAndroid Build Coastguard Worker   len = varend(var->str)-var->str;
1068*cf5a6c84SAndroid Build Coastguard Worker   out = ss + sprintf(ss, "declare -%s %.*s", flags, len, var->str);
1069*cf5a6c84SAndroid Build Coastguard Worker   if (var->flags != VAR_MAGIC)  {
1070*cf5a6c84SAndroid Build Coastguard Worker     out = stpcpy(out, "=\"");
1071*cf5a6c84SAndroid Build Coastguard Worker     for (in = var->str+len+1; *in; *out++ = *in++)
1072*cf5a6c84SAndroid Build Coastguard Worker       if (strchr(esc, *in)) *out++ = '\\';
1073*cf5a6c84SAndroid Build Coastguard Worker     *out++ = '"';
1074*cf5a6c84SAndroid Build Coastguard Worker   }
1075*cf5a6c84SAndroid Build Coastguard Worker   *out = 0;
1076*cf5a6c84SAndroid Build Coastguard Worker 
1077*cf5a6c84SAndroid Build Coastguard Worker   return ss;
1078*cf5a6c84SAndroid Build Coastguard Worker }
1079*cf5a6c84SAndroid Build Coastguard Worker 
1080*cf5a6c84SAndroid Build Coastguard Worker // Skip past valid prefix that could go before redirect
skip_redir_prefix(char * word)1081*cf5a6c84SAndroid Build Coastguard Worker static char *skip_redir_prefix(char *word)
1082*cf5a6c84SAndroid Build Coastguard Worker {
1083*cf5a6c84SAndroid Build Coastguard Worker   char *s = word;
1084*cf5a6c84SAndroid Build Coastguard Worker 
1085*cf5a6c84SAndroid Build Coastguard Worker   if (*s == '{') {
1086*cf5a6c84SAndroid Build Coastguard Worker     if (*(s = varend(s+1)) == '}' && s != word+1) s++;
1087*cf5a6c84SAndroid Build Coastguard Worker     else s = word;
1088*cf5a6c84SAndroid Build Coastguard Worker   } else while (isdigit(*s)) s++;
1089*cf5a6c84SAndroid Build Coastguard Worker 
1090*cf5a6c84SAndroid Build Coastguard Worker   return s;
1091*cf5a6c84SAndroid Build Coastguard Worker }
1092*cf5a6c84SAndroid Build Coastguard Worker 
1093*cf5a6c84SAndroid Build Coastguard Worker // parse next word from command line. Returns end, or 0 if need continuation
1094*cf5a6c84SAndroid Build Coastguard Worker // caller eats leading spaces. early = skip one quote block (or return start)
parse_word(char * start,int early)1095*cf5a6c84SAndroid Build Coastguard Worker static char *parse_word(char *start, int early)
1096*cf5a6c84SAndroid Build Coastguard Worker {
1097*cf5a6c84SAndroid Build Coastguard Worker   int ii, qq, qc = 0, quote = 0;
1098*cf5a6c84SAndroid Build Coastguard Worker   char *end = start, *ss;
1099*cf5a6c84SAndroid Build Coastguard Worker 
1100*cf5a6c84SAndroid Build Coastguard Worker   // Handle redirections, <(), (( )) that only count at the start of word
1101*cf5a6c84SAndroid Build Coastguard Worker   ss = skip_redir_prefix(end); // 123<<file- parses as 2 args: "123<<" "file-"
1102*cf5a6c84SAndroid Build Coastguard Worker   if (strstart(&ss, "<(") || strstart(&ss, ">(")) {
1103*cf5a6c84SAndroid Build Coastguard Worker     toybuf[quote++]=')';
1104*cf5a6c84SAndroid Build Coastguard Worker     end = ss;
1105*cf5a6c84SAndroid Build Coastguard Worker   } else if ((ii = anystart(ss, (void *)redirectors))) return ss+ii;
1106*cf5a6c84SAndroid Build Coastguard Worker   if (strstart(&end, "((")) toybuf[quote++] = 254;
1107*cf5a6c84SAndroid Build Coastguard Worker 
1108*cf5a6c84SAndroid Build Coastguard Worker   // Loop to find end of this word
1109*cf5a6c84SAndroid Build Coastguard Worker   while (*end) {
1110*cf5a6c84SAndroid Build Coastguard Worker     // If we're stopping early and already handled a symbol...
1111*cf5a6c84SAndroid Build Coastguard Worker     if (early && end!=start && !quote) break;
1112*cf5a6c84SAndroid Build Coastguard Worker 
1113*cf5a6c84SAndroid Build Coastguard Worker     // barf if we're near overloading quote stack (nesting ridiculously deep)
1114*cf5a6c84SAndroid Build Coastguard Worker     if (quote>4000) {
1115*cf5a6c84SAndroid Build Coastguard Worker       syntax_err("bad quote depth");
1116*cf5a6c84SAndroid Build Coastguard Worker       return (void *)1;
1117*cf5a6c84SAndroid Build Coastguard Worker     }
1118*cf5a6c84SAndroid Build Coastguard Worker 
1119*cf5a6c84SAndroid Build Coastguard Worker     // Are we in a quote context?
1120*cf5a6c84SAndroid Build Coastguard Worker     if ((qq = quote ? toybuf[quote-1] : 0)) {
1121*cf5a6c84SAndroid Build Coastguard Worker       ii = *end++;
1122*cf5a6c84SAndroid Build Coastguard Worker       if ((qq==')' || qq>=254) && (ii=='(' || ii==')')) { // parentheses nest
1123*cf5a6c84SAndroid Build Coastguard Worker         if (ii=='(') qc++;
1124*cf5a6c84SAndroid Build Coastguard Worker         else if (qc) qc--;
1125*cf5a6c84SAndroid Build Coastguard Worker         else if (qq>=254) {
1126*cf5a6c84SAndroid Build Coastguard Worker           // (( can end with )) or retroactively become two (( if we hit one )
1127*cf5a6c84SAndroid Build Coastguard Worker           if (ii==')' && *end==')') quote--, end++;
1128*cf5a6c84SAndroid Build Coastguard Worker           else if (qq==254) return start+1;
1129*cf5a6c84SAndroid Build Coastguard Worker           else if (qq==255) toybuf[quote-1] = ')';
1130*cf5a6c84SAndroid Build Coastguard Worker         } else if (ii==')') quote--;
1131*cf5a6c84SAndroid Build Coastguard Worker       } else if (ii==(qq&127)) quote--;        // matching end quote
1132*cf5a6c84SAndroid Build Coastguard Worker       else if (qq!='\'') end--, ii = 0;  // single quote claims everything
1133*cf5a6c84SAndroid Build Coastguard Worker       if (ii) continue;                  // fall through for other quote types
1134*cf5a6c84SAndroid Build Coastguard Worker 
1135*cf5a6c84SAndroid Build Coastguard Worker     // space and flow control chars only end word when not quoted in any way
1136*cf5a6c84SAndroid Build Coastguard Worker     } else {
1137*cf5a6c84SAndroid Build Coastguard Worker       if (isspace(*end)) break;
1138*cf5a6c84SAndroid Build Coastguard Worker       ss = end + anystart(end, (char *[]){";;&", ";;", ";&", ";", "||",
1139*cf5a6c84SAndroid Build Coastguard Worker         "|&", "|", "&&", "&", "(", ")", 0});
1140*cf5a6c84SAndroid Build Coastguard Worker       if (ss==end) ss += anystart(end, (void *)redirectors);
1141*cf5a6c84SAndroid Build Coastguard Worker       if (ss!=end) return (end==start) ? ss : end;
1142*cf5a6c84SAndroid Build Coastguard Worker     }
1143*cf5a6c84SAndroid Build Coastguard Worker 
1144*cf5a6c84SAndroid Build Coastguard Worker     // start new quote context? (' not special within ")
1145*cf5a6c84SAndroid Build Coastguard Worker     if (strchr("'\"`"+(qq=='"'), ii = *end++)) toybuf[quote++] = ii;
1146*cf5a6c84SAndroid Build Coastguard Worker 
1147*cf5a6c84SAndroid Build Coastguard Worker     // \? $() ${} $[] ?() *() +() @() !()
1148*cf5a6c84SAndroid Build Coastguard Worker     else {
1149*cf5a6c84SAndroid Build Coastguard Worker       if (ii=='$' && qq != 0247 && -1!=(qq = stridx("({['", *end))) {
1150*cf5a6c84SAndroid Build Coastguard Worker         if (strstart(&end, "((")) {
1151*cf5a6c84SAndroid Build Coastguard Worker           end--;
1152*cf5a6c84SAndroid Build Coastguard Worker           toybuf[quote++] = 255;
1153*cf5a6c84SAndroid Build Coastguard Worker         } else toybuf[quote++] = ")}]\247"[qq]; // last is '+128
1154*cf5a6c84SAndroid Build Coastguard Worker       } else if (*end=='(' && strchr("?*+@!", ii)) toybuf[quote++] = ')';
1155*cf5a6c84SAndroid Build Coastguard Worker       else {
1156*cf5a6c84SAndroid Build Coastguard Worker         if (ii!='\\') end--;
1157*cf5a6c84SAndroid Build Coastguard Worker         else if (!end[*end=='\n']) return (*end && !early) ? 0 : end;
1158*cf5a6c84SAndroid Build Coastguard Worker         if (early && !quote) return end;
1159*cf5a6c84SAndroid Build Coastguard Worker       }
1160*cf5a6c84SAndroid Build Coastguard Worker       end++;
1161*cf5a6c84SAndroid Build Coastguard Worker     }
1162*cf5a6c84SAndroid Build Coastguard Worker   }
1163*cf5a6c84SAndroid Build Coastguard Worker 
1164*cf5a6c84SAndroid Build Coastguard Worker   return (quote && !early) ? 0 : end;
1165*cf5a6c84SAndroid Build Coastguard Worker }
1166*cf5a6c84SAndroid Build Coastguard Worker 
1167*cf5a6c84SAndroid Build Coastguard Worker // Return next available high (>=10) file descriptor
next_hfd()1168*cf5a6c84SAndroid Build Coastguard Worker static int next_hfd()
1169*cf5a6c84SAndroid Build Coastguard Worker {
1170*cf5a6c84SAndroid Build Coastguard Worker   int hfd;
1171*cf5a6c84SAndroid Build Coastguard Worker 
1172*cf5a6c84SAndroid Build Coastguard Worker   for (; TT.hfd<=99999; TT.hfd++) if (-1 == fcntl(TT.hfd, F_GETFL)) break;
1173*cf5a6c84SAndroid Build Coastguard Worker   hfd = TT.hfd;
1174*cf5a6c84SAndroid Build Coastguard Worker   if (TT.hfd>99999) {
1175*cf5a6c84SAndroid Build Coastguard Worker     hfd = -1;
1176*cf5a6c84SAndroid Build Coastguard Worker     if (!errno) errno = EMFILE;
1177*cf5a6c84SAndroid Build Coastguard Worker   }
1178*cf5a6c84SAndroid Build Coastguard Worker 
1179*cf5a6c84SAndroid Build Coastguard Worker   return hfd;
1180*cf5a6c84SAndroid Build Coastguard Worker }
1181*cf5a6c84SAndroid Build Coastguard Worker 
1182*cf5a6c84SAndroid Build Coastguard Worker // Perform a redirect, saving displaced filehandle to a high (>10) fd
1183*cf5a6c84SAndroid Build Coastguard Worker // rd is an int array: [0] = count, followed by from/to pairs to restore later.
1184*cf5a6c84SAndroid Build Coastguard Worker // If from >= 0 dup from->to after saving to. If from == -1 just save to.
1185*cf5a6c84SAndroid Build Coastguard Worker // if from == -2 schedule "to" to be closed by unredirect.
save_redirect(int ** rd,int from,int to)1186*cf5a6c84SAndroid Build Coastguard Worker static int save_redirect(int **rd, int from, int to)
1187*cf5a6c84SAndroid Build Coastguard Worker {
1188*cf5a6c84SAndroid Build Coastguard Worker   int cnt, hfd, *rr;
1189*cf5a6c84SAndroid Build Coastguard Worker 
1190*cf5a6c84SAndroid Build Coastguard Worker //dprintf(2, "%d redir %d to %d\n", getpid(), from, to);
1191*cf5a6c84SAndroid Build Coastguard Worker   if (from == to) return 0;
1192*cf5a6c84SAndroid Build Coastguard Worker   // save displaced to, copying to high (>=10) file descriptor to undo later
1193*cf5a6c84SAndroid Build Coastguard Worker   // except if we're saving to environment variable instead (don't undo that)
1194*cf5a6c84SAndroid Build Coastguard Worker   if (from>-2) {
1195*cf5a6c84SAndroid Build Coastguard Worker     if ((hfd = next_hfd())==-1) return 1;
1196*cf5a6c84SAndroid Build Coastguard Worker     if (hfd != dup2(to, hfd)) hfd = -1;
1197*cf5a6c84SAndroid Build Coastguard Worker     else fcntl(hfd, F_SETFD, FD_CLOEXEC);
1198*cf5a6c84SAndroid Build Coastguard Worker 
1199*cf5a6c84SAndroid Build Coastguard Worker     // dup "to"
1200*cf5a6c84SAndroid Build Coastguard Worker     if (from >= 0 && to != dup2(from, to)) {
1201*cf5a6c84SAndroid Build Coastguard Worker       if (hfd >= 0) close(hfd);
1202*cf5a6c84SAndroid Build Coastguard Worker 
1203*cf5a6c84SAndroid Build Coastguard Worker       return 1;
1204*cf5a6c84SAndroid Build Coastguard Worker     }
1205*cf5a6c84SAndroid Build Coastguard Worker   } else {
1206*cf5a6c84SAndroid Build Coastguard Worker     hfd = to;
1207*cf5a6c84SAndroid Build Coastguard Worker     to = -1;
1208*cf5a6c84SAndroid Build Coastguard Worker   }
1209*cf5a6c84SAndroid Build Coastguard Worker 
1210*cf5a6c84SAndroid Build Coastguard Worker   // Append undo information to redirect list so we can restore saved hfd later.
1211*cf5a6c84SAndroid Build Coastguard Worker   if (!((cnt = *rd ? **rd : 0)&31)) *rd = xrealloc(*rd, (cnt+33)*2*sizeof(int));
1212*cf5a6c84SAndroid Build Coastguard Worker   *(rr = *rd) = ++cnt;
1213*cf5a6c84SAndroid Build Coastguard Worker   rr[2*cnt-1] = hfd;
1214*cf5a6c84SAndroid Build Coastguard Worker   rr[2*cnt] = to;
1215*cf5a6c84SAndroid Build Coastguard Worker 
1216*cf5a6c84SAndroid Build Coastguard Worker   return 0;
1217*cf5a6c84SAndroid Build Coastguard Worker }
1218*cf5a6c84SAndroid Build Coastguard Worker 
1219*cf5a6c84SAndroid Build Coastguard Worker // restore displaced filehandles, closing high filehandles they were copied to
unredirect(int * urd)1220*cf5a6c84SAndroid Build Coastguard Worker static void unredirect(int *urd)
1221*cf5a6c84SAndroid Build Coastguard Worker {
1222*cf5a6c84SAndroid Build Coastguard Worker   int *rr = urd+1, i;
1223*cf5a6c84SAndroid Build Coastguard Worker 
1224*cf5a6c84SAndroid Build Coastguard Worker   if (!urd) return;
1225*cf5a6c84SAndroid Build Coastguard Worker 
1226*cf5a6c84SAndroid Build Coastguard Worker   for (i = 0; i<*urd; i++, rr += 2) if (rr[0] != -1) {
1227*cf5a6c84SAndroid Build Coastguard Worker     // No idea what to do about fd exhaustion here, so Steinbach's Guideline.
1228*cf5a6c84SAndroid Build Coastguard Worker     dup2(rr[0], rr[1]);
1229*cf5a6c84SAndroid Build Coastguard Worker     close(rr[0]);
1230*cf5a6c84SAndroid Build Coastguard Worker   }
1231*cf5a6c84SAndroid Build Coastguard Worker   free(urd);
1232*cf5a6c84SAndroid Build Coastguard Worker }
1233*cf5a6c84SAndroid Build Coastguard Worker 
1234*cf5a6c84SAndroid Build Coastguard Worker // TODO: waitpid(WNOHANG) to clean up zombies and catch background& ending
subshell_callback(char ** argv)1235*cf5a6c84SAndroid Build Coastguard Worker static void subshell_callback(char **argv)
1236*cf5a6c84SAndroid Build Coastguard Worker {
1237*cf5a6c84SAndroid Build Coastguard Worker   int i;
1238*cf5a6c84SAndroid Build Coastguard Worker 
1239*cf5a6c84SAndroid Build Coastguard Worker   // Don't leave open filehandles to scripts in children
1240*cf5a6c84SAndroid Build Coastguard Worker   for (i = 0; i<TT.recursion; i++)  if (TT.recfile[i]>0) close(TT.recfile[i]);
1241*cf5a6c84SAndroid Build Coastguard Worker 
1242*cf5a6c84SAndroid Build Coastguard Worker   // This depends on environ having been replaced by caller
1243*cf5a6c84SAndroid Build Coastguard Worker   environ[1] = xmprintf("@%d,%d", getpid(), getppid());
1244*cf5a6c84SAndroid Build Coastguard Worker   environ[2] = xmprintf("$=%d", TT.pid);
1245*cf5a6c84SAndroid Build Coastguard Worker // TODO: test $$ in (nommu)
1246*cf5a6c84SAndroid Build Coastguard Worker }
1247*cf5a6c84SAndroid Build Coastguard Worker 
1248*cf5a6c84SAndroid Build Coastguard Worker // TODO what happens when you background a function?
1249*cf5a6c84SAndroid Build Coastguard Worker // turn a parsed pipeline back into a string.
pl2str(struct sh_pipeline * pl,int one)1250*cf5a6c84SAndroid Build Coastguard Worker static char *pl2str(struct sh_pipeline *pl, int one)
1251*cf5a6c84SAndroid Build Coastguard Worker {
1252*cf5a6c84SAndroid Build Coastguard Worker   struct sh_pipeline *end = 0, *pp;
1253*cf5a6c84SAndroid Build Coastguard Worker   int len QUIET, i;
1254*cf5a6c84SAndroid Build Coastguard Worker   char *ss;
1255*cf5a6c84SAndroid Build Coastguard Worker 
1256*cf5a6c84SAndroid Build Coastguard Worker   // Find end of block (or one argument)
1257*cf5a6c84SAndroid Build Coastguard Worker   if (one) end = pl->next;
1258*cf5a6c84SAndroid Build Coastguard Worker   else for (end = pl, len = 0; end; end = end->next)
1259*cf5a6c84SAndroid Build Coastguard Worker     if (end->type == 1) len++;
1260*cf5a6c84SAndroid Build Coastguard Worker     else if (end->type == 3 && --len<0) break;
1261*cf5a6c84SAndroid Build Coastguard Worker 
1262*cf5a6c84SAndroid Build Coastguard Worker   // measure, then allocate
1263*cf5a6c84SAndroid Build Coastguard Worker   for (ss = 0;; ss = xmalloc(len+1)) {
1264*cf5a6c84SAndroid Build Coastguard Worker     for (pp = pl; pp != end; pp = pp->next) {
1265*cf5a6c84SAndroid Build Coastguard Worker       if (pp->type == 'F') continue; // TODO fix this
1266*cf5a6c84SAndroid Build Coastguard Worker       for (i = len = 0; i<=pp->arg->c; i++)
1267*cf5a6c84SAndroid Build Coastguard Worker         len += snprintf(ss+len, ss ? INT_MAX : 0, " %s"+!i,
1268*cf5a6c84SAndroid Build Coastguard Worker            pp->arg->v[i] ? : ";"+(pp->next==end));
1269*cf5a6c84SAndroid Build Coastguard Worker     }
1270*cf5a6c84SAndroid Build Coastguard Worker     if (ss) return ss;
1271*cf5a6c84SAndroid Build Coastguard Worker   }
1272*cf5a6c84SAndroid Build Coastguard Worker 
1273*cf5a6c84SAndroid Build Coastguard Worker // TODO test output with case and function
1274*cf5a6c84SAndroid Build Coastguard Worker // TODO add HERE documents back in
1275*cf5a6c84SAndroid Build Coastguard Worker // TODO handle functions
1276*cf5a6c84SAndroid Build Coastguard Worker }
1277*cf5a6c84SAndroid Build Coastguard Worker 
clear_block(struct sh_blockstack * blk)1278*cf5a6c84SAndroid Build Coastguard Worker static struct sh_blockstack *clear_block(struct sh_blockstack *blk)
1279*cf5a6c84SAndroid Build Coastguard Worker {
1280*cf5a6c84SAndroid Build Coastguard Worker   memset(blk, 0, sizeof(*blk));
1281*cf5a6c84SAndroid Build Coastguard Worker   blk->start = TT.ff->pl;
1282*cf5a6c84SAndroid Build Coastguard Worker   blk->run = 1;
1283*cf5a6c84SAndroid Build Coastguard Worker   blk->pout = -1;
1284*cf5a6c84SAndroid Build Coastguard Worker 
1285*cf5a6c84SAndroid Build Coastguard Worker   return blk;
1286*cf5a6c84SAndroid Build Coastguard Worker }
1287*cf5a6c84SAndroid Build Coastguard Worker 
1288*cf5a6c84SAndroid Build Coastguard Worker // when ending a block, free, cleanup redirects and pop stack.
pop_block(void)1289*cf5a6c84SAndroid Build Coastguard Worker static struct sh_pipeline *pop_block(void)
1290*cf5a6c84SAndroid Build Coastguard Worker {
1291*cf5a6c84SAndroid Build Coastguard Worker   struct sh_pipeline *pl = 0;
1292*cf5a6c84SAndroid Build Coastguard Worker   struct sh_blockstack *blk = TT.ff->blk;
1293*cf5a6c84SAndroid Build Coastguard Worker 
1294*cf5a6c84SAndroid Build Coastguard Worker   // when ending a block, free, cleanup redirects and pop stack.
1295*cf5a6c84SAndroid Build Coastguard Worker   if (blk->pout != -1) close(blk->pout);
1296*cf5a6c84SAndroid Build Coastguard Worker   unredirect(blk->urd);
1297*cf5a6c84SAndroid Build Coastguard Worker   llist_traverse(blk->fdelete, llist_free_arg);
1298*cf5a6c84SAndroid Build Coastguard Worker   free(blk->farg.v);
1299*cf5a6c84SAndroid Build Coastguard Worker   if (TT.ff->blk->next) {
1300*cf5a6c84SAndroid Build Coastguard Worker     pl = blk->start->end;
1301*cf5a6c84SAndroid Build Coastguard Worker     free(llist_pop(&TT.ff->blk));
1302*cf5a6c84SAndroid Build Coastguard Worker   } else clear_block(blk);
1303*cf5a6c84SAndroid Build Coastguard Worker 
1304*cf5a6c84SAndroid Build Coastguard Worker   return pl;
1305*cf5a6c84SAndroid Build Coastguard Worker }
1306*cf5a6c84SAndroid Build Coastguard Worker 
1307*cf5a6c84SAndroid Build Coastguard Worker // Push a new empty block to the stack
add_block(void)1308*cf5a6c84SAndroid Build Coastguard Worker static void add_block(void)
1309*cf5a6c84SAndroid Build Coastguard Worker {
1310*cf5a6c84SAndroid Build Coastguard Worker   struct sh_blockstack *blk = clear_block(xmalloc(sizeof(*blk)));
1311*cf5a6c84SAndroid Build Coastguard Worker 
1312*cf5a6c84SAndroid Build Coastguard Worker   blk->next = TT.ff->blk;
1313*cf5a6c84SAndroid Build Coastguard Worker   TT.ff->blk = blk;
1314*cf5a6c84SAndroid Build Coastguard Worker }
1315*cf5a6c84SAndroid Build Coastguard Worker 
1316*cf5a6c84SAndroid Build Coastguard Worker // Add entry to runtime function call stack
call_function(void)1317*cf5a6c84SAndroid Build Coastguard Worker static void call_function(void)
1318*cf5a6c84SAndroid Build Coastguard Worker {
1319*cf5a6c84SAndroid Build Coastguard Worker   // dlist in reverse order: TT.ff = current function, TT.ff->prev = globals
1320*cf5a6c84SAndroid Build Coastguard Worker   dlist_add_nomalloc((void *)&TT.ff, xzalloc(sizeof(struct sh_fcall)));
1321*cf5a6c84SAndroid Build Coastguard Worker   TT.ff = TT.ff->prev;
1322*cf5a6c84SAndroid Build Coastguard Worker   add_block();
1323*cf5a6c84SAndroid Build Coastguard Worker 
1324*cf5a6c84SAndroid Build Coastguard Worker // TODO caller needs to set pl, vars, func
1325*cf5a6c84SAndroid Build Coastguard Worker   // default $* is to copy previous
1326*cf5a6c84SAndroid Build Coastguard Worker   TT.ff->arg.v = TT.ff->next->arg.v;
1327*cf5a6c84SAndroid Build Coastguard Worker   TT.ff->arg.c = TT.ff->next->arg.c;
1328*cf5a6c84SAndroid Build Coastguard Worker   TT.ff->ifs = TT.ff->next->ifs;
1329*cf5a6c84SAndroid Build Coastguard Worker }
1330*cf5a6c84SAndroid Build Coastguard Worker 
free_function(struct sh_function * funky)1331*cf5a6c84SAndroid Build Coastguard Worker static void free_function(struct sh_function *funky)
1332*cf5a6c84SAndroid Build Coastguard Worker {
1333*cf5a6c84SAndroid Build Coastguard Worker   if (!funky || --funky->refcount) return;
1334*cf5a6c84SAndroid Build Coastguard Worker 
1335*cf5a6c84SAndroid Build Coastguard Worker   free(funky->name);
1336*cf5a6c84SAndroid Build Coastguard Worker   llist_traverse(funky->pipeline, free_pipeline);
1337*cf5a6c84SAndroid Build Coastguard Worker   free(funky);
1338*cf5a6c84SAndroid Build Coastguard Worker }
1339*cf5a6c84SAndroid Build Coastguard Worker 
1340*cf5a6c84SAndroid Build Coastguard Worker // TODO: old function-vs-source definition is "has variables", but no ff->func?
1341*cf5a6c84SAndroid Build Coastguard Worker // returns 0 if source popped, nonzero if function popped
end_fcall(int funconly)1342*cf5a6c84SAndroid Build Coastguard Worker static int end_fcall(int funconly)
1343*cf5a6c84SAndroid Build Coastguard Worker {
1344*cf5a6c84SAndroid Build Coastguard Worker   struct sh_fcall *ff = TT.ff;
1345*cf5a6c84SAndroid Build Coastguard Worker   int func = ff->next!=ff && ff->vars;
1346*cf5a6c84SAndroid Build Coastguard Worker 
1347*cf5a6c84SAndroid Build Coastguard Worker   if (!func && funconly) return 0;
1348*cf5a6c84SAndroid Build Coastguard Worker   llist_traverse(ff->delete, llist_free_arg);
1349*cf5a6c84SAndroid Build Coastguard Worker   ff->delete = 0;
1350*cf5a6c84SAndroid Build Coastguard Worker   while (ff->blk->next) pop_block();
1351*cf5a6c84SAndroid Build Coastguard Worker   pop_block();
1352*cf5a6c84SAndroid Build Coastguard Worker 
1353*cf5a6c84SAndroid Build Coastguard Worker   // for a function, free variables and pop context
1354*cf5a6c84SAndroid Build Coastguard Worker   if (!func) return 0;
1355*cf5a6c84SAndroid Build Coastguard Worker   while (ff->varslen)
1356*cf5a6c84SAndroid Build Coastguard Worker     if (!(ff->vars[--ff->varslen].flags&VAR_NOFREE))
1357*cf5a6c84SAndroid Build Coastguard Worker       free(ff->vars[ff->varslen].str);
1358*cf5a6c84SAndroid Build Coastguard Worker   free(ff->vars);
1359*cf5a6c84SAndroid Build Coastguard Worker   free(ff->blk);
1360*cf5a6c84SAndroid Build Coastguard Worker   free_function(ff->func);
1361*cf5a6c84SAndroid Build Coastguard Worker   free(dlist_pop(&TT.ff));
1362*cf5a6c84SAndroid Build Coastguard Worker 
1363*cf5a6c84SAndroid Build Coastguard Worker   return 1;
1364*cf5a6c84SAndroid Build Coastguard Worker }
1365*cf5a6c84SAndroid Build Coastguard Worker 
1366*cf5a6c84SAndroid Build Coastguard Worker // TODO check every caller of run_subshell for error, or syntax_error() here
1367*cf5a6c84SAndroid Build Coastguard Worker // from pipe() failure
1368*cf5a6c84SAndroid Build Coastguard Worker 
1369*cf5a6c84SAndroid Build Coastguard Worker // TODO need CLOFORK? CLOEXEC doesn't help if we don't exec...
1370*cf5a6c84SAndroid Build Coastguard Worker 
1371*cf5a6c84SAndroid Build Coastguard Worker // Pass environment and command string to child shell, return PID of child
run_subshell(char * str,int len)1372*cf5a6c84SAndroid Build Coastguard Worker static int run_subshell(char *str, int len)
1373*cf5a6c84SAndroid Build Coastguard Worker {
1374*cf5a6c84SAndroid Build Coastguard Worker   pid_t pid;
1375*cf5a6c84SAndroid Build Coastguard Worker //dprintf(2, "%d run_subshell %.*s\n", getpid(), len, str); debug_show_fds();
1376*cf5a6c84SAndroid Build Coastguard Worker   // The with-mmu path is significantly faster.
1377*cf5a6c84SAndroid Build Coastguard Worker   if (CFG_TOYBOX_FORK) {
1378*cf5a6c84SAndroid Build Coastguard Worker     if ((pid = fork())<0) perror_msg("fork");
1379*cf5a6c84SAndroid Build Coastguard Worker     else if (!pid) {
1380*cf5a6c84SAndroid Build Coastguard Worker       call_function();
1381*cf5a6c84SAndroid Build Coastguard Worker       if (str) {
1382*cf5a6c84SAndroid Build Coastguard Worker         do_source(0, fmemopen(str, len, "r"));
1383*cf5a6c84SAndroid Build Coastguard Worker         _exit(toys.exitval);
1384*cf5a6c84SAndroid Build Coastguard Worker       }
1385*cf5a6c84SAndroid Build Coastguard Worker     }
1386*cf5a6c84SAndroid Build Coastguard Worker 
1387*cf5a6c84SAndroid Build Coastguard Worker   // On nommu vfork, exec /proc/self/exe, and pipe state data to ourselves.
1388*cf5a6c84SAndroid Build Coastguard Worker   } else {
1389*cf5a6c84SAndroid Build Coastguard Worker     int pipes[2];
1390*cf5a6c84SAndroid Build Coastguard Worker     unsigned i;
1391*cf5a6c84SAndroid Build Coastguard Worker     char **oldenv = environ, *ss = str ? : pl2str(TT.ff->pl->next, 0);
1392*cf5a6c84SAndroid Build Coastguard Worker     struct sh_vars **vv;
1393*cf5a6c84SAndroid Build Coastguard Worker 
1394*cf5a6c84SAndroid Build Coastguard Worker     // open pipe to child
1395*cf5a6c84SAndroid Build Coastguard Worker     if (pipe(pipes) || 254 != dup2(pipes[0], 254)) return 1;
1396*cf5a6c84SAndroid Build Coastguard Worker     close(pipes[0]);
1397*cf5a6c84SAndroid Build Coastguard Worker     fcntl(pipes[1], F_SETFD, FD_CLOEXEC);
1398*cf5a6c84SAndroid Build Coastguard Worker 
1399*cf5a6c84SAndroid Build Coastguard Worker     // vfork child with clean environment
1400*cf5a6c84SAndroid Build Coastguard Worker     environ = xzalloc(4*sizeof(char *));
1401*cf5a6c84SAndroid Build Coastguard Worker     *environ = getvar("PATH") ? : "PATH=";
1402*cf5a6c84SAndroid Build Coastguard Worker     pid = xpopen_setup(0, 0, subshell_callback);
1403*cf5a6c84SAndroid Build Coastguard Worker // TODO what if pid -1? Handle process exhaustion.
1404*cf5a6c84SAndroid Build Coastguard Worker     // free entries added to end of environment by callback (shared heap)
1405*cf5a6c84SAndroid Build Coastguard Worker     free(environ[1]);
1406*cf5a6c84SAndroid Build Coastguard Worker     free(environ[2]);
1407*cf5a6c84SAndroid Build Coastguard Worker     free(environ);
1408*cf5a6c84SAndroid Build Coastguard Worker     environ = oldenv;
1409*cf5a6c84SAndroid Build Coastguard Worker 
1410*cf5a6c84SAndroid Build Coastguard Worker     // marshall context to child
1411*cf5a6c84SAndroid Build Coastguard Worker     close(254);
1412*cf5a6c84SAndroid Build Coastguard Worker     dprintf(pipes[1], "%lld %u %u %u %u\n", TT.SECONDS,
1413*cf5a6c84SAndroid Build Coastguard Worker       TT.options, TT.LINENO, TT.pid, TT.bangpid);
1414*cf5a6c84SAndroid Build Coastguard Worker 
1415*cf5a6c84SAndroid Build Coastguard Worker     for (i = 0, vv = visible_vars(); vv[i]; i++)
1416*cf5a6c84SAndroid Build Coastguard Worker       dprintf(pipes[1], "%u %lu\n%.*s", (unsigned)strlen(vv[i]->str),
1417*cf5a6c84SAndroid Build Coastguard Worker               vv[i]->flags, (int)strlen(vv[i]->str), vv[i]->str);
1418*cf5a6c84SAndroid Build Coastguard Worker     free(vv);
1419*cf5a6c84SAndroid Build Coastguard Worker 
1420*cf5a6c84SAndroid Build Coastguard Worker     // send command
1421*cf5a6c84SAndroid Build Coastguard Worker     dprintf(pipes[1], "0 0\n%.*s\n", len, ss);
1422*cf5a6c84SAndroid Build Coastguard Worker     if (!str) free(ss);
1423*cf5a6c84SAndroid Build Coastguard Worker     close(pipes[1]);
1424*cf5a6c84SAndroid Build Coastguard Worker   }
1425*cf5a6c84SAndroid Build Coastguard Worker 
1426*cf5a6c84SAndroid Build Coastguard Worker   return pid;
1427*cf5a6c84SAndroid Build Coastguard Worker }
1428*cf5a6c84SAndroid Build Coastguard Worker 
1429*cf5a6c84SAndroid Build Coastguard Worker // Call subshell with either stdin/stdout redirected, return other end of pipe
pipe_subshell(char * s,int len,int out)1430*cf5a6c84SAndroid Build Coastguard Worker static int pipe_subshell(char *s, int len, int out)
1431*cf5a6c84SAndroid Build Coastguard Worker {
1432*cf5a6c84SAndroid Build Coastguard Worker   int pipes[2], *uu = 0, in = !out;
1433*cf5a6c84SAndroid Build Coastguard Worker 
1434*cf5a6c84SAndroid Build Coastguard Worker   // Grab subshell data
1435*cf5a6c84SAndroid Build Coastguard Worker   if (pipe(pipes)) {
1436*cf5a6c84SAndroid Build Coastguard Worker     perror_msg("%.*s", len, s);
1437*cf5a6c84SAndroid Build Coastguard Worker 
1438*cf5a6c84SAndroid Build Coastguard Worker     return -1;
1439*cf5a6c84SAndroid Build Coastguard Worker   }
1440*cf5a6c84SAndroid Build Coastguard Worker 
1441*cf5a6c84SAndroid Build Coastguard Worker   // Perform input or output redirect and launch process (ignoring errors)
1442*cf5a6c84SAndroid Build Coastguard Worker   save_redirect(&uu, pipes[in], in);
1443*cf5a6c84SAndroid Build Coastguard Worker   close(pipes[in]);
1444*cf5a6c84SAndroid Build Coastguard Worker   fcntl(pipes[!in], F_SETFD, FD_CLOEXEC);
1445*cf5a6c84SAndroid Build Coastguard Worker   run_subshell(s, len);
1446*cf5a6c84SAndroid Build Coastguard Worker   fcntl(pipes[!in], F_SETFD, 0);
1447*cf5a6c84SAndroid Build Coastguard Worker   unredirect(uu);
1448*cf5a6c84SAndroid Build Coastguard Worker 
1449*cf5a6c84SAndroid Build Coastguard Worker   return pipes[out];
1450*cf5a6c84SAndroid Build Coastguard Worker }
1451*cf5a6c84SAndroid Build Coastguard Worker 
1452*cf5a6c84SAndroid Build Coastguard Worker // grab variable or special param (ala $$) up to len bytes. Return value.
1453*cf5a6c84SAndroid Build Coastguard Worker // set *used to length consumed. Does not handle $* and $@
getvar_special(char * str,int len,int * used,struct arg_list ** delete)1454*cf5a6c84SAndroid Build Coastguard Worker char *getvar_special(char *str, int len, int *used, struct arg_list **delete)
1455*cf5a6c84SAndroid Build Coastguard Worker {
1456*cf5a6c84SAndroid Build Coastguard Worker   char *s = 0, *ss, cc = *str;
1457*cf5a6c84SAndroid Build Coastguard Worker   unsigned uu;
1458*cf5a6c84SAndroid Build Coastguard Worker 
1459*cf5a6c84SAndroid Build Coastguard Worker   *used = 1;
1460*cf5a6c84SAndroid Build Coastguard Worker   if (cc == '-') {
1461*cf5a6c84SAndroid Build Coastguard Worker     s = ss = xmalloc(8);
1462*cf5a6c84SAndroid Build Coastguard Worker     if (TT.options&FLAG_i) *ss++ = 'i';
1463*cf5a6c84SAndroid Build Coastguard Worker     if (TT.options&OPT_B) *ss++ = 'B';
1464*cf5a6c84SAndroid Build Coastguard Worker     if (TT.options&FLAG_s) *ss++ = 's';
1465*cf5a6c84SAndroid Build Coastguard Worker     if (TT.options&FLAG_c) *ss++ = 'c';
1466*cf5a6c84SAndroid Build Coastguard Worker     *ss = 0;
1467*cf5a6c84SAndroid Build Coastguard Worker   } else if (cc == '?') s = xmprintf("%d", toys.exitval);
1468*cf5a6c84SAndroid Build Coastguard Worker   else if (cc == '$') s = xmprintf("%d", TT.pid);
1469*cf5a6c84SAndroid Build Coastguard Worker   else if (cc == '#') s = xmprintf("%d", TT.ff->arg.c ? TT.ff->arg.c-1 : 0);
1470*cf5a6c84SAndroid Build Coastguard Worker   else if (cc == '!') s = xmprintf("%d"+2*!TT.bangpid, TT.bangpid);
1471*cf5a6c84SAndroid Build Coastguard Worker   else {
1472*cf5a6c84SAndroid Build Coastguard Worker     delete = 0;
1473*cf5a6c84SAndroid Build Coastguard Worker     for (*used = uu = 0; *used<len && isdigit(str[*used]); ++*used)
1474*cf5a6c84SAndroid Build Coastguard Worker       uu = (10*uu)+str[*used]-'0';
1475*cf5a6c84SAndroid Build Coastguard Worker     if (*used) {
1476*cf5a6c84SAndroid Build Coastguard Worker       if (uu) uu += TT.ff->shift;
1477*cf5a6c84SAndroid Build Coastguard Worker       if (uu<TT.ff->arg.c) s = TT.ff->arg.v[uu];
1478*cf5a6c84SAndroid Build Coastguard Worker     } else if ((*used = varend(str)-str)) return getvar(str);
1479*cf5a6c84SAndroid Build Coastguard Worker   }
1480*cf5a6c84SAndroid Build Coastguard Worker   if (s) push_arg(delete, s);
1481*cf5a6c84SAndroid Build Coastguard Worker 
1482*cf5a6c84SAndroid Build Coastguard Worker   return s;
1483*cf5a6c84SAndroid Build Coastguard Worker }
1484*cf5a6c84SAndroid Build Coastguard Worker 
1485*cf5a6c84SAndroid Build Coastguard Worker #define WILD_SHORT 1 // else longest match
1486*cf5a6c84SAndroid Build Coastguard Worker #define WILD_CASE  2 // case insensitive
1487*cf5a6c84SAndroid Build Coastguard Worker #define WILD_ANY   4 // advance through pattern instead of str
1488*cf5a6c84SAndroid Build Coastguard Worker // Returns length of str matched by pattern, or -1 if not all pattern consumed
wildcard_matchlen(char * str,int len,char * pattern,int plen,struct sh_arg * deck,int flags)1489*cf5a6c84SAndroid Build Coastguard Worker static int wildcard_matchlen(char *str, int len, char *pattern, int plen,
1490*cf5a6c84SAndroid Build Coastguard Worker   struct sh_arg *deck, int flags)
1491*cf5a6c84SAndroid Build Coastguard Worker {
1492*cf5a6c84SAndroid Build Coastguard Worker   struct sh_arg ant = {0};    // stack: of str offsets
1493*cf5a6c84SAndroid Build Coastguard Worker   long ss, pp, dd, best = -1;
1494*cf5a6c84SAndroid Build Coastguard Worker   int i, j, c, not;
1495*cf5a6c84SAndroid Build Coastguard Worker 
1496*cf5a6c84SAndroid Build Coastguard Worker   // Loop through wildcards in pattern.
1497*cf5a6c84SAndroid Build Coastguard Worker   for (ss = pp = dd = 0; ;) {
1498*cf5a6c84SAndroid Build Coastguard Worker     if ((flags&WILD_ANY) && best!=-1) break;
1499*cf5a6c84SAndroid Build Coastguard Worker 
1500*cf5a6c84SAndroid Build Coastguard Worker     // did we consume pattern?
1501*cf5a6c84SAndroid Build Coastguard Worker     if (pp==plen) {
1502*cf5a6c84SAndroid Build Coastguard Worker       if (ss>best) best = ss;
1503*cf5a6c84SAndroid Build Coastguard Worker       if (ss==len || (flags&WILD_SHORT)) break;
1504*cf5a6c84SAndroid Build Coastguard Worker     // attempt literal match?
1505*cf5a6c84SAndroid Build Coastguard Worker     } else if (dd>=deck->c || pp!=(long)deck->v[dd]) {
1506*cf5a6c84SAndroid Build Coastguard Worker       if (ss<len) {
1507*cf5a6c84SAndroid Build Coastguard Worker         if (flags&WILD_CASE) {
1508*cf5a6c84SAndroid Build Coastguard Worker           ss += getutf8(str+ss, len-ss, &c);
1509*cf5a6c84SAndroid Build Coastguard Worker           c = towupper(c);
1510*cf5a6c84SAndroid Build Coastguard Worker           pp += getutf8(pattern+pp, pp-plen, &i);
1511*cf5a6c84SAndroid Build Coastguard Worker           i = towupper(i);
1512*cf5a6c84SAndroid Build Coastguard Worker         } else c = str[ss++], i = pattern[pp++];
1513*cf5a6c84SAndroid Build Coastguard Worker         if (c==i) continue;
1514*cf5a6c84SAndroid Build Coastguard Worker       }
1515*cf5a6c84SAndroid Build Coastguard Worker 
1516*cf5a6c84SAndroid Build Coastguard Worker     // Wildcard chars: |+@!*?()[]
1517*cf5a6c84SAndroid Build Coastguard Worker     } else {
1518*cf5a6c84SAndroid Build Coastguard Worker       c = pattern[pp++];
1519*cf5a6c84SAndroid Build Coastguard Worker       dd++;
1520*cf5a6c84SAndroid Build Coastguard Worker       if (c=='?' || ((flags&WILD_ANY) && c=='*')) {
1521*cf5a6c84SAndroid Build Coastguard Worker         ss += (i = getutf8(str+ss, len-ss, 0));
1522*cf5a6c84SAndroid Build Coastguard Worker         if (i) continue;
1523*cf5a6c84SAndroid Build Coastguard Worker       } else if (c=='*') {
1524*cf5a6c84SAndroid Build Coastguard Worker 
1525*cf5a6c84SAndroid Build Coastguard Worker         // start with zero length match, don't record consecutive **
1526*cf5a6c84SAndroid Build Coastguard Worker         if (dd==1 || pp-2!=(long)deck->v[dd-1] || pattern[pp-2]!='*') {
1527*cf5a6c84SAndroid Build Coastguard Worker           arg_add(&ant, (void *)ss);
1528*cf5a6c84SAndroid Build Coastguard Worker           arg_add(&ant, 0);
1529*cf5a6c84SAndroid Build Coastguard Worker         }
1530*cf5a6c84SAndroid Build Coastguard Worker 
1531*cf5a6c84SAndroid Build Coastguard Worker         continue;
1532*cf5a6c84SAndroid Build Coastguard Worker       } else if (c == '[') {
1533*cf5a6c84SAndroid Build Coastguard Worker         pp += (not = !!strchr("!^", pattern[pp]));
1534*cf5a6c84SAndroid Build Coastguard Worker         ss += getutf8(str+ss, len-ss, &c);
1535*cf5a6c84SAndroid Build Coastguard Worker         for (i = 0; pp<(long)deck->v[dd]; i = 0) {
1536*cf5a6c84SAndroid Build Coastguard Worker           pp += getutf8(pattern+pp, plen-pp, &i);
1537*cf5a6c84SAndroid Build Coastguard Worker           if (pattern[pp]=='-') {
1538*cf5a6c84SAndroid Build Coastguard Worker             ++pp;
1539*cf5a6c84SAndroid Build Coastguard Worker             pp += getutf8(pattern+pp, plen-pp, &j);
1540*cf5a6c84SAndroid Build Coastguard Worker             if (not^(i<=c && j>=c)) break;
1541*cf5a6c84SAndroid Build Coastguard Worker           } else if (not^(i==c)) break;
1542*cf5a6c84SAndroid Build Coastguard Worker         }
1543*cf5a6c84SAndroid Build Coastguard Worker         if (i) {
1544*cf5a6c84SAndroid Build Coastguard Worker           pp = 1+(long)deck->v[dd++];
1545*cf5a6c84SAndroid Build Coastguard Worker 
1546*cf5a6c84SAndroid Build Coastguard Worker           continue;
1547*cf5a6c84SAndroid Build Coastguard Worker         }
1548*cf5a6c84SAndroid Build Coastguard Worker 
1549*cf5a6c84SAndroid Build Coastguard Worker       // ( preceded by +@!*?
1550*cf5a6c84SAndroid Build Coastguard Worker 
1551*cf5a6c84SAndroid Build Coastguard Worker       } else { // TODO ( ) |
1552*cf5a6c84SAndroid Build Coastguard Worker         dd++;
1553*cf5a6c84SAndroid Build Coastguard Worker         continue;
1554*cf5a6c84SAndroid Build Coastguard Worker       }
1555*cf5a6c84SAndroid Build Coastguard Worker     }
1556*cf5a6c84SAndroid Build Coastguard Worker 
1557*cf5a6c84SAndroid Build Coastguard Worker     // match failure
1558*cf5a6c84SAndroid Build Coastguard Worker     if (flags&WILD_ANY) {
1559*cf5a6c84SAndroid Build Coastguard Worker       ss = 0;
1560*cf5a6c84SAndroid Build Coastguard Worker       if (plen==pp) break;
1561*cf5a6c84SAndroid Build Coastguard Worker       continue;
1562*cf5a6c84SAndroid Build Coastguard Worker     }
1563*cf5a6c84SAndroid Build Coastguard Worker 
1564*cf5a6c84SAndroid Build Coastguard Worker     // pop retry stack or return failure (TODO: seek to next | in paren)
1565*cf5a6c84SAndroid Build Coastguard Worker     while (ant.c) {
1566*cf5a6c84SAndroid Build Coastguard Worker       if ((c = pattern[(long)deck->v[--dd]])=='*') {
1567*cf5a6c84SAndroid Build Coastguard Worker         if (len<(ss = (long)ant.v[ant.c-2]+(long)++ant.v[ant.c-1])) ant.c -= 2;
1568*cf5a6c84SAndroid Build Coastguard Worker         else {
1569*cf5a6c84SAndroid Build Coastguard Worker           pp = (long)deck->v[dd++]+1;
1570*cf5a6c84SAndroid Build Coastguard Worker           break;
1571*cf5a6c84SAndroid Build Coastguard Worker         }
1572*cf5a6c84SAndroid Build Coastguard Worker       } else if (c == '(') dprintf(2, "TODO: (");
1573*cf5a6c84SAndroid Build Coastguard Worker     }
1574*cf5a6c84SAndroid Build Coastguard Worker 
1575*cf5a6c84SAndroid Build Coastguard Worker     if (!ant.c) break;
1576*cf5a6c84SAndroid Build Coastguard Worker   }
1577*cf5a6c84SAndroid Build Coastguard Worker   free (ant.v);
1578*cf5a6c84SAndroid Build Coastguard Worker 
1579*cf5a6c84SAndroid Build Coastguard Worker   return best;
1580*cf5a6c84SAndroid Build Coastguard Worker }
1581*cf5a6c84SAndroid Build Coastguard Worker 
wildcard_match(char * s,char * p,struct sh_arg * deck,int flags)1582*cf5a6c84SAndroid Build Coastguard Worker static int wildcard_match(char *s, char *p, struct sh_arg *deck, int flags)
1583*cf5a6c84SAndroid Build Coastguard Worker {
1584*cf5a6c84SAndroid Build Coastguard Worker   return wildcard_matchlen(s, strlen(s), p, strlen(p), deck, flags);
1585*cf5a6c84SAndroid Build Coastguard Worker }
1586*cf5a6c84SAndroid Build Coastguard Worker 
1587*cf5a6c84SAndroid Build Coastguard Worker 
1588*cf5a6c84SAndroid Build Coastguard Worker // TODO: test that * matches ""
1589*cf5a6c84SAndroid Build Coastguard Worker 
1590*cf5a6c84SAndroid Build Coastguard Worker // skip to next slash in wildcard path, passing count active ranges.
1591*cf5a6c84SAndroid Build Coastguard Worker // start at pattern[off] and deck[*idx], return pattern pos and update *idx
wildcard_path(char * pattern,int off,struct sh_arg * deck,int * idx,int count)1592*cf5a6c84SAndroid Build Coastguard Worker char *wildcard_path(char *pattern, int off, struct sh_arg *deck, int *idx,
1593*cf5a6c84SAndroid Build Coastguard Worker   int count)
1594*cf5a6c84SAndroid Build Coastguard Worker {
1595*cf5a6c84SAndroid Build Coastguard Worker   char *p, *old;
1596*cf5a6c84SAndroid Build Coastguard Worker   int i = 0, j = 0;
1597*cf5a6c84SAndroid Build Coastguard Worker 
1598*cf5a6c84SAndroid Build Coastguard Worker   // Skip [] and nested () ranges within deck until / or NUL
1599*cf5a6c84SAndroid Build Coastguard Worker   for (p = old = pattern+off;; p++) {
1600*cf5a6c84SAndroid Build Coastguard Worker     if (!*p) return p;
1601*cf5a6c84SAndroid Build Coastguard Worker     while (*p=='/') {
1602*cf5a6c84SAndroid Build Coastguard Worker       old = p++;
1603*cf5a6c84SAndroid Build Coastguard Worker       if (j && !count) return old;
1604*cf5a6c84SAndroid Build Coastguard Worker       j = 0;
1605*cf5a6c84SAndroid Build Coastguard Worker     }
1606*cf5a6c84SAndroid Build Coastguard Worker 
1607*cf5a6c84SAndroid Build Coastguard Worker     // Got wildcard? Return start of name if out of count, else skip [] ()
1608*cf5a6c84SAndroid Build Coastguard Worker     if (*idx<deck->c && p-pattern == (long)deck->v[*idx]) {
1609*cf5a6c84SAndroid Build Coastguard Worker       if (!j++ && !count--) return old;
1610*cf5a6c84SAndroid Build Coastguard Worker       ++*idx;
1611*cf5a6c84SAndroid Build Coastguard Worker       if (*p=='[') p = pattern+(long)deck->v[(*idx)++];
1612*cf5a6c84SAndroid Build Coastguard Worker       else if (*p=='(') while (*++p) if (p-pattern == (long)deck->v[*idx]) {
1613*cf5a6c84SAndroid Build Coastguard Worker         ++*idx;
1614*cf5a6c84SAndroid Build Coastguard Worker         if (*p == ')') {
1615*cf5a6c84SAndroid Build Coastguard Worker           if (!i) break;
1616*cf5a6c84SAndroid Build Coastguard Worker           i--;
1617*cf5a6c84SAndroid Build Coastguard Worker         } else if (*p == '(') i++;
1618*cf5a6c84SAndroid Build Coastguard Worker       }
1619*cf5a6c84SAndroid Build Coastguard Worker     }
1620*cf5a6c84SAndroid Build Coastguard Worker   }
1621*cf5a6c84SAndroid Build Coastguard Worker }
1622*cf5a6c84SAndroid Build Coastguard Worker 
1623*cf5a6c84SAndroid Build Coastguard Worker // TODO ** means this directory as well as ones below it, shopt -s globstar
1624*cf5a6c84SAndroid Build Coastguard Worker 
1625*cf5a6c84SAndroid Build Coastguard Worker // Filesystem traversal callback
1626*cf5a6c84SAndroid Build Coastguard Worker // pass on: filename, portion of deck, portion of pattern,
1627*cf5a6c84SAndroid Build Coastguard Worker // input: pattern+offset, deck+offset. Need to update offsets.
do_wildcard_files(struct dirtree * node)1628*cf5a6c84SAndroid Build Coastguard Worker int do_wildcard_files(struct dirtree *node)
1629*cf5a6c84SAndroid Build Coastguard Worker {
1630*cf5a6c84SAndroid Build Coastguard Worker   struct dirtree *nn;
1631*cf5a6c84SAndroid Build Coastguard Worker   char *pattern, *patend;
1632*cf5a6c84SAndroid Build Coastguard Worker   int lvl, ll = 0, ii = 0, rc;
1633*cf5a6c84SAndroid Build Coastguard Worker   struct sh_arg ant;
1634*cf5a6c84SAndroid Build Coastguard Worker 
1635*cf5a6c84SAndroid Build Coastguard Worker   // Top level entry has no pattern in it
1636*cf5a6c84SAndroid Build Coastguard Worker   if (!node->parent) return DIRTREE_RECURSE;
1637*cf5a6c84SAndroid Build Coastguard Worker 
1638*cf5a6c84SAndroid Build Coastguard Worker   // Find active pattern range
1639*cf5a6c84SAndroid Build Coastguard Worker   for (nn = node->parent; nn; nn = nn->parent) if (nn->parent) ii++;
1640*cf5a6c84SAndroid Build Coastguard Worker   pattern = wildcard_path(TT.wcpat, 0, TT.wcdeck, &ll, ii);
1641*cf5a6c84SAndroid Build Coastguard Worker   while (*pattern=='/') pattern++;
1642*cf5a6c84SAndroid Build Coastguard Worker   lvl = ll;
1643*cf5a6c84SAndroid Build Coastguard Worker   patend = wildcard_path(TT.wcpat, pattern-TT.wcpat, TT.wcdeck, &ll, 1);
1644*cf5a6c84SAndroid Build Coastguard Worker 
1645*cf5a6c84SAndroid Build Coastguard Worker   // Don't include . entries unless explicitly asked for them
1646*cf5a6c84SAndroid Build Coastguard Worker   if (*node->name=='.' && *pattern!='.') return 0;
1647*cf5a6c84SAndroid Build Coastguard Worker 
1648*cf5a6c84SAndroid Build Coastguard Worker   // Don't descend into non-directory (was called with DIRTREE_SYMFOLLOW)
1649*cf5a6c84SAndroid Build Coastguard Worker   if (*patend && !S_ISDIR(node->st.st_mode) && *node->name) return 0;
1650*cf5a6c84SAndroid Build Coastguard Worker 
1651*cf5a6c84SAndroid Build Coastguard Worker   // match this filename from pattern to p in deck from lvl to ll
1652*cf5a6c84SAndroid Build Coastguard Worker   ant.c = ll-lvl;
1653*cf5a6c84SAndroid Build Coastguard Worker   ant.v = TT.wcdeck->v+lvl;
1654*cf5a6c84SAndroid Build Coastguard Worker   for (ii = 0; ii<ant.c; ii++) TT.wcdeck->v[lvl+ii] -= pattern-TT.wcpat;
1655*cf5a6c84SAndroid Build Coastguard Worker   rc = wildcard_matchlen(node->name, strlen(node->name), pattern,
1656*cf5a6c84SAndroid Build Coastguard Worker     patend-pattern, &ant, 0);
1657*cf5a6c84SAndroid Build Coastguard Worker   for (ii = 0; ii<ant.c; ii++) TT.wcdeck->v[lvl+ii] += pattern-TT.wcpat;
1658*cf5a6c84SAndroid Build Coastguard Worker 
1659*cf5a6c84SAndroid Build Coastguard Worker   // Return failure or save exact match.
1660*cf5a6c84SAndroid Build Coastguard Worker   if (rc<0 || node->name[rc]) return 0;
1661*cf5a6c84SAndroid Build Coastguard Worker   if (!*patend) return DIRTREE_SAVE;
1662*cf5a6c84SAndroid Build Coastguard Worker 
1663*cf5a6c84SAndroid Build Coastguard Worker   // Are there more wildcards to test children against?
1664*cf5a6c84SAndroid Build Coastguard Worker   if (TT.wcdeck->c!=ll) return DIRTREE_RECURSE;
1665*cf5a6c84SAndroid Build Coastguard Worker 
1666*cf5a6c84SAndroid Build Coastguard Worker   // No more wildcards: check for child and return failure if it isn't there.
1667*cf5a6c84SAndroid Build Coastguard Worker   pattern = xmprintf("%s%s", node->name, patend);
1668*cf5a6c84SAndroid Build Coastguard Worker   rc = faccessat(dirtree_parentfd(node), pattern, F_OK, AT_SYMLINK_NOFOLLOW);
1669*cf5a6c84SAndroid Build Coastguard Worker   free(pattern);
1670*cf5a6c84SAndroid Build Coastguard Worker   if (rc) return 0;
1671*cf5a6c84SAndroid Build Coastguard Worker 
1672*cf5a6c84SAndroid Build Coastguard Worker   // Save child and self. (Child could be trailing / but only one saved.)
1673*cf5a6c84SAndroid Build Coastguard Worker   while (*patend=='/' && patend[1]) patend++;
1674*cf5a6c84SAndroid Build Coastguard Worker   node->child = xzalloc(sizeof(struct dirtree)+1+strlen(patend));
1675*cf5a6c84SAndroid Build Coastguard Worker   node->child->parent = node;
1676*cf5a6c84SAndroid Build Coastguard Worker   strcpy(node->child->name, patend);
1677*cf5a6c84SAndroid Build Coastguard Worker 
1678*cf5a6c84SAndroid Build Coastguard Worker   return DIRTREE_SAVE;
1679*cf5a6c84SAndroid Build Coastguard Worker }
1680*cf5a6c84SAndroid Build Coastguard Worker 
1681*cf5a6c84SAndroid Build Coastguard Worker // Record active wildcard chars in output string
1682*cf5a6c84SAndroid Build Coastguard Worker // *new start of string, oo offset into string, deck is found wildcards,
collect_wildcards(char * new,long oo,struct sh_arg * deck)1683*cf5a6c84SAndroid Build Coastguard Worker static void collect_wildcards(char *new, long oo, struct sh_arg *deck)
1684*cf5a6c84SAndroid Build Coastguard Worker {
1685*cf5a6c84SAndroid Build Coastguard Worker   long bracket, *vv;
1686*cf5a6c84SAndroid Build Coastguard Worker   char cc = new[oo];
1687*cf5a6c84SAndroid Build Coastguard Worker 
1688*cf5a6c84SAndroid Build Coastguard Worker   // Record unescaped/unquoted wildcard metadata for later processing
1689*cf5a6c84SAndroid Build Coastguard Worker 
1690*cf5a6c84SAndroid Build Coastguard Worker   if (!deck->c) arg_add(deck, 0);
1691*cf5a6c84SAndroid Build Coastguard Worker   vv = (long *)deck->v;
1692*cf5a6c84SAndroid Build Coastguard Worker 
1693*cf5a6c84SAndroid Build Coastguard Worker   // vv[0] used for paren level (bottom 16 bits) + bracket start offset<<16
1694*cf5a6c84SAndroid Build Coastguard Worker 
1695*cf5a6c84SAndroid Build Coastguard Worker   // at end loop backwards through live wildcards to remove pending unmatched (
1696*cf5a6c84SAndroid Build Coastguard Worker   if (!cc) {
1697*cf5a6c84SAndroid Build Coastguard Worker     long ii = 0, jj = 65535&*vv, kk;
1698*cf5a6c84SAndroid Build Coastguard Worker 
1699*cf5a6c84SAndroid Build Coastguard Worker     for (kk = deck->c; jj;) {
1700*cf5a6c84SAndroid Build Coastguard Worker       if (')' == (cc = new[vv[--kk]])) ii++;
1701*cf5a6c84SAndroid Build Coastguard Worker       else if ('(' == cc) {
1702*cf5a6c84SAndroid Build Coastguard Worker         if (ii) ii--;
1703*cf5a6c84SAndroid Build Coastguard Worker         else {
1704*cf5a6c84SAndroid Build Coastguard Worker           memmove(vv+kk, vv+kk+1, sizeof(long)*(deck->c-- -kk));
1705*cf5a6c84SAndroid Build Coastguard Worker           jj--;
1706*cf5a6c84SAndroid Build Coastguard Worker         }
1707*cf5a6c84SAndroid Build Coastguard Worker       }
1708*cf5a6c84SAndroid Build Coastguard Worker     }
1709*cf5a6c84SAndroid Build Coastguard Worker     if (deck->c) memmove(vv, vv+1, sizeof(long)*deck->c--);
1710*cf5a6c84SAndroid Build Coastguard Worker 
1711*cf5a6c84SAndroid Build Coastguard Worker     return;
1712*cf5a6c84SAndroid Build Coastguard Worker   }
1713*cf5a6c84SAndroid Build Coastguard Worker 
1714*cf5a6c84SAndroid Build Coastguard Worker   // Start +( range, or remove first char that isn't wildcard without (
1715*cf5a6c84SAndroid Build Coastguard Worker   if (deck->c>1 && vv[deck->c-1] == oo-1 && strchr("+@!*?", new[oo-1])) {
1716*cf5a6c84SAndroid Build Coastguard Worker     if (cc == '(') {
1717*cf5a6c84SAndroid Build Coastguard Worker       vv[deck->c-1] = oo;
1718*cf5a6c84SAndroid Build Coastguard Worker       return;
1719*cf5a6c84SAndroid Build Coastguard Worker     } else if (!strchr("*?", new[oo-1])) deck->c--;
1720*cf5a6c84SAndroid Build Coastguard Worker   }
1721*cf5a6c84SAndroid Build Coastguard Worker 
1722*cf5a6c84SAndroid Build Coastguard Worker   // fall through to add wildcard, popping parentheses stack as necessary
1723*cf5a6c84SAndroid Build Coastguard Worker   if (strchr("|+@!*?", cc));
1724*cf5a6c84SAndroid Build Coastguard Worker   else if (cc == ')' && (65535&*vv)) --*vv;
1725*cf5a6c84SAndroid Build Coastguard Worker 
1726*cf5a6c84SAndroid Build Coastguard Worker   // complete [range], discard wildcards within, add [, fall through to add ]
1727*cf5a6c84SAndroid Build Coastguard Worker   else if (cc == ']' && (bracket = *vv>>16)) {
1728*cf5a6c84SAndroid Build Coastguard Worker 
1729*cf5a6c84SAndroid Build Coastguard Worker     // don't end range yet for [] or [^]
1730*cf5a6c84SAndroid Build Coastguard Worker     if (bracket+1 == oo || (bracket+2 == oo && strchr("!^", new[oo-1]))) return;
1731*cf5a6c84SAndroid Build Coastguard Worker     while (deck->c>1 && vv[deck->c-1]>=bracket) deck->c--;
1732*cf5a6c84SAndroid Build Coastguard Worker     *vv &= 65535;
1733*cf5a6c84SAndroid Build Coastguard Worker     arg_add(deck, (void *)bracket);
1734*cf5a6c84SAndroid Build Coastguard Worker 
1735*cf5a6c84SAndroid Build Coastguard Worker   // Not a wildcard
1736*cf5a6c84SAndroid Build Coastguard Worker   } else {
1737*cf5a6c84SAndroid Build Coastguard Worker     // [ is speculative, don't add to deck yet, just record we saw it
1738*cf5a6c84SAndroid Build Coastguard Worker     if (cc == '[' && !(*vv>>16)) *vv = (oo<<16)+(65535&*vv);
1739*cf5a6c84SAndroid Build Coastguard Worker     return;
1740*cf5a6c84SAndroid Build Coastguard Worker   }
1741*cf5a6c84SAndroid Build Coastguard Worker 
1742*cf5a6c84SAndroid Build Coastguard Worker   // add active wildcard location
1743*cf5a6c84SAndroid Build Coastguard Worker   arg_add(deck, (void *)oo);
1744*cf5a6c84SAndroid Build Coastguard Worker }
1745*cf5a6c84SAndroid Build Coastguard Worker 
1746*cf5a6c84SAndroid Build Coastguard Worker // wildcard expand data against filesystem, and add results to arg list
1747*cf5a6c84SAndroid Build Coastguard Worker // Note: this wildcard deck has extra argument at start (leftover from parsing)
wildcard_add_files(struct sh_arg * arg,char * pattern,struct sh_arg * deck,struct arg_list ** delete)1748*cf5a6c84SAndroid Build Coastguard Worker static void wildcard_add_files(struct sh_arg *arg, char *pattern,
1749*cf5a6c84SAndroid Build Coastguard Worker   struct sh_arg *deck, struct arg_list **delete)
1750*cf5a6c84SAndroid Build Coastguard Worker {
1751*cf5a6c84SAndroid Build Coastguard Worker   struct dirtree *dt;
1752*cf5a6c84SAndroid Build Coastguard Worker   char *pp;
1753*cf5a6c84SAndroid Build Coastguard Worker   int ll = 0;
1754*cf5a6c84SAndroid Build Coastguard Worker 
1755*cf5a6c84SAndroid Build Coastguard Worker   // fast path: when no wildcards, add pattern verbatim
1756*cf5a6c84SAndroid Build Coastguard Worker   collect_wildcards("", 0, deck);
1757*cf5a6c84SAndroid Build Coastguard Worker   if (!deck->c) return arg_add(arg, pattern);
1758*cf5a6c84SAndroid Build Coastguard Worker 
1759*cf5a6c84SAndroid Build Coastguard Worker   // Traverse starting with leading patternless path.
1760*cf5a6c84SAndroid Build Coastguard Worker   pp = wildcard_path(TT.wcpat = pattern, 0, TT.wcdeck = deck, &ll, 0);
1761*cf5a6c84SAndroid Build Coastguard Worker   pp = (pp==pattern) ? 0 : xstrndup(pattern, pp-pattern);
1762*cf5a6c84SAndroid Build Coastguard Worker   dt = dirtree_flagread(pp, DIRTREE_STATLESS|DIRTREE_SYMFOLLOW,
1763*cf5a6c84SAndroid Build Coastguard Worker     do_wildcard_files);
1764*cf5a6c84SAndroid Build Coastguard Worker   free(pp);
1765*cf5a6c84SAndroid Build Coastguard Worker   deck->c = 0;
1766*cf5a6c84SAndroid Build Coastguard Worker 
1767*cf5a6c84SAndroid Build Coastguard Worker   // If no match save pattern, else free tree saving each path found.
1768*cf5a6c84SAndroid Build Coastguard Worker   if (!dt) return arg_add(arg, pattern);
1769*cf5a6c84SAndroid Build Coastguard Worker   while (dt) {
1770*cf5a6c84SAndroid Build Coastguard Worker     while (dt->child) dt = dt->child;
1771*cf5a6c84SAndroid Build Coastguard Worker     arg_add(arg, push_arg(delete, dirtree_path(dt, 0)));
1772*cf5a6c84SAndroid Build Coastguard Worker     do {
1773*cf5a6c84SAndroid Build Coastguard Worker       pp = (void *)dt;
1774*cf5a6c84SAndroid Build Coastguard Worker       if ((dt = dt->parent)) dt->child = dt->child->next;
1775*cf5a6c84SAndroid Build Coastguard Worker       free(pp);
1776*cf5a6c84SAndroid Build Coastguard Worker     } while (dt && !dt->child);
1777*cf5a6c84SAndroid Build Coastguard Worker   }
1778*cf5a6c84SAndroid Build Coastguard Worker // TODO: test .*/../
1779*cf5a6c84SAndroid Build Coastguard Worker }
1780*cf5a6c84SAndroid Build Coastguard Worker 
1781*cf5a6c84SAndroid Build Coastguard Worker // Copy string until } including escaped }
1782*cf5a6c84SAndroid Build Coastguard Worker // if deck collect wildcards, and store terminator at deck->v[deck->c]
slashcopy(char * s,char * c,struct sh_arg * deck)1783*cf5a6c84SAndroid Build Coastguard Worker char *slashcopy(char *s, char *c, struct sh_arg *deck)
1784*cf5a6c84SAndroid Build Coastguard Worker {
1785*cf5a6c84SAndroid Build Coastguard Worker   char *ss;
1786*cf5a6c84SAndroid Build Coastguard Worker   long ii, jj;
1787*cf5a6c84SAndroid Build Coastguard Worker 
1788*cf5a6c84SAndroid Build Coastguard Worker   for (ii = 0; !strchr(c, s[ii]); ii++) if (s[ii] == '\\') ii++;
1789*cf5a6c84SAndroid Build Coastguard Worker   ss = xmalloc(ii+1);
1790*cf5a6c84SAndroid Build Coastguard Worker   for (ii = jj = 0; !strchr(c, s[jj]); ii++)
1791*cf5a6c84SAndroid Build Coastguard Worker     if ('\\'==(ss[ii] = s[jj++])) ss[ii] = s[jj++];
1792*cf5a6c84SAndroid Build Coastguard Worker     else if (deck) collect_wildcards(ss, ii, deck);
1793*cf5a6c84SAndroid Build Coastguard Worker   ss[ii] = 0;
1794*cf5a6c84SAndroid Build Coastguard Worker   if (deck) {
1795*cf5a6c84SAndroid Build Coastguard Worker     arg_add(deck, 0);
1796*cf5a6c84SAndroid Build Coastguard Worker     deck->v[--deck->c] = (void *)jj;
1797*cf5a6c84SAndroid Build Coastguard Worker     collect_wildcards("", 0, deck);
1798*cf5a6c84SAndroid Build Coastguard Worker   }
1799*cf5a6c84SAndroid Build Coastguard Worker 
1800*cf5a6c84SAndroid Build Coastguard Worker   return ss;
1801*cf5a6c84SAndroid Build Coastguard Worker }
1802*cf5a6c84SAndroid Build Coastguard Worker 
1803*cf5a6c84SAndroid Build Coastguard Worker #define NO_QUOTE (1<<0)    // quote removal
1804*cf5a6c84SAndroid Build Coastguard Worker #define NO_PATH  (1<<1)    // path expansion (wildcards)
1805*cf5a6c84SAndroid Build Coastguard Worker #define NO_SPLIT (1<<2)    // word splitting
1806*cf5a6c84SAndroid Build Coastguard Worker #define NO_BRACE (1<<3)    // {brace,expansion}
1807*cf5a6c84SAndroid Build Coastguard Worker #define NO_TILDE (1<<4)    // ~username/path
1808*cf5a6c84SAndroid Build Coastguard Worker #define NO_NULL  (1<<5)    // Expand to "" instead of NULL
1809*cf5a6c84SAndroid Build Coastguard Worker #define SEMI_IFS (1<<6)    // Use ' ' instead of IFS to combine $*
1810*cf5a6c84SAndroid Build Coastguard Worker // expand str appending to arg using above flag defines, add mallocs to delete
1811*cf5a6c84SAndroid Build Coastguard Worker // if ant not null, save wildcard deck there instead of expanding vs filesystem
1812*cf5a6c84SAndroid Build Coastguard Worker // returns 0 for success, 1 for error.
1813*cf5a6c84SAndroid Build Coastguard Worker // If measure stop at *measure and return input bytes consumed in *measure
expand_arg_nobrace(struct sh_arg * arg,char * str,unsigned flags,struct arg_list ** delete,struct sh_arg * ant,long * measure)1814*cf5a6c84SAndroid Build Coastguard Worker static int expand_arg_nobrace(struct sh_arg *arg, char *str, unsigned flags,
1815*cf5a6c84SAndroid Build Coastguard Worker   struct arg_list **delete, struct sh_arg *ant, long *measure)
1816*cf5a6c84SAndroid Build Coastguard Worker {
1817*cf5a6c84SAndroid Build Coastguard Worker   char cc, qq = flags&NO_QUOTE, sep[6], *new = str, *s, *ss = ss, *ifs, *slice;
1818*cf5a6c84SAndroid Build Coastguard Worker   int ii = 0, oo = 0, xx, yy, dd, jj, kk, ll, mm;
1819*cf5a6c84SAndroid Build Coastguard Worker   struct sh_arg deck = {0};
1820*cf5a6c84SAndroid Build Coastguard Worker 
1821*cf5a6c84SAndroid Build Coastguard Worker   // Tilde expansion
1822*cf5a6c84SAndroid Build Coastguard Worker   if (!(flags&NO_TILDE) && *str == '~') {
1823*cf5a6c84SAndroid Build Coastguard Worker     struct passwd *pw = 0;
1824*cf5a6c84SAndroid Build Coastguard Worker 
1825*cf5a6c84SAndroid Build Coastguard Worker     ss = 0;
1826*cf5a6c84SAndroid Build Coastguard Worker     while (str[ii] && str[ii]!=':' && str[ii]!='/') ii++;
1827*cf5a6c84SAndroid Build Coastguard Worker     if (ii==1) {
1828*cf5a6c84SAndroid Build Coastguard Worker       if (!(ss = getvar("HOME")) || !*ss) pw = bufgetpwuid(getuid());
1829*cf5a6c84SAndroid Build Coastguard Worker     } else {
1830*cf5a6c84SAndroid Build Coastguard Worker       // TODO bufgetpwnam
1831*cf5a6c84SAndroid Build Coastguard Worker       pw = getpwnam(s = xstrndup(str+1, ii-1));
1832*cf5a6c84SAndroid Build Coastguard Worker       free(s);
1833*cf5a6c84SAndroid Build Coastguard Worker     }
1834*cf5a6c84SAndroid Build Coastguard Worker     if (pw) {
1835*cf5a6c84SAndroid Build Coastguard Worker       ss = pw->pw_dir;
1836*cf5a6c84SAndroid Build Coastguard Worker       if (!ss || !*ss) ss = "/";
1837*cf5a6c84SAndroid Build Coastguard Worker     }
1838*cf5a6c84SAndroid Build Coastguard Worker     if (ss) {
1839*cf5a6c84SAndroid Build Coastguard Worker       oo = strlen(ss);
1840*cf5a6c84SAndroid Build Coastguard Worker       s = xmprintf("%s%s", ss, str+ii);
1841*cf5a6c84SAndroid Build Coastguard Worker       if (str != new) free(new);
1842*cf5a6c84SAndroid Build Coastguard Worker       new = s;
1843*cf5a6c84SAndroid Build Coastguard Worker     }
1844*cf5a6c84SAndroid Build Coastguard Worker   }
1845*cf5a6c84SAndroid Build Coastguard Worker 
1846*cf5a6c84SAndroid Build Coastguard Worker   // parameter/variable expansion and dequoting
1847*cf5a6c84SAndroid Build Coastguard Worker   if (!ant) ant = &deck;
1848*cf5a6c84SAndroid Build Coastguard Worker   for (; (cc = str[ii++]); str!=new && (new[oo] = 0)) {
1849*cf5a6c84SAndroid Build Coastguard Worker     struct sh_arg aa = {0};
1850*cf5a6c84SAndroid Build Coastguard Worker     int nosplit = 0;
1851*cf5a6c84SAndroid Build Coastguard Worker 
1852*cf5a6c84SAndroid Build Coastguard Worker     if (measure && cc==*measure) break;
1853*cf5a6c84SAndroid Build Coastguard Worker 
1854*cf5a6c84SAndroid Build Coastguard Worker     // skip literal chars
1855*cf5a6c84SAndroid Build Coastguard Worker     if (!strchr("'\"\\$`"+2*(flags&NO_QUOTE), cc)) {
1856*cf5a6c84SAndroid Build Coastguard Worker       if (str != new) new[oo] = cc;
1857*cf5a6c84SAndroid Build Coastguard Worker       if (!(flags&NO_PATH) && !(qq&1)) collect_wildcards(new, oo, ant);
1858*cf5a6c84SAndroid Build Coastguard Worker       oo++;
1859*cf5a6c84SAndroid Build Coastguard Worker       continue;
1860*cf5a6c84SAndroid Build Coastguard Worker     }
1861*cf5a6c84SAndroid Build Coastguard Worker 
1862*cf5a6c84SAndroid Build Coastguard Worker     // allocate snapshot if we just started modifying
1863*cf5a6c84SAndroid Build Coastguard Worker     if (str == new) {
1864*cf5a6c84SAndroid Build Coastguard Worker       new = xstrdup(new);
1865*cf5a6c84SAndroid Build Coastguard Worker       new[oo] = 0;
1866*cf5a6c84SAndroid Build Coastguard Worker     }
1867*cf5a6c84SAndroid Build Coastguard Worker     ifs = slice = 0;
1868*cf5a6c84SAndroid Build Coastguard Worker 
1869*cf5a6c84SAndroid Build Coastguard Worker     // handle escapes and quoting
1870*cf5a6c84SAndroid Build Coastguard Worker     if (cc == '"') qq++;
1871*cf5a6c84SAndroid Build Coastguard Worker     else if (cc == '\'') {
1872*cf5a6c84SAndroid Build Coastguard Worker       if (qq&1) new[oo++] = cc;
1873*cf5a6c84SAndroid Build Coastguard Worker       else {
1874*cf5a6c84SAndroid Build Coastguard Worker         qq += 2;
1875*cf5a6c84SAndroid Build Coastguard Worker         while ((cc = str[ii++]) != '\'') new[oo++] = cc;
1876*cf5a6c84SAndroid Build Coastguard Worker       }
1877*cf5a6c84SAndroid Build Coastguard Worker 
1878*cf5a6c84SAndroid Build Coastguard Worker     // both types of subshell work the same, so do $( here not in '$' below
1879*cf5a6c84SAndroid Build Coastguard Worker // TODO $((echo hello) | cat) ala $(( becomes $( ( retroactively
1880*cf5a6c84SAndroid Build Coastguard Worker     } else if (cc == '`' || (cc == '$' && (str[ii]=='(' || str[ii]=='['))) {
1881*cf5a6c84SAndroid Build Coastguard Worker       off_t pp = 0;
1882*cf5a6c84SAndroid Build Coastguard Worker 
1883*cf5a6c84SAndroid Build Coastguard Worker       s = str+ii-1;
1884*cf5a6c84SAndroid Build Coastguard Worker       kk = parse_word(s, 1)-s;
1885*cf5a6c84SAndroid Build Coastguard Worker       if (str[ii] == '[' || *toybuf == 255) { // (( parsed together, not (( ) )
1886*cf5a6c84SAndroid Build Coastguard Worker         struct sh_arg aa = {0};
1887*cf5a6c84SAndroid Build Coastguard Worker         long long ll;
1888*cf5a6c84SAndroid Build Coastguard Worker 
1889*cf5a6c84SAndroid Build Coastguard Worker         // Expand $VARS in math string
1890*cf5a6c84SAndroid Build Coastguard Worker         ss = str+ii+1+(str[ii]=='(');
1891*cf5a6c84SAndroid Build Coastguard Worker         push_arg(delete, ss = xstrndup(ss, kk - (3+2*(str[ii]!='['))));
1892*cf5a6c84SAndroid Build Coastguard Worker         expand_arg_nobrace(&aa, ss, NO_PATH|NO_SPLIT, delete, 0, 0);
1893*cf5a6c84SAndroid Build Coastguard Worker         s = ss = (aa.v && *aa.v) ? *aa.v : "";
1894*cf5a6c84SAndroid Build Coastguard Worker         free(aa.v);
1895*cf5a6c84SAndroid Build Coastguard Worker 
1896*cf5a6c84SAndroid Build Coastguard Worker         // Recursively calculate result
1897*cf5a6c84SAndroid Build Coastguard Worker         if (!recalculate(&ll, &s, 0) || *s) {
1898*cf5a6c84SAndroid Build Coastguard Worker           error_msg("bad math: %s @ %ld", ss, (long)(s-ss)+1);
1899*cf5a6c84SAndroid Build Coastguard Worker           goto fail;
1900*cf5a6c84SAndroid Build Coastguard Worker         }
1901*cf5a6c84SAndroid Build Coastguard Worker         ii += kk-1;
1902*cf5a6c84SAndroid Build Coastguard Worker         push_arg(delete, ifs = xmprintf("%lld", ll));
1903*cf5a6c84SAndroid Build Coastguard Worker       } else {
1904*cf5a6c84SAndroid Build Coastguard Worker         // Run subshell and trim trailing newlines
1905*cf5a6c84SAndroid Build Coastguard Worker         s += (jj = 1+(cc == '$'));
1906*cf5a6c84SAndroid Build Coastguard Worker         ii += --kk;
1907*cf5a6c84SAndroid Build Coastguard Worker         kk -= jj;
1908*cf5a6c84SAndroid Build Coastguard Worker 
1909*cf5a6c84SAndroid Build Coastguard Worker         // Special case echo $(<input)
1910*cf5a6c84SAndroid Build Coastguard Worker         for (ss = s; isspace(*ss); ss++);
1911*cf5a6c84SAndroid Build Coastguard Worker         if (*ss != '<') ss = 0;
1912*cf5a6c84SAndroid Build Coastguard Worker         else {
1913*cf5a6c84SAndroid Build Coastguard Worker           while (isspace(*++ss));
1914*cf5a6c84SAndroid Build Coastguard Worker           // Can't return NULL because guaranteed ) context end
1915*cf5a6c84SAndroid Build Coastguard Worker           if (!(ll = parse_word(ss, 0)-ss)) ss = 0;
1916*cf5a6c84SAndroid Build Coastguard Worker           else {
1917*cf5a6c84SAndroid Build Coastguard Worker             jj = ll+(ss-s);
1918*cf5a6c84SAndroid Build Coastguard Worker             while (isspace(s[jj])) jj++;
1919*cf5a6c84SAndroid Build Coastguard Worker             if (jj != kk) ss = 0;
1920*cf5a6c84SAndroid Build Coastguard Worker             else {
1921*cf5a6c84SAndroid Build Coastguard Worker               jj = xcreate_stdio(ss = xstrndup(ss, ll), O_RDONLY|WARN_ONLY, 0);
1922*cf5a6c84SAndroid Build Coastguard Worker               free(ss);
1923*cf5a6c84SAndroid Build Coastguard Worker             }
1924*cf5a6c84SAndroid Build Coastguard Worker           }
1925*cf5a6c84SAndroid Build Coastguard Worker         }
1926*cf5a6c84SAndroid Build Coastguard Worker 
1927*cf5a6c84SAndroid Build Coastguard Worker // TODO what does \ in `` mean? What is echo `printf %s \$x` supposed to do?
1928*cf5a6c84SAndroid Build Coastguard Worker         // This has to be async so pipe buffer doesn't fill up
1929*cf5a6c84SAndroid Build Coastguard Worker         if (!ss) jj = pipe_subshell(s, kk, 0); // TODO $(true &&) syntax_err()
1930*cf5a6c84SAndroid Build Coastguard Worker         if ((ifs = readfd(jj, 0, &pp)))
1931*cf5a6c84SAndroid Build Coastguard Worker           for (kk = strlen(ifs); kk && ifs[kk-1]=='\n'; ifs[--kk] = 0);
1932*cf5a6c84SAndroid Build Coastguard Worker         close(jj);
1933*cf5a6c84SAndroid Build Coastguard Worker       }
1934*cf5a6c84SAndroid Build Coastguard Worker     } else if (!str[ii]) new[oo++] = cc;
1935*cf5a6c84SAndroid Build Coastguard Worker     else if (cc=='\\') {
1936*cf5a6c84SAndroid Build Coastguard Worker       if (str[ii]=='\n') ii++;
1937*cf5a6c84SAndroid Build Coastguard Worker       else new[oo++] = (!(qq&1) || strchr("\"\\$`", str[ii])) ? str[ii++] : cc;
1938*cf5a6c84SAndroid Build Coastguard Worker     }
1939*cf5a6c84SAndroid Build Coastguard Worker 
1940*cf5a6c84SAndroid Build Coastguard Worker     // $VARIABLE expansions
1941*cf5a6c84SAndroid Build Coastguard Worker 
1942*cf5a6c84SAndroid Build Coastguard Worker     else if (cc == '$') {
1943*cf5a6c84SAndroid Build Coastguard Worker       cc = *(ss = str+ii++);
1944*cf5a6c84SAndroid Build Coastguard Worker       if (cc=='\'') {
1945*cf5a6c84SAndroid Build Coastguard Worker         for (s = str+ii; *s != '\''; oo += wcrtomb(new+oo, unescape2(&s, 0),0));
1946*cf5a6c84SAndroid Build Coastguard Worker         ii = s-str+1;
1947*cf5a6c84SAndroid Build Coastguard Worker 
1948*cf5a6c84SAndroid Build Coastguard Worker         continue;
1949*cf5a6c84SAndroid Build Coastguard Worker       } else if (cc=='"' && !(qq&1)) {
1950*cf5a6c84SAndroid Build Coastguard Worker         qq++;
1951*cf5a6c84SAndroid Build Coastguard Worker 
1952*cf5a6c84SAndroid Build Coastguard Worker         continue;
1953*cf5a6c84SAndroid Build Coastguard Worker       } else if (cc == '{') {
1954*cf5a6c84SAndroid Build Coastguard Worker 
1955*cf5a6c84SAndroid Build Coastguard Worker         // Skip escapes to find }, parse_word() guarantees ${} terminates
1956*cf5a6c84SAndroid Build Coastguard Worker         for (cc = *++ss; str[ii] != '}'; ii++) if (str[ii]=='\\') ii++;
1957*cf5a6c84SAndroid Build Coastguard Worker         ii++;
1958*cf5a6c84SAndroid Build Coastguard Worker 
1959*cf5a6c84SAndroid Build Coastguard Worker         if (cc == '}') ifs = (void *)1;
1960*cf5a6c84SAndroid Build Coastguard Worker         else if (strchr("#!", cc)) ss++;
1961*cf5a6c84SAndroid Build Coastguard Worker         if (!(jj = varend(ss)-ss)) while (isdigit(ss[jj])) jj++;
1962*cf5a6c84SAndroid Build Coastguard Worker         if (!jj && strchr("#$_*", *ss)) jj++;
1963*cf5a6c84SAndroid Build Coastguard Worker         // parameter or operator? Maybe not a prefix: ${#-} vs ${#-x}
1964*cf5a6c84SAndroid Build Coastguard Worker         if (!jj && strchr("-?@", *ss)) if (ss[++jj]!='}' && ss[-1]!='{') ss--;
1965*cf5a6c84SAndroid Build Coastguard Worker         slice = ss+jj;        // start of :operation
1966*cf5a6c84SAndroid Build Coastguard Worker 
1967*cf5a6c84SAndroid Build Coastguard Worker         if (!jj) {
1968*cf5a6c84SAndroid Build Coastguard Worker           // literal ${#} or ${!} wasn't a prefix
1969*cf5a6c84SAndroid Build Coastguard Worker           if (strchr("#!", cc)) ifs = getvar_special(--ss, 1, &kk, delete);
1970*cf5a6c84SAndroid Build Coastguard Worker           else ifs = (void *)1;  // unrecognized char ala ${~}
1971*cf5a6c84SAndroid Build Coastguard Worker         } else if (ss[-1]=='{'); // not prefix, fall through
1972*cf5a6c84SAndroid Build Coastguard Worker         else if (cc == '#') {  // TODO ${#x[@]}
1973*cf5a6c84SAndroid Build Coastguard Worker           dd = !!strchr("@*", *ss);  // For ${#@} or ${#*} do normal ${#}
1974*cf5a6c84SAndroid Build Coastguard Worker           if (!(ifs = getvar_special(ss-dd, jj, &kk, delete))) {
1975*cf5a6c84SAndroid Build Coastguard Worker             if (TT.options&OPT_u) goto barf;
1976*cf5a6c84SAndroid Build Coastguard Worker             ifs = "";
1977*cf5a6c84SAndroid Build Coastguard Worker           }
1978*cf5a6c84SAndroid Build Coastguard Worker           if (!dd) push_arg(delete, ifs = xmprintf("%zu", strlen(ifs)));
1979*cf5a6c84SAndroid Build Coastguard Worker         // ${!@} ${!@Q} ${!x} ${!x@} ${!x@Q} ${!x#} ${!x[} ${!x[*]}
1980*cf5a6c84SAndroid Build Coastguard Worker         } else if (cc == '!') {  // TODO: ${var[@]} array
1981*cf5a6c84SAndroid Build Coastguard Worker 
1982*cf5a6c84SAndroid Build Coastguard Worker           // special case: normal varname followed by @} or *} = prefix list
1983*cf5a6c84SAndroid Build Coastguard Worker           if (ss[jj] == '*' || (ss[jj] == '@' && !isalpha(ss[jj+1]))) {
1984*cf5a6c84SAndroid Build Coastguard Worker             struct sh_vars **vv = visible_vars();
1985*cf5a6c84SAndroid Build Coastguard Worker 
1986*cf5a6c84SAndroid Build Coastguard Worker             for (slice++, kk = 0; vv[kk]; kk++) {
1987*cf5a6c84SAndroid Build Coastguard Worker               if (vv[kk]->flags&VAR_WHITEOUT) continue;
1988*cf5a6c84SAndroid Build Coastguard Worker               if (!strncmp(s = vv[kk]->str, ss, jj))
1989*cf5a6c84SAndroid Build Coastguard Worker                 arg_add(&aa, push_arg(delete, s = xstrndup(s, stridx(s, '='))));
1990*cf5a6c84SAndroid Build Coastguard Worker             }
1991*cf5a6c84SAndroid Build Coastguard Worker             if (aa.c) push_arg(delete, aa.v);
1992*cf5a6c84SAndroid Build Coastguard Worker             free(vv);
1993*cf5a6c84SAndroid Build Coastguard Worker 
1994*cf5a6c84SAndroid Build Coastguard Worker           // else dereference to get new varname, discarding if none, check err
1995*cf5a6c84SAndroid Build Coastguard Worker           } else {
1996*cf5a6c84SAndroid Build Coastguard Worker             // First expansion
1997*cf5a6c84SAndroid Build Coastguard Worker             if (strchr("@*", *ss)) { // special case ${!*}/${!@}
1998*cf5a6c84SAndroid Build Coastguard Worker               expand_arg_nobrace(&aa, "\"$*\"", NO_PATH|NO_SPLIT, delete, 0, 0);
1999*cf5a6c84SAndroid Build Coastguard Worker               ifs = *aa.v;
2000*cf5a6c84SAndroid Build Coastguard Worker               free(aa.v);
2001*cf5a6c84SAndroid Build Coastguard Worker               memset(&aa, 0, sizeof(aa));
2002*cf5a6c84SAndroid Build Coastguard Worker               jj = 1;
2003*cf5a6c84SAndroid Build Coastguard Worker             } else ifs = getvar_special(ss, jj, &jj, delete);
2004*cf5a6c84SAndroid Build Coastguard Worker             slice = ss+jj;
2005*cf5a6c84SAndroid Build Coastguard Worker 
2006*cf5a6c84SAndroid Build Coastguard Worker             // Second expansion
2007*cf5a6c84SAndroid Build Coastguard Worker             if (!jj) ifs = (void *)1;
2008*cf5a6c84SAndroid Build Coastguard Worker             else if (ifs && *(ss = ifs)) {
2009*cf5a6c84SAndroid Build Coastguard Worker               if (strchr("@*", cc)) {
2010*cf5a6c84SAndroid Build Coastguard Worker                 aa.c = TT.ff->arg.c-1;
2011*cf5a6c84SAndroid Build Coastguard Worker                 aa.v = TT.ff->arg.v+1;
2012*cf5a6c84SAndroid Build Coastguard Worker                 jj = 1;
2013*cf5a6c84SAndroid Build Coastguard Worker               } else ifs = getvar_special(ifs, strlen(ifs), &jj, delete);
2014*cf5a6c84SAndroid Build Coastguard Worker               if (ss && ss[jj]) {
2015*cf5a6c84SAndroid Build Coastguard Worker                 ifs = (void *)1;
2016*cf5a6c84SAndroid Build Coastguard Worker                 slice = ss+strlen(ss);
2017*cf5a6c84SAndroid Build Coastguard Worker               }
2018*cf5a6c84SAndroid Build Coastguard Worker             }
2019*cf5a6c84SAndroid Build Coastguard Worker           }
2020*cf5a6c84SAndroid Build Coastguard Worker         }
2021*cf5a6c84SAndroid Build Coastguard Worker 
2022*cf5a6c84SAndroid Build Coastguard Worker         // Substitution error?
2023*cf5a6c84SAndroid Build Coastguard Worker         if (ifs == (void *)1) {
2024*cf5a6c84SAndroid Build Coastguard Worker barf:
2025*cf5a6c84SAndroid Build Coastguard Worker           if (!(((unsigned long)ifs)>>1)) ifs = "bad substitution";
2026*cf5a6c84SAndroid Build Coastguard Worker           error_msg("%.*s: %s", (int)(slice-ss), ss, ifs);
2027*cf5a6c84SAndroid Build Coastguard Worker           goto fail;
2028*cf5a6c84SAndroid Build Coastguard Worker         }
2029*cf5a6c84SAndroid Build Coastguard Worker       } else jj = 1;
2030*cf5a6c84SAndroid Build Coastguard Worker 
2031*cf5a6c84SAndroid Build Coastguard Worker       // Resolve unprefixed variables
2032*cf5a6c84SAndroid Build Coastguard Worker       if (strchr("{$", ss[-1])) {
2033*cf5a6c84SAndroid Build Coastguard Worker         if (strchr("@*", cc)) {
2034*cf5a6c84SAndroid Build Coastguard Worker           aa.c = TT.ff->arg.c-1;
2035*cf5a6c84SAndroid Build Coastguard Worker           aa.v = TT.ff->arg.v+1;
2036*cf5a6c84SAndroid Build Coastguard Worker         } else {
2037*cf5a6c84SAndroid Build Coastguard Worker           ifs = getvar_special(ss, jj, &jj, delete);
2038*cf5a6c84SAndroid Build Coastguard Worker           if (!ifs && (TT.options&OPT_u)) goto barf;
2039*cf5a6c84SAndroid Build Coastguard Worker           if (!jj) {
2040*cf5a6c84SAndroid Build Coastguard Worker             if (ss[-1] == '{') goto barf;
2041*cf5a6c84SAndroid Build Coastguard Worker             new[oo++] = '$';
2042*cf5a6c84SAndroid Build Coastguard Worker             ii--;
2043*cf5a6c84SAndroid Build Coastguard Worker             continue;
2044*cf5a6c84SAndroid Build Coastguard Worker           } else if (ss[-1] != '{') ii += jj-1;
2045*cf5a6c84SAndroid Build Coastguard Worker         }
2046*cf5a6c84SAndroid Build Coastguard Worker       }
2047*cf5a6c84SAndroid Build Coastguard Worker     }
2048*cf5a6c84SAndroid Build Coastguard Worker 
2049*cf5a6c84SAndroid Build Coastguard Worker     // combine before/ifs/after sections & split words on $IFS in ifs
2050*cf5a6c84SAndroid Build Coastguard Worker     // keep oo bytes of str before (already parsed)
2051*cf5a6c84SAndroid Build Coastguard Worker     // insert ifs (active for wildcards+splitting)
2052*cf5a6c84SAndroid Build Coastguard Worker     // keep str+ii after (still to parse)
2053*cf5a6c84SAndroid Build Coastguard Worker 
2054*cf5a6c84SAndroid Build Coastguard Worker     // Fetch separator to glue string back together with
2055*cf5a6c84SAndroid Build Coastguard Worker     *sep = 0;
2056*cf5a6c84SAndroid Build Coastguard Worker     if (((qq&1) && cc=='*') || (flags&NO_SPLIT)) {
2057*cf5a6c84SAndroid Build Coastguard Worker       unsigned wc;
2058*cf5a6c84SAndroid Build Coastguard Worker 
2059*cf5a6c84SAndroid Build Coastguard Worker       nosplit++;
2060*cf5a6c84SAndroid Build Coastguard Worker       if (flags&SEMI_IFS) strcpy(sep, " ");
2061*cf5a6c84SAndroid Build Coastguard Worker // TODO what if separator is bigger? Need to grab 1 column of combining chars
2062*cf5a6c84SAndroid Build Coastguard Worker       else if (0<(dd = utf8towc(&wc, TT.ff->ifs, 4)))
2063*cf5a6c84SAndroid Build Coastguard Worker         sprintf(sep, "%.*s", dd, TT.ff->ifs);
2064*cf5a6c84SAndroid Build Coastguard Worker     }
2065*cf5a6c84SAndroid Build Coastguard Worker 
2066*cf5a6c84SAndroid Build Coastguard Worker     // when aa proceed through entries until NULL, else process ifs once
2067*cf5a6c84SAndroid Build Coastguard Worker     mm = yy = 0;
2068*cf5a6c84SAndroid Build Coastguard Worker     do {
2069*cf5a6c84SAndroid Build Coastguard Worker       // get next argument
2070*cf5a6c84SAndroid Build Coastguard Worker       if (aa.c) ifs = aa.v[mm++] ? : "";
2071*cf5a6c84SAndroid Build Coastguard Worker 
2072*cf5a6c84SAndroid Build Coastguard Worker       // Are we performing surgery on this argument?
2073*cf5a6c84SAndroid Build Coastguard Worker       if (slice && *slice != '}') {
2074*cf5a6c84SAndroid Build Coastguard Worker         dd = slice[xx = (*slice == ':')];
2075*cf5a6c84SAndroid Build Coastguard Worker         if (!ifs || (xx && !*ifs)) {
2076*cf5a6c84SAndroid Build Coastguard Worker           if (strchr("-?=", dd)) { // - use default = assign default ? error
2077*cf5a6c84SAndroid Build Coastguard Worker             push_arg(delete, ifs = slashcopy(slice+xx+1, "}", 0));
2078*cf5a6c84SAndroid Build Coastguard Worker             if (dd == '?' || (dd == '=' &&
2079*cf5a6c84SAndroid Build Coastguard Worker               !(setvar(s = xmprintf("%.*s=%s", (int)(slice-ss), ss, ifs)))))
2080*cf5a6c84SAndroid Build Coastguard Worker                 goto barf; // TODO ? exits past "source" boundary
2081*cf5a6c84SAndroid Build Coastguard Worker           }
2082*cf5a6c84SAndroid Build Coastguard Worker         } else if (dd == '-'); // NOP when ifs not empty
2083*cf5a6c84SAndroid Build Coastguard Worker         // use alternate value
2084*cf5a6c84SAndroid Build Coastguard Worker         else if (dd == '+')
2085*cf5a6c84SAndroid Build Coastguard Worker           push_arg(delete, ifs = slashcopy(slice+xx+1, "}", 0));
2086*cf5a6c84SAndroid Build Coastguard Worker         else if (xx) { // ${x::}
2087*cf5a6c84SAndroid Build Coastguard Worker           long long la = 0, lb = LLONG_MAX, lc = 1;
2088*cf5a6c84SAndroid Build Coastguard Worker 
2089*cf5a6c84SAndroid Build Coastguard Worker           ss = ++slice;
2090*cf5a6c84SAndroid Build Coastguard Worker           nospace(&ss);
2091*cf5a6c84SAndroid Build Coastguard Worker           if ((*ss==':' ? 1 : (lc = recalculate(&la, &ss, 0))) && *ss == ':') {
2092*cf5a6c84SAndroid Build Coastguard Worker             ss++;
2093*cf5a6c84SAndroid Build Coastguard Worker             if (**nospace(&ss)=='}') lb = 0;
2094*cf5a6c84SAndroid Build Coastguard Worker             else lc = recalculate(&lb, &ss, 0);
2095*cf5a6c84SAndroid Build Coastguard Worker           }
2096*cf5a6c84SAndroid Build Coastguard Worker           if (!lc || *ss != '}') {
2097*cf5a6c84SAndroid Build Coastguard Worker             // Find ${blah} context for error message
2098*cf5a6c84SAndroid Build Coastguard Worker             while (*slice!='$') slice--;
2099*cf5a6c84SAndroid Build Coastguard Worker             error_msg("bad %.*s @ %ld", (int)(strchr(ss, '}')+1-slice), slice,
2100*cf5a6c84SAndroid Build Coastguard Worker               (long)(ss-slice));
2101*cf5a6c84SAndroid Build Coastguard Worker             goto fail;
2102*cf5a6c84SAndroid Build Coastguard Worker           }
2103*cf5a6c84SAndroid Build Coastguard Worker 
2104*cf5a6c84SAndroid Build Coastguard Worker           // This isn't quite what bash does, but close enough.
2105*cf5a6c84SAndroid Build Coastguard Worker           if (!(lc = aa.c)) lc = strlen(ifs);
2106*cf5a6c84SAndroid Build Coastguard Worker           else if (!la && !yy && strchr("@*", *slice)) {
2107*cf5a6c84SAndroid Build Coastguard Worker             aa.v--; // ${*:0} shows $0 even though default is 1-indexed
2108*cf5a6c84SAndroid Build Coastguard Worker             aa.c++;
2109*cf5a6c84SAndroid Build Coastguard Worker             yy++;
2110*cf5a6c84SAndroid Build Coastguard Worker           }
2111*cf5a6c84SAndroid Build Coastguard Worker           if (la<0 && (la += lc)<0) continue;
2112*cf5a6c84SAndroid Build Coastguard Worker           if (lb<0) lb = lc+lb-la;
2113*cf5a6c84SAndroid Build Coastguard Worker           if (aa.c) {
2114*cf5a6c84SAndroid Build Coastguard Worker             if (mm<la || mm>=la+lb) continue;
2115*cf5a6c84SAndroid Build Coastguard Worker           } else if (la>=lc || lb<0) ifs = "";
2116*cf5a6c84SAndroid Build Coastguard Worker           else if (la+lb>=lc) ifs += la;
2117*cf5a6c84SAndroid Build Coastguard Worker           else if (!*delete || ifs != (*delete)->arg)
2118*cf5a6c84SAndroid Build Coastguard Worker             push_arg(delete, ifs = xmprintf("%.*s", (int)lb, ifs+la));
2119*cf5a6c84SAndroid Build Coastguard Worker           else {
2120*cf5a6c84SAndroid Build Coastguard Worker             for (dd = 0; dd<lb ; dd++) if (!(ifs[dd] = ifs[dd+la])) break;
2121*cf5a6c84SAndroid Build Coastguard Worker             ifs[dd] = 0;
2122*cf5a6c84SAndroid Build Coastguard Worker           }
2123*cf5a6c84SAndroid Build Coastguard Worker         } else if (strchr("#%^,", *slice)) {
2124*cf5a6c84SAndroid Build Coastguard Worker           struct sh_arg wild = {0};
2125*cf5a6c84SAndroid Build Coastguard Worker           char buf[8];
2126*cf5a6c84SAndroid Build Coastguard Worker 
2127*cf5a6c84SAndroid Build Coastguard Worker           s = slashcopy(slice+(xx = slice[1]==*slice)+1, "}", &wild);
2128*cf5a6c84SAndroid Build Coastguard Worker 
2129*cf5a6c84SAndroid Build Coastguard Worker           // ${x^pat} ${x^^pat} uppercase ${x,} ${x,,} lowercase (no pat = ?)
2130*cf5a6c84SAndroid Build Coastguard Worker           if (strchr("^,", *slice)) {
2131*cf5a6c84SAndroid Build Coastguard Worker             for (ss = ifs; *ss; ss += dd) {
2132*cf5a6c84SAndroid Build Coastguard Worker               dd = getutf8(ss, 4, &jj);
2133*cf5a6c84SAndroid Build Coastguard Worker               if (!*s || 0<wildcard_match(ss, s, &wild, WILD_ANY)) {
2134*cf5a6c84SAndroid Build Coastguard Worker                 ll = ((*slice=='^') ? towupper : towlower)(jj);
2135*cf5a6c84SAndroid Build Coastguard Worker 
2136*cf5a6c84SAndroid Build Coastguard Worker                 // Of COURSE unicode case switch can change utf8 encoding length
2137*cf5a6c84SAndroid Build Coastguard Worker                 // Lower case U+0069 becomes u+0130 in turkish.
2138*cf5a6c84SAndroid Build Coastguard Worker                 // Greek U+0390 becomes 3 characters TODO test this
2139*cf5a6c84SAndroid Build Coastguard Worker                 if (ll != jj) {
2140*cf5a6c84SAndroid Build Coastguard Worker                   yy = ss-ifs;
2141*cf5a6c84SAndroid Build Coastguard Worker                   if (!*delete || (*delete)->arg!=ifs)
2142*cf5a6c84SAndroid Build Coastguard Worker                     push_arg(delete, ifs = xstrdup(ifs));
2143*cf5a6c84SAndroid Build Coastguard Worker                   if (dd != (ll = wctoutf8(buf, ll))) {
2144*cf5a6c84SAndroid Build Coastguard Worker                     if (dd<ll)
2145*cf5a6c84SAndroid Build Coastguard Worker                       ifs = (*delete)->arg = xrealloc(ifs, strlen(ifs)+1+dd-ll);
2146*cf5a6c84SAndroid Build Coastguard Worker                     memmove(ifs+yy+dd-ll, ifs+yy+ll, strlen(ifs+yy+ll)+1);
2147*cf5a6c84SAndroid Build Coastguard Worker                   }
2148*cf5a6c84SAndroid Build Coastguard Worker                   memcpy(ss = ifs+yy, buf, dd = ll);
2149*cf5a6c84SAndroid Build Coastguard Worker                 }
2150*cf5a6c84SAndroid Build Coastguard Worker               }
2151*cf5a6c84SAndroid Build Coastguard Worker               if (!xx) break;
2152*cf5a6c84SAndroid Build Coastguard Worker             }
2153*cf5a6c84SAndroid Build Coastguard Worker           // ${x#y} remove shortest prefix ${x##y} remove longest prefix
2154*cf5a6c84SAndroid Build Coastguard Worker           } else if (*slice=='#') {
2155*cf5a6c84SAndroid Build Coastguard Worker             if (0<(dd = wildcard_match(ifs, s, &wild, WILD_SHORT*!xx)))
2156*cf5a6c84SAndroid Build Coastguard Worker               ifs += dd;
2157*cf5a6c84SAndroid Build Coastguard Worker           // ${x%y} ${x%%y} suffix
2158*cf5a6c84SAndroid Build Coastguard Worker           } else if (*slice=='%') {
2159*cf5a6c84SAndroid Build Coastguard Worker             for (ss = ifs+strlen(ifs), yy = -1; ss>=ifs; ss--) {
2160*cf5a6c84SAndroid Build Coastguard Worker               if (0<(dd = wildcard_match(ss, s, &wild, WILD_SHORT*xx))&&!ss[dd])
2161*cf5a6c84SAndroid Build Coastguard Worker               {
2162*cf5a6c84SAndroid Build Coastguard Worker                 yy = ss-ifs;
2163*cf5a6c84SAndroid Build Coastguard Worker                 if (!xx) break;
2164*cf5a6c84SAndroid Build Coastguard Worker               }
2165*cf5a6c84SAndroid Build Coastguard Worker             }
2166*cf5a6c84SAndroid Build Coastguard Worker 
2167*cf5a6c84SAndroid Build Coastguard Worker             if (yy != -1) {
2168*cf5a6c84SAndroid Build Coastguard Worker               if (delete && *delete && (*delete)->arg==ifs) ifs[yy] = 0;
2169*cf5a6c84SAndroid Build Coastguard Worker               else push_arg(delete, ifs = xstrndup(ifs, yy));
2170*cf5a6c84SAndroid Build Coastguard Worker             }
2171*cf5a6c84SAndroid Build Coastguard Worker           }
2172*cf5a6c84SAndroid Build Coastguard Worker           free(s);
2173*cf5a6c84SAndroid Build Coastguard Worker           free(wild.v);
2174*cf5a6c84SAndroid Build Coastguard Worker 
2175*cf5a6c84SAndroid Build Coastguard Worker         // ${x/pat/sub} substitute ${x//pat/sub} global ${x/#pat/sub} begin
2176*cf5a6c84SAndroid Build Coastguard Worker         // ${x/%pat/sub} end ${x/pat} delete pat (x can be @ or *)
2177*cf5a6c84SAndroid Build Coastguard Worker         } else if (*slice=='/') {
2178*cf5a6c84SAndroid Build Coastguard Worker           struct sh_arg wild = {0};
2179*cf5a6c84SAndroid Build Coastguard Worker 
2180*cf5a6c84SAndroid Build Coastguard Worker           xx = !!strchr("/#%", slice[1]);
2181*cf5a6c84SAndroid Build Coastguard Worker           s = slashcopy(ss = slice+xx+1, "/}", &wild);
2182*cf5a6c84SAndroid Build Coastguard Worker           ss += (long)wild.v[wild.c];
2183*cf5a6c84SAndroid Build Coastguard Worker           ss = (*ss == '/') ? slashcopy(ss+1, "}", 0) : 0;
2184*cf5a6c84SAndroid Build Coastguard Worker           jj = ss ? strlen(ss) : 0;
2185*cf5a6c84SAndroid Build Coastguard Worker           for (ll = 0; ifs[ll];) {
2186*cf5a6c84SAndroid Build Coastguard Worker             // TODO nocasematch option
2187*cf5a6c84SAndroid Build Coastguard Worker             if (0<(dd = wildcard_match(ifs+ll, s, &wild, 0))) {
2188*cf5a6c84SAndroid Build Coastguard Worker               char *bird = 0;
2189*cf5a6c84SAndroid Build Coastguard Worker 
2190*cf5a6c84SAndroid Build Coastguard Worker               if (slice[1]=='%' && ifs[ll+dd]) {
2191*cf5a6c84SAndroid Build Coastguard Worker                 ll++;
2192*cf5a6c84SAndroid Build Coastguard Worker                 continue;
2193*cf5a6c84SAndroid Build Coastguard Worker               }
2194*cf5a6c84SAndroid Build Coastguard Worker               if (delete && *delete && (*delete)->arg==ifs) {
2195*cf5a6c84SAndroid Build Coastguard Worker                 if (jj==dd) memcpy(ifs+ll, ss, jj);
2196*cf5a6c84SAndroid Build Coastguard Worker                 else if (jj<dd) sprintf(ifs+ll, "%s%s", ss, ifs+ll+dd);
2197*cf5a6c84SAndroid Build Coastguard Worker                 else bird = ifs;
2198*cf5a6c84SAndroid Build Coastguard Worker               } else bird = (void *)1;
2199*cf5a6c84SAndroid Build Coastguard Worker               if (bird) {
2200*cf5a6c84SAndroid Build Coastguard Worker                 ifs = xmprintf("%.*s%s%s", ll, ifs, ss ? : "", ifs+ll+dd);
2201*cf5a6c84SAndroid Build Coastguard Worker                 if (bird != (void *)1) {
2202*cf5a6c84SAndroid Build Coastguard Worker                   free(bird);
2203*cf5a6c84SAndroid Build Coastguard Worker                   (*delete)->arg = ifs;
2204*cf5a6c84SAndroid Build Coastguard Worker                 } else push_arg(delete, ifs);
2205*cf5a6c84SAndroid Build Coastguard Worker               }
2206*cf5a6c84SAndroid Build Coastguard Worker               if (slice[1]!='/') break;
2207*cf5a6c84SAndroid Build Coastguard Worker             } else ll++;
2208*cf5a6c84SAndroid Build Coastguard Worker             if (slice[1]=='#') break;
2209*cf5a6c84SAndroid Build Coastguard Worker           }
2210*cf5a6c84SAndroid Build Coastguard Worker 
2211*cf5a6c84SAndroid Build Coastguard Worker // ${x@QEPAa} Q=$'blah' E=blah without the $'' wrap, P=expand as $PS1
2212*cf5a6c84SAndroid Build Coastguard Worker //   A=declare that recreates var a=attribute flags
2213*cf5a6c84SAndroid Build Coastguard Worker //   x can be @*
2214*cf5a6c84SAndroid Build Coastguard Worker //      } else if (*slice=='@') {
2215*cf5a6c84SAndroid Build Coastguard Worker 
2216*cf5a6c84SAndroid Build Coastguard Worker // TODO test x can be @ or *
2217*cf5a6c84SAndroid Build Coastguard Worker         } else {
2218*cf5a6c84SAndroid Build Coastguard Worker // TODO test ${-abc} as error
2219*cf5a6c84SAndroid Build Coastguard Worker           ifs = slice;
2220*cf5a6c84SAndroid Build Coastguard Worker           goto barf;
2221*cf5a6c84SAndroid Build Coastguard Worker         }
2222*cf5a6c84SAndroid Build Coastguard Worker 
2223*cf5a6c84SAndroid Build Coastguard Worker // TODO: $((a=42)) can change var, affect lifetime
2224*cf5a6c84SAndroid Build Coastguard Worker // must replace ifs AND any previous output arg[] within pointer strlen()
2225*cf5a6c84SAndroid Build Coastguard Worker // also x=;echo $x${x:=4}$x
2226*cf5a6c84SAndroid Build Coastguard Worker       }
2227*cf5a6c84SAndroid Build Coastguard Worker 
2228*cf5a6c84SAndroid Build Coastguard Worker       // Nothing left to do?
2229*cf5a6c84SAndroid Build Coastguard Worker       if (!ifs) break;
2230*cf5a6c84SAndroid Build Coastguard Worker       if (!*ifs && !qq) continue;
2231*cf5a6c84SAndroid Build Coastguard Worker 
2232*cf5a6c84SAndroid Build Coastguard Worker       // loop within current ifs checking region to split words
2233*cf5a6c84SAndroid Build Coastguard Worker       do {
2234*cf5a6c84SAndroid Build Coastguard Worker 
2235*cf5a6c84SAndroid Build Coastguard Worker         // find end of (split) word
2236*cf5a6c84SAndroid Build Coastguard Worker         if ((qq&1) || nosplit) ss = ifs+strlen(ifs);
2237*cf5a6c84SAndroid Build Coastguard Worker         else for (ss = ifs; *ss; ss += kk)
2238*cf5a6c84SAndroid Build Coastguard Worker           if (utf8chr(ss, TT.ff->ifs, &kk)) break;
2239*cf5a6c84SAndroid Build Coastguard Worker 
2240*cf5a6c84SAndroid Build Coastguard Worker         // when no prefix, not splitting, no suffix: use existing memory
2241*cf5a6c84SAndroid Build Coastguard Worker         if (!oo && !*ss && !((mm==aa.c) ? str[ii] : nosplit)) {
2242*cf5a6c84SAndroid Build Coastguard Worker           if (qq || ss!=ifs) {
2243*cf5a6c84SAndroid Build Coastguard Worker             if (!(flags&NO_PATH))
2244*cf5a6c84SAndroid Build Coastguard Worker               for (jj = 0; ifs[jj]; jj++) collect_wildcards(ifs, jj, ant);
2245*cf5a6c84SAndroid Build Coastguard Worker             wildcard_add_files(arg, ifs, &deck, delete);
2246*cf5a6c84SAndroid Build Coastguard Worker           }
2247*cf5a6c84SAndroid Build Coastguard Worker           continue;
2248*cf5a6c84SAndroid Build Coastguard Worker         }
2249*cf5a6c84SAndroid Build Coastguard Worker 
2250*cf5a6c84SAndroid Build Coastguard Worker         // resize allocation and copy next chunk of IFS-free data
2251*cf5a6c84SAndroid Build Coastguard Worker         jj = (mm == aa.c) && !*ss;
2252*cf5a6c84SAndroid Build Coastguard Worker         new = xrealloc(new, oo + (ss-ifs) + ((nosplit&!jj) ? strlen(sep) : 0) +
2253*cf5a6c84SAndroid Build Coastguard Worker                        (jj ? strlen(str+ii) : 0) + 1);
2254*cf5a6c84SAndroid Build Coastguard Worker         dd = sprintf(new + oo, "%.*s%s", (int)(ss-ifs), ifs,
2255*cf5a6c84SAndroid Build Coastguard Worker           (nosplit&!jj) ? sep : "");
2256*cf5a6c84SAndroid Build Coastguard Worker         if (flags&NO_PATH) oo += dd;
2257*cf5a6c84SAndroid Build Coastguard Worker         else while (dd--) collect_wildcards(new, oo++, ant);
2258*cf5a6c84SAndroid Build Coastguard Worker         if (jj) break;
2259*cf5a6c84SAndroid Build Coastguard Worker 
2260*cf5a6c84SAndroid Build Coastguard Worker         // If splitting, keep quoted, non-blank, or non-whitespace separator
2261*cf5a6c84SAndroid Build Coastguard Worker         if (!nosplit) {
2262*cf5a6c84SAndroid Build Coastguard Worker           if (qq || *new || *ss) {
2263*cf5a6c84SAndroid Build Coastguard Worker             push_arg(delete, new = xrealloc(new, strlen(new)+1));
2264*cf5a6c84SAndroid Build Coastguard Worker             wildcard_add_files(arg, new, &deck, delete);
2265*cf5a6c84SAndroid Build Coastguard Worker             new = xstrdup(str+ii);
2266*cf5a6c84SAndroid Build Coastguard Worker           }
2267*cf5a6c84SAndroid Build Coastguard Worker           qq &= 1;
2268*cf5a6c84SAndroid Build Coastguard Worker           oo = 0;
2269*cf5a6c84SAndroid Build Coastguard Worker         }
2270*cf5a6c84SAndroid Build Coastguard Worker 
2271*cf5a6c84SAndroid Build Coastguard Worker         // Skip trailing seperator (combining whitespace)
2272*cf5a6c84SAndroid Build Coastguard Worker         kk = 0;
2273*cf5a6c84SAndroid Build Coastguard Worker         while ((jj = utf8chr(ss, TT.ff->ifs, &ll))) {
2274*cf5a6c84SAndroid Build Coastguard Worker           if (!iswspace(jj) && kk++) break;
2275*cf5a6c84SAndroid Build Coastguard Worker           ss += ll;
2276*cf5a6c84SAndroid Build Coastguard Worker         }
2277*cf5a6c84SAndroid Build Coastguard Worker       } while (*(ifs = ss));
2278*cf5a6c84SAndroid Build Coastguard Worker     } while (!(mm == aa.c));
2279*cf5a6c84SAndroid Build Coastguard Worker   }
2280*cf5a6c84SAndroid Build Coastguard Worker 
2281*cf5a6c84SAndroid Build Coastguard Worker // TODO globbing * ? [] +() happens after variable resolution
2282*cf5a6c84SAndroid Build Coastguard Worker 
2283*cf5a6c84SAndroid Build Coastguard Worker // TODO test word splitting completely eliminating argument when no non-$IFS data left
2284*cf5a6c84SAndroid Build Coastguard Worker // wordexp keeps pattern when no matches
2285*cf5a6c84SAndroid Build Coastguard Worker 
2286*cf5a6c84SAndroid Build Coastguard Worker // TODO test NO_SPLIT cares about IFS, see also trailing \n
2287*cf5a6c84SAndroid Build Coastguard Worker 
2288*cf5a6c84SAndroid Build Coastguard Worker   // Record result.
2289*cf5a6c84SAndroid Build Coastguard Worker   if (*new || qq) {
2290*cf5a6c84SAndroid Build Coastguard Worker     if (str != new) push_arg(delete, new);
2291*cf5a6c84SAndroid Build Coastguard Worker     wildcard_add_files(arg, new, &deck, delete);
2292*cf5a6c84SAndroid Build Coastguard Worker     new = 0;
2293*cf5a6c84SAndroid Build Coastguard Worker   }
2294*cf5a6c84SAndroid Build Coastguard Worker 
2295*cf5a6c84SAndroid Build Coastguard Worker   // return success after freeing
2296*cf5a6c84SAndroid Build Coastguard Worker   arg = 0;
2297*cf5a6c84SAndroid Build Coastguard Worker 
2298*cf5a6c84SAndroid Build Coastguard Worker fail:
2299*cf5a6c84SAndroid Build Coastguard Worker   if (str != new) free(new);
2300*cf5a6c84SAndroid Build Coastguard Worker   free(deck.v);
2301*cf5a6c84SAndroid Build Coastguard Worker   if (ant!=&deck && ant->v) collect_wildcards("", 0, ant);
2302*cf5a6c84SAndroid Build Coastguard Worker   if (measure) *measure = --ii;
2303*cf5a6c84SAndroid Build Coastguard Worker 
2304*cf5a6c84SAndroid Build Coastguard Worker   return !!arg;
2305*cf5a6c84SAndroid Build Coastguard Worker }
2306*cf5a6c84SAndroid Build Coastguard Worker 
2307*cf5a6c84SAndroid Build Coastguard Worker struct sh_brace {
2308*cf5a6c84SAndroid Build Coastguard Worker   struct sh_brace *next, *prev, *stack;
2309*cf5a6c84SAndroid Build Coastguard Worker   int active, cnt, idx, commas[];
2310*cf5a6c84SAndroid Build Coastguard Worker };
2311*cf5a6c84SAndroid Build Coastguard Worker 
brace_end(struct sh_brace * bb)2312*cf5a6c84SAndroid Build Coastguard Worker static int brace_end(struct sh_brace *bb)
2313*cf5a6c84SAndroid Build Coastguard Worker {
2314*cf5a6c84SAndroid Build Coastguard Worker   return bb->commas[(bb->cnt<0 ? 0 : bb->cnt)+1];
2315*cf5a6c84SAndroid Build Coastguard Worker }
2316*cf5a6c84SAndroid Build Coastguard Worker 
2317*cf5a6c84SAndroid Build Coastguard Worker // expand braces (ala {a,b,c}) and call expand_arg_nobrace() each permutation
expand_arg(struct sh_arg * arg,char * old,unsigned flags,struct arg_list ** delete)2318*cf5a6c84SAndroid Build Coastguard Worker static int expand_arg(struct sh_arg *arg, char *old, unsigned flags,
2319*cf5a6c84SAndroid Build Coastguard Worker   struct arg_list **delete)
2320*cf5a6c84SAndroid Build Coastguard Worker {
2321*cf5a6c84SAndroid Build Coastguard Worker   struct sh_brace *bb = 0, *blist = 0, *bstk, *bnext;
2322*cf5a6c84SAndroid Build Coastguard Worker   int i, j, k, x;
2323*cf5a6c84SAndroid Build Coastguard Worker   char *s, *ss;
2324*cf5a6c84SAndroid Build Coastguard Worker 
2325*cf5a6c84SAndroid Build Coastguard Worker   // collect brace spans
2326*cf5a6c84SAndroid Build Coastguard Worker   if ((TT.options&OPT_B) && !(flags&NO_BRACE)) for (i = 0; ; i++) {
2327*cf5a6c84SAndroid Build Coastguard Worker     // skip quoted/escaped text
2328*cf5a6c84SAndroid Build Coastguard Worker     while ((s = parse_word(old+i, 1)) != old+i) i += s-(old+i);
2329*cf5a6c84SAndroid Build Coastguard Worker 
2330*cf5a6c84SAndroid Build Coastguard Worker     // start a new span
2331*cf5a6c84SAndroid Build Coastguard Worker     if (old[i] == '{') {
2332*cf5a6c84SAndroid Build Coastguard Worker       dlist_add_nomalloc((void *)&blist,
2333*cf5a6c84SAndroid Build Coastguard Worker         (void *)(bb = xzalloc(sizeof(struct sh_brace)+34*4)));
2334*cf5a6c84SAndroid Build Coastguard Worker       bb->commas[0] = i;
2335*cf5a6c84SAndroid Build Coastguard Worker     // end of string: abort unfinished spans and end loop
2336*cf5a6c84SAndroid Build Coastguard Worker     } else if (!old[i]) {
2337*cf5a6c84SAndroid Build Coastguard Worker       for (bb = blist; bb;) {
2338*cf5a6c84SAndroid Build Coastguard Worker         if (!bb->active) {
2339*cf5a6c84SAndroid Build Coastguard Worker           if (bb==blist) {
2340*cf5a6c84SAndroid Build Coastguard Worker             dlist_pop(&blist);
2341*cf5a6c84SAndroid Build Coastguard Worker             bb = blist;
2342*cf5a6c84SAndroid Build Coastguard Worker           } else dlist_pop(&bb);
2343*cf5a6c84SAndroid Build Coastguard Worker         } else bb = (bb->next==blist) ? 0 : bb->next;
2344*cf5a6c84SAndroid Build Coastguard Worker       }
2345*cf5a6c84SAndroid Build Coastguard Worker       break;
2346*cf5a6c84SAndroid Build Coastguard Worker     // no active span?
2347*cf5a6c84SAndroid Build Coastguard Worker     } else if (!bb) continue;
2348*cf5a6c84SAndroid Build Coastguard Worker     // end current span
2349*cf5a6c84SAndroid Build Coastguard Worker     else if (old[i] == '}') {
2350*cf5a6c84SAndroid Build Coastguard Worker       bb->active = bb->commas[bb->cnt+1] = i;
2351*cf5a6c84SAndroid Build Coastguard Worker       // Is this a .. span?
2352*cf5a6c84SAndroid Build Coastguard Worker       j = 1+*bb->commas;
2353*cf5a6c84SAndroid Build Coastguard Worker       if (!bb->cnt && i-j>=4) {
2354*cf5a6c84SAndroid Build Coastguard Worker         // a..z span? Single digit numbers handled here too. TODO: utf8
2355*cf5a6c84SAndroid Build Coastguard Worker         if (old[j+1]=='.' && old[j+2]=='.') {
2356*cf5a6c84SAndroid Build Coastguard Worker           bb->commas[2] = old[j];
2357*cf5a6c84SAndroid Build Coastguard Worker           bb->commas[3] = old[j+3];
2358*cf5a6c84SAndroid Build Coastguard Worker           k = 0;
2359*cf5a6c84SAndroid Build Coastguard Worker           if (old[j+4]=='}' ||
2360*cf5a6c84SAndroid Build Coastguard Worker             (sscanf(old+j+4, "..%u}%n", bb->commas+4, &k) && k))
2361*cf5a6c84SAndroid Build Coastguard Worker               bb->cnt = -1;
2362*cf5a6c84SAndroid Build Coastguard Worker         }
2363*cf5a6c84SAndroid Build Coastguard Worker         // 3..11 numeric span?
2364*cf5a6c84SAndroid Build Coastguard Worker         if (!bb->cnt) {
2365*cf5a6c84SAndroid Build Coastguard Worker           for (k=0, j = 1+*bb->commas; k<3; k++, j += x)
2366*cf5a6c84SAndroid Build Coastguard Worker             if (!sscanf(old+j, "..%u%n"+2*!k, bb->commas+2+k, &x)) break;
2367*cf5a6c84SAndroid Build Coastguard Worker           if (old[j]=='}') bb->cnt = -2;
2368*cf5a6c84SAndroid Build Coastguard Worker         }
2369*cf5a6c84SAndroid Build Coastguard Worker         // Increment goes in the right direction by at least 1
2370*cf5a6c84SAndroid Build Coastguard Worker         if (bb->cnt) {
2371*cf5a6c84SAndroid Build Coastguard Worker           if (!bb->commas[4]) bb->commas[4] = 1;
2372*cf5a6c84SAndroid Build Coastguard Worker           if ((bb->commas[3]-bb->commas[2]>0) != (bb->commas[4]>0))
2373*cf5a6c84SAndroid Build Coastguard Worker             bb->commas[4] *= -1;
2374*cf5a6c84SAndroid Build Coastguard Worker         }
2375*cf5a6c84SAndroid Build Coastguard Worker       }
2376*cf5a6c84SAndroid Build Coastguard Worker       // discard commaless span that wasn't x..y
2377*cf5a6c84SAndroid Build Coastguard Worker       if (!bb->cnt) free(dlist_pop((blist==bb) ? &blist : &bb));
2378*cf5a6c84SAndroid Build Coastguard Worker       // Set bb to last unfinished brace (if any)
2379*cf5a6c84SAndroid Build Coastguard Worker       for (bb = blist ? blist->prev : 0; bb && bb->active;
2380*cf5a6c84SAndroid Build Coastguard Worker            bb = (bb==blist) ? 0 : bb->prev);
2381*cf5a6c84SAndroid Build Coastguard Worker     // add a comma to current span
2382*cf5a6c84SAndroid Build Coastguard Worker     } else if (old[i] == ',') {
2383*cf5a6c84SAndroid Build Coastguard Worker       if (bb->cnt && !(bb->cnt&31)) {
2384*cf5a6c84SAndroid Build Coastguard Worker         dlist_lpop(&blist);
2385*cf5a6c84SAndroid Build Coastguard Worker         dlist_add_nomalloc((void *)&blist,
2386*cf5a6c84SAndroid Build Coastguard Worker           (void *)(bb = xrealloc(bb, sizeof(struct sh_brace)+(bb->cnt+34)*4)));
2387*cf5a6c84SAndroid Build Coastguard Worker       }
2388*cf5a6c84SAndroid Build Coastguard Worker       bb->commas[++bb->cnt] = i;
2389*cf5a6c84SAndroid Build Coastguard Worker     }
2390*cf5a6c84SAndroid Build Coastguard Worker   }
2391*cf5a6c84SAndroid Build Coastguard Worker 
2392*cf5a6c84SAndroid Build Coastguard Worker // TODO NO_SPLIT with braces? (Collate with spaces?)
2393*cf5a6c84SAndroid Build Coastguard Worker   // If none, pass on verbatim
2394*cf5a6c84SAndroid Build Coastguard Worker   if (!blist) return expand_arg_nobrace(arg, old, flags, delete, 0, 0);
2395*cf5a6c84SAndroid Build Coastguard Worker 
2396*cf5a6c84SAndroid Build Coastguard Worker   // enclose entire range in top level brace.
2397*cf5a6c84SAndroid Build Coastguard Worker   (bstk = xzalloc(sizeof(struct sh_brace)+8))->commas[1] = strlen(old)+1;
2398*cf5a6c84SAndroid Build Coastguard Worker   bstk->commas[0] = -1;
2399*cf5a6c84SAndroid Build Coastguard Worker 
2400*cf5a6c84SAndroid Build Coastguard Worker   // loop through each combination
2401*cf5a6c84SAndroid Build Coastguard Worker   for (;;) {
2402*cf5a6c84SAndroid Build Coastguard Worker 
2403*cf5a6c84SAndroid Build Coastguard Worker     // Brace expansion can't be longer than original string. Keep start to {
2404*cf5a6c84SAndroid Build Coastguard Worker     s = ss = xmalloc(bstk->commas[1]);
2405*cf5a6c84SAndroid Build Coastguard Worker 
2406*cf5a6c84SAndroid Build Coastguard Worker     // Append output from active braces to string
2407*cf5a6c84SAndroid Build Coastguard Worker     for (bb = blist; bb; bb = (bnext == blist) ? 0 : bnext) {
2408*cf5a6c84SAndroid Build Coastguard Worker 
2409*cf5a6c84SAndroid Build Coastguard Worker       // If this brace already tip of stack, pop it. (We'll re-add in a moment.)
2410*cf5a6c84SAndroid Build Coastguard Worker       if (bstk == bb) bstk = bstk->stack;
2411*cf5a6c84SAndroid Build Coastguard Worker       // if bb is within bstk, save prefix text from bstk's "," to bb's "{"
2412*cf5a6c84SAndroid Build Coastguard Worker       if (brace_end(bstk)>bb->commas[0]) {
2413*cf5a6c84SAndroid Build Coastguard Worker         i = bstk->commas[bstk->idx]+1;
2414*cf5a6c84SAndroid Build Coastguard Worker         s = stpncpy(s, old+i, bb->commas[0]-i);
2415*cf5a6c84SAndroid Build Coastguard Worker       }
2416*cf5a6c84SAndroid Build Coastguard Worker       else bstk = bstk->stack; // bb past bstk so done with old bstk, pop it
2417*cf5a6c84SAndroid Build Coastguard Worker       // push self onto stack as active
2418*cf5a6c84SAndroid Build Coastguard Worker       bb->stack = bstk;
2419*cf5a6c84SAndroid Build Coastguard Worker       bb->active = 1;
2420*cf5a6c84SAndroid Build Coastguard Worker       bstk = bnext = bb;
2421*cf5a6c84SAndroid Build Coastguard Worker 
2422*cf5a6c84SAndroid Build Coastguard Worker       // Find next active range: skip inactive spans from earlier/later commas
2423*cf5a6c84SAndroid Build Coastguard Worker       while ((bnext = (bnext->next==blist) ? 0 : bnext->next)) {
2424*cf5a6c84SAndroid Build Coastguard Worker 
2425*cf5a6c84SAndroid Build Coastguard Worker         // past end of this brace (always true for a..b ranges)
2426*cf5a6c84SAndroid Build Coastguard Worker         if ((i = bnext->commas[0])>brace_end(bb)) break;
2427*cf5a6c84SAndroid Build Coastguard Worker 
2428*cf5a6c84SAndroid Build Coastguard Worker         // in this brace but not this section
2429*cf5a6c84SAndroid Build Coastguard Worker         if (i<bb->commas[bb->idx] || i>bb->commas[bb->idx+1]) {
2430*cf5a6c84SAndroid Build Coastguard Worker           bnext->active = 0;
2431*cf5a6c84SAndroid Build Coastguard Worker           bnext->stack = 0;
2432*cf5a6c84SAndroid Build Coastguard Worker 
2433*cf5a6c84SAndroid Build Coastguard Worker         // in this section
2434*cf5a6c84SAndroid Build Coastguard Worker         } else break;
2435*cf5a6c84SAndroid Build Coastguard Worker       }
2436*cf5a6c84SAndroid Build Coastguard Worker 
2437*cf5a6c84SAndroid Build Coastguard Worker       // is next span past this range?
2438*cf5a6c84SAndroid Build Coastguard Worker       if (!bnext || bb->cnt<0 || bnext->commas[0]>bb->commas[bb->idx+1]) {
2439*cf5a6c84SAndroid Build Coastguard Worker 
2440*cf5a6c84SAndroid Build Coastguard Worker         // output uninterrupted span
2441*cf5a6c84SAndroid Build Coastguard Worker         if (bb->cnt<0) {
2442*cf5a6c84SAndroid Build Coastguard Worker           k = bb->commas[2]+bb->commas[4]*bb->idx;
2443*cf5a6c84SAndroid Build Coastguard Worker           s += sprintf(s, (bb->cnt==-1) ? "\\%c"+!ispunct(k) : "%d", k);
2444*cf5a6c84SAndroid Build Coastguard Worker         } else {
2445*cf5a6c84SAndroid Build Coastguard Worker           i = bb->commas[bstk->idx]+1;
2446*cf5a6c84SAndroid Build Coastguard Worker           s = stpncpy(s, old+i, bb->commas[bb->idx+1]-i);
2447*cf5a6c84SAndroid Build Coastguard Worker         }
2448*cf5a6c84SAndroid Build Coastguard Worker 
2449*cf5a6c84SAndroid Build Coastguard Worker         // While not sibling, output tail and pop
2450*cf5a6c84SAndroid Build Coastguard Worker         while (!bnext || bnext->commas[0]>brace_end(bstk)) {
2451*cf5a6c84SAndroid Build Coastguard Worker           if (!(bb = bstk->stack)) break;
2452*cf5a6c84SAndroid Build Coastguard Worker           i = brace_end(bstk)+1; // start of span
2453*cf5a6c84SAndroid Build Coastguard Worker           j = bb->commas[bb->idx+1]; // enclosing comma span (can't be a..b)
2454*cf5a6c84SAndroid Build Coastguard Worker 
2455*cf5a6c84SAndroid Build Coastguard Worker           while (bnext) {
2456*cf5a6c84SAndroid Build Coastguard Worker             if (bnext->commas[0]<j) {
2457*cf5a6c84SAndroid Build Coastguard Worker               j = bnext->commas[0];// sibling
2458*cf5a6c84SAndroid Build Coastguard Worker               break;
2459*cf5a6c84SAndroid Build Coastguard Worker             } else if (brace_end(bb)>bnext->commas[0])
2460*cf5a6c84SAndroid Build Coastguard Worker               bnext = (bnext->next == blist) ? 0 : bnext->next;
2461*cf5a6c84SAndroid Build Coastguard Worker             else break;
2462*cf5a6c84SAndroid Build Coastguard Worker           }
2463*cf5a6c84SAndroid Build Coastguard Worker           s = stpncpy(s, old+i, j-i);
2464*cf5a6c84SAndroid Build Coastguard Worker 
2465*cf5a6c84SAndroid Build Coastguard Worker           // if next is sibling but parent _not_ a sibling, don't pop
2466*cf5a6c84SAndroid Build Coastguard Worker           if (bnext && bnext->commas[0]<brace_end(bb)) break;
2467*cf5a6c84SAndroid Build Coastguard Worker           bstk = bb;
2468*cf5a6c84SAndroid Build Coastguard Worker         }
2469*cf5a6c84SAndroid Build Coastguard Worker       }
2470*cf5a6c84SAndroid Build Coastguard Worker     }
2471*cf5a6c84SAndroid Build Coastguard Worker 
2472*cf5a6c84SAndroid Build Coastguard Worker     // Save result, aborting on expand error
2473*cf5a6c84SAndroid Build Coastguard Worker     if (expand_arg_nobrace(arg, push_arg(delete, ss), flags, delete, 0, 0)) {
2474*cf5a6c84SAndroid Build Coastguard Worker       llist_traverse(blist, free);
2475*cf5a6c84SAndroid Build Coastguard Worker 
2476*cf5a6c84SAndroid Build Coastguard Worker       return 1;
2477*cf5a6c84SAndroid Build Coastguard Worker     }
2478*cf5a6c84SAndroid Build Coastguard Worker 
2479*cf5a6c84SAndroid Build Coastguard Worker     // increment
2480*cf5a6c84SAndroid Build Coastguard Worker     for (bb = blist->prev; bb; bb = (bb == blist) ? 0 : bb->prev) {
2481*cf5a6c84SAndroid Build Coastguard Worker       if (!bb->stack) continue;
2482*cf5a6c84SAndroid Build Coastguard Worker       else if (bb->cnt<0) {
2483*cf5a6c84SAndroid Build Coastguard Worker         if (abs(bb->commas[2]-bb->commas[3]) < abs(++bb->idx*bb->commas[4]))
2484*cf5a6c84SAndroid Build Coastguard Worker           bb->idx = 0;
2485*cf5a6c84SAndroid Build Coastguard Worker         else break;
2486*cf5a6c84SAndroid Build Coastguard Worker       } else if (++bb->idx > bb->cnt) bb->idx = 0;
2487*cf5a6c84SAndroid Build Coastguard Worker       else break;
2488*cf5a6c84SAndroid Build Coastguard Worker     }
2489*cf5a6c84SAndroid Build Coastguard Worker 
2490*cf5a6c84SAndroid Build Coastguard Worker     // if increment went off left edge, done expanding
2491*cf5a6c84SAndroid Build Coastguard Worker     if (!bb) break;
2492*cf5a6c84SAndroid Build Coastguard Worker   }
2493*cf5a6c84SAndroid Build Coastguard Worker   llist_traverse(blist, free);
2494*cf5a6c84SAndroid Build Coastguard Worker 
2495*cf5a6c84SAndroid Build Coastguard Worker   return 0;
2496*cf5a6c84SAndroid Build Coastguard Worker }
2497*cf5a6c84SAndroid Build Coastguard Worker 
2498*cf5a6c84SAndroid Build Coastguard Worker // Expand exactly one arg, returning NULL on error.
expand_one_arg(char * new,unsigned flags)2499*cf5a6c84SAndroid Build Coastguard Worker static char *expand_one_arg(char *new, unsigned flags)
2500*cf5a6c84SAndroid Build Coastguard Worker {
2501*cf5a6c84SAndroid Build Coastguard Worker   struct arg_list *del = 0, *dd;
2502*cf5a6c84SAndroid Build Coastguard Worker   struct sh_arg arg = {0};
2503*cf5a6c84SAndroid Build Coastguard Worker   char *s = 0;
2504*cf5a6c84SAndroid Build Coastguard Worker 
2505*cf5a6c84SAndroid Build Coastguard Worker   // TODO: ${var:?error} here?
2506*cf5a6c84SAndroid Build Coastguard Worker   if (!expand_arg(&arg, new, flags|NO_PATH|NO_SPLIT, &del))
2507*cf5a6c84SAndroid Build Coastguard Worker     if (!(s = *arg.v) && (flags&(SEMI_IFS|NO_NULL))) s = "";
2508*cf5a6c84SAndroid Build Coastguard Worker 
2509*cf5a6c84SAndroid Build Coastguard Worker   // Free non-returned allocations.
2510*cf5a6c84SAndroid Build Coastguard Worker   while (del) {
2511*cf5a6c84SAndroid Build Coastguard Worker     dd = del->next;
2512*cf5a6c84SAndroid Build Coastguard Worker     if (del->arg != s) free(del->arg);
2513*cf5a6c84SAndroid Build Coastguard Worker     free(del);
2514*cf5a6c84SAndroid Build Coastguard Worker     del = dd;
2515*cf5a6c84SAndroid Build Coastguard Worker   }
2516*cf5a6c84SAndroid Build Coastguard Worker   free(arg.v);
2517*cf5a6c84SAndroid Build Coastguard Worker 
2518*cf5a6c84SAndroid Build Coastguard Worker   return s;
2519*cf5a6c84SAndroid Build Coastguard Worker }
2520*cf5a6c84SAndroid Build Coastguard Worker 
2521*cf5a6c84SAndroid Build Coastguard Worker // TODO |&
2522*cf5a6c84SAndroid Build Coastguard Worker 
2523*cf5a6c84SAndroid Build Coastguard Worker // Expand arguments and perform redirections. Return new process object with
2524*cf5a6c84SAndroid Build Coastguard Worker // expanded args. This can be called from command or block context.
expand_redir(struct sh_arg * arg,int skip,int * urd)2525*cf5a6c84SAndroid Build Coastguard Worker static struct sh_process *expand_redir(struct sh_arg *arg, int skip, int *urd)
2526*cf5a6c84SAndroid Build Coastguard Worker {
2527*cf5a6c84SAndroid Build Coastguard Worker   struct sh_process *pp;
2528*cf5a6c84SAndroid Build Coastguard Worker   char *s = s, *ss, *sss, *cv = 0;
2529*cf5a6c84SAndroid Build Coastguard Worker   int j, to, from, here = 0;
2530*cf5a6c84SAndroid Build Coastguard Worker 
2531*cf5a6c84SAndroid Build Coastguard Worker   TT.hfd = 10;
2532*cf5a6c84SAndroid Build Coastguard Worker   pp = xzalloc(sizeof(struct sh_process));
2533*cf5a6c84SAndroid Build Coastguard Worker   pp->urd = urd;
2534*cf5a6c84SAndroid Build Coastguard Worker   pp->raw = arg;
2535*cf5a6c84SAndroid Build Coastguard Worker 
2536*cf5a6c84SAndroid Build Coastguard Worker   // When redirecting, copy each displaced filehandle to restore it later.
2537*cf5a6c84SAndroid Build Coastguard Worker   // Expand arguments and perform redirections
2538*cf5a6c84SAndroid Build Coastguard Worker   for (j = skip; j<arg->c; j++) {
2539*cf5a6c84SAndroid Build Coastguard Worker     int saveclose = 0, bad = 0;
2540*cf5a6c84SAndroid Build Coastguard Worker 
2541*cf5a6c84SAndroid Build Coastguard Worker     if (!strcmp(s = arg->v[j], "!")) {
2542*cf5a6c84SAndroid Build Coastguard Worker       pp->flags ^= PFLAG_NOT;
2543*cf5a6c84SAndroid Build Coastguard Worker 
2544*cf5a6c84SAndroid Build Coastguard Worker       continue;
2545*cf5a6c84SAndroid Build Coastguard Worker     }
2546*cf5a6c84SAndroid Build Coastguard Worker 
2547*cf5a6c84SAndroid Build Coastguard Worker     // Handle <() >() redirectionss
2548*cf5a6c84SAndroid Build Coastguard Worker     if ((*s == '<' || *s == '>') && s[1] == '(') {
2549*cf5a6c84SAndroid Build Coastguard Worker       int new = pipe_subshell(s+2, strlen(s+2)-1, *s == '>');
2550*cf5a6c84SAndroid Build Coastguard Worker 
2551*cf5a6c84SAndroid Build Coastguard Worker       // Grab subshell data
2552*cf5a6c84SAndroid Build Coastguard Worker       if (new == -1) {
2553*cf5a6c84SAndroid Build Coastguard Worker         pp->exit = 1;
2554*cf5a6c84SAndroid Build Coastguard Worker 
2555*cf5a6c84SAndroid Build Coastguard Worker         return pp;
2556*cf5a6c84SAndroid Build Coastguard Worker       }
2557*cf5a6c84SAndroid Build Coastguard Worker       save_redirect(&pp->urd, -2, new);
2558*cf5a6c84SAndroid Build Coastguard Worker 
2559*cf5a6c84SAndroid Build Coastguard Worker       // bash uses /dev/fd/%d which requires /dev/fd to be a symlink to
2560*cf5a6c84SAndroid Build Coastguard Worker       // /proc/self/fd so we just produce that directly.
2561*cf5a6c84SAndroid Build Coastguard Worker       arg_add_del(&pp->arg, ss = xmprintf("/proc/self/fd/%d", new),&pp->delete);
2562*cf5a6c84SAndroid Build Coastguard Worker 
2563*cf5a6c84SAndroid Build Coastguard Worker       continue;
2564*cf5a6c84SAndroid Build Coastguard Worker     }
2565*cf5a6c84SAndroid Build Coastguard Worker 
2566*cf5a6c84SAndroid Build Coastguard Worker     // Is this a redirect? s = prefix, ss = operator
2567*cf5a6c84SAndroid Build Coastguard Worker     ss = skip_redir_prefix(s);
2568*cf5a6c84SAndroid Build Coastguard Worker     sss = ss + anystart(ss, (void *)redirectors);
2569*cf5a6c84SAndroid Build Coastguard Worker     if (ss == sss) {
2570*cf5a6c84SAndroid Build Coastguard Worker       // Nope: save/expand argument and loop
2571*cf5a6c84SAndroid Build Coastguard Worker       if (expand_arg(&pp->arg, s, 0, &pp->delete)) {
2572*cf5a6c84SAndroid Build Coastguard Worker         pp->exit = 1;
2573*cf5a6c84SAndroid Build Coastguard Worker 
2574*cf5a6c84SAndroid Build Coastguard Worker         return pp;
2575*cf5a6c84SAndroid Build Coastguard Worker       }
2576*cf5a6c84SAndroid Build Coastguard Worker       continue;
2577*cf5a6c84SAndroid Build Coastguard Worker     } else if (j+1 >= arg->c) {
2578*cf5a6c84SAndroid Build Coastguard Worker       // redirect needs one argument
2579*cf5a6c84SAndroid Build Coastguard Worker       s = "\\n";
2580*cf5a6c84SAndroid Build Coastguard Worker       break;
2581*cf5a6c84SAndroid Build Coastguard Worker     }
2582*cf5a6c84SAndroid Build Coastguard Worker     sss = arg->v[++j];
2583*cf5a6c84SAndroid Build Coastguard Worker 
2584*cf5a6c84SAndroid Build Coastguard Worker     // It's a redirect: for [to]<from s = start of [to], ss = <, sss = from
2585*cf5a6c84SAndroid Build Coastguard Worker     if (isdigit(*s) && ss-s>5) break;
2586*cf5a6c84SAndroid Build Coastguard Worker 
2587*cf5a6c84SAndroid Build Coastguard Worker     // expand arguments for everything but HERE docs
2588*cf5a6c84SAndroid Build Coastguard Worker     if (strncmp(ss, "<<", 2)) {
2589*cf5a6c84SAndroid Build Coastguard Worker       struct sh_arg tmp = {0};
2590*cf5a6c84SAndroid Build Coastguard Worker 
2591*cf5a6c84SAndroid Build Coastguard Worker       if (!expand_arg(&tmp, sss, 0, &pp->delete) && tmp.c == 1) sss = *tmp.v;
2592*cf5a6c84SAndroid Build Coastguard Worker       else {
2593*cf5a6c84SAndroid Build Coastguard Worker         if (tmp.c > 1) error_msg("%s: ambiguous redirect", sss);
2594*cf5a6c84SAndroid Build Coastguard Worker         s = 0;
2595*cf5a6c84SAndroid Build Coastguard Worker       }
2596*cf5a6c84SAndroid Build Coastguard Worker       free(tmp.v);
2597*cf5a6c84SAndroid Build Coastguard Worker       if (!s) break;
2598*cf5a6c84SAndroid Build Coastguard Worker     }
2599*cf5a6c84SAndroid Build Coastguard Worker 
2600*cf5a6c84SAndroid Build Coastguard Worker     // Parse the [fd] part of [fd]<name
2601*cf5a6c84SAndroid Build Coastguard Worker     to = *ss != '<';
2602*cf5a6c84SAndroid Build Coastguard Worker     if (isdigit(*s)) to = atoi(s);
2603*cf5a6c84SAndroid Build Coastguard Worker     else if (*s == '{') {
2604*cf5a6c84SAndroid Build Coastguard Worker       if (*varend(s+1) != '}') break;
2605*cf5a6c84SAndroid Build Coastguard Worker       // when we close a filehandle, we _read_ from {var}, not write to it
2606*cf5a6c84SAndroid Build Coastguard Worker       if ((!strcmp(ss, "<&") || !strcmp(ss, ">&")) && !strcmp(sss, "-")) {
2607*cf5a6c84SAndroid Build Coastguard Worker         if (!(ss = getvar(s+1))) break;
2608*cf5a6c84SAndroid Build Coastguard Worker         to = atoi(ss); // TODO trailing garbage?
2609*cf5a6c84SAndroid Build Coastguard Worker         if (save_redirect(&pp->urd, -1, to)) break;
2610*cf5a6c84SAndroid Build Coastguard Worker         close(to);
2611*cf5a6c84SAndroid Build Coastguard Worker 
2612*cf5a6c84SAndroid Build Coastguard Worker         continue;
2613*cf5a6c84SAndroid Build Coastguard Worker       // record high file descriptor in {to}<from environment variable
2614*cf5a6c84SAndroid Build Coastguard Worker       } else {
2615*cf5a6c84SAndroid Build Coastguard Worker         // we don't save this, it goes in the env var and user can close it.
2616*cf5a6c84SAndroid Build Coastguard Worker         if (-1 == (to = next_hfd())) break;
2617*cf5a6c84SAndroid Build Coastguard Worker         cv = xmprintf("%.*s=%d", (int)(ss-s-2), s+1, to);
2618*cf5a6c84SAndroid Build Coastguard Worker       }
2619*cf5a6c84SAndroid Build Coastguard Worker     }
2620*cf5a6c84SAndroid Build Coastguard Worker 
2621*cf5a6c84SAndroid Build Coastguard Worker     // HERE documents?
2622*cf5a6c84SAndroid Build Coastguard Worker     if (!strncmp(ss, "<<", 2)) {
2623*cf5a6c84SAndroid Build Coastguard Worker       char *tmp = xmprintf("%s/sh-XXXXXX", getvar("TMPDIR") ? : "/tmp");
2624*cf5a6c84SAndroid Build Coastguard Worker       int i, h, len, zap = (ss[2] == '-'), x = !sss[strcspn(sss, "\\\"'")];
2625*cf5a6c84SAndroid Build Coastguard Worker 
2626*cf5a6c84SAndroid Build Coastguard Worker       // store contents in open-but-deleted /tmp file: write then lseek(start)
2627*cf5a6c84SAndroid Build Coastguard Worker       if ((from = mkstemp(tmp))>=0) {
2628*cf5a6c84SAndroid Build Coastguard Worker         if (unlink(tmp)) bad++;
2629*cf5a6c84SAndroid Build Coastguard Worker         else if (ss[2] == '<') { // not stored in arg[here]
2630*cf5a6c84SAndroid Build Coastguard Worker           if (!(ss = expand_one_arg(sss, 0))) {
2631*cf5a6c84SAndroid Build Coastguard Worker             s = 0;
2632*cf5a6c84SAndroid Build Coastguard Worker             break;
2633*cf5a6c84SAndroid Build Coastguard Worker           }
2634*cf5a6c84SAndroid Build Coastguard Worker           len = strlen(ss);
2635*cf5a6c84SAndroid Build Coastguard Worker           if (len != writeall(from, ss, len) || 1 != writeall(from, "\n", 1))
2636*cf5a6c84SAndroid Build Coastguard Worker             bad++;
2637*cf5a6c84SAndroid Build Coastguard Worker           if (ss != sss) free(ss);
2638*cf5a6c84SAndroid Build Coastguard Worker         } else {
2639*cf5a6c84SAndroid Build Coastguard Worker           struct sh_arg *hh = arg+ ++here;
2640*cf5a6c84SAndroid Build Coastguard Worker 
2641*cf5a6c84SAndroid Build Coastguard Worker           for (i = 0; i<hh->c; i++) {
2642*cf5a6c84SAndroid Build Coastguard Worker             sss = ss = hh->v[i];
2643*cf5a6c84SAndroid Build Coastguard Worker             while (zap && *ss == '\t') ss++;
2644*cf5a6c84SAndroid Build Coastguard Worker // TODO audit this ala man page
2645*cf5a6c84SAndroid Build Coastguard Worker             // expand_parameter, commands, and arithmetic
2646*cf5a6c84SAndroid Build Coastguard Worker             if (x && !(sss = expand_one_arg(ss, ~SEMI_IFS))) {
2647*cf5a6c84SAndroid Build Coastguard Worker               s = 0;
2648*cf5a6c84SAndroid Build Coastguard Worker               break;
2649*cf5a6c84SAndroid Build Coastguard Worker             }
2650*cf5a6c84SAndroid Build Coastguard Worker 
2651*cf5a6c84SAndroid Build Coastguard Worker             h = writeall(from, sss, len = strlen(sss));
2652*cf5a6c84SAndroid Build Coastguard Worker             if (ss != sss) free(sss);
2653*cf5a6c84SAndroid Build Coastguard Worker             if (len != h) break;
2654*cf5a6c84SAndroid Build Coastguard Worker           }
2655*cf5a6c84SAndroid Build Coastguard Worker           if (i != hh->c) bad++;
2656*cf5a6c84SAndroid Build Coastguard Worker         }
2657*cf5a6c84SAndroid Build Coastguard Worker         if (!bad && lseek(from, 0, SEEK_SET)) bad++;
2658*cf5a6c84SAndroid Build Coastguard Worker         if (bad) close(from);
2659*cf5a6c84SAndroid Build Coastguard Worker       } else bad++;
2660*cf5a6c84SAndroid Build Coastguard Worker       free(tmp);
2661*cf5a6c84SAndroid Build Coastguard Worker       if (bad) break;
2662*cf5a6c84SAndroid Build Coastguard Worker 
2663*cf5a6c84SAndroid Build Coastguard Worker     // from is fd<<2 (new fd to dup2() after vfork()) plus
2664*cf5a6c84SAndroid Build Coastguard Worker     // 2 if we should close(from>>2) after dup2(from>>2, to),
2665*cf5a6c84SAndroid Build Coastguard Worker     // 1 if we should close but dup for nofork recovery (ala <&2-)
2666*cf5a6c84SAndroid Build Coastguard Worker 
2667*cf5a6c84SAndroid Build Coastguard Worker     // Handle file descriptor duplication/close (&> &>> <& >& with number or -)
2668*cf5a6c84SAndroid Build Coastguard Worker     // These redirect existing fd so nothing to open()
2669*cf5a6c84SAndroid Build Coastguard Worker     } else if (*ss == '&' || ss[1] == '&') {
2670*cf5a6c84SAndroid Build Coastguard Worker 
2671*cf5a6c84SAndroid Build Coastguard Worker       // is there an explicit fd?
2672*cf5a6c84SAndroid Build Coastguard Worker       for (ss = sss; isdigit(*ss); ss++);
2673*cf5a6c84SAndroid Build Coastguard Worker       if (ss-sss>5 || (*ss && (*ss != '-' || ss[1]))) {
2674*cf5a6c84SAndroid Build Coastguard Worker         if (*ss=='&') ss++;
2675*cf5a6c84SAndroid Build Coastguard Worker         saveclose = 4;
2676*cf5a6c84SAndroid Build Coastguard Worker         goto notfd;
2677*cf5a6c84SAndroid Build Coastguard Worker       }
2678*cf5a6c84SAndroid Build Coastguard Worker 
2679*cf5a6c84SAndroid Build Coastguard Worker       from = (ss==sss) ? to : atoi(sss);
2680*cf5a6c84SAndroid Build Coastguard Worker       saveclose = 2-(*ss == '-');
2681*cf5a6c84SAndroid Build Coastguard Worker     } else {
2682*cf5a6c84SAndroid Build Coastguard Worker notfd:
2683*cf5a6c84SAndroid Build Coastguard Worker       // Permissions to open external file with: < > >> <& >& <> >| &>> &>
2684*cf5a6c84SAndroid Build Coastguard Worker       if (!strcmp(ss, "<>")) from = O_CREAT|O_RDWR;
2685*cf5a6c84SAndroid Build Coastguard Worker       else if (strstr(ss, ">>")) from = O_CREAT|O_APPEND|O_WRONLY;
2686*cf5a6c84SAndroid Build Coastguard Worker       else {
2687*cf5a6c84SAndroid Build Coastguard Worker         from = (*ss == '<') ? O_RDONLY : O_CREAT|O_WRONLY|O_TRUNC;
2688*cf5a6c84SAndroid Build Coastguard Worker         if (!strcmp(ss, ">") && (TT.options&OPT_C)) {
2689*cf5a6c84SAndroid Build Coastguard Worker           struct stat st;
2690*cf5a6c84SAndroid Build Coastguard Worker 
2691*cf5a6c84SAndroid Build Coastguard Worker           // Not _just_ O_EXCL: > /dev/null allowed
2692*cf5a6c84SAndroid Build Coastguard Worker           if (stat(sss, &st) || !S_ISREG(st.st_mode)) from |= O_EXCL;
2693*cf5a6c84SAndroid Build Coastguard Worker         }
2694*cf5a6c84SAndroid Build Coastguard Worker       }
2695*cf5a6c84SAndroid Build Coastguard Worker 
2696*cf5a6c84SAndroid Build Coastguard Worker       // we expect /dev/fd/# and /dev/{stdin,stdout,stderr} to be in /dev
2697*cf5a6c84SAndroid Build Coastguard Worker 
2698*cf5a6c84SAndroid Build Coastguard Worker // TODO: /dev/{tcp,udp}/host/port
2699*cf5a6c84SAndroid Build Coastguard Worker 
2700*cf5a6c84SAndroid Build Coastguard Worker       // Open the file
2701*cf5a6c84SAndroid Build Coastguard Worker       if (-1 == (from = xcreate_stdio(sss, from|WARN_ONLY, 0666))) {
2702*cf5a6c84SAndroid Build Coastguard Worker         s = 0;
2703*cf5a6c84SAndroid Build Coastguard Worker 
2704*cf5a6c84SAndroid Build Coastguard Worker         break;
2705*cf5a6c84SAndroid Build Coastguard Worker       } else if (from==to) saveclose |= 2;
2706*cf5a6c84SAndroid Build Coastguard Worker     }
2707*cf5a6c84SAndroid Build Coastguard Worker 
2708*cf5a6c84SAndroid Build Coastguard Worker     // perform redirect, saving displaced "to".
2709*cf5a6c84SAndroid Build Coastguard Worker     if (save_redirect(&pp->urd, from, to)) bad++;
2710*cf5a6c84SAndroid Build Coastguard Worker     // Do we save displaced "to" in env variable instead of undo list?
2711*cf5a6c84SAndroid Build Coastguard Worker     if (cv) {
2712*cf5a6c84SAndroid Build Coastguard Worker       --*pp->urd;
2713*cf5a6c84SAndroid Build Coastguard Worker       if (!setvar(cv)) bad++;
2714*cf5a6c84SAndroid Build Coastguard Worker       cv = 0;
2715*cf5a6c84SAndroid Build Coastguard Worker     }
2716*cf5a6c84SAndroid Build Coastguard Worker     if ((saveclose&1) && save_redirect(&pp->urd, -1, from)) bad++;
2717*cf5a6c84SAndroid Build Coastguard Worker     if ((saveclose&4) && save_redirect(&pp->urd, from, 2)) bad++;
2718*cf5a6c84SAndroid Build Coastguard Worker     if (!(saveclose&2)) close(from);
2719*cf5a6c84SAndroid Build Coastguard Worker     if (bad) break;
2720*cf5a6c84SAndroid Build Coastguard Worker   }
2721*cf5a6c84SAndroid Build Coastguard Worker 
2722*cf5a6c84SAndroid Build Coastguard Worker   // didn't parse everything?
2723*cf5a6c84SAndroid Build Coastguard Worker   if (j != arg->c) {
2724*cf5a6c84SAndroid Build Coastguard Worker     if (s) syntax_err(s);
2725*cf5a6c84SAndroid Build Coastguard Worker     if (!pp->exit) pp->exit = 1;
2726*cf5a6c84SAndroid Build Coastguard Worker     free(cv);
2727*cf5a6c84SAndroid Build Coastguard Worker   }
2728*cf5a6c84SAndroid Build Coastguard Worker 
2729*cf5a6c84SAndroid Build Coastguard Worker   return pp;
2730*cf5a6c84SAndroid Build Coastguard Worker }
2731*cf5a6c84SAndroid Build Coastguard Worker 
2732*cf5a6c84SAndroid Build Coastguard Worker // Call binary, or run script via xexec("sh --")
sh_exec(char ** argv)2733*cf5a6c84SAndroid Build Coastguard Worker static void sh_exec(char **argv)
2734*cf5a6c84SAndroid Build Coastguard Worker {
2735*cf5a6c84SAndroid Build Coastguard Worker   char *pp = getvar("PATH" ? : _PATH_DEFPATH), *ss = TT.isexec ? : *argv,
2736*cf5a6c84SAndroid Build Coastguard Worker     **sss = 0, **oldenv = environ, **argv2;
2737*cf5a6c84SAndroid Build Coastguard Worker   int norecurse = CFG_TOYBOX_NORECURSE || !toys.stacktop || TT.isexec, ii;
2738*cf5a6c84SAndroid Build Coastguard Worker   struct string_list *sl = 0;
2739*cf5a6c84SAndroid Build Coastguard Worker   struct toy_list *tl = 0;
2740*cf5a6c84SAndroid Build Coastguard Worker 
2741*cf5a6c84SAndroid Build Coastguard Worker   if (getpid() != TT.pid) signal(SIGINT, SIG_DFL); // TODO: restore all?
2742*cf5a6c84SAndroid Build Coastguard Worker   errno = ENOENT;
2743*cf5a6c84SAndroid Build Coastguard Worker   if (strchr(ss, '/')) {
2744*cf5a6c84SAndroid Build Coastguard Worker     if (access(ss, X_OK)) ss = 0;
2745*cf5a6c84SAndroid Build Coastguard Worker   } else if (norecurse || !(tl = toy_find(ss)))
2746*cf5a6c84SAndroid Build Coastguard Worker     for (sl = find_in_path(pp, ss); sl || (ss = 0); free(llist_pop(&sl)))
2747*cf5a6c84SAndroid Build Coastguard Worker       if (!access(ss = sl->str, X_OK)) break;
2748*cf5a6c84SAndroid Build Coastguard Worker 
2749*cf5a6c84SAndroid Build Coastguard Worker   if (ss) {
2750*cf5a6c84SAndroid Build Coastguard Worker     struct sh_vars **vv = visible_vars();
2751*cf5a6c84SAndroid Build Coastguard Worker     struct sh_arg aa;
2752*cf5a6c84SAndroid Build Coastguard Worker     unsigned uu, argc;
2753*cf5a6c84SAndroid Build Coastguard Worker 
2754*cf5a6c84SAndroid Build Coastguard Worker     // convert vars in-place and use original sh_arg alloc to add one more
2755*cf5a6c84SAndroid Build Coastguard Worker     aa.v = environ = (void *)vv;
2756*cf5a6c84SAndroid Build Coastguard Worker     for (aa.c = uu = 0; vv[uu]; uu++) {
2757*cf5a6c84SAndroid Build Coastguard Worker       if ((vv[uu]->flags&(VAR_WHITEOUT|VAR_EXPORT))==VAR_EXPORT) {
2758*cf5a6c84SAndroid Build Coastguard Worker         if (*(pp = vv[uu]->str)=='_' && pp[1]=='=') sss = aa.v+aa.c;
2759*cf5a6c84SAndroid Build Coastguard Worker         aa.v[aa.c++] = pp;
2760*cf5a6c84SAndroid Build Coastguard Worker       }
2761*cf5a6c84SAndroid Build Coastguard Worker     }
2762*cf5a6c84SAndroid Build Coastguard Worker     aa.v[aa.c] = 0;
2763*cf5a6c84SAndroid Build Coastguard Worker     if (!sss) {
2764*cf5a6c84SAndroid Build Coastguard Worker       if (aa.c<uu) aa.v[++aa.c] = 0;
2765*cf5a6c84SAndroid Build Coastguard Worker       else arg_add(&aa, 0);
2766*cf5a6c84SAndroid Build Coastguard Worker       sss = aa.v+aa.c-1;
2767*cf5a6c84SAndroid Build Coastguard Worker     }
2768*cf5a6c84SAndroid Build Coastguard Worker     *sss = xmprintf("_=%s", ss);
2769*cf5a6c84SAndroid Build Coastguard Worker 
2770*cf5a6c84SAndroid Build Coastguard Worker     // Don't leave open filehandles to scripts in children
2771*cf5a6c84SAndroid Build Coastguard Worker     if (!TT.isexec)
2772*cf5a6c84SAndroid Build Coastguard Worker       for (ii = 0; ii<TT.recursion; ii++)
2773*cf5a6c84SAndroid Build Coastguard Worker         if (TT.recfile[ii]>0) close(TT.recfile[ii]);
2774*cf5a6c84SAndroid Build Coastguard Worker 
2775*cf5a6c84SAndroid Build Coastguard Worker     // Run builtin, exec command, or call shell script without #!
2776*cf5a6c84SAndroid Build Coastguard Worker     toy_exec_which(tl, argv);
2777*cf5a6c84SAndroid Build Coastguard Worker     execve(ss, argv, environ);
2778*cf5a6c84SAndroid Build Coastguard Worker     // shell script without #!
2779*cf5a6c84SAndroid Build Coastguard Worker     if (errno == ENOEXEC) {
2780*cf5a6c84SAndroid Build Coastguard Worker       for (argc = 0; argv[argc]; argc++);
2781*cf5a6c84SAndroid Build Coastguard Worker       argv2 = xmalloc((argc+3)*sizeof(char *));
2782*cf5a6c84SAndroid Build Coastguard Worker       memcpy(argv2+3, argv+1, argc*sizeof(char *));
2783*cf5a6c84SAndroid Build Coastguard Worker       argv2[0] = "sh";
2784*cf5a6c84SAndroid Build Coastguard Worker       argv2[1] = "--";
2785*cf5a6c84SAndroid Build Coastguard Worker       argv2[2] = ss;
2786*cf5a6c84SAndroid Build Coastguard Worker       xexec(argv2);
2787*cf5a6c84SAndroid Build Coastguard Worker       free(argv2);
2788*cf5a6c84SAndroid Build Coastguard Worker     }
2789*cf5a6c84SAndroid Build Coastguard Worker     environ = oldenv;
2790*cf5a6c84SAndroid Build Coastguard Worker     free(*sss);
2791*cf5a6c84SAndroid Build Coastguard Worker     free(aa.v);
2792*cf5a6c84SAndroid Build Coastguard Worker   }
2793*cf5a6c84SAndroid Build Coastguard Worker 
2794*cf5a6c84SAndroid Build Coastguard Worker   perror_msg("%s", *argv);
2795*cf5a6c84SAndroid Build Coastguard Worker   if (!TT.isexec) _exit(127);
2796*cf5a6c84SAndroid Build Coastguard Worker   llist_traverse(sl, free);
2797*cf5a6c84SAndroid Build Coastguard Worker }
2798*cf5a6c84SAndroid Build Coastguard Worker 
2799*cf5a6c84SAndroid Build Coastguard Worker // Execute a single command at TT.ff->pl
run_command(void)2800*cf5a6c84SAndroid Build Coastguard Worker static struct sh_process *run_command(void)
2801*cf5a6c84SAndroid Build Coastguard Worker {
2802*cf5a6c84SAndroid Build Coastguard Worker   char *s, *ss, *sss;
2803*cf5a6c84SAndroid Build Coastguard Worker   struct sh_arg *arg = TT.ff->pl->arg;
2804*cf5a6c84SAndroid Build Coastguard Worker   int envlen, skiplen, funk = TT.funcslen, ii, jj = 0, prefix = 0;
2805*cf5a6c84SAndroid Build Coastguard Worker   struct sh_process *pp;
2806*cf5a6c84SAndroid Build Coastguard Worker 
2807*cf5a6c84SAndroid Build Coastguard Worker   // Count leading variable assignments
2808*cf5a6c84SAndroid Build Coastguard Worker   for (envlen = skiplen = 0; envlen<arg->c; envlen++)
2809*cf5a6c84SAndroid Build Coastguard Worker     if ((ss = varend(arg->v[envlen]))==arg->v[envlen] || ss[*ss=='+']!='=')
2810*cf5a6c84SAndroid Build Coastguard Worker       break;
2811*cf5a6c84SAndroid Build Coastguard Worker 
2812*cf5a6c84SAndroid Build Coastguard Worker   // Skip [[ ]] and (( )) contents for now
2813*cf5a6c84SAndroid Build Coastguard Worker   if ((s = arg->v[envlen])) {
2814*cf5a6c84SAndroid Build Coastguard Worker     if (!smemcmp(s, "((", 2)) skiplen = 1;
2815*cf5a6c84SAndroid Build Coastguard Worker     else if (!strcmp(s, "[[")) while (strcmp(arg->v[envlen+skiplen++], "]]"));
2816*cf5a6c84SAndroid Build Coastguard Worker   }
2817*cf5a6c84SAndroid Build Coastguard Worker   pp = expand_redir(arg, envlen+skiplen, 0);
2818*cf5a6c84SAndroid Build Coastguard Worker 
2819*cf5a6c84SAndroid Build Coastguard Worker // TODO: if error stops redir, expansion assignments, prefix assignments,
2820*cf5a6c84SAndroid Build Coastguard Worker // what sequence do they occur in?
2821*cf5a6c84SAndroid Build Coastguard Worker   if (skiplen) {
2822*cf5a6c84SAndroid Build Coastguard Worker     // Trailing redirects can't expand to any contents
2823*cf5a6c84SAndroid Build Coastguard Worker     if (pp->arg.c) {
2824*cf5a6c84SAndroid Build Coastguard Worker       syntax_err(*pp->arg.v);
2825*cf5a6c84SAndroid Build Coastguard Worker       pp->exit = 1;
2826*cf5a6c84SAndroid Build Coastguard Worker     }
2827*cf5a6c84SAndroid Build Coastguard Worker     if (!pp->exit) {
2828*cf5a6c84SAndroid Build Coastguard Worker       for (ii = 0; ii<skiplen; ii++)
2829*cf5a6c84SAndroid Build Coastguard Worker // TODO: [[ ~ ] expands but ((~)) doesn't, what else?
2830*cf5a6c84SAndroid Build Coastguard Worker         if (expand_arg(&pp->arg, arg->v[envlen+ii], NO_PATH|NO_SPLIT, &pp->delete))
2831*cf5a6c84SAndroid Build Coastguard Worker           break;
2832*cf5a6c84SAndroid Build Coastguard Worker       if (ii != skiplen) pp->exit = toys.exitval = 1;
2833*cf5a6c84SAndroid Build Coastguard Worker     }
2834*cf5a6c84SAndroid Build Coastguard Worker     if (pp->exit) return pp;
2835*cf5a6c84SAndroid Build Coastguard Worker   }
2836*cf5a6c84SAndroid Build Coastguard Worker 
2837*cf5a6c84SAndroid Build Coastguard Worker   // Are we calling a shell function?  TODO binary search
2838*cf5a6c84SAndroid Build Coastguard Worker   if (pp->arg.c)
2839*cf5a6c84SAndroid Build Coastguard Worker     if (!strchr(s, '/')) for (funk = 0; funk<TT.funcslen; funk++)
2840*cf5a6c84SAndroid Build Coastguard Worker        if (!strcmp(s, TT.functions[funk]->name)) break;
2841*cf5a6c84SAndroid Build Coastguard Worker 
2842*cf5a6c84SAndroid Build Coastguard Worker   // Create new function context to hold local vars?
2843*cf5a6c84SAndroid Build Coastguard Worker   if (funk != TT.funcslen || (envlen && pp->arg.c) || TT.ff->blk->pipe) {
2844*cf5a6c84SAndroid Build Coastguard Worker     call_function();
2845*cf5a6c84SAndroid Build Coastguard Worker // TODO function needs to run asynchronously in pipeline
2846*cf5a6c84SAndroid Build Coastguard Worker     if (funk != TT.funcslen) {
2847*cf5a6c84SAndroid Build Coastguard Worker       TT.ff->delete = pp->delete;
2848*cf5a6c84SAndroid Build Coastguard Worker       pp->delete = 0;
2849*cf5a6c84SAndroid Build Coastguard Worker     }
2850*cf5a6c84SAndroid Build Coastguard Worker     addvar(0, TT.ff); // function context (not source) so end_fcall deletes
2851*cf5a6c84SAndroid Build Coastguard Worker     prefix = 1;  // create local variables for function prefix assignment
2852*cf5a6c84SAndroid Build Coastguard Worker   }
2853*cf5a6c84SAndroid Build Coastguard Worker 
2854*cf5a6c84SAndroid Build Coastguard Worker   // perform any assignments
2855*cf5a6c84SAndroid Build Coastguard Worker   if (envlen) for (; jj<envlen && !pp->exit; jj++) {
2856*cf5a6c84SAndroid Build Coastguard Worker     struct sh_vars *vv;
2857*cf5a6c84SAndroid Build Coastguard Worker 
2858*cf5a6c84SAndroid Build Coastguard Worker     if ((sss = expand_one_arg(ss = arg->v[jj], SEMI_IFS))) {
2859*cf5a6c84SAndroid Build Coastguard Worker       if (!prefix && sss==ss) sss = xstrdup(sss);
2860*cf5a6c84SAndroid Build Coastguard Worker       if ((vv = setvar_long(sss, sss!=ss, prefix ? TT.ff : TT.ff->prev))) {
2861*cf5a6c84SAndroid Build Coastguard Worker         if (prefix) vv->flags |= VAR_EXPORT;
2862*cf5a6c84SAndroid Build Coastguard Worker         continue;
2863*cf5a6c84SAndroid Build Coastguard Worker       }
2864*cf5a6c84SAndroid Build Coastguard Worker     }
2865*cf5a6c84SAndroid Build Coastguard Worker 
2866*cf5a6c84SAndroid Build Coastguard Worker     pp->exit = 1;
2867*cf5a6c84SAndroid Build Coastguard Worker     break;
2868*cf5a6c84SAndroid Build Coastguard Worker   }
2869*cf5a6c84SAndroid Build Coastguard Worker 
2870*cf5a6c84SAndroid Build Coastguard Worker   // Do the thing
2871*cf5a6c84SAndroid Build Coastguard Worker   if (pp->exit || envlen==arg->c) s = 0; // leave $_ alone
2872*cf5a6c84SAndroid Build Coastguard Worker   else if (!pp->arg.c) s = "";           // nothing to do but blank $_
2873*cf5a6c84SAndroid Build Coastguard Worker 
2874*cf5a6c84SAndroid Build Coastguard Worker // TODO: call functions() FUNCTION
2875*cf5a6c84SAndroid Build Coastguard Worker // TODO what about "echo | x=1 | export fruit", must subshell? Test this.
2876*cf5a6c84SAndroid Build Coastguard Worker //   Several NOFORK can just NOP in a pipeline? Except ${a?b} still errors
2877*cf5a6c84SAndroid Build Coastguard Worker 
2878*cf5a6c84SAndroid Build Coastguard Worker   // ((math))
2879*cf5a6c84SAndroid Build Coastguard Worker   else if (!smemcmp(s = *pp->arg.v, "((", 2)) {
2880*cf5a6c84SAndroid Build Coastguard Worker     char *ss = s+2;
2881*cf5a6c84SAndroid Build Coastguard Worker     long long ll;
2882*cf5a6c84SAndroid Build Coastguard Worker 
2883*cf5a6c84SAndroid Build Coastguard Worker     funk = TT.funcslen;
2884*cf5a6c84SAndroid Build Coastguard Worker     ii = strlen(s)-2;
2885*cf5a6c84SAndroid Build Coastguard Worker     if (!recalculate(&ll, &ss, 0) || ss!=s+ii)
2886*cf5a6c84SAndroid Build Coastguard Worker       perror_msg("bad math: %.*s @ %ld", ii-2, s+2, (long)(ss-s)-2);
2887*cf5a6c84SAndroid Build Coastguard Worker     else toys.exitval = !ll;
2888*cf5a6c84SAndroid Build Coastguard Worker     pp->exit = toys.exitval;
2889*cf5a6c84SAndroid Build Coastguard Worker     s = 0; // Really!
2890*cf5a6c84SAndroid Build Coastguard Worker 
2891*cf5a6c84SAndroid Build Coastguard Worker   // call shell function
2892*cf5a6c84SAndroid Build Coastguard Worker   } else if (funk != TT.funcslen) {
2893*cf5a6c84SAndroid Build Coastguard Worker     s = 0; // $_ set on return, not here
2894*cf5a6c84SAndroid Build Coastguard Worker     (TT.ff->func = TT.functions[funk])->refcount++;
2895*cf5a6c84SAndroid Build Coastguard Worker     TT.ff->pl = TT.ff->func->pipeline;
2896*cf5a6c84SAndroid Build Coastguard Worker     TT.ff->arg = pp->arg;
2897*cf5a6c84SAndroid Build Coastguard Worker // TODO: unredirect(pp->urd) called below but haven't traversed function yet
2898*cf5a6c84SAndroid Build Coastguard Worker   } else {
2899*cf5a6c84SAndroid Build Coastguard Worker     struct toy_list *tl = toy_find(*pp->arg.v);
2900*cf5a6c84SAndroid Build Coastguard Worker 
2901*cf5a6c84SAndroid Build Coastguard Worker     jj = tl ? tl->flags : 0;
2902*cf5a6c84SAndroid Build Coastguard Worker     TT.pp = pp;
2903*cf5a6c84SAndroid Build Coastguard Worker     s = pp->arg.v[pp->arg.c-1];
2904*cf5a6c84SAndroid Build Coastguard Worker     sss = pp->arg.v[pp->arg.c];
2905*cf5a6c84SAndroid Build Coastguard Worker //dprintf(2, "%d run command %p %s\n", getpid(), TT.ff, *pp->arg.v); debug_show_fds();
2906*cf5a6c84SAndroid Build Coastguard Worker // TODO: figure out when can exec instead of forking, ala sh -c blah
2907*cf5a6c84SAndroid Build Coastguard Worker 
2908*cf5a6c84SAndroid Build Coastguard Worker     // Is this command a builtin that should run in this process?
2909*cf5a6c84SAndroid Build Coastguard Worker     if ((jj&TOYFLAG_NOFORK) || ((jj&TOYFLAG_MAYFORK) && !prefix)) {
2910*cf5a6c84SAndroid Build Coastguard Worker       sigjmp_buf rebound, *prebound = toys.rebound;
2911*cf5a6c84SAndroid Build Coastguard Worker       char temp[jj = offsetof(struct toy_context, rebound)];
2912*cf5a6c84SAndroid Build Coastguard Worker 
2913*cf5a6c84SAndroid Build Coastguard Worker       // This fakes lots of what toybox_main() does.
2914*cf5a6c84SAndroid Build Coastguard Worker       memcpy(&temp, &toys, jj);
2915*cf5a6c84SAndroid Build Coastguard Worker       memset(&toys, 0, jj);
2916*cf5a6c84SAndroid Build Coastguard Worker 
2917*cf5a6c84SAndroid Build Coastguard Worker       // The compiler complains "declaration does not declare anything" if we
2918*cf5a6c84SAndroid Build Coastguard Worker       // name the union in TT, only works WITHOUT name. So we can't
2919*cf5a6c84SAndroid Build Coastguard Worker       // sizeof(union) instead offsetof() first thing after union to get size.
2920*cf5a6c84SAndroid Build Coastguard Worker       memset(&TT, 0, offsetof(struct sh_data, SECONDS));
2921*cf5a6c84SAndroid Build Coastguard Worker       if (!sigsetjmp(rebound, 1)) {
2922*cf5a6c84SAndroid Build Coastguard Worker         toys.rebound = &rebound;
2923*cf5a6c84SAndroid Build Coastguard Worker //dprintf(2, "%d builtin", getpid()); for (int xx = 0; xx<=pp->arg.c; xx++) dprintf(2, "{%s}", pp->arg.v[xx]); dprintf(2, "\n");
2924*cf5a6c84SAndroid Build Coastguard Worker         toy_singleinit(tl, pp->arg.v);
2925*cf5a6c84SAndroid Build Coastguard Worker         tl->toy_main();
2926*cf5a6c84SAndroid Build Coastguard Worker         xexit();
2927*cf5a6c84SAndroid Build Coastguard Worker       }
2928*cf5a6c84SAndroid Build Coastguard Worker       toys.rebound = prebound;
2929*cf5a6c84SAndroid Build Coastguard Worker       pp->exit = toys.exitval;
2930*cf5a6c84SAndroid Build Coastguard Worker       clearerr(stdout);
2931*cf5a6c84SAndroid Build Coastguard Worker       if (toys.optargs != toys.argv+1) free(toys.optargs);
2932*cf5a6c84SAndroid Build Coastguard Worker       if (toys.old_umask) umask(toys.old_umask);
2933*cf5a6c84SAndroid Build Coastguard Worker       memcpy(&toys, &temp, jj);
2934*cf5a6c84SAndroid Build Coastguard Worker     } else if (-1==(pp->pid = xpopen_setup(pp->arg.v, 0, sh_exec)))
2935*cf5a6c84SAndroid Build Coastguard Worker         perror_msg("%s: vfork", *pp->arg.v);
2936*cf5a6c84SAndroid Build Coastguard Worker   }
2937*cf5a6c84SAndroid Build Coastguard Worker 
2938*cf5a6c84SAndroid Build Coastguard Worker   // cleanup process
2939*cf5a6c84SAndroid Build Coastguard Worker   unredirect(pp->urd);
2940*cf5a6c84SAndroid Build Coastguard Worker   pp->urd = 0;
2941*cf5a6c84SAndroid Build Coastguard Worker   if (prefix && funk == TT.funcslen) end_fcall(0);
2942*cf5a6c84SAndroid Build Coastguard Worker   if (s) setvarval("_", s);
2943*cf5a6c84SAndroid Build Coastguard Worker 
2944*cf5a6c84SAndroid Build Coastguard Worker   return pp;
2945*cf5a6c84SAndroid Build Coastguard Worker }
2946*cf5a6c84SAndroid Build Coastguard Worker 
free_process(struct sh_process * pp)2947*cf5a6c84SAndroid Build Coastguard Worker static int free_process(struct sh_process *pp)
2948*cf5a6c84SAndroid Build Coastguard Worker {
2949*cf5a6c84SAndroid Build Coastguard Worker   int rc;
2950*cf5a6c84SAndroid Build Coastguard Worker 
2951*cf5a6c84SAndroid Build Coastguard Worker   if (!pp) return 127;
2952*cf5a6c84SAndroid Build Coastguard Worker   rc = pp->exit;
2953*cf5a6c84SAndroid Build Coastguard Worker   llist_traverse(pp->delete, llist_free_arg);
2954*cf5a6c84SAndroid Build Coastguard Worker   free(pp);
2955*cf5a6c84SAndroid Build Coastguard Worker 
2956*cf5a6c84SAndroid Build Coastguard Worker   return rc;
2957*cf5a6c84SAndroid Build Coastguard Worker }
2958*cf5a6c84SAndroid Build Coastguard Worker 
2959*cf5a6c84SAndroid Build Coastguard Worker // if then fi for while until select done done case esac break continue return
2960*cf5a6c84SAndroid Build Coastguard Worker 
2961*cf5a6c84SAndroid Build Coastguard Worker // Free one pipeline segment.
free_pipeline(void * pipeline)2962*cf5a6c84SAndroid Build Coastguard Worker static void free_pipeline(void *pipeline)
2963*cf5a6c84SAndroid Build Coastguard Worker {
2964*cf5a6c84SAndroid Build Coastguard Worker   struct sh_pipeline *pl = pipeline;
2965*cf5a6c84SAndroid Build Coastguard Worker   int i, j, k;
2966*cf5a6c84SAndroid Build Coastguard Worker 
2967*cf5a6c84SAndroid Build Coastguard Worker   if (!pl) return;
2968*cf5a6c84SAndroid Build Coastguard Worker 
2969*cf5a6c84SAndroid Build Coastguard Worker   // free either function or arguments and HERE doc contents
2970*cf5a6c84SAndroid Build Coastguard Worker   if (pl->type == 'F') {
2971*cf5a6c84SAndroid Build Coastguard Worker     free_function((void *)*pl->arg->v);
2972*cf5a6c84SAndroid Build Coastguard Worker     *pl->arg->v = 0;
2973*cf5a6c84SAndroid Build Coastguard Worker   }
2974*cf5a6c84SAndroid Build Coastguard Worker   for (j=0; j<=pl->count; j++) {
2975*cf5a6c84SAndroid Build Coastguard Worker     if (!pl->arg[j].v) continue;
2976*cf5a6c84SAndroid Build Coastguard Worker     k = pl->arg[j].c-!!pl->count;
2977*cf5a6c84SAndroid Build Coastguard Worker     for (i = 0; i<=k; i++) free(pl->arg[j].v[i]);
2978*cf5a6c84SAndroid Build Coastguard Worker     free(pl->arg[j].v);
2979*cf5a6c84SAndroid Build Coastguard Worker   }
2980*cf5a6c84SAndroid Build Coastguard Worker   free(pl);
2981*cf5a6c84SAndroid Build Coastguard Worker }
2982*cf5a6c84SAndroid Build Coastguard Worker 
2983*cf5a6c84SAndroid Build Coastguard Worker // Append a new pipeline to function, returning pipeline and pipeline's arg
add_pl(struct sh_pipeline ** ppl,struct sh_arg ** arg)2984*cf5a6c84SAndroid Build Coastguard Worker static struct sh_pipeline *add_pl(struct sh_pipeline **ppl, struct sh_arg **arg)
2985*cf5a6c84SAndroid Build Coastguard Worker {
2986*cf5a6c84SAndroid Build Coastguard Worker   struct sh_pipeline *pl = xzalloc(sizeof(struct sh_pipeline));
2987*cf5a6c84SAndroid Build Coastguard Worker 
2988*cf5a6c84SAndroid Build Coastguard Worker   if (arg) *arg = pl->arg;
2989*cf5a6c84SAndroid Build Coastguard Worker   pl->lineno = TT.LINENO;
2990*cf5a6c84SAndroid Build Coastguard Worker   dlist_add_nomalloc((void *)ppl, (void *)pl);
2991*cf5a6c84SAndroid Build Coastguard Worker 
2992*cf5a6c84SAndroid Build Coastguard Worker   return pl->end = pl;
2993*cf5a6c84SAndroid Build Coastguard Worker }
2994*cf5a6c84SAndroid Build Coastguard Worker 
2995*cf5a6c84SAndroid Build Coastguard Worker // Add a line of shell script to a shell function. Returns 0 if finished,
2996*cf5a6c84SAndroid Build Coastguard Worker // 1 to request another line of input (> prompt), -1 for syntax err
parse_line(char * line,struct sh_pipeline ** ppl,struct double_list ** expect)2997*cf5a6c84SAndroid Build Coastguard Worker static int parse_line(char *line, struct sh_pipeline **ppl,
2998*cf5a6c84SAndroid Build Coastguard Worker    struct double_list **expect)
2999*cf5a6c84SAndroid Build Coastguard Worker {
3000*cf5a6c84SAndroid Build Coastguard Worker   char *start = line, *delete = 0, *end, *s, *ex, done = 0,
3001*cf5a6c84SAndroid Build Coastguard Worker     *tails[] = {"fi", "done", "esac", "}", "]]", ")", 0};
3002*cf5a6c84SAndroid Build Coastguard Worker   struct sh_pipeline *pl = *ppl ? (*ppl)->prev : 0, *pl2, *pl3;
3003*cf5a6c84SAndroid Build Coastguard Worker   struct sh_arg *arg = 0;
3004*cf5a6c84SAndroid Build Coastguard Worker   long i;
3005*cf5a6c84SAndroid Build Coastguard Worker 
3006*cf5a6c84SAndroid Build Coastguard Worker   // Resume appending to last statement?
3007*cf5a6c84SAndroid Build Coastguard Worker   if (pl) {
3008*cf5a6c84SAndroid Build Coastguard Worker     arg = pl->arg;
3009*cf5a6c84SAndroid Build Coastguard Worker 
3010*cf5a6c84SAndroid Build Coastguard Worker     // Extend/resume quoted block
3011*cf5a6c84SAndroid Build Coastguard Worker     if (arg->c<0) {
3012*cf5a6c84SAndroid Build Coastguard Worker       arg->c = (-arg->c)-1;
3013*cf5a6c84SAndroid Build Coastguard Worker       if (start) {
3014*cf5a6c84SAndroid Build Coastguard Worker         delete = start = xmprintf("%s%s", arg->v[arg->c], start);
3015*cf5a6c84SAndroid Build Coastguard Worker         free(arg->v[arg->c]);
3016*cf5a6c84SAndroid Build Coastguard Worker       } else start = arg->v[arg->c];
3017*cf5a6c84SAndroid Build Coastguard Worker       arg->v[arg->c] = 0;
3018*cf5a6c84SAndroid Build Coastguard Worker 
3019*cf5a6c84SAndroid Build Coastguard Worker     // is a HERE document in progress?
3020*cf5a6c84SAndroid Build Coastguard Worker     } else if (pl->count != pl->here) {
3021*cf5a6c84SAndroid Build Coastguard Worker here_loop:
3022*cf5a6c84SAndroid Build Coastguard Worker       // Back up to oldest unfinished pipeline segment.
3023*cf5a6c84SAndroid Build Coastguard Worker       while (pl != *ppl && pl->prev->count != pl->prev->here) pl = pl->prev;
3024*cf5a6c84SAndroid Build Coastguard Worker       arg = pl->arg+1+pl->here;
3025*cf5a6c84SAndroid Build Coastguard Worker 
3026*cf5a6c84SAndroid Build Coastguard Worker       // Match unquoted EOF.
3027*cf5a6c84SAndroid Build Coastguard Worker       if (!line) {
3028*cf5a6c84SAndroid Build Coastguard Worker         error_msg("%u: <<%s EOF", TT.LINENO, arg->v[arg->c]);
3029*cf5a6c84SAndroid Build Coastguard Worker         goto here_end;
3030*cf5a6c84SAndroid Build Coastguard Worker       }
3031*cf5a6c84SAndroid Build Coastguard Worker       for (s = line, end = arg->v[arg->c]; *end; s++, end++) {
3032*cf5a6c84SAndroid Build Coastguard Worker         end += strspn(end, "\\\"'\n");
3033*cf5a6c84SAndroid Build Coastguard Worker         if (!*s || *s != *end) break;
3034*cf5a6c84SAndroid Build Coastguard Worker       }
3035*cf5a6c84SAndroid Build Coastguard Worker 
3036*cf5a6c84SAndroid Build Coastguard Worker       // Add this line, else EOF hit so end HERE document
3037*cf5a6c84SAndroid Build Coastguard Worker       if ((*s && *s!='\n') || *end) {
3038*cf5a6c84SAndroid Build Coastguard Worker         end = arg->v[arg->c];
3039*cf5a6c84SAndroid Build Coastguard Worker         arg_add(arg, xstrdup(line));
3040*cf5a6c84SAndroid Build Coastguard Worker         arg->v[arg->c] = end;
3041*cf5a6c84SAndroid Build Coastguard Worker       } else {
3042*cf5a6c84SAndroid Build Coastguard Worker here_end:
3043*cf5a6c84SAndroid Build Coastguard Worker         // End segment and advance/consume bridge segments
3044*cf5a6c84SAndroid Build Coastguard Worker         arg->v[arg->c] = 0;
3045*cf5a6c84SAndroid Build Coastguard Worker         if (pl->count == ++pl->here)
3046*cf5a6c84SAndroid Build Coastguard Worker           while (pl->next != *ppl && (pl = pl->next)->here == -1)
3047*cf5a6c84SAndroid Build Coastguard Worker             pl->here = pl->count;
3048*cf5a6c84SAndroid Build Coastguard Worker       }
3049*cf5a6c84SAndroid Build Coastguard Worker       if (pl->here != pl->count) {
3050*cf5a6c84SAndroid Build Coastguard Worker         if (!line) goto here_loop;
3051*cf5a6c84SAndroid Build Coastguard Worker         else return 1;
3052*cf5a6c84SAndroid Build Coastguard Worker       }
3053*cf5a6c84SAndroid Build Coastguard Worker       start = 0;
3054*cf5a6c84SAndroid Build Coastguard Worker 
3055*cf5a6c84SAndroid Build Coastguard Worker     // Nope, new segment if not self-managing type
3056*cf5a6c84SAndroid Build Coastguard Worker     } else if (pl->type < 128) pl = 0;
3057*cf5a6c84SAndroid Build Coastguard Worker   }
3058*cf5a6c84SAndroid Build Coastguard Worker 
3059*cf5a6c84SAndroid Build Coastguard Worker   // Parse words, assemble argv[] pipelines, check flow control and HERE docs
3060*cf5a6c84SAndroid Build Coastguard Worker   if (start) for (;;) {
3061*cf5a6c84SAndroid Build Coastguard Worker     ex = *expect ? (*expect)->prev->data : 0;
3062*cf5a6c84SAndroid Build Coastguard Worker 
3063*cf5a6c84SAndroid Build Coastguard Worker     // Look for << HERE redirections in completed pipeline segment
3064*cf5a6c84SAndroid Build Coastguard Worker     if (pl && pl->count == -1) {
3065*cf5a6c84SAndroid Build Coastguard Worker       // find arguments of the form [{n}]<<[-] with another one after it
3066*cf5a6c84SAndroid Build Coastguard Worker       for (arg = pl->arg, pl->count = i = 0; i<arg->c; i++) {
3067*cf5a6c84SAndroid Build Coastguard Worker         s = skip_redir_prefix(arg->v[i]);
3068*cf5a6c84SAndroid Build Coastguard Worker         if (strncmp(s, "<<", 2) || s[2]=='<') continue;
3069*cf5a6c84SAndroid Build Coastguard Worker         if (i+1 == arg->c) goto flush;
3070*cf5a6c84SAndroid Build Coastguard Worker 
3071*cf5a6c84SAndroid Build Coastguard Worker         // Add another arg[] to the pipeline segment (removing/re-adding
3072*cf5a6c84SAndroid Build Coastguard Worker         // to list because realloc can move pointer, and adjusing end pointers)
3073*cf5a6c84SAndroid Build Coastguard Worker         dlist_lpop(ppl);
3074*cf5a6c84SAndroid Build Coastguard Worker         pl2 = pl;
3075*cf5a6c84SAndroid Build Coastguard Worker         pl = xrealloc(pl, sizeof(*pl)+(++pl->count+1)*sizeof(struct sh_arg));
3076*cf5a6c84SAndroid Build Coastguard Worker         arg = pl->arg;
3077*cf5a6c84SAndroid Build Coastguard Worker         dlist_add_nomalloc((void *)ppl, (void *)pl);
3078*cf5a6c84SAndroid Build Coastguard Worker         for (pl3 = *ppl;;) {
3079*cf5a6c84SAndroid Build Coastguard Worker           if (pl3->end == pl2) pl3->end = pl;
3080*cf5a6c84SAndroid Build Coastguard Worker           if ((pl3 = pl3->next) == *ppl) break;
3081*cf5a6c84SAndroid Build Coastguard Worker         }
3082*cf5a6c84SAndroid Build Coastguard Worker 
3083*cf5a6c84SAndroid Build Coastguard Worker         // queue up HERE EOF so input loop asks for more lines.
3084*cf5a6c84SAndroid Build Coastguard Worker         memset(arg+pl->count, 0, sizeof(*arg));
3085*cf5a6c84SAndroid Build Coastguard Worker         arg_add(arg+pl->count, arg->v[++i]);
3086*cf5a6c84SAndroid Build Coastguard Worker         arg[pl->count].c--;
3087*cf5a6c84SAndroid Build Coastguard Worker       }
3088*cf5a6c84SAndroid Build Coastguard Worker       // Mark "bridge" segment when previous pl had HERE but this doesn't
3089*cf5a6c84SAndroid Build Coastguard Worker       if (!pl->count && pl->prev->count != pl->prev->here) pl->here = -1;
3090*cf5a6c84SAndroid Build Coastguard Worker       pl = 0;
3091*cf5a6c84SAndroid Build Coastguard Worker     }
3092*cf5a6c84SAndroid Build Coastguard Worker     if (done) break;
3093*cf5a6c84SAndroid Build Coastguard Worker     s = 0;
3094*cf5a6c84SAndroid Build Coastguard Worker 
3095*cf5a6c84SAndroid Build Coastguard Worker     // skip leading whitespace/comment here to know where next word starts
3096*cf5a6c84SAndroid Build Coastguard Worker     while (isspace(*start)) ++start;
3097*cf5a6c84SAndroid Build Coastguard Worker     if (*start=='#') while (*start) ++start;
3098*cf5a6c84SAndroid Build Coastguard Worker 
3099*cf5a6c84SAndroid Build Coastguard Worker     // Parse next word and detect overflow (too many nested quotes).
3100*cf5a6c84SAndroid Build Coastguard Worker     if ((end = parse_word(start, 0)) == (void *)1) goto flush;
3101*cf5a6c84SAndroid Build Coastguard Worker //dprintf(2, "%d %p(%d) %s word=%.*s\n", getpid(), pl, pl ? pl->type : -1, ex, (int)(end-start), end ? start : "");
3102*cf5a6c84SAndroid Build Coastguard Worker 
3103*cf5a6c84SAndroid Build Coastguard Worker     // End function declaration?
3104*cf5a6c84SAndroid Build Coastguard Worker     if (pl && pl->type == 'f' && arg->c == 1 && (end-start!=1 || *start!='(')) {
3105*cf5a6c84SAndroid Build Coastguard Worker       // end (possibly multiline) function segment, expect function body next
3106*cf5a6c84SAndroid Build Coastguard Worker       dlist_add(expect, 0);
3107*cf5a6c84SAndroid Build Coastguard Worker       pl = 0;
3108*cf5a6c84SAndroid Build Coastguard Worker 
3109*cf5a6c84SAndroid Build Coastguard Worker       continue;
3110*cf5a6c84SAndroid Build Coastguard Worker     }
3111*cf5a6c84SAndroid Build Coastguard Worker 
3112*cf5a6c84SAndroid Build Coastguard Worker     // Is this a new pipeline segment?
3113*cf5a6c84SAndroid Build Coastguard Worker     if (!pl) pl = add_pl(ppl, &arg);
3114*cf5a6c84SAndroid Build Coastguard Worker 
3115*cf5a6c84SAndroid Build Coastguard Worker     // Do we need to request another line to finish word (find ending quote)?
3116*cf5a6c84SAndroid Build Coastguard Worker     if (!end) {
3117*cf5a6c84SAndroid Build Coastguard Worker       // Save unparsed bit of this line, we'll need to re-parse it.
3118*cf5a6c84SAndroid Build Coastguard Worker       if (*start=='\\' && (!start[1] || start[1]=='\n')) start++;
3119*cf5a6c84SAndroid Build Coastguard Worker       arg_add(arg, xstrndup(start, strlen(start)));
3120*cf5a6c84SAndroid Build Coastguard Worker       arg->c = -arg->c;
3121*cf5a6c84SAndroid Build Coastguard Worker       free(delete);
3122*cf5a6c84SAndroid Build Coastguard Worker 
3123*cf5a6c84SAndroid Build Coastguard Worker       return 1;
3124*cf5a6c84SAndroid Build Coastguard Worker     }
3125*cf5a6c84SAndroid Build Coastguard Worker 
3126*cf5a6c84SAndroid Build Coastguard Worker     // Ok, we have a word. What does it _mean_?
3127*cf5a6c84SAndroid Build Coastguard Worker 
3128*cf5a6c84SAndroid Build Coastguard Worker     // case/esac parsing is weird (unbalanced parentheses!), handle first
3129*cf5a6c84SAndroid Build Coastguard Worker     i = ex && !strcmp(ex, "esac") &&
3130*cf5a6c84SAndroid Build Coastguard Worker         ((pl->type && pl->type != 3) || (*start==';' && end-start>1));
3131*cf5a6c84SAndroid Build Coastguard Worker     if (i) {
3132*cf5a6c84SAndroid Build Coastguard Worker 
3133*cf5a6c84SAndroid Build Coastguard Worker       // Premature EOL in type 1 (case x\nin) or 2 (at start or after ;;) is ok
3134*cf5a6c84SAndroid Build Coastguard Worker       if (end == start) {
3135*cf5a6c84SAndroid Build Coastguard Worker         if (pl->type==128 && arg->c==2) break;  // case x\nin
3136*cf5a6c84SAndroid Build Coastguard Worker         if (pl->type==129 && (!arg->c || (arg->c==1 && **arg->v==';'))) break;
3137*cf5a6c84SAndroid Build Coastguard Worker         s = "newline";
3138*cf5a6c84SAndroid Build Coastguard Worker         goto flush;
3139*cf5a6c84SAndroid Build Coastguard Worker       }
3140*cf5a6c84SAndroid Build Coastguard Worker 
3141*cf5a6c84SAndroid Build Coastguard Worker       // type 0 means just got ;; so start new type 2
3142*cf5a6c84SAndroid Build Coastguard Worker       if (!pl->type || pl->type==3) {
3143*cf5a6c84SAndroid Build Coastguard Worker         // catch "echo | ;;" errors
3144*cf5a6c84SAndroid Build Coastguard Worker         if (arg->v && arg->v[arg->c] && strcmp(arg->v[arg->c], "&")) goto flush;
3145*cf5a6c84SAndroid Build Coastguard Worker         if (!arg->c) {
3146*cf5a6c84SAndroid Build Coastguard Worker           if (pl->prev->type == 2) {
3147*cf5a6c84SAndroid Build Coastguard Worker             // Add a call to "true" between empty ) ;;
3148*cf5a6c84SAndroid Build Coastguard Worker             arg_add(arg, xstrdup(":"));
3149*cf5a6c84SAndroid Build Coastguard Worker             pl = add_pl(ppl, &arg);
3150*cf5a6c84SAndroid Build Coastguard Worker           }
3151*cf5a6c84SAndroid Build Coastguard Worker           pl->type = 129;
3152*cf5a6c84SAndroid Build Coastguard Worker         } else {
3153*cf5a6c84SAndroid Build Coastguard Worker           // check for here documents
3154*cf5a6c84SAndroid Build Coastguard Worker           pl->count = -1;
3155*cf5a6c84SAndroid Build Coastguard Worker           continue;
3156*cf5a6c84SAndroid Build Coastguard Worker         }
3157*cf5a6c84SAndroid Build Coastguard Worker       }
3158*cf5a6c84SAndroid Build Coastguard Worker 
3159*cf5a6c84SAndroid Build Coastguard Worker     // Did we hit end of line or ) outside a function declaration?
3160*cf5a6c84SAndroid Build Coastguard Worker     // ) is only saved at start of a statement, ends current statement
3161*cf5a6c84SAndroid Build Coastguard Worker     } else if (end == start || (arg->c && *start == ')' && pl->type!='f')) {
3162*cf5a6c84SAndroid Build Coastguard Worker //TODO: test ) within ]]
3163*cf5a6c84SAndroid Build Coastguard Worker       // function () needs both parentheses or neither
3164*cf5a6c84SAndroid Build Coastguard Worker       if (pl->type == 'f' && arg->c != 1 && arg->c != 3) {
3165*cf5a6c84SAndroid Build Coastguard Worker         s = "function(";
3166*cf5a6c84SAndroid Build Coastguard Worker         goto flush;
3167*cf5a6c84SAndroid Build Coastguard Worker       }
3168*cf5a6c84SAndroid Build Coastguard Worker 
3169*cf5a6c84SAndroid Build Coastguard Worker       // "for" on its own line is an error.
3170*cf5a6c84SAndroid Build Coastguard Worker       if (arg->c == 1 && !smemcmp(ex, "do\0A", 4)) {
3171*cf5a6c84SAndroid Build Coastguard Worker         s = "newline";
3172*cf5a6c84SAndroid Build Coastguard Worker         goto flush;
3173*cf5a6c84SAndroid Build Coastguard Worker       }
3174*cf5a6c84SAndroid Build Coastguard Worker 
3175*cf5a6c84SAndroid Build Coastguard Worker       // Stop at EOL. Discard blank pipeline segment, else end segment
3176*cf5a6c84SAndroid Build Coastguard Worker       if (end == start) done++;
3177*cf5a6c84SAndroid Build Coastguard Worker       if (!pl->type && !arg->c) {
3178*cf5a6c84SAndroid Build Coastguard Worker         free_pipeline(dlist_lpop(ppl));
3179*cf5a6c84SAndroid Build Coastguard Worker         pl = *ppl ? (*ppl)->prev : 0;
3180*cf5a6c84SAndroid Build Coastguard Worker       } else pl->count = -1;
3181*cf5a6c84SAndroid Build Coastguard Worker 
3182*cf5a6c84SAndroid Build Coastguard Worker       continue;
3183*cf5a6c84SAndroid Build Coastguard Worker     }
3184*cf5a6c84SAndroid Build Coastguard Worker 
3185*cf5a6c84SAndroid Build Coastguard Worker     // Save word and check for flow control
3186*cf5a6c84SAndroid Build Coastguard Worker     arg_add(arg, s = xstrndup(start, end-start));
3187*cf5a6c84SAndroid Build Coastguard Worker     start = end;
3188*cf5a6c84SAndroid Build Coastguard Worker 
3189*cf5a6c84SAndroid Build Coastguard Worker     // Second half of case/esac parsing
3190*cf5a6c84SAndroid Build Coastguard Worker     if (i) {
3191*cf5a6c84SAndroid Build Coastguard Worker       // type 1 (128): case x [\n] in
3192*cf5a6c84SAndroid Build Coastguard Worker       if (pl->type==128) {
3193*cf5a6c84SAndroid Build Coastguard Worker         if (arg->c==2 && strchr("()|;&", *s)) goto flush;
3194*cf5a6c84SAndroid Build Coastguard Worker         if (arg->c==3) {
3195*cf5a6c84SAndroid Build Coastguard Worker           if (strcmp(s, "in")) goto flush;
3196*cf5a6c84SAndroid Build Coastguard Worker           pl->type = 1;
3197*cf5a6c84SAndroid Build Coastguard Worker           (pl = add_pl(ppl, &arg))->type = 129;
3198*cf5a6c84SAndroid Build Coastguard Worker         }
3199*cf5a6c84SAndroid Build Coastguard Worker 
3200*cf5a6c84SAndroid Build Coastguard Worker         continue;
3201*cf5a6c84SAndroid Build Coastguard Worker 
3202*cf5a6c84SAndroid Build Coastguard Worker       // type 2 (129): [;;] [(] pattern [|pattern...] )
3203*cf5a6c84SAndroid Build Coastguard Worker       } else {
3204*cf5a6c84SAndroid Build Coastguard Worker 
3205*cf5a6c84SAndroid Build Coastguard Worker         // can't start with line break or ";;" or "case ? in ;;" without ")"
3206*cf5a6c84SAndroid Build Coastguard Worker         if (*s==';') {
3207*cf5a6c84SAndroid Build Coastguard Worker           if (arg->c>1 || (arg->c==1 && pl->prev->type==1)) goto flush;
3208*cf5a6c84SAndroid Build Coastguard Worker         } else pl->type = 2;
3209*cf5a6c84SAndroid Build Coastguard Worker         i = arg->c - (**arg->v==';' && arg->v[0][1]);
3210*cf5a6c84SAndroid Build Coastguard Worker         if (i==1 && !strcmp(s, "esac")) {
3211*cf5a6c84SAndroid Build Coastguard Worker           // esac right after "in" or ";;" ends block, fall through
3212*cf5a6c84SAndroid Build Coastguard Worker           if (arg->c>1) {
3213*cf5a6c84SAndroid Build Coastguard Worker             arg->v[1] = 0;
3214*cf5a6c84SAndroid Build Coastguard Worker             pl = add_pl(ppl, &arg);
3215*cf5a6c84SAndroid Build Coastguard Worker             arg_add(arg, s);
3216*cf5a6c84SAndroid Build Coastguard Worker           } else pl->type = 0;
3217*cf5a6c84SAndroid Build Coastguard Worker         } else {
3218*cf5a6c84SAndroid Build Coastguard Worker           if (arg->c>1) i -= *arg->v[1]=='(';
3219*cf5a6c84SAndroid Build Coastguard Worker           if (i>0 && ((i&1)==!!strchr("|)", *s) || strchr(";(", *s)))
3220*cf5a6c84SAndroid Build Coastguard Worker             goto flush;
3221*cf5a6c84SAndroid Build Coastguard Worker           if (*s=='&' || !strcmp(s, "||")) goto flush;
3222*cf5a6c84SAndroid Build Coastguard Worker           if (*s==')') pl = add_pl(ppl, &arg);
3223*cf5a6c84SAndroid Build Coastguard Worker 
3224*cf5a6c84SAndroid Build Coastguard Worker           continue;
3225*cf5a6c84SAndroid Build Coastguard Worker         }
3226*cf5a6c84SAndroid Build Coastguard Worker       }
3227*cf5a6c84SAndroid Build Coastguard Worker     }
3228*cf5a6c84SAndroid Build Coastguard Worker 
3229*cf5a6c84SAndroid Build Coastguard Worker     // Are we starting a new [function] name [()] definition
3230*cf5a6c84SAndroid Build Coastguard Worker     if (!pl->type || pl->type=='f') {
3231*cf5a6c84SAndroid Build Coastguard Worker       if (!pl->type && arg->c==1 && !strcmp(s, "function")) {
3232*cf5a6c84SAndroid Build Coastguard Worker         free(arg->v[--arg->c]);
3233*cf5a6c84SAndroid Build Coastguard Worker         arg->v[arg->c] = 0;
3234*cf5a6c84SAndroid Build Coastguard Worker         pl->type = 'f';
3235*cf5a6c84SAndroid Build Coastguard Worker         continue;
3236*cf5a6c84SAndroid Build Coastguard Worker       } else if (arg->c==2 && !strcmp(s, "(")) pl->type = 'f';
3237*cf5a6c84SAndroid Build Coastguard Worker     }
3238*cf5a6c84SAndroid Build Coastguard Worker 
3239*cf5a6c84SAndroid Build Coastguard Worker     // one or both of [function] name[()]
3240*cf5a6c84SAndroid Build Coastguard Worker     if (pl->type=='f') {
3241*cf5a6c84SAndroid Build Coastguard Worker       if (arg->v[0][strcspn(*arg->v, "\"'`><;|&$")]) {
3242*cf5a6c84SAndroid Build Coastguard Worker         s = *arg->v;
3243*cf5a6c84SAndroid Build Coastguard Worker         goto flush;
3244*cf5a6c84SAndroid Build Coastguard Worker       }
3245*cf5a6c84SAndroid Build Coastguard Worker       if (arg->c == 2 && strcmp(s, "(")) goto flush;
3246*cf5a6c84SAndroid Build Coastguard Worker       if (arg->c == 3) {
3247*cf5a6c84SAndroid Build Coastguard Worker         if (strcmp(s, ")")) goto flush;
3248*cf5a6c84SAndroid Build Coastguard Worker         dlist_add(expect, 0);
3249*cf5a6c84SAndroid Build Coastguard Worker         pl = 0;
3250*cf5a6c84SAndroid Build Coastguard Worker       }
3251*cf5a6c84SAndroid Build Coastguard Worker 
3252*cf5a6c84SAndroid Build Coastguard Worker       continue;
3253*cf5a6c84SAndroid Build Coastguard Worker 
3254*cf5a6c84SAndroid Build Coastguard Worker     // is it a line break token?
3255*cf5a6c84SAndroid Build Coastguard Worker     } else if (strchr(";|&", *s) && strncmp(s, "&>", 2)) {
3256*cf5a6c84SAndroid Build Coastguard Worker       arg->c--;
3257*cf5a6c84SAndroid Build Coastguard Worker 
3258*cf5a6c84SAndroid Build Coastguard Worker       // Connecting nonexistent statements is an error
3259*cf5a6c84SAndroid Build Coastguard Worker       if (!arg->c || !smemcmp(ex, "do\0A", 4)) goto flush;
3260*cf5a6c84SAndroid Build Coastguard Worker 
3261*cf5a6c84SAndroid Build Coastguard Worker       // treat ; as newline so we don't have to check both elsewhere.
3262*cf5a6c84SAndroid Build Coastguard Worker       if (!strcmp(s, ";")) {
3263*cf5a6c84SAndroid Build Coastguard Worker         arg->v[arg->c] = 0;
3264*cf5a6c84SAndroid Build Coastguard Worker         free(s);
3265*cf5a6c84SAndroid Build Coastguard Worker         s = 0;
3266*cf5a6c84SAndroid Build Coastguard Worker // TODO can't have ; between "for i" and in or do. (Newline yes, ; no. Why?)
3267*cf5a6c84SAndroid Build Coastguard Worker         if (!arg->c && !smemcmp(ex, "do\0C", 4)) continue;
3268*cf5a6c84SAndroid Build Coastguard Worker 
3269*cf5a6c84SAndroid Build Coastguard Worker       // ;; and friends only allowed in case statements
3270*cf5a6c84SAndroid Build Coastguard Worker       } else if (*s == ';') goto flush;
3271*cf5a6c84SAndroid Build Coastguard Worker       pl->count = -1;
3272*cf5a6c84SAndroid Build Coastguard Worker 
3273*cf5a6c84SAndroid Build Coastguard Worker       continue;
3274*cf5a6c84SAndroid Build Coastguard Worker 
3275*cf5a6c84SAndroid Build Coastguard Worker     // a for/select must have at least one additional argument on same line
3276*cf5a6c84SAndroid Build Coastguard Worker     } else if (!smemcmp(ex, "do\0A", 4)) {
3277*cf5a6c84SAndroid Build Coastguard Worker       // Sanity check and break the segment
3278*cf5a6c84SAndroid Build Coastguard Worker       if (strncmp(s, "((", 2) && *varend(s)) goto flush;
3279*cf5a6c84SAndroid Build Coastguard Worker       pl->count = -1;
3280*cf5a6c84SAndroid Build Coastguard Worker       (*expect)->prev->data = "do\0C";
3281*cf5a6c84SAndroid Build Coastguard Worker 
3282*cf5a6c84SAndroid Build Coastguard Worker       continue;
3283*cf5a6c84SAndroid Build Coastguard Worker 
3284*cf5a6c84SAndroid Build Coastguard Worker     // flow control is the first word of a pipeline segment
3285*cf5a6c84SAndroid Build Coastguard Worker     } else if (arg->c>1) {
3286*cf5a6c84SAndroid Build Coastguard Worker       // Except that [[ ]] is a type 0 segment
3287*cf5a6c84SAndroid Build Coastguard Worker       if (ex && *ex==']' && !strcmp(s, ex)) free(dlist_lpop(expect));
3288*cf5a6c84SAndroid Build Coastguard Worker 
3289*cf5a6c84SAndroid Build Coastguard Worker       continue;
3290*cf5a6c84SAndroid Build Coastguard Worker     }
3291*cf5a6c84SAndroid Build Coastguard Worker 
3292*cf5a6c84SAndroid Build Coastguard Worker     // The "test" part of for/select loops can have (at most) one "in" line,
3293*cf5a6c84SAndroid Build Coastguard Worker     // for {((;;))|name [in...]} do
3294*cf5a6c84SAndroid Build Coastguard Worker     if (!smemcmp(ex, "do\0C", 4)) {
3295*cf5a6c84SAndroid Build Coastguard Worker       if (strcmp(s, "do")) {
3296*cf5a6c84SAndroid Build Coastguard Worker         // can only have one "in" line between for/do, but not with for(())
3297*cf5a6c84SAndroid Build Coastguard Worker         if (pl->prev->type == 's') goto flush;
3298*cf5a6c84SAndroid Build Coastguard Worker         if (!strncmp(pl->prev->arg->v[1], "((", 2)) goto flush;
3299*cf5a6c84SAndroid Build Coastguard Worker         else if (strcmp(s, "in")) goto flush;
3300*cf5a6c84SAndroid Build Coastguard Worker         pl->type = 's';
3301*cf5a6c84SAndroid Build Coastguard Worker 
3302*cf5a6c84SAndroid Build Coastguard Worker         continue;
3303*cf5a6c84SAndroid Build Coastguard Worker       }
3304*cf5a6c84SAndroid Build Coastguard Worker     }
3305*cf5a6c84SAndroid Build Coastguard Worker 
3306*cf5a6c84SAndroid Build Coastguard Worker     // start of a new block?
3307*cf5a6c84SAndroid Build Coastguard Worker 
3308*cf5a6c84SAndroid Build Coastguard Worker     // for/select/case require var name on same line, can't break segment yet
3309*cf5a6c84SAndroid Build Coastguard Worker     if (!strcmp(s, "for") || !strcmp(s, "select") || !strcmp(s, "case")) {
3310*cf5a6c84SAndroid Build Coastguard Worker // TODO why !pl->type here
3311*cf5a6c84SAndroid Build Coastguard Worker       if (!pl->type) pl->type = (*s == 'c') ? 128 : 1;
3312*cf5a6c84SAndroid Build Coastguard Worker       dlist_add(expect, (*s == 'c') ? "esac" : "do\0A");
3313*cf5a6c84SAndroid Build Coastguard Worker 
3314*cf5a6c84SAndroid Build Coastguard Worker       continue;
3315*cf5a6c84SAndroid Build Coastguard Worker     }
3316*cf5a6c84SAndroid Build Coastguard Worker 
3317*cf5a6c84SAndroid Build Coastguard Worker     end = 0;
3318*cf5a6c84SAndroid Build Coastguard Worker     if (!strcmp(s, "if")) end = "then";
3319*cf5a6c84SAndroid Build Coastguard Worker     else if (!strcmp(s, "while") || !strcmp(s, "until")) end = "do\0B";
3320*cf5a6c84SAndroid Build Coastguard Worker     else if (!strcmp(s, "{")) end = "}";
3321*cf5a6c84SAndroid Build Coastguard Worker     else if (!strcmp(s, "(")) end = ")";
3322*cf5a6c84SAndroid Build Coastguard Worker     else if (!strcmp(s, "[[")) end = "]]";
3323*cf5a6c84SAndroid Build Coastguard Worker 
3324*cf5a6c84SAndroid Build Coastguard Worker     // Expecting NULL means any statement (don't care which).
3325*cf5a6c84SAndroid Build Coastguard Worker     if (!ex && *expect) {
3326*cf5a6c84SAndroid Build Coastguard Worker       if (pl->prev->type == 'f' && !end && smemcmp(s, "((", 2)) goto flush;
3327*cf5a6c84SAndroid Build Coastguard Worker       free(dlist_lpop(expect));
3328*cf5a6c84SAndroid Build Coastguard Worker     }
3329*cf5a6c84SAndroid Build Coastguard Worker 
3330*cf5a6c84SAndroid Build Coastguard Worker     // Did we start a new statement
3331*cf5a6c84SAndroid Build Coastguard Worker     if (end) {
3332*cf5a6c84SAndroid Build Coastguard Worker       if (*end!=']') pl->type = 1;
3333*cf5a6c84SAndroid Build Coastguard Worker       else {
3334*cf5a6c84SAndroid Build Coastguard Worker         // [[ ]] is a type 0 segment, not a flow control block
3335*cf5a6c84SAndroid Build Coastguard Worker         dlist_add(expect, end);
3336*cf5a6c84SAndroid Build Coastguard Worker         continue;
3337*cf5a6c84SAndroid Build Coastguard Worker       }
3338*cf5a6c84SAndroid Build Coastguard Worker 
3339*cf5a6c84SAndroid Build Coastguard Worker       // Only innermost statement needed in { { { echo ;} ;} ;} and such
3340*cf5a6c84SAndroid Build Coastguard Worker       if (*expect && !(*expect)->prev->data) free(dlist_lpop(expect));
3341*cf5a6c84SAndroid Build Coastguard Worker 
3342*cf5a6c84SAndroid Build Coastguard Worker     // if not looking for end of statement skip next few tests
3343*cf5a6c84SAndroid Build Coastguard Worker     } else if (!ex);
3344*cf5a6c84SAndroid Build Coastguard Worker 
3345*cf5a6c84SAndroid Build Coastguard Worker     // If we got here we expect a specific word to end this block: is this it?
3346*cf5a6c84SAndroid Build Coastguard Worker     else if (!strcmp(s, ex)) {
3347*cf5a6c84SAndroid Build Coastguard Worker       // can't "if | then" or "while && do", only ; & or newline works
3348*cf5a6c84SAndroid Build Coastguard Worker       if (strcmp(pl->prev->arg->v[pl->prev->arg->c] ? : "&", "&")) goto flush;
3349*cf5a6c84SAndroid Build Coastguard Worker 
3350*cf5a6c84SAndroid Build Coastguard Worker       // consume word, record block end in earlier !0 type (non-nested) blocks
3351*cf5a6c84SAndroid Build Coastguard Worker       free(dlist_lpop(expect));
3352*cf5a6c84SAndroid Build Coastguard Worker       if (3 == (pl->type = anystr(s, tails) ? 3 : 2)) {
3353*cf5a6c84SAndroid Build Coastguard Worker         for (i = 0, pl2 = pl3 = pl; (pl2 = pl2->prev);) {
3354*cf5a6c84SAndroid Build Coastguard Worker           if (pl2->type == 3) i++;
3355*cf5a6c84SAndroid Build Coastguard Worker           else if (pl2->type) {
3356*cf5a6c84SAndroid Build Coastguard Worker             if (!i) {
3357*cf5a6c84SAndroid Build Coastguard Worker               if (pl2->type == 2) {
3358*cf5a6c84SAndroid Build Coastguard Worker                 pl2->end = pl3;
3359*cf5a6c84SAndroid Build Coastguard Worker                 pl3 = pl2;   // chain multiple gearshifts for case/esac
3360*cf5a6c84SAndroid Build Coastguard Worker               } else pl2->end = pl;
3361*cf5a6c84SAndroid Build Coastguard Worker             }
3362*cf5a6c84SAndroid Build Coastguard Worker             if (pl2->type == 1 && --i<0) break;
3363*cf5a6c84SAndroid Build Coastguard Worker           }
3364*cf5a6c84SAndroid Build Coastguard Worker         }
3365*cf5a6c84SAndroid Build Coastguard Worker       }
3366*cf5a6c84SAndroid Build Coastguard Worker 
3367*cf5a6c84SAndroid Build Coastguard Worker       // if it's a multipart block, what comes next?
3368*cf5a6c84SAndroid Build Coastguard Worker       if (!strcmp(s, "do")) end = "done";
3369*cf5a6c84SAndroid Build Coastguard Worker       else if (!strcmp(s, "then")) end = "fi\0A";
3370*cf5a6c84SAndroid Build Coastguard Worker 
3371*cf5a6c84SAndroid Build Coastguard Worker     // fi could have elif, which queues a then.
3372*cf5a6c84SAndroid Build Coastguard Worker     } else if (!strcmp(ex, "fi")) {
3373*cf5a6c84SAndroid Build Coastguard Worker       if (!strcmp(s, "elif")) {
3374*cf5a6c84SAndroid Build Coastguard Worker         free(dlist_lpop(expect));
3375*cf5a6c84SAndroid Build Coastguard Worker         end = "then";
3376*cf5a6c84SAndroid Build Coastguard Worker       // catch duplicate else while we're here
3377*cf5a6c84SAndroid Build Coastguard Worker       } else if (!strcmp(s, "else")) {
3378*cf5a6c84SAndroid Build Coastguard Worker         if (ex[3] != 'A') {
3379*cf5a6c84SAndroid Build Coastguard Worker           s = "2 else";
3380*cf5a6c84SAndroid Build Coastguard Worker           goto flush;
3381*cf5a6c84SAndroid Build Coastguard Worker         }
3382*cf5a6c84SAndroid Build Coastguard Worker         free(dlist_lpop(expect));
3383*cf5a6c84SAndroid Build Coastguard Worker         end = "fi\0B";
3384*cf5a6c84SAndroid Build Coastguard Worker       }
3385*cf5a6c84SAndroid Build Coastguard Worker     }
3386*cf5a6c84SAndroid Build Coastguard Worker 
3387*cf5a6c84SAndroid Build Coastguard Worker     // Queue up the next thing to expect, all preceded by a statement
3388*cf5a6c84SAndroid Build Coastguard Worker     if (end) {
3389*cf5a6c84SAndroid Build Coastguard Worker       if (!pl->type) pl->type = 2;
3390*cf5a6c84SAndroid Build Coastguard Worker 
3391*cf5a6c84SAndroid Build Coastguard Worker       dlist_add(expect, end);
3392*cf5a6c84SAndroid Build Coastguard Worker       if (!anystr(end, tails)) dlist_add(expect, 0);
3393*cf5a6c84SAndroid Build Coastguard Worker       pl->count = -1;
3394*cf5a6c84SAndroid Build Coastguard Worker     }
3395*cf5a6c84SAndroid Build Coastguard Worker 
3396*cf5a6c84SAndroid Build Coastguard Worker     // syntax error check: these can't be the first word in an unexpected place
3397*cf5a6c84SAndroid Build Coastguard Worker     if (!pl->type && anystr(s, (char *[]){"then", "do", "esac", "}", "]]", ")",
3398*cf5a6c84SAndroid Build Coastguard Worker         "done", "fi", "elif", "else", 0})) goto flush;
3399*cf5a6c84SAndroid Build Coastguard Worker   }
3400*cf5a6c84SAndroid Build Coastguard Worker   free(delete);
3401*cf5a6c84SAndroid Build Coastguard Worker 
3402*cf5a6c84SAndroid Build Coastguard Worker   // Return now if line didn't tell us to DO anything.
3403*cf5a6c84SAndroid Build Coastguard Worker   if (!*ppl) return 0;
3404*cf5a6c84SAndroid Build Coastguard Worker   pl = (*ppl)->prev;
3405*cf5a6c84SAndroid Build Coastguard Worker 
3406*cf5a6c84SAndroid Build Coastguard Worker   // return if HERE document pending or more flow control needed to complete
3407*cf5a6c84SAndroid Build Coastguard Worker   if (pl->count != pl->here) return 1;
3408*cf5a6c84SAndroid Build Coastguard Worker   if (*expect) return 1;
3409*cf5a6c84SAndroid Build Coastguard Worker   if (pl->arg->v[pl->arg->c] && strcmp(pl->arg->v[pl->arg->c], "&")) return 1;
3410*cf5a6c84SAndroid Build Coastguard Worker 
3411*cf5a6c84SAndroid Build Coastguard Worker   // Transplant completed function bodies into reference counted structures
3412*cf5a6c84SAndroid Build Coastguard Worker   for (;;) {
3413*cf5a6c84SAndroid Build Coastguard Worker     if (pl->type=='f') {
3414*cf5a6c84SAndroid Build Coastguard Worker       struct sh_function *funky;
3415*cf5a6c84SAndroid Build Coastguard Worker 
3416*cf5a6c84SAndroid Build Coastguard Worker       // Create sh_function struct, attach to declaration's pipeline segment
3417*cf5a6c84SAndroid Build Coastguard Worker       funky = xmalloc(sizeof(struct sh_function));
3418*cf5a6c84SAndroid Build Coastguard Worker       funky->refcount = 1;
3419*cf5a6c84SAndroid Build Coastguard Worker       funky->name = *pl->arg->v;
3420*cf5a6c84SAndroid Build Coastguard Worker       *pl->arg->v = (void *)funky;
3421*cf5a6c84SAndroid Build Coastguard Worker       pl->type = 'F'; // different cleanup
3422*cf5a6c84SAndroid Build Coastguard Worker 
3423*cf5a6c84SAndroid Build Coastguard Worker       // Transplant function body into new struct, re-circling both lists
3424*cf5a6c84SAndroid Build Coastguard Worker       pl2 = pl->next;
3425*cf5a6c84SAndroid Build Coastguard Worker       // Add NOP 'f' segment (TODO: remove need for this?)
3426*cf5a6c84SAndroid Build Coastguard Worker       (funky->pipeline = add_pl(&pl2, 0))->type = 'f';
3427*cf5a6c84SAndroid Build Coastguard Worker       // Find end of block
3428*cf5a6c84SAndroid Build Coastguard Worker       for (i = 0, pl3 = pl2->next;;pl3 = pl3->next)
3429*cf5a6c84SAndroid Build Coastguard Worker         if (pl3->type == 1) i++;
3430*cf5a6c84SAndroid Build Coastguard Worker         else if (pl3->type == 3 && --i<0) break;
3431*cf5a6c84SAndroid Build Coastguard Worker       // Chop removed segment out of old list.
3432*cf5a6c84SAndroid Build Coastguard Worker       pl3->next->prev = pl;
3433*cf5a6c84SAndroid Build Coastguard Worker       pl->next = pl3->next;
3434*cf5a6c84SAndroid Build Coastguard Worker       // Terminate removed segment.
3435*cf5a6c84SAndroid Build Coastguard Worker       pl2->prev = 0;
3436*cf5a6c84SAndroid Build Coastguard Worker       pl3->next = 0;
3437*cf5a6c84SAndroid Build Coastguard Worker     }
3438*cf5a6c84SAndroid Build Coastguard Worker     if (pl == *ppl) break;
3439*cf5a6c84SAndroid Build Coastguard Worker     pl = pl->prev;
3440*cf5a6c84SAndroid Build Coastguard Worker   }
3441*cf5a6c84SAndroid Build Coastguard Worker 
3442*cf5a6c84SAndroid Build Coastguard Worker   // Don't need more input, can start executing.
3443*cf5a6c84SAndroid Build Coastguard Worker 
3444*cf5a6c84SAndroid Build Coastguard Worker   dlist_terminate(*ppl);
3445*cf5a6c84SAndroid Build Coastguard Worker   return 0;
3446*cf5a6c84SAndroid Build Coastguard Worker 
3447*cf5a6c84SAndroid Build Coastguard Worker flush:
3448*cf5a6c84SAndroid Build Coastguard Worker   if (s) syntax_err(s);
3449*cf5a6c84SAndroid Build Coastguard Worker   llist_traverse(*ppl, free_pipeline);
3450*cf5a6c84SAndroid Build Coastguard Worker   *ppl = 0;
3451*cf5a6c84SAndroid Build Coastguard Worker   llist_traverse(*expect, free);
3452*cf5a6c84SAndroid Build Coastguard Worker   *expect = 0;
3453*cf5a6c84SAndroid Build Coastguard Worker 
3454*cf5a6c84SAndroid Build Coastguard Worker   return 0-!!s;
3455*cf5a6c84SAndroid Build Coastguard Worker }
3456*cf5a6c84SAndroid Build Coastguard Worker 
3457*cf5a6c84SAndroid Build Coastguard Worker // Find + and - jobs. Returns index of plus, writes minus to *minus
find_plus_minus(int * minus)3458*cf5a6c84SAndroid Build Coastguard Worker int find_plus_minus(int *minus)
3459*cf5a6c84SAndroid Build Coastguard Worker {
3460*cf5a6c84SAndroid Build Coastguard Worker   long long when, then;
3461*cf5a6c84SAndroid Build Coastguard Worker   int i, plus;
3462*cf5a6c84SAndroid Build Coastguard Worker 
3463*cf5a6c84SAndroid Build Coastguard Worker   if (minus) *minus = 0;
3464*cf5a6c84SAndroid Build Coastguard Worker   for (then = i = plus = 0; i<TT.jobs.c; i++) {
3465*cf5a6c84SAndroid Build Coastguard Worker     if ((when = ((struct sh_process *)TT.jobs.v[i])->when) > then) {
3466*cf5a6c84SAndroid Build Coastguard Worker       then = when;
3467*cf5a6c84SAndroid Build Coastguard Worker       if (minus) *minus = plus;
3468*cf5a6c84SAndroid Build Coastguard Worker       plus = i;
3469*cf5a6c84SAndroid Build Coastguard Worker     }
3470*cf5a6c84SAndroid Build Coastguard Worker   }
3471*cf5a6c84SAndroid Build Coastguard Worker 
3472*cf5a6c84SAndroid Build Coastguard Worker   return plus;
3473*cf5a6c84SAndroid Build Coastguard Worker }
3474*cf5a6c84SAndroid Build Coastguard Worker 
is_plus_minus(int i,int plus,int minus)3475*cf5a6c84SAndroid Build Coastguard Worker char is_plus_minus(int i, int plus, int minus)
3476*cf5a6c84SAndroid Build Coastguard Worker {
3477*cf5a6c84SAndroid Build Coastguard Worker   return (i == plus) ? '+' : (i == minus) ? '-' : ' ';
3478*cf5a6c84SAndroid Build Coastguard Worker }
3479*cf5a6c84SAndroid Build Coastguard Worker 
3480*cf5a6c84SAndroid Build Coastguard Worker 
3481*cf5a6c84SAndroid Build Coastguard Worker // We pass in dash to avoid looping over every job each time
show_job(struct sh_process * pp,char dash)3482*cf5a6c84SAndroid Build Coastguard Worker char *show_job(struct sh_process *pp, char dash)
3483*cf5a6c84SAndroid Build Coastguard Worker {
3484*cf5a6c84SAndroid Build Coastguard Worker   char *s = "Run", *buf = 0;
3485*cf5a6c84SAndroid Build Coastguard Worker   int i, j, len, len2;
3486*cf5a6c84SAndroid Build Coastguard Worker 
3487*cf5a6c84SAndroid Build Coastguard Worker // TODO Terminated (Exited)
3488*cf5a6c84SAndroid Build Coastguard Worker   if (pp->exit<0) s = "Stop";
3489*cf5a6c84SAndroid Build Coastguard Worker   else if (pp->exit>126) s = "Kill";
3490*cf5a6c84SAndroid Build Coastguard Worker   else if (pp->exit>0) s = "Done";
3491*cf5a6c84SAndroid Build Coastguard Worker   for (i = len = len2 = 0;; i++) {
3492*cf5a6c84SAndroid Build Coastguard Worker     len += snprintf(buf, len2, "[%d]%c  %-6s", pp->job, dash, s);
3493*cf5a6c84SAndroid Build Coastguard Worker     for (j = 0; j<pp->raw->c; j++)
3494*cf5a6c84SAndroid Build Coastguard Worker       len += snprintf(buf, len2, " %s"+!j, pp->raw->v[j]);
3495*cf5a6c84SAndroid Build Coastguard Worker     if (!i) buf = xmalloc(len2 = len+1);
3496*cf5a6c84SAndroid Build Coastguard Worker     else break;
3497*cf5a6c84SAndroid Build Coastguard Worker   }
3498*cf5a6c84SAndroid Build Coastguard Worker 
3499*cf5a6c84SAndroid Build Coastguard Worker   return buf;
3500*cf5a6c84SAndroid Build Coastguard Worker }
3501*cf5a6c84SAndroid Build Coastguard Worker 
3502*cf5a6c84SAndroid Build Coastguard Worker // Wait for pid to exit and remove from jobs table, returning process or 0.
wait_job(int pid,int nohang)3503*cf5a6c84SAndroid Build Coastguard Worker struct sh_process *wait_job(int pid, int nohang)
3504*cf5a6c84SAndroid Build Coastguard Worker {
3505*cf5a6c84SAndroid Build Coastguard Worker   struct sh_process *pp = pp;
3506*cf5a6c84SAndroid Build Coastguard Worker   int ii, status, minus, plus;
3507*cf5a6c84SAndroid Build Coastguard Worker 
3508*cf5a6c84SAndroid Build Coastguard Worker   if (TT.jobs.c<1) return 0;
3509*cf5a6c84SAndroid Build Coastguard Worker   for (;;) {
3510*cf5a6c84SAndroid Build Coastguard Worker     errno = 0;
3511*cf5a6c84SAndroid Build Coastguard Worker     if (1>(pid = waitpid(pid, &status, nohang ? WNOHANG : 0))) {
3512*cf5a6c84SAndroid Build Coastguard Worker       if (!nohang && errno==EINTR && !toys.signal) continue;
3513*cf5a6c84SAndroid Build Coastguard Worker       return 0;
3514*cf5a6c84SAndroid Build Coastguard Worker     }
3515*cf5a6c84SAndroid Build Coastguard Worker     for (ii = 0; ii<TT.jobs.c; ii++) {
3516*cf5a6c84SAndroid Build Coastguard Worker       pp = (void *)TT.jobs.v[ii];
3517*cf5a6c84SAndroid Build Coastguard Worker       if (pp->pid == pid) break;
3518*cf5a6c84SAndroid Build Coastguard Worker     }
3519*cf5a6c84SAndroid Build Coastguard Worker     if (ii == TT.jobs.c) continue;
3520*cf5a6c84SAndroid Build Coastguard Worker     if (pid<1) return 0;
3521*cf5a6c84SAndroid Build Coastguard Worker     if (!WIFSTOPPED(status) && !WIFCONTINUED(status)) break;
3522*cf5a6c84SAndroid Build Coastguard Worker   }
3523*cf5a6c84SAndroid Build Coastguard Worker   plus = find_plus_minus(&minus);
3524*cf5a6c84SAndroid Build Coastguard Worker   memmove(TT.jobs.v+ii, TT.jobs.v+ii+1, (TT.jobs.c--)-ii);
3525*cf5a6c84SAndroid Build Coastguard Worker   pp->exit = WIFEXITED(status) ? WEXITSTATUS(status) : WTERMSIG(status)+128;
3526*cf5a6c84SAndroid Build Coastguard Worker   pp->dash = is_plus_minus(ii, plus, minus);
3527*cf5a6c84SAndroid Build Coastguard Worker 
3528*cf5a6c84SAndroid Build Coastguard Worker   return pp;
3529*cf5a6c84SAndroid Build Coastguard Worker }
3530*cf5a6c84SAndroid Build Coastguard Worker 
3531*cf5a6c84SAndroid Build Coastguard Worker // wait for every process in a pipeline to end
wait_pipeline(struct sh_process * pp)3532*cf5a6c84SAndroid Build Coastguard Worker static int wait_pipeline(struct sh_process *pp)
3533*cf5a6c84SAndroid Build Coastguard Worker {
3534*cf5a6c84SAndroid Build Coastguard Worker   int rc = 0;
3535*cf5a6c84SAndroid Build Coastguard Worker 
3536*cf5a6c84SAndroid Build Coastguard Worker   for (dlist_terminate(pp); pp; pp = pp->next) {
3537*cf5a6c84SAndroid Build Coastguard Worker     if (pp->pid) {
3538*cf5a6c84SAndroid Build Coastguard Worker       // TODO job control: not xwait, handle EINTR ourselves and check signals
3539*cf5a6c84SAndroid Build Coastguard Worker       pp->exit = xwaitpid(pp->pid);
3540*cf5a6c84SAndroid Build Coastguard Worker       pp->pid = 0;
3541*cf5a6c84SAndroid Build Coastguard Worker     }
3542*cf5a6c84SAndroid Build Coastguard Worker     // TODO handle set -o pipefail here
3543*cf5a6c84SAndroid Build Coastguard Worker     rc = (pp->flags&PFLAG_NOT) ? !pp->exit : pp->exit;
3544*cf5a6c84SAndroid Build Coastguard Worker   }
3545*cf5a6c84SAndroid Build Coastguard Worker 
3546*cf5a6c84SAndroid Build Coastguard Worker   while ((pp = wait_job(-1, 1)) && (TT.options&FLAG_i)) {
3547*cf5a6c84SAndroid Build Coastguard Worker     char *s = show_job(pp, pp->dash);
3548*cf5a6c84SAndroid Build Coastguard Worker 
3549*cf5a6c84SAndroid Build Coastguard Worker     dprintf(2, "%s\n", s);
3550*cf5a6c84SAndroid Build Coastguard Worker     free(s);
3551*cf5a6c84SAndroid Build Coastguard Worker   }
3552*cf5a6c84SAndroid Build Coastguard Worker 
3553*cf5a6c84SAndroid Build Coastguard Worker   return rc;
3554*cf5a6c84SAndroid Build Coastguard Worker }
3555*cf5a6c84SAndroid Build Coastguard Worker 
3556*cf5a6c84SAndroid Build Coastguard Worker // Print prompt to stderr, parsing escapes
3557*cf5a6c84SAndroid Build Coastguard Worker // Truncated to 4k at the moment, waiting for somebody to complain.
do_prompt(char * prompt)3558*cf5a6c84SAndroid Build Coastguard Worker static void do_prompt(char *prompt)
3559*cf5a6c84SAndroid Build Coastguard Worker {
3560*cf5a6c84SAndroid Build Coastguard Worker   char *s, *ss, c, cc, *pp = toybuf;
3561*cf5a6c84SAndroid Build Coastguard Worker   int len, ll;
3562*cf5a6c84SAndroid Build Coastguard Worker 
3563*cf5a6c84SAndroid Build Coastguard Worker   if (!prompt) return;
3564*cf5a6c84SAndroid Build Coastguard Worker   while ((len = sizeof(toybuf)-(pp-toybuf))>0 && *prompt) {
3565*cf5a6c84SAndroid Build Coastguard Worker     c = *(prompt++);
3566*cf5a6c84SAndroid Build Coastguard Worker 
3567*cf5a6c84SAndroid Build Coastguard Worker     if (c=='!') {
3568*cf5a6c84SAndroid Build Coastguard Worker       if (*prompt=='!') prompt++;
3569*cf5a6c84SAndroid Build Coastguard Worker       else {
3570*cf5a6c84SAndroid Build Coastguard Worker         pp += snprintf(pp, len, "%u", TT.LINENO);
3571*cf5a6c84SAndroid Build Coastguard Worker         continue;
3572*cf5a6c84SAndroid Build Coastguard Worker       }
3573*cf5a6c84SAndroid Build Coastguard Worker     } else if (c=='\\') {
3574*cf5a6c84SAndroid Build Coastguard Worker       cc = *(prompt++);
3575*cf5a6c84SAndroid Build Coastguard Worker       if (!cc) {
3576*cf5a6c84SAndroid Build Coastguard Worker         *pp++ = c;
3577*cf5a6c84SAndroid Build Coastguard Worker         break;
3578*cf5a6c84SAndroid Build Coastguard Worker       }
3579*cf5a6c84SAndroid Build Coastguard Worker 
3580*cf5a6c84SAndroid Build Coastguard Worker       // \nnn \dD{}hHjlstT@AuvVwW!#$
3581*cf5a6c84SAndroid Build Coastguard Worker       // Ignore bash's "nonprintable" hack; query our cursor position instead.
3582*cf5a6c84SAndroid Build Coastguard Worker       if (cc=='[' || cc==']') continue;
3583*cf5a6c84SAndroid Build Coastguard Worker       else if (cc=='$') *pp++ = getuid() ? '$' : '#';
3584*cf5a6c84SAndroid Build Coastguard Worker       else if (cc=='h' || cc=='H') {
3585*cf5a6c84SAndroid Build Coastguard Worker         *pp = 0;
3586*cf5a6c84SAndroid Build Coastguard Worker         gethostname(pp, len);
3587*cf5a6c84SAndroid Build Coastguard Worker         pp[len-1] = 0;
3588*cf5a6c84SAndroid Build Coastguard Worker         if (cc=='h' && (s = strchr(pp, '.'))) *s = 0;
3589*cf5a6c84SAndroid Build Coastguard Worker         pp += strlen(pp);
3590*cf5a6c84SAndroid Build Coastguard Worker       } else if (cc=='s') {
3591*cf5a6c84SAndroid Build Coastguard Worker         s = getbasename(*toys.argv);
3592*cf5a6c84SAndroid Build Coastguard Worker         while (*s && len--) *pp++ = *s++;
3593*cf5a6c84SAndroid Build Coastguard Worker       } else if (cc=='w') {
3594*cf5a6c84SAndroid Build Coastguard Worker         if ((s = getvar("PWD"))) {
3595*cf5a6c84SAndroid Build Coastguard Worker           if ((ss = getvar("HOME")) && strstart(&s, ss)) {
3596*cf5a6c84SAndroid Build Coastguard Worker             *pp++ = '~';
3597*cf5a6c84SAndroid Build Coastguard Worker             if (--len && *s!='/') *pp++ = '/';
3598*cf5a6c84SAndroid Build Coastguard Worker             len--;
3599*cf5a6c84SAndroid Build Coastguard Worker           }
3600*cf5a6c84SAndroid Build Coastguard Worker           if (len>0) {
3601*cf5a6c84SAndroid Build Coastguard Worker             ll = strlen(s);
3602*cf5a6c84SAndroid Build Coastguard Worker             pp = stpncpy(pp, s, ll>len ? len : ll);
3603*cf5a6c84SAndroid Build Coastguard Worker           }
3604*cf5a6c84SAndroid Build Coastguard Worker         }
3605*cf5a6c84SAndroid Build Coastguard Worker       } else if (!(c = unescape(cc))) {
3606*cf5a6c84SAndroid Build Coastguard Worker         *pp++ = '\\';
3607*cf5a6c84SAndroid Build Coastguard Worker         if (--len) *pp++ = c;
3608*cf5a6c84SAndroid Build Coastguard Worker       } else *pp++ = c;
3609*cf5a6c84SAndroid Build Coastguard Worker     } else *pp++ = c;
3610*cf5a6c84SAndroid Build Coastguard Worker   }
3611*cf5a6c84SAndroid Build Coastguard Worker   len = pp-toybuf;
3612*cf5a6c84SAndroid Build Coastguard Worker   if (len>=sizeof(toybuf)) len = sizeof(toybuf);
3613*cf5a6c84SAndroid Build Coastguard Worker   writeall(2, toybuf, len);
3614*cf5a6c84SAndroid Build Coastguard Worker }
3615*cf5a6c84SAndroid Build Coastguard Worker 
3616*cf5a6c84SAndroid Build Coastguard Worker // returns NULL for EOF, 1 for invalid, else null terminated string.
get_next_line(FILE * ff,int prompt)3617*cf5a6c84SAndroid Build Coastguard Worker static char *get_next_line(FILE *ff, int prompt)
3618*cf5a6c84SAndroid Build Coastguard Worker {
3619*cf5a6c84SAndroid Build Coastguard Worker   char *new;
3620*cf5a6c84SAndroid Build Coastguard Worker   int len, cc;
3621*cf5a6c84SAndroid Build Coastguard Worker 
3622*cf5a6c84SAndroid Build Coastguard Worker   if (!ff) {
3623*cf5a6c84SAndroid Build Coastguard Worker     char ps[16];
3624*cf5a6c84SAndroid Build Coastguard Worker 
3625*cf5a6c84SAndroid Build Coastguard Worker     sprintf(ps, "PS%d", prompt);
3626*cf5a6c84SAndroid Build Coastguard Worker     do_prompt(getvar(ps));
3627*cf5a6c84SAndroid Build Coastguard Worker   }
3628*cf5a6c84SAndroid Build Coastguard Worker 
3629*cf5a6c84SAndroid Build Coastguard Worker // TODO what should ctrl-C do? (also in "select")
3630*cf5a6c84SAndroid Build Coastguard Worker // TODO line editing/history, should set $COLUMNS $LINES and sigwinch update
3631*cf5a6c84SAndroid Build Coastguard Worker //  TODO: after first EINTR returns closed?
3632*cf5a6c84SAndroid Build Coastguard Worker // TODO: ctrl-z during script read having already read partial line,
3633*cf5a6c84SAndroid Build Coastguard Worker // SIGSTOP and SIGTSTP need SA_RESTART, but child proc should stop
3634*cf5a6c84SAndroid Build Coastguard Worker // TODO if (!isspace(*new)) add_to_history(line);
3635*cf5a6c84SAndroid Build Coastguard Worker // TODO: embedded nul bytes need signaling for the "tried to run binary" test.
3636*cf5a6c84SAndroid Build Coastguard Worker 
3637*cf5a6c84SAndroid Build Coastguard Worker   for (new = 0, len = 0;;) {
3638*cf5a6c84SAndroid Build Coastguard Worker     errno = 0;
3639*cf5a6c84SAndroid Build Coastguard Worker     if (!(cc = getc(ff ? : stdin))) {
3640*cf5a6c84SAndroid Build Coastguard Worker       if (TT.LINENO) continue;
3641*cf5a6c84SAndroid Build Coastguard Worker       free(new);
3642*cf5a6c84SAndroid Build Coastguard Worker       return (char *)1;
3643*cf5a6c84SAndroid Build Coastguard Worker     }
3644*cf5a6c84SAndroid Build Coastguard Worker     if (cc<0) {
3645*cf5a6c84SAndroid Build Coastguard Worker       if (errno == EINTR) continue;
3646*cf5a6c84SAndroid Build Coastguard Worker       break;
3647*cf5a6c84SAndroid Build Coastguard Worker     }
3648*cf5a6c84SAndroid Build Coastguard Worker     if (!(len&63)) new = xrealloc(new, len+65);
3649*cf5a6c84SAndroid Build Coastguard Worker     if ((new[len++] = cc) == '\n') break;
3650*cf5a6c84SAndroid Build Coastguard Worker   }
3651*cf5a6c84SAndroid Build Coastguard Worker   if (new) new[len] = 0;
3652*cf5a6c84SAndroid Build Coastguard Worker 
3653*cf5a6c84SAndroid Build Coastguard Worker   return new;
3654*cf5a6c84SAndroid Build Coastguard Worker }
3655*cf5a6c84SAndroid Build Coastguard Worker 
3656*cf5a6c84SAndroid Build Coastguard Worker /*
3657*cf5a6c84SAndroid Build Coastguard Worker  TODO: "echo | read i" is backgroundable with ctrl-Z despite read = builtin.
3658*cf5a6c84SAndroid Build Coastguard Worker        probably have to inline run_command here to do that? Implicit ()
3659*cf5a6c84SAndroid Build Coastguard Worker        also "X=42 | true; echo $X" doesn't get X.
3660*cf5a6c84SAndroid Build Coastguard Worker        I.E. run_subshell() here sometimes? (But when?)
3661*cf5a6c84SAndroid Build Coastguard Worker  TODO If we just started a new pipeline, implicit parentheses (subshell)
3662*cf5a6c84SAndroid Build Coastguard Worker  TODO can't free sh_process delete until ready to dispose else no debug output
3663*cf5a6c84SAndroid Build Coastguard Worker  TODO: a | b | c needs subshell for builtins?
3664*cf5a6c84SAndroid Build Coastguard Worker         - anything that can produce output
3665*cf5a6c84SAndroid Build Coastguard Worker         - echo declare dirs
3666*cf5a6c84SAndroid Build Coastguard Worker       (a; b; c) like { } but subshell
3667*cf5a6c84SAndroid Build Coastguard Worker       when to auto-exec? ps vs sh -c 'ps' vs sh -c '(ps)'
3668*cf5a6c84SAndroid Build Coastguard Worker */
3669*cf5a6c84SAndroid Build Coastguard Worker 
3670*cf5a6c84SAndroid Build Coastguard Worker // run a parsed shell function. Handle flow control blocks and characters,
3671*cf5a6c84SAndroid Build Coastguard Worker // setup pipes and block redirection, break/continue, call builtins, functions,
3672*cf5a6c84SAndroid Build Coastguard Worker // vfork/exec external commands. Return when out of input.
run_lines(void)3673*cf5a6c84SAndroid Build Coastguard Worker static void run_lines(void)
3674*cf5a6c84SAndroid Build Coastguard Worker {
3675*cf5a6c84SAndroid Build Coastguard Worker   char *ctl, *s, *ss, **vv;
3676*cf5a6c84SAndroid Build Coastguard Worker   struct sh_process *pp, *pplist = 0; // processes piping into current level
3677*cf5a6c84SAndroid Build Coastguard Worker   long i, j, k;
3678*cf5a6c84SAndroid Build Coastguard Worker 
3679*cf5a6c84SAndroid Build Coastguard Worker   // iterate through pipeline segments
3680*cf5a6c84SAndroid Build Coastguard Worker   for (;;) {
3681*cf5a6c84SAndroid Build Coastguard Worker     if (!TT.ff->pl) {
3682*cf5a6c84SAndroid Build Coastguard Worker       if (!end_fcall(1)) break;
3683*cf5a6c84SAndroid Build Coastguard Worker       goto advance;
3684*cf5a6c84SAndroid Build Coastguard Worker     }
3685*cf5a6c84SAndroid Build Coastguard Worker 
3686*cf5a6c84SAndroid Build Coastguard Worker     ctl = TT.ff->pl->end->arg->v[TT.ff->pl->end->arg->c];
3687*cf5a6c84SAndroid Build Coastguard Worker     s = *TT.ff->pl->arg->v;
3688*cf5a6c84SAndroid Build Coastguard Worker     ss = TT.ff->pl->arg->v[1];
3689*cf5a6c84SAndroid Build Coastguard Worker //dprintf(2, "%d s=%s ss=%s ctl=%s type=%d pl=%p ff=%p\n", getpid(), (TT.ff->pl->type == 'F') ? ((struct sh_function *)s)->name : s, ss, ctl, TT.ff->pl->type, TT.ff->pl, TT.ff);
3690*cf5a6c84SAndroid Build Coastguard Worker     if (!pplist) TT.hfd = 10;
3691*cf5a6c84SAndroid Build Coastguard Worker 
3692*cf5a6c84SAndroid Build Coastguard Worker     // Skip disabled blocks, handle pipes and backgrounding
3693*cf5a6c84SAndroid Build Coastguard Worker     if (TT.ff->pl->type<2) {
3694*cf5a6c84SAndroid Build Coastguard Worker       if (!TT.ff->blk->run) {
3695*cf5a6c84SAndroid Build Coastguard Worker         TT.ff->pl = TT.ff->pl->end->next;
3696*cf5a6c84SAndroid Build Coastguard Worker 
3697*cf5a6c84SAndroid Build Coastguard Worker         continue;
3698*cf5a6c84SAndroid Build Coastguard Worker       }
3699*cf5a6c84SAndroid Build Coastguard Worker 
3700*cf5a6c84SAndroid Build Coastguard Worker       if (TT.options&OPT_x) {
3701*cf5a6c84SAndroid Build Coastguard Worker         unsigned lineno;
3702*cf5a6c84SAndroid Build Coastguard Worker         char *ss, *ps4 = getvar("PS4");
3703*cf5a6c84SAndroid Build Coastguard Worker 
3704*cf5a6c84SAndroid Build Coastguard Worker         // duplicate first char of ps4 call depth times
3705*cf5a6c84SAndroid Build Coastguard Worker         if (ps4 && *ps4) {
3706*cf5a6c84SAndroid Build Coastguard Worker           j = getutf8(ps4, k = strlen(ps4), 0);
3707*cf5a6c84SAndroid Build Coastguard Worker           ss = xmalloc(TT.srclvl*j+k+1);
3708*cf5a6c84SAndroid Build Coastguard Worker           for (k = 0; k<TT.srclvl; k++) memcpy(ss+k*j, ps4, j);
3709*cf5a6c84SAndroid Build Coastguard Worker           strcpy(ss+k*j, ps4+j);
3710*cf5a6c84SAndroid Build Coastguard Worker           // show saved line number from function, not next to read
3711*cf5a6c84SAndroid Build Coastguard Worker           lineno = TT.LINENO;
3712*cf5a6c84SAndroid Build Coastguard Worker           TT.LINENO = TT.ff->pl->lineno;
3713*cf5a6c84SAndroid Build Coastguard Worker           do_prompt(ss);
3714*cf5a6c84SAndroid Build Coastguard Worker           TT.LINENO = lineno;
3715*cf5a6c84SAndroid Build Coastguard Worker           free(ss);
3716*cf5a6c84SAndroid Build Coastguard Worker 
3717*cf5a6c84SAndroid Build Coastguard Worker           // TODO resolve variables
3718*cf5a6c84SAndroid Build Coastguard Worker           ss = pl2str(TT.ff->pl, 1);
3719*cf5a6c84SAndroid Build Coastguard Worker           dprintf(2, "%s\n", ss);
3720*cf5a6c84SAndroid Build Coastguard Worker           free(ss);
3721*cf5a6c84SAndroid Build Coastguard Worker         }
3722*cf5a6c84SAndroid Build Coastguard Worker       }
3723*cf5a6c84SAndroid Build Coastguard Worker 
3724*cf5a6c84SAndroid Build Coastguard Worker       // pipe data into and out of this segment, I.E. leading/trailing |
3725*cf5a6c84SAndroid Build Coastguard Worker       unredirect(TT.ff->blk->urd);
3726*cf5a6c84SAndroid Build Coastguard Worker       TT.ff->blk->urd = 0;
3727*cf5a6c84SAndroid Build Coastguard Worker       TT.ff->blk->pipe = 0;
3728*cf5a6c84SAndroid Build Coastguard Worker 
3729*cf5a6c84SAndroid Build Coastguard Worker       // Consume pipe from previous segment as stdin.
3730*cf5a6c84SAndroid Build Coastguard Worker       if (TT.ff->blk->pout != -1) {
3731*cf5a6c84SAndroid Build Coastguard Worker         TT.ff->blk->pipe++;
3732*cf5a6c84SAndroid Build Coastguard Worker         if (save_redirect(&TT.ff->blk->urd, TT.ff->blk->pout, 0)) break;
3733*cf5a6c84SAndroid Build Coastguard Worker         close(TT.ff->blk->pout);
3734*cf5a6c84SAndroid Build Coastguard Worker         TT.ff->blk->pout = -1;
3735*cf5a6c84SAndroid Build Coastguard Worker       }
3736*cf5a6c84SAndroid Build Coastguard Worker 
3737*cf5a6c84SAndroid Build Coastguard Worker       // Create output pipe and save next process's stdin in pout
3738*cf5a6c84SAndroid Build Coastguard Worker       if (ctl && *ctl == '|' && ctl[1] != '|') {
3739*cf5a6c84SAndroid Build Coastguard Worker         int pipes[2] = {-1, -1};
3740*cf5a6c84SAndroid Build Coastguard Worker 
3741*cf5a6c84SAndroid Build Coastguard Worker         TT.ff->blk->pipe++;
3742*cf5a6c84SAndroid Build Coastguard Worker         if (pipe(pipes)) {
3743*cf5a6c84SAndroid Build Coastguard Worker           perror_msg("pipe");
3744*cf5a6c84SAndroid Build Coastguard Worker 
3745*cf5a6c84SAndroid Build Coastguard Worker           break;
3746*cf5a6c84SAndroid Build Coastguard Worker         }
3747*cf5a6c84SAndroid Build Coastguard Worker         if (save_redirect(&TT.ff->blk->urd, pipes[1], 1)) {
3748*cf5a6c84SAndroid Build Coastguard Worker           close(pipes[0]);
3749*cf5a6c84SAndroid Build Coastguard Worker           close(pipes[1]);
3750*cf5a6c84SAndroid Build Coastguard Worker 
3751*cf5a6c84SAndroid Build Coastguard Worker           break;
3752*cf5a6c84SAndroid Build Coastguard Worker         }
3753*cf5a6c84SAndroid Build Coastguard Worker         if (pipes[1] != 1) close(pipes[1]);
3754*cf5a6c84SAndroid Build Coastguard Worker         fcntl(TT.ff->blk->pout = *pipes, F_SETFD, FD_CLOEXEC);
3755*cf5a6c84SAndroid Build Coastguard Worker         if (ctl[1] == '&') save_redirect(&TT.ff->blk->urd, 1, 2);
3756*cf5a6c84SAndroid Build Coastguard Worker       }
3757*cf5a6c84SAndroid Build Coastguard Worker     }
3758*cf5a6c84SAndroid Build Coastguard Worker 
3759*cf5a6c84SAndroid Build Coastguard Worker     // If executable segment parse and run next command saving resulting process
3760*cf5a6c84SAndroid Build Coastguard Worker     if (!TT.ff->pl->type)
3761*cf5a6c84SAndroid Build Coastguard Worker       dlist_add_nomalloc((void *)&pplist, (void *)run_command());
3762*cf5a6c84SAndroid Build Coastguard Worker 
3763*cf5a6c84SAndroid Build Coastguard Worker     // Start of flow control block?
3764*cf5a6c84SAndroid Build Coastguard Worker     else if (TT.ff->pl->type == 1) {
3765*cf5a6c84SAndroid Build Coastguard Worker 
3766*cf5a6c84SAndroid Build Coastguard Worker // TODO test cat | {thingy} is new PID: { is ( for |
3767*cf5a6c84SAndroid Build Coastguard Worker 
3768*cf5a6c84SAndroid Build Coastguard Worker       // perform/save trailing redirects
3769*cf5a6c84SAndroid Build Coastguard Worker       pp = expand_redir(TT.ff->pl->end->arg, 1, TT.ff->blk->urd);
3770*cf5a6c84SAndroid Build Coastguard Worker       TT.ff->blk->urd = pp->urd;
3771*cf5a6c84SAndroid Build Coastguard Worker       pp->urd = 0;
3772*cf5a6c84SAndroid Build Coastguard Worker       if (pp->arg.c) syntax_err(*pp->arg.v);
3773*cf5a6c84SAndroid Build Coastguard Worker       llist_traverse(pp->delete, llist_free_arg);
3774*cf5a6c84SAndroid Build Coastguard Worker       pp->delete = 0;
3775*cf5a6c84SAndroid Build Coastguard Worker       if (pp->exit || pp->arg.c) {
3776*cf5a6c84SAndroid Build Coastguard Worker         free(pp);
3777*cf5a6c84SAndroid Build Coastguard Worker         toys.exitval = 1;
3778*cf5a6c84SAndroid Build Coastguard Worker 
3779*cf5a6c84SAndroid Build Coastguard Worker         break;
3780*cf5a6c84SAndroid Build Coastguard Worker       }
3781*cf5a6c84SAndroid Build Coastguard Worker       add_block();
3782*cf5a6c84SAndroid Build Coastguard Worker 
3783*cf5a6c84SAndroid Build Coastguard Worker // TODO test background a block: { abc; } &
3784*cf5a6c84SAndroid Build Coastguard Worker 
3785*cf5a6c84SAndroid Build Coastguard Worker       // If we spawn a subshell, pass data off to child process
3786*cf5a6c84SAndroid Build Coastguard Worker       if (TT.ff->blk->next->pipe || !strcmp(s, "(") || (ctl && !strcmp(ctl, "&"))) {
3787*cf5a6c84SAndroid Build Coastguard Worker         if (!(pp->pid = run_subshell(0, -1))) {
3788*cf5a6c84SAndroid Build Coastguard Worker 
3789*cf5a6c84SAndroid Build Coastguard Worker           // zap forked child's cleanup context and advance to next statement
3790*cf5a6c84SAndroid Build Coastguard Worker           pplist = 0;
3791*cf5a6c84SAndroid Build Coastguard Worker           while (TT.ff->blk->next) TT.ff->blk = TT.ff->blk->next;
3792*cf5a6c84SAndroid Build Coastguard Worker           TT.ff->blk->pout = -1;
3793*cf5a6c84SAndroid Build Coastguard Worker           TT.ff->blk->urd = 0;
3794*cf5a6c84SAndroid Build Coastguard Worker           TT.ff->pl = TT.ff->next->pl->next;
3795*cf5a6c84SAndroid Build Coastguard Worker 
3796*cf5a6c84SAndroid Build Coastguard Worker           continue;
3797*cf5a6c84SAndroid Build Coastguard Worker         }
3798*cf5a6c84SAndroid Build Coastguard Worker         TT.ff->pl = TT.ff->pl->end;
3799*cf5a6c84SAndroid Build Coastguard Worker         pop_block();
3800*cf5a6c84SAndroid Build Coastguard Worker         dlist_add_nomalloc((void *)&pplist, (void *)pp);
3801*cf5a6c84SAndroid Build Coastguard Worker 
3802*cf5a6c84SAndroid Build Coastguard Worker       // handle start of block in this process
3803*cf5a6c84SAndroid Build Coastguard Worker       } else {
3804*cf5a6c84SAndroid Build Coastguard Worker         free(pp);
3805*cf5a6c84SAndroid Build Coastguard Worker 
3806*cf5a6c84SAndroid Build Coastguard Worker         // What flow control statement is this?
3807*cf5a6c84SAndroid Build Coastguard Worker 
3808*cf5a6c84SAndroid Build Coastguard Worker         // {/} if/then/elif/else/fi, while until/do/done - no special handling
3809*cf5a6c84SAndroid Build Coastguard Worker 
3810*cf5a6c84SAndroid Build Coastguard Worker         // for/select/do/done: populate blk->farg with expanded args (if any)
3811*cf5a6c84SAndroid Build Coastguard Worker         if (!strcmp(s, "for") || !strcmp(s, "select")) {
3812*cf5a6c84SAndroid Build Coastguard Worker           if (TT.ff->blk->loop); // skip init, not first time through loop
3813*cf5a6c84SAndroid Build Coastguard Worker 
3814*cf5a6c84SAndroid Build Coastguard Worker           // in (;;)
3815*cf5a6c84SAndroid Build Coastguard Worker           else if (!strncmp(TT.ff->blk->fvar = ss, "((", 2)) {
3816*cf5a6c84SAndroid Build Coastguard Worker             char *in = ss+2, *out;
3817*cf5a6c84SAndroid Build Coastguard Worker             long long ll;
3818*cf5a6c84SAndroid Build Coastguard Worker 
3819*cf5a6c84SAndroid Build Coastguard Worker             TT.ff->blk->loop = 1;
3820*cf5a6c84SAndroid Build Coastguard Worker             for (i = 0; i<3; i++) {
3821*cf5a6c84SAndroid Build Coastguard Worker               if (i==2) k = strlen(in)-2;
3822*cf5a6c84SAndroid Build Coastguard Worker               else {
3823*cf5a6c84SAndroid Build Coastguard Worker                 // perform expansion but immediately discard it to find ;
3824*cf5a6c84SAndroid Build Coastguard Worker                 k = ';';
3825*cf5a6c84SAndroid Build Coastguard Worker                 pp = xzalloc(sizeof(*pp));
3826*cf5a6c84SAndroid Build Coastguard Worker                 if (expand_arg_nobrace(&pp->arg, ss+2, NO_PATH|NO_SPLIT,
3827*cf5a6c84SAndroid Build Coastguard Worker                     &pp->delete, 0, &k)) break;
3828*cf5a6c84SAndroid Build Coastguard Worker                 free_process(pp);
3829*cf5a6c84SAndroid Build Coastguard Worker                 if (in[k] != ';') break;
3830*cf5a6c84SAndroid Build Coastguard Worker               }
3831*cf5a6c84SAndroid Build Coastguard Worker               (out = xmalloc(k+1))[k] = 0;
3832*cf5a6c84SAndroid Build Coastguard Worker               memcpy(out, in, k);
3833*cf5a6c84SAndroid Build Coastguard Worker               arg_add(&TT.ff->blk->farg, push_arg(&TT.ff->blk->fdelete, out));
3834*cf5a6c84SAndroid Build Coastguard Worker               in += k+1;
3835*cf5a6c84SAndroid Build Coastguard Worker             }
3836*cf5a6c84SAndroid Build Coastguard Worker             if (i!=3) {
3837*cf5a6c84SAndroid Build Coastguard Worker               syntax_err(ss);
3838*cf5a6c84SAndroid Build Coastguard Worker               break;
3839*cf5a6c84SAndroid Build Coastguard Worker             }
3840*cf5a6c84SAndroid Build Coastguard Worker             in = out = *TT.ff->blk->farg.v;
3841*cf5a6c84SAndroid Build Coastguard Worker             if (!recalculate(&ll, &in, 0) || *in) {
3842*cf5a6c84SAndroid Build Coastguard Worker               perror_msg("bad math: %s @ %ld", in, (long)(in-out));
3843*cf5a6c84SAndroid Build Coastguard Worker               break;
3844*cf5a6c84SAndroid Build Coastguard Worker             }
3845*cf5a6c84SAndroid Build Coastguard Worker 
3846*cf5a6c84SAndroid Build Coastguard Worker           // in LIST
3847*cf5a6c84SAndroid Build Coastguard Worker           } else if (TT.ff->pl->next->type == 's') {
3848*cf5a6c84SAndroid Build Coastguard Worker             for (i = 1; i<TT.ff->pl->next->arg->c; i++)
3849*cf5a6c84SAndroid Build Coastguard Worker               if (expand_arg(&TT.ff->blk->farg, TT.ff->pl->next->arg->v[i],
3850*cf5a6c84SAndroid Build Coastguard Worker                              0, &TT.ff->blk->fdelete)) break;
3851*cf5a6c84SAndroid Build Coastguard Worker             if (i != TT.ff->pl->next->arg->c) TT.ff->pl = pop_block();
3852*cf5a6c84SAndroid Build Coastguard Worker 
3853*cf5a6c84SAndroid Build Coastguard Worker           // in without LIST. (This expansion can't return error.)
3854*cf5a6c84SAndroid Build Coastguard Worker           } else expand_arg(&TT.ff->blk->farg, "\"$@\"", 0,
3855*cf5a6c84SAndroid Build Coastguard Worker                             &TT.ff->blk->fdelete);
3856*cf5a6c84SAndroid Build Coastguard Worker 
3857*cf5a6c84SAndroid Build Coastguard Worker           // TODO: ls -C style output
3858*cf5a6c84SAndroid Build Coastguard Worker           if (*s == 's') for (i = 0; i<TT.ff->blk->farg.c; i++)
3859*cf5a6c84SAndroid Build Coastguard Worker             dprintf(2, "%ld) %s\n", i+1, TT.ff->blk->farg.v[i]);
3860*cf5a6c84SAndroid Build Coastguard Worker 
3861*cf5a6c84SAndroid Build Coastguard Worker         // TODO: bash man page says it performs <(process substituion) here?!?
3862*cf5a6c84SAndroid Build Coastguard Worker         } else if (!strcmp(s, "case")) {
3863*cf5a6c84SAndroid Build Coastguard Worker           if (!(TT.ff->blk->fvar = expand_one_arg(ss, NO_NULL))) break;
3864*cf5a6c84SAndroid Build Coastguard Worker           if (ss != TT.ff->blk->fvar)
3865*cf5a6c84SAndroid Build Coastguard Worker             push_arg(&TT.ff->blk->fdelete, TT.ff->blk->fvar);
3866*cf5a6c84SAndroid Build Coastguard Worker         }
3867*cf5a6c84SAndroid Build Coastguard Worker 
3868*cf5a6c84SAndroid Build Coastguard Worker // TODO [[/]] ((/)) function/}
3869*cf5a6c84SAndroid Build Coastguard Worker       }
3870*cf5a6c84SAndroid Build Coastguard Worker 
3871*cf5a6c84SAndroid Build Coastguard Worker     // gearshift from block start to block body (end of flow control test)
3872*cf5a6c84SAndroid Build Coastguard Worker     } else if (TT.ff->pl->type == 2) {
3873*cf5a6c84SAndroid Build Coastguard Worker       int match, err;
3874*cf5a6c84SAndroid Build Coastguard Worker 
3875*cf5a6c84SAndroid Build Coastguard Worker       TT.ff->blk->middle = TT.ff->pl;
3876*cf5a6c84SAndroid Build Coastguard Worker 
3877*cf5a6c84SAndroid Build Coastguard Worker       // ;; end, ;& continue through next block, ;;& test next block
3878*cf5a6c84SAndroid Build Coastguard Worker       if (!strcmp(*TT.ff->blk->start->arg->v, "case")) {
3879*cf5a6c84SAndroid Build Coastguard Worker         if (!strcmp(s, ";;")) {
3880*cf5a6c84SAndroid Build Coastguard Worker           while (TT.ff->pl->type!=3) TT.ff->pl = TT.ff->pl->end;
3881*cf5a6c84SAndroid Build Coastguard Worker           continue;
3882*cf5a6c84SAndroid Build Coastguard Worker         } else if (strcmp(s, ";&")) {
3883*cf5a6c84SAndroid Build Coastguard Worker           struct sh_arg arg = {0}, arg2 = {0};
3884*cf5a6c84SAndroid Build Coastguard Worker 
3885*cf5a6c84SAndroid Build Coastguard Worker           for (err = 0, vv = 0;;) {
3886*cf5a6c84SAndroid Build Coastguard Worker             if (!vv) {
3887*cf5a6c84SAndroid Build Coastguard Worker               vv = TT.ff->pl->arg->v + (**TT.ff->pl->arg->v == ';');
3888*cf5a6c84SAndroid Build Coastguard Worker               if (!*vv) {
3889*cf5a6c84SAndroid Build Coastguard Worker                 // TODO syntax err if not type==3, catch above
3890*cf5a6c84SAndroid Build Coastguard Worker                 TT.ff->pl = TT.ff->pl->next;
3891*cf5a6c84SAndroid Build Coastguard Worker                 break;
3892*cf5a6c84SAndroid Build Coastguard Worker               } else vv += **vv == '(';
3893*cf5a6c84SAndroid Build Coastguard Worker             }
3894*cf5a6c84SAndroid Build Coastguard Worker             arg.c = arg2.c = 0;
3895*cf5a6c84SAndroid Build Coastguard Worker             if ((err = expand_arg_nobrace(&arg, *vv++, NO_SPLIT,
3896*cf5a6c84SAndroid Build Coastguard Worker               &TT.ff->blk->fdelete, &arg2, 0))) break;
3897*cf5a6c84SAndroid Build Coastguard Worker             s = arg.c ? *arg.v : "";
3898*cf5a6c84SAndroid Build Coastguard Worker             match = wildcard_match(TT.ff->blk->fvar, s, &arg2, 0);
3899*cf5a6c84SAndroid Build Coastguard Worker             if (match>=0 && !s[match]) break;
3900*cf5a6c84SAndroid Build Coastguard Worker             else if (**vv++ == ')') {
3901*cf5a6c84SAndroid Build Coastguard Worker               vv = 0;
3902*cf5a6c84SAndroid Build Coastguard Worker               if ((TT.ff->pl = TT.ff->pl->end)->type!=2) break;
3903*cf5a6c84SAndroid Build Coastguard Worker             }
3904*cf5a6c84SAndroid Build Coastguard Worker           }
3905*cf5a6c84SAndroid Build Coastguard Worker           free(arg.v);
3906*cf5a6c84SAndroid Build Coastguard Worker           free(arg2.v);
3907*cf5a6c84SAndroid Build Coastguard Worker           if (err) break;
3908*cf5a6c84SAndroid Build Coastguard Worker           if (TT.ff->pl->type==3) continue;
3909*cf5a6c84SAndroid Build Coastguard Worker         }
3910*cf5a6c84SAndroid Build Coastguard Worker 
3911*cf5a6c84SAndroid Build Coastguard Worker       // Handle if/else/elif statement
3912*cf5a6c84SAndroid Build Coastguard Worker       } else if (!strcmp(s, "then")) {
3913*cf5a6c84SAndroid Build Coastguard Worker do_then:
3914*cf5a6c84SAndroid Build Coastguard Worker         TT.ff->blk->run = TT.ff->blk->run && !toys.exitval;
3915*cf5a6c84SAndroid Build Coastguard Worker         toys.exitval = 0;
3916*cf5a6c84SAndroid Build Coastguard Worker       } else if (!strcmp(s, "else") || !strcmp(s, "elif"))
3917*cf5a6c84SAndroid Build Coastguard Worker         TT.ff->blk->run = !TT.ff->blk->run;
3918*cf5a6c84SAndroid Build Coastguard Worker 
3919*cf5a6c84SAndroid Build Coastguard Worker       // Loop
3920*cf5a6c84SAndroid Build Coastguard Worker       else if (!strcmp(s, "do")) {
3921*cf5a6c84SAndroid Build Coastguard Worker         struct sh_blockstack *blk = TT.ff->blk;
3922*cf5a6c84SAndroid Build Coastguard Worker 
3923*cf5a6c84SAndroid Build Coastguard Worker         ss = *blk->start->arg->v;
3924*cf5a6c84SAndroid Build Coastguard Worker         if (!strcmp(ss, "while")) goto do_then;
3925*cf5a6c84SAndroid Build Coastguard Worker         else if (!strcmp(ss, "until")) {
3926*cf5a6c84SAndroid Build Coastguard Worker           blk->run = blk->run && toys.exitval;
3927*cf5a6c84SAndroid Build Coastguard Worker           toys.exitval = 0;
3928*cf5a6c84SAndroid Build Coastguard Worker         } else if (!strcmp(ss, "select")) {
3929*cf5a6c84SAndroid Build Coastguard Worker           if (!(ss = get_next_line(0, 3)) || ss==(void *)1) {
3930*cf5a6c84SAndroid Build Coastguard Worker             TT.ff->pl = pop_block();
3931*cf5a6c84SAndroid Build Coastguard Worker             printf("\n");
3932*cf5a6c84SAndroid Build Coastguard Worker           } else {
3933*cf5a6c84SAndroid Build Coastguard Worker             match = atoi(ss);
3934*cf5a6c84SAndroid Build Coastguard Worker             i = *s;
3935*cf5a6c84SAndroid Build Coastguard Worker             free(ss);
3936*cf5a6c84SAndroid Build Coastguard Worker             if (!i) {
3937*cf5a6c84SAndroid Build Coastguard Worker               TT.ff->pl = blk->start;
3938*cf5a6c84SAndroid Build Coastguard Worker               continue;
3939*cf5a6c84SAndroid Build Coastguard Worker             } else setvarval(blk->fvar, (match<1 || match>blk->farg.c)
3940*cf5a6c84SAndroid Build Coastguard Worker                                         ? "" : blk->farg.v[match-1]);
3941*cf5a6c84SAndroid Build Coastguard Worker           }
3942*cf5a6c84SAndroid Build Coastguard Worker         } else if (blk->loop >= blk->farg.c) TT.ff->pl = pop_block();
3943*cf5a6c84SAndroid Build Coastguard Worker         else if (!strncmp(blk->fvar, "((", 2)) {
3944*cf5a6c84SAndroid Build Coastguard Worker           char *aa, *bb;
3945*cf5a6c84SAndroid Build Coastguard Worker           long long ll;
3946*cf5a6c84SAndroid Build Coastguard Worker 
3947*cf5a6c84SAndroid Build Coastguard Worker           for (i = 2; i; i--) {
3948*cf5a6c84SAndroid Build Coastguard Worker             if (TT.ff->blk->loop == 1) {
3949*cf5a6c84SAndroid Build Coastguard Worker               TT.ff->blk->loop++;
3950*cf5a6c84SAndroid Build Coastguard Worker               i--;
3951*cf5a6c84SAndroid Build Coastguard Worker             }
3952*cf5a6c84SAndroid Build Coastguard Worker             aa = bb = TT.ff->blk->farg.v[i];
3953*cf5a6c84SAndroid Build Coastguard Worker             if (!recalculate(&ll, &aa, 0) || *aa) {
3954*cf5a6c84SAndroid Build Coastguard Worker               perror_msg("bad math: %s @ %ld", aa, (long)(aa-bb));
3955*cf5a6c84SAndroid Build Coastguard Worker               break;
3956*cf5a6c84SAndroid Build Coastguard Worker             }
3957*cf5a6c84SAndroid Build Coastguard Worker             if (i==1 && !ll) TT.ff->pl = pop_block();
3958*cf5a6c84SAndroid Build Coastguard Worker           }
3959*cf5a6c84SAndroid Build Coastguard Worker         } else setvarval(blk->fvar, blk->farg.v[blk->loop++]);
3960*cf5a6c84SAndroid Build Coastguard Worker       }
3961*cf5a6c84SAndroid Build Coastguard Worker 
3962*cf5a6c84SAndroid Build Coastguard Worker     // end of block
3963*cf5a6c84SAndroid Build Coastguard Worker     } else if (TT.ff->pl->type == 3) {
3964*cf5a6c84SAndroid Build Coastguard Worker       // If we end a block we're not in, exit subshell
3965*cf5a6c84SAndroid Build Coastguard Worker       if (!TT.ff->blk->next) xexit();
3966*cf5a6c84SAndroid Build Coastguard Worker 
3967*cf5a6c84SAndroid Build Coastguard Worker       // repeating block?
3968*cf5a6c84SAndroid Build Coastguard Worker       if (TT.ff->blk->run && !strcmp(s, "done")) {
3969*cf5a6c84SAndroid Build Coastguard Worker         TT.ff->pl = (**TT.ff->blk->start->arg->v == 'w')
3970*cf5a6c84SAndroid Build Coastguard Worker           ? TT.ff->blk->start->next : TT.ff->blk->middle;
3971*cf5a6c84SAndroid Build Coastguard Worker         continue;
3972*cf5a6c84SAndroid Build Coastguard Worker       }
3973*cf5a6c84SAndroid Build Coastguard Worker 
3974*cf5a6c84SAndroid Build Coastguard Worker       // cleans up after trailing redirections/pipe
3975*cf5a6c84SAndroid Build Coastguard Worker       pop_block();
3976*cf5a6c84SAndroid Build Coastguard Worker 
3977*cf5a6c84SAndroid Build Coastguard Worker     // declare a shell function
3978*cf5a6c84SAndroid Build Coastguard Worker     } else if (TT.ff->pl->type == 'F') {
3979*cf5a6c84SAndroid Build Coastguard Worker       struct sh_function *funky = (void *)*TT.ff->pl->arg->v;
3980*cf5a6c84SAndroid Build Coastguard Worker 
3981*cf5a6c84SAndroid Build Coastguard Worker // TODO binary search
3982*cf5a6c84SAndroid Build Coastguard Worker       for (i = 0; i<TT.funcslen; i++)
3983*cf5a6c84SAndroid Build Coastguard Worker         if (!strcmp(TT.functions[i]->name, funky->name)) break;
3984*cf5a6c84SAndroid Build Coastguard Worker       if (i == TT.funcslen) {
3985*cf5a6c84SAndroid Build Coastguard Worker         struct sh_arg arg = {(void *)TT.functions, TT.funcslen};
3986*cf5a6c84SAndroid Build Coastguard Worker 
3987*cf5a6c84SAndroid Build Coastguard Worker         arg_add(&arg, (void *)funky); // TODO possibly an expand@31 function?
3988*cf5a6c84SAndroid Build Coastguard Worker         TT.functions = (void *)arg.v;
3989*cf5a6c84SAndroid Build Coastguard Worker         TT.funcslen++;
3990*cf5a6c84SAndroid Build Coastguard Worker       } else {
3991*cf5a6c84SAndroid Build Coastguard Worker         free_function(TT.functions[i]);
3992*cf5a6c84SAndroid Build Coastguard Worker         TT.functions[i] = funky;
3993*cf5a6c84SAndroid Build Coastguard Worker       }
3994*cf5a6c84SAndroid Build Coastguard Worker       TT.functions[i]->refcount++;
3995*cf5a6c84SAndroid Build Coastguard Worker     }
3996*cf5a6c84SAndroid Build Coastguard Worker 
3997*cf5a6c84SAndroid Build Coastguard Worker     // Three cases: 1) background & 2) pipeline | 3) last process in pipeline ;
3998*cf5a6c84SAndroid Build Coastguard Worker     // If we ran a process and didn't pipe output, background or wait for exit
3999*cf5a6c84SAndroid Build Coastguard Worker     if (pplist && TT.ff->blk->pout == -1) {
4000*cf5a6c84SAndroid Build Coastguard Worker       if (ctl && !strcmp(ctl, "&")) {
4001*cf5a6c84SAndroid Build Coastguard Worker         if (!TT.jobs.c) TT.jobcnt = 0;
4002*cf5a6c84SAndroid Build Coastguard Worker         pplist->job = ++TT.jobcnt;
4003*cf5a6c84SAndroid Build Coastguard Worker         arg_add(&TT.jobs, (void *)pplist);
4004*cf5a6c84SAndroid Build Coastguard Worker         if (TT.options&FLAG_i) dprintf(2, "[%u] %u\n", pplist->job,pplist->pid);
4005*cf5a6c84SAndroid Build Coastguard Worker       } else {
4006*cf5a6c84SAndroid Build Coastguard Worker         toys.exitval = wait_pipeline(pplist);
4007*cf5a6c84SAndroid Build Coastguard Worker         llist_traverse(pplist, (void *)free_process);
4008*cf5a6c84SAndroid Build Coastguard Worker       }
4009*cf5a6c84SAndroid Build Coastguard Worker       pplist = 0;
4010*cf5a6c84SAndroid Build Coastguard Worker     }
4011*cf5a6c84SAndroid Build Coastguard Worker advance:
4012*cf5a6c84SAndroid Build Coastguard Worker     // for && and || skip pipeline segment(s) based on return code
4013*cf5a6c84SAndroid Build Coastguard Worker     if (!TT.ff->pl->type || TT.ff->pl->type == 3) {
4014*cf5a6c84SAndroid Build Coastguard Worker       for (;;) {
4015*cf5a6c84SAndroid Build Coastguard Worker         ctl = TT.ff->pl->arg->v[TT.ff->pl->arg->c];
4016*cf5a6c84SAndroid Build Coastguard Worker         if (!ctl || strcmp(ctl, toys.exitval ? "&&" : "||")) break;
4017*cf5a6c84SAndroid Build Coastguard Worker         if ((TT.ff->pl = TT.ff->pl->next)->type) TT.ff->pl = TT.ff->pl->end;
4018*cf5a6c84SAndroid Build Coastguard Worker       }
4019*cf5a6c84SAndroid Build Coastguard Worker     }
4020*cf5a6c84SAndroid Build Coastguard Worker     TT.ff->pl = TT.ff->pl->next;
4021*cf5a6c84SAndroid Build Coastguard Worker   }
4022*cf5a6c84SAndroid Build Coastguard Worker 
4023*cf5a6c84SAndroid Build Coastguard Worker   // clean up any unfinished stuff
4024*cf5a6c84SAndroid Build Coastguard Worker   if (pplist) {
4025*cf5a6c84SAndroid Build Coastguard Worker     toys.exitval = wait_pipeline(pplist);
4026*cf5a6c84SAndroid Build Coastguard Worker     llist_traverse(pplist, (void *)free_process);
4027*cf5a6c84SAndroid Build Coastguard Worker   }
4028*cf5a6c84SAndroid Build Coastguard Worker 
4029*cf5a6c84SAndroid Build Coastguard Worker   // exit source context (and function calls on syntax err)
4030*cf5a6c84SAndroid Build Coastguard Worker   while (end_fcall(0));
4031*cf5a6c84SAndroid Build Coastguard Worker }
4032*cf5a6c84SAndroid Build Coastguard Worker 
4033*cf5a6c84SAndroid Build Coastguard Worker // set variable
initvar(char * name,char * val)4034*cf5a6c84SAndroid Build Coastguard Worker static struct sh_vars *initvar(char *name, char *val)
4035*cf5a6c84SAndroid Build Coastguard Worker {
4036*cf5a6c84SAndroid Build Coastguard Worker   return addvar(xmprintf("%s=%s", name, val ? val : ""), TT.ff);
4037*cf5a6c84SAndroid Build Coastguard Worker }
4038*cf5a6c84SAndroid Build Coastguard Worker 
initvardef(char * name,char * val,char * def)4039*cf5a6c84SAndroid Build Coastguard Worker static struct sh_vars *initvardef(char *name, char *val, char *def)
4040*cf5a6c84SAndroid Build Coastguard Worker {
4041*cf5a6c84SAndroid Build Coastguard Worker   return initvar(name, (!val || !*val) ? def : val);
4042*cf5a6c84SAndroid Build Coastguard Worker }
4043*cf5a6c84SAndroid Build Coastguard Worker 
4044*cf5a6c84SAndroid Build Coastguard Worker // export existing "name" or assign/export name=value string (making new copy)
set_varflags(char * str,unsigned set_flags,unsigned unset_flags)4045*cf5a6c84SAndroid Build Coastguard Worker static void set_varflags(char *str, unsigned set_flags, unsigned unset_flags)
4046*cf5a6c84SAndroid Build Coastguard Worker {
4047*cf5a6c84SAndroid Build Coastguard Worker   struct sh_vars *shv = 0;
4048*cf5a6c84SAndroid Build Coastguard Worker   struct sh_fcall *ff;
4049*cf5a6c84SAndroid Build Coastguard Worker   char *s;
4050*cf5a6c84SAndroid Build Coastguard Worker 
4051*cf5a6c84SAndroid Build Coastguard Worker   // Make sure variable exists and is updated
4052*cf5a6c84SAndroid Build Coastguard Worker   if (strchr(str, '=')) shv = setvar(xstrdup(str));
4053*cf5a6c84SAndroid Build Coastguard Worker   else if (!(shv = findvar(str, &ff))) {
4054*cf5a6c84SAndroid Build Coastguard Worker     if (!set_flags) return;
4055*cf5a6c84SAndroid Build Coastguard Worker     shv = addvar(str = xmprintf("%s=", str), TT.ff->prev);
4056*cf5a6c84SAndroid Build Coastguard Worker     shv->flags = VAR_WHITEOUT;
4057*cf5a6c84SAndroid Build Coastguard Worker   } else if (shv->flags&VAR_WHITEOUT) shv->flags |= VAR_EXPORT;
4058*cf5a6c84SAndroid Build Coastguard Worker   if (!shv || (shv->flags&VAR_EXPORT)) return;
4059*cf5a6c84SAndroid Build Coastguard Worker 
4060*cf5a6c84SAndroid Build Coastguard Worker   // Resolve magic for export (bash bug compatibility, really should be dynamic)
4061*cf5a6c84SAndroid Build Coastguard Worker   if (shv->flags&VAR_MAGIC) {
4062*cf5a6c84SAndroid Build Coastguard Worker     s = shv->str;
4063*cf5a6c84SAndroid Build Coastguard Worker     shv->str = xmprintf("%.*s=%s", (int)(varend(str)-str), str, getvar(str));
4064*cf5a6c84SAndroid Build Coastguard Worker     if (!(shv->flags&VAR_NOFREE)) free(s);
4065*cf5a6c84SAndroid Build Coastguard Worker     else shv->flags ^= VAR_NOFREE;
4066*cf5a6c84SAndroid Build Coastguard Worker   }
4067*cf5a6c84SAndroid Build Coastguard Worker   shv->flags |= set_flags;
4068*cf5a6c84SAndroid Build Coastguard Worker   shv->flags &= ~unset_flags;
4069*cf5a6c84SAndroid Build Coastguard Worker }
4070*cf5a6c84SAndroid Build Coastguard Worker 
export(char * str)4071*cf5a6c84SAndroid Build Coastguard Worker static void export(char *str)
4072*cf5a6c84SAndroid Build Coastguard Worker {
4073*cf5a6c84SAndroid Build Coastguard Worker   set_varflags(str, VAR_EXPORT, 0);
4074*cf5a6c84SAndroid Build Coastguard Worker }
4075*cf5a6c84SAndroid Build Coastguard Worker 
fpathopen(char * name)4076*cf5a6c84SAndroid Build Coastguard Worker FILE *fpathopen(char *name)
4077*cf5a6c84SAndroid Build Coastguard Worker {
4078*cf5a6c84SAndroid Build Coastguard Worker   int fd = open(name, O_RDONLY|O_CLOEXEC), ii;
4079*cf5a6c84SAndroid Build Coastguard Worker   struct string_list *sl = 0;
4080*cf5a6c84SAndroid Build Coastguard Worker   char *pp = getvar("PATH") ? : _PATH_DEFPATH;
4081*cf5a6c84SAndroid Build Coastguard Worker 
4082*cf5a6c84SAndroid Build Coastguard Worker   if (fd==-1) {
4083*cf5a6c84SAndroid Build Coastguard Worker     for (sl = find_in_path(pp, name); sl; free(llist_pop(&sl)))
4084*cf5a6c84SAndroid Build Coastguard Worker       if (-1==(fd = open(sl->str, O_RDONLY|O_CLOEXEC))) break;
4085*cf5a6c84SAndroid Build Coastguard Worker     if (sl) llist_traverse(sl, free);
4086*cf5a6c84SAndroid Build Coastguard Worker   }
4087*cf5a6c84SAndroid Build Coastguard Worker   if (fd != -1) {
4088*cf5a6c84SAndroid Build Coastguard Worker     dup2(fd, ii = next_hfd());
4089*cf5a6c84SAndroid Build Coastguard Worker     fcntl(ii, F_SETFD, FD_CLOEXEC);
4090*cf5a6c84SAndroid Build Coastguard Worker     close(fd);
4091*cf5a6c84SAndroid Build Coastguard Worker     fd = ii;
4092*cf5a6c84SAndroid Build Coastguard Worker   }
4093*cf5a6c84SAndroid Build Coastguard Worker 
4094*cf5a6c84SAndroid Build Coastguard Worker   return fd==-1 ? 0 : fdopen(fd, "r");
4095*cf5a6c84SAndroid Build Coastguard Worker }
4096*cf5a6c84SAndroid Build Coastguard Worker 
4097*cf5a6c84SAndroid Build Coastguard Worker // Read script input and execute lines, with or without prompts
4098*cf5a6c84SAndroid Build Coastguard Worker // If !ff input is interactive (prompt, editing, etc)
do_source(char * name,FILE * ff)4099*cf5a6c84SAndroid Build Coastguard Worker int do_source(char *name, FILE *ff)
4100*cf5a6c84SAndroid Build Coastguard Worker {
4101*cf5a6c84SAndroid Build Coastguard Worker   struct sh_pipeline *pl = 0;
4102*cf5a6c84SAndroid Build Coastguard Worker   struct double_list *expect = 0;
4103*cf5a6c84SAndroid Build Coastguard Worker   unsigned lineno = TT.LINENO, more = 0, wc;
4104*cf5a6c84SAndroid Build Coastguard Worker   int cc, ii;
4105*cf5a6c84SAndroid Build Coastguard Worker   char *new;
4106*cf5a6c84SAndroid Build Coastguard Worker 
4107*cf5a6c84SAndroid Build Coastguard Worker   TT.recfile[TT.recursion++] = ff ? fileno(ff) : 0;
4108*cf5a6c84SAndroid Build Coastguard Worker   if (TT.recursion++>ARRAY_LEN(TT.recfile)) {
4109*cf5a6c84SAndroid Build Coastguard Worker     error_msg("recursive occlusion");
4110*cf5a6c84SAndroid Build Coastguard Worker 
4111*cf5a6c84SAndroid Build Coastguard Worker     goto end;
4112*cf5a6c84SAndroid Build Coastguard Worker   }
4113*cf5a6c84SAndroid Build Coastguard Worker 
4114*cf5a6c84SAndroid Build Coastguard Worker   if (name) TT.ff->omnom = name;
4115*cf5a6c84SAndroid Build Coastguard Worker 
4116*cf5a6c84SAndroid Build Coastguard Worker // TODO fix/catch O_NONBLOCK on input?
4117*cf5a6c84SAndroid Build Coastguard Worker // TODO when DO we reset lineno? (!LINENO means \0 returns 1)
4118*cf5a6c84SAndroid Build Coastguard Worker // when do we NOT reset lineno? Inherit but preserve perhaps? newline in $()?
4119*cf5a6c84SAndroid Build Coastguard Worker   if (!name) TT.LINENO = 0;
4120*cf5a6c84SAndroid Build Coastguard Worker 
4121*cf5a6c84SAndroid Build Coastguard Worker   do {
4122*cf5a6c84SAndroid Build Coastguard Worker     if ((void *)1 == (new = get_next_line(ff, more+1))) goto is_binary;
4123*cf5a6c84SAndroid Build Coastguard Worker //dprintf(2, "%d getline from %p %s\n", getpid(), ff, new); debug_show_fds();
4124*cf5a6c84SAndroid Build Coastguard Worker     // did we exec an ELF file or something?
4125*cf5a6c84SAndroid Build Coastguard Worker     if (!TT.LINENO++ && name && new) {
4126*cf5a6c84SAndroid Build Coastguard Worker       // A shell script's first line has no high bytes that aren't valid utf-8.
4127*cf5a6c84SAndroid Build Coastguard Worker       for (ii = 0; new[ii]>6 && 0<(cc = utf8towc(&wc, new+ii, 4)); ii += cc);
4128*cf5a6c84SAndroid Build Coastguard Worker       if (new[ii]) {
4129*cf5a6c84SAndroid Build Coastguard Worker is_binary:
4130*cf5a6c84SAndroid Build Coastguard Worker         if (name) error_msg("'%s' is binary", name); // TODO syntax_err() exit?
4131*cf5a6c84SAndroid Build Coastguard Worker         if (new != (void *)1) free(new);
4132*cf5a6c84SAndroid Build Coastguard Worker         new = 0;
4133*cf5a6c84SAndroid Build Coastguard Worker       }
4134*cf5a6c84SAndroid Build Coastguard Worker     }
4135*cf5a6c84SAndroid Build Coastguard Worker 
4136*cf5a6c84SAndroid Build Coastguard Worker     // TODO: source <(echo 'echo hello\') vs source <(echo -n 'echo hello\')
4137*cf5a6c84SAndroid Build Coastguard Worker     // prints "hello" vs "hello\"
4138*cf5a6c84SAndroid Build Coastguard Worker 
4139*cf5a6c84SAndroid Build Coastguard Worker     // returns 0 if line consumed, command if it needs more data
4140*cf5a6c84SAndroid Build Coastguard Worker     more = parse_line(new, &pl, &expect);
4141*cf5a6c84SAndroid Build Coastguard Worker     free(new);
4142*cf5a6c84SAndroid Build Coastguard Worker     if (more==1) {
4143*cf5a6c84SAndroid Build Coastguard Worker       if (!new) syntax_err("unexpected end of file");
4144*cf5a6c84SAndroid Build Coastguard Worker       else continue;
4145*cf5a6c84SAndroid Build Coastguard Worker     } else if (!more && pl) {
4146*cf5a6c84SAndroid Build Coastguard Worker       TT.ff->pl = pl;
4147*cf5a6c84SAndroid Build Coastguard Worker       run_lines();
4148*cf5a6c84SAndroid Build Coastguard Worker     } else more = 0;
4149*cf5a6c84SAndroid Build Coastguard Worker 
4150*cf5a6c84SAndroid Build Coastguard Worker     llist_traverse(pl, free_pipeline);
4151*cf5a6c84SAndroid Build Coastguard Worker     pl = 0;
4152*cf5a6c84SAndroid Build Coastguard Worker     llist_traverse(expect, free);
4153*cf5a6c84SAndroid Build Coastguard Worker     expect = 0;
4154*cf5a6c84SAndroid Build Coastguard Worker   } while (new);
4155*cf5a6c84SAndroid Build Coastguard Worker 
4156*cf5a6c84SAndroid Build Coastguard Worker   if (ff) fclose(ff);
4157*cf5a6c84SAndroid Build Coastguard Worker 
4158*cf5a6c84SAndroid Build Coastguard Worker   if (!name) TT.LINENO = lineno;
4159*cf5a6c84SAndroid Build Coastguard Worker 
4160*cf5a6c84SAndroid Build Coastguard Worker end:
4161*cf5a6c84SAndroid Build Coastguard Worker   TT.recursion--;
4162*cf5a6c84SAndroid Build Coastguard Worker 
4163*cf5a6c84SAndroid Build Coastguard Worker   return more;
4164*cf5a6c84SAndroid Build Coastguard Worker }
4165*cf5a6c84SAndroid Build Coastguard Worker 
4166*cf5a6c84SAndroid Build Coastguard Worker // On nommu we had to exec(), so parent environment is passed via a pipe.
nommu_reentry(void)4167*cf5a6c84SAndroid Build Coastguard Worker static void nommu_reentry(void)
4168*cf5a6c84SAndroid Build Coastguard Worker {
4169*cf5a6c84SAndroid Build Coastguard Worker   struct stat st;
4170*cf5a6c84SAndroid Build Coastguard Worker   int ii, pid, ppid, len;
4171*cf5a6c84SAndroid Build Coastguard Worker   unsigned long ll;
4172*cf5a6c84SAndroid Build Coastguard Worker   char *s = 0;
4173*cf5a6c84SAndroid Build Coastguard Worker   FILE *fp;
4174*cf5a6c84SAndroid Build Coastguard Worker 
4175*cf5a6c84SAndroid Build Coastguard Worker   // Sanity check
4176*cf5a6c84SAndroid Build Coastguard Worker   if (!fstat(254, &st) && S_ISFIFO(st.st_mode)) {
4177*cf5a6c84SAndroid Build Coastguard Worker     for (ii = len = 0; (s = environ[ii]); ii++) {
4178*cf5a6c84SAndroid Build Coastguard Worker       if (*s!='@') continue;
4179*cf5a6c84SAndroid Build Coastguard Worker       sscanf(s, "@%u,%u%n", &pid, &ppid, &len);
4180*cf5a6c84SAndroid Build Coastguard Worker       break;
4181*cf5a6c84SAndroid Build Coastguard Worker     }
4182*cf5a6c84SAndroid Build Coastguard Worker   }
4183*cf5a6c84SAndroid Build Coastguard Worker   if (!s || s[len] || pid!=getpid() || ppid!=getppid()) error_exit(0);
4184*cf5a6c84SAndroid Build Coastguard Worker 
4185*cf5a6c84SAndroid Build Coastguard Worker // TODO signal setup before this so fscanf can't EINTR.
4186*cf5a6c84SAndroid Build Coastguard Worker // TODO marshall TT.jobcnt TT.funcslen: child needs jobs and function list
4187*cf5a6c84SAndroid Build Coastguard Worker   // Marshall magics: $SECONDS $- $LINENO $$ $!
4188*cf5a6c84SAndroid Build Coastguard Worker   if (5!=fscanf(fp = fdopen(254, "r"), "%lld %u %u %u %u%*[^\n]", &TT.SECONDS,
4189*cf5a6c84SAndroid Build Coastguard Worker       &TT.options, &TT.LINENO, &TT.pid, &TT.bangpid)) error_exit(0);
4190*cf5a6c84SAndroid Build Coastguard Worker 
4191*cf5a6c84SAndroid Build Coastguard Worker   // Read named variables: type, len, var=value\0
4192*cf5a6c84SAndroid Build Coastguard Worker   for (;;) {
4193*cf5a6c84SAndroid Build Coastguard Worker     len = ll = 0;
4194*cf5a6c84SAndroid Build Coastguard Worker     (void)fscanf(fp, "%u %lu%*[^\n]", &len, &ll);
4195*cf5a6c84SAndroid Build Coastguard Worker     fgetc(fp); // Discard the newline fscanf didn't eat.
4196*cf5a6c84SAndroid Build Coastguard Worker     if (!len) break;
4197*cf5a6c84SAndroid Build Coastguard Worker     (s = xmalloc(len+1))[len] = 0;
4198*cf5a6c84SAndroid Build Coastguard Worker     for (ii = 0; ii<len; ii += pid)
4199*cf5a6c84SAndroid Build Coastguard Worker       if (1>(pid = fread(s+ii, 1, len-ii, fp))) error_exit(0);
4200*cf5a6c84SAndroid Build Coastguard Worker     set_varflags(s, ll, 0);
4201*cf5a6c84SAndroid Build Coastguard Worker   }
4202*cf5a6c84SAndroid Build Coastguard Worker 
4203*cf5a6c84SAndroid Build Coastguard Worker   // Perform subshell command(s)
4204*cf5a6c84SAndroid Build Coastguard Worker   do_source(0, fp);
4205*cf5a6c84SAndroid Build Coastguard Worker   xexit();
4206*cf5a6c84SAndroid Build Coastguard Worker }
4207*cf5a6c84SAndroid Build Coastguard Worker 
4208*cf5a6c84SAndroid Build Coastguard Worker // init locals, sanitize environment, handle nommu subshell handoff
subshell_setup(void)4209*cf5a6c84SAndroid Build Coastguard Worker static void subshell_setup(void)
4210*cf5a6c84SAndroid Build Coastguard Worker {
4211*cf5a6c84SAndroid Build Coastguard Worker   int ii, from, uid = getuid();
4212*cf5a6c84SAndroid Build Coastguard Worker   struct passwd *pw = getpwuid(uid);
4213*cf5a6c84SAndroid Build Coastguard Worker   char *s, *ss, *magic[] = {"SECONDS", "RANDOM", "LINENO", "GROUPS", "BASHPID",
4214*cf5a6c84SAndroid Build Coastguard Worker     "EPOCHREALTIME", "EPOCHSECONDS"},
4215*cf5a6c84SAndroid Build Coastguard Worker     *readonly[] = {xmprintf("EUID=%d", geteuid()), xmprintf("UID=%d", uid),
4216*cf5a6c84SAndroid Build Coastguard Worker                    xmprintf("PPID=%d", getppid())};
4217*cf5a6c84SAndroid Build Coastguard Worker   struct sh_vars *shv;
4218*cf5a6c84SAndroid Build Coastguard Worker   struct utsname uu;
4219*cf5a6c84SAndroid Build Coastguard Worker 
4220*cf5a6c84SAndroid Build Coastguard Worker   // Initialize magic and read only local variables
4221*cf5a6c84SAndroid Build Coastguard Worker   for (ii = 0; ii<ARRAY_LEN(magic) && (s = magic[ii]); ii++)
4222*cf5a6c84SAndroid Build Coastguard Worker     initvar(s, "")->flags = VAR_MAGIC+VAR_INT*('G'!=*s)+VAR_READONLY*('B'==*s);
4223*cf5a6c84SAndroid Build Coastguard Worker   for (ii = 0; ii<ARRAY_LEN(readonly); ii++)
4224*cf5a6c84SAndroid Build Coastguard Worker     addvar(readonly[ii], TT.ff)->flags = VAR_READONLY|VAR_INT;
4225*cf5a6c84SAndroid Build Coastguard Worker 
4226*cf5a6c84SAndroid Build Coastguard Worker   // Add local variables that can be overwritten
4227*cf5a6c84SAndroid Build Coastguard Worker   initvar("PATH", _PATH_DEFPATH);
4228*cf5a6c84SAndroid Build Coastguard Worker   if (!pw) pw = (void *)toybuf; // first use, so still zeroed
4229*cf5a6c84SAndroid Build Coastguard Worker   sprintf(toybuf+1024, "%u", uid);
4230*cf5a6c84SAndroid Build Coastguard Worker   initvardef("HOME", pw->pw_dir, "/");
4231*cf5a6c84SAndroid Build Coastguard Worker   initvardef("SHELL", pw->pw_shell, "/bin/sh");
4232*cf5a6c84SAndroid Build Coastguard Worker   initvardef("USER", pw->pw_name, toybuf+1024);
4233*cf5a6c84SAndroid Build Coastguard Worker   initvardef("LOGNAME", pw->pw_name, toybuf+1024);
4234*cf5a6c84SAndroid Build Coastguard Worker   gethostname(toybuf, sizeof(toybuf)-1);
4235*cf5a6c84SAndroid Build Coastguard Worker   initvar("HOSTNAME", toybuf);
4236*cf5a6c84SAndroid Build Coastguard Worker   uname(&uu);
4237*cf5a6c84SAndroid Build Coastguard Worker   initvar("HOSTTYPE", uu.machine);
4238*cf5a6c84SAndroid Build Coastguard Worker   sprintf(toybuf, "%s-unknown-linux", uu.machine);
4239*cf5a6c84SAndroid Build Coastguard Worker   initvar("MACHTYPE", toybuf);
4240*cf5a6c84SAndroid Build Coastguard Worker   initvar("OSTYPE", uu.sysname);
4241*cf5a6c84SAndroid Build Coastguard Worker   // sprintf(toybuf, "%s-toybox", TOYBOX_VERSION);
4242*cf5a6c84SAndroid Build Coastguard Worker   // initvar("BASH_VERSION", toybuf); TODO
4243*cf5a6c84SAndroid Build Coastguard Worker   initvar("OPTERR", "1"); // TODO: test if already exported?
4244*cf5a6c84SAndroid Build Coastguard Worker   if (readlink0("/proc/self/exe", s = toybuf, sizeof(toybuf))||(s=getenv("_")))
4245*cf5a6c84SAndroid Build Coastguard Worker     initvar("BASH", s);
4246*cf5a6c84SAndroid Build Coastguard Worker   initvar("PS2", "> ");
4247*cf5a6c84SAndroid Build Coastguard Worker   initvar("PS3", "#? ");
4248*cf5a6c84SAndroid Build Coastguard Worker   initvar("PS4", "+ ");
4249*cf5a6c84SAndroid Build Coastguard Worker 
4250*cf5a6c84SAndroid Build Coastguard Worker   // Ensure environ copied and toys.envc set, and clean out illegal entries
4251*cf5a6c84SAndroid Build Coastguard Worker   for (from = 0; (s = environ[from]); from++) {
4252*cf5a6c84SAndroid Build Coastguard Worker     if (*varend(s) != '=') continue;
4253*cf5a6c84SAndroid Build Coastguard Worker     if (!(shv = findvar(s, 0))) addvar(s, TT.ff)->flags = VAR_EXPORT|VAR_NOFREE;
4254*cf5a6c84SAndroid Build Coastguard Worker     else if (shv->flags&VAR_READONLY) continue;
4255*cf5a6c84SAndroid Build Coastguard Worker     else {
4256*cf5a6c84SAndroid Build Coastguard Worker       if (!(shv->flags&VAR_NOFREE)) {
4257*cf5a6c84SAndroid Build Coastguard Worker         free(shv->str);
4258*cf5a6c84SAndroid Build Coastguard Worker         shv->flags ^= VAR_NOFREE;
4259*cf5a6c84SAndroid Build Coastguard Worker       }
4260*cf5a6c84SAndroid Build Coastguard Worker       shv->flags |= VAR_EXPORT;
4261*cf5a6c84SAndroid Build Coastguard Worker       shv->str = s;
4262*cf5a6c84SAndroid Build Coastguard Worker     }
4263*cf5a6c84SAndroid Build Coastguard Worker     cache_ifs(s, TT.ff); // TODO: replace with set(get("IFS")) after loop
4264*cf5a6c84SAndroid Build Coastguard Worker   }
4265*cf5a6c84SAndroid Build Coastguard Worker 
4266*cf5a6c84SAndroid Build Coastguard Worker   // set/update PWD
4267*cf5a6c84SAndroid Build Coastguard Worker   do_source(0, fmemopen("cd .", 4, "r"));
4268*cf5a6c84SAndroid Build Coastguard Worker 
4269*cf5a6c84SAndroid Build Coastguard Worker   // set _ to path to this shell
4270*cf5a6c84SAndroid Build Coastguard Worker   s = toys.argv[0];
4271*cf5a6c84SAndroid Build Coastguard Worker   ss = 0;
4272*cf5a6c84SAndroid Build Coastguard Worker   if (!strchr(s, '/')) {
4273*cf5a6c84SAndroid Build Coastguard Worker     if ((ss = getcwd(0, 0))) {
4274*cf5a6c84SAndroid Build Coastguard Worker       s = xmprintf("%s/%s", ss, s);
4275*cf5a6c84SAndroid Build Coastguard Worker       free(ss);
4276*cf5a6c84SAndroid Build Coastguard Worker       ss = s;
4277*cf5a6c84SAndroid Build Coastguard Worker     } else if (*toybuf) s = toybuf; // from /proc/self/exe
4278*cf5a6c84SAndroid Build Coastguard Worker   }
4279*cf5a6c84SAndroid Build Coastguard Worker   setvarval("_", s)->flags |= VAR_EXPORT;
4280*cf5a6c84SAndroid Build Coastguard Worker   free(ss);
4281*cf5a6c84SAndroid Build Coastguard Worker 
4282*cf5a6c84SAndroid Build Coastguard Worker   // TODO: this is in pipe, not environment
4283*cf5a6c84SAndroid Build Coastguard Worker   if (!(ss = getvar("SHLVL"))) export("SHLVL=1"); // Bash 5.0
4284*cf5a6c84SAndroid Build Coastguard Worker   else {
4285*cf5a6c84SAndroid Build Coastguard Worker     char buf[16];
4286*cf5a6c84SAndroid Build Coastguard Worker 
4287*cf5a6c84SAndroid Build Coastguard Worker     sprintf(buf, "%u", atoi(ss+6)+1);
4288*cf5a6c84SAndroid Build Coastguard Worker     setvarval("SHLVL", buf)->flags |= VAR_EXPORT;
4289*cf5a6c84SAndroid Build Coastguard Worker   }
4290*cf5a6c84SAndroid Build Coastguard Worker }
4291*cf5a6c84SAndroid Build Coastguard Worker 
sh_main(void)4292*cf5a6c84SAndroid Build Coastguard Worker void sh_main(void)
4293*cf5a6c84SAndroid Build Coastguard Worker {
4294*cf5a6c84SAndroid Build Coastguard Worker   char *cc = 0;
4295*cf5a6c84SAndroid Build Coastguard Worker   FILE *ff;
4296*cf5a6c84SAndroid Build Coastguard Worker 
4297*cf5a6c84SAndroid Build Coastguard Worker //dprintf(2, "%d main", getpid()); for (unsigned uu = 0; toys.argv[uu]; uu++) dprintf(2, " %s", toys.argv[uu]); dprintf(2, "\n");
4298*cf5a6c84SAndroid Build Coastguard Worker 
4299*cf5a6c84SAndroid Build Coastguard Worker   signal(SIGPIPE, SIG_IGN);
4300*cf5a6c84SAndroid Build Coastguard Worker   TT.options = OPT_B;
4301*cf5a6c84SAndroid Build Coastguard Worker   TT.pid = getpid();
4302*cf5a6c84SAndroid Build Coastguard Worker   srandom(TT.SECONDS = millitime());
4303*cf5a6c84SAndroid Build Coastguard Worker 
4304*cf5a6c84SAndroid Build Coastguard Worker   // TODO euid stuff?
4305*cf5a6c84SAndroid Build Coastguard Worker   // TODO login shell?
4306*cf5a6c84SAndroid Build Coastguard Worker   // TODO read profile, read rc
4307*cf5a6c84SAndroid Build Coastguard Worker 
4308*cf5a6c84SAndroid Build Coastguard Worker   // if (!FLAG(noprofile)) { }
4309*cf5a6c84SAndroid Build Coastguard Worker 
4310*cf5a6c84SAndroid Build Coastguard Worker   // If not reentering, figure out if this is an interactive shell.
4311*cf5a6c84SAndroid Build Coastguard Worker   if (toys.stacktop) {
4312*cf5a6c84SAndroid Build Coastguard Worker     cc = TT.sh.c;
4313*cf5a6c84SAndroid Build Coastguard Worker     if (!FLAG(c)) {
4314*cf5a6c84SAndroid Build Coastguard Worker       if (toys.optc==1) toys.optflags |= FLAG_s;
4315*cf5a6c84SAndroid Build Coastguard Worker       if (FLAG(s) && isatty(0)) toys.optflags |= FLAG_i;
4316*cf5a6c84SAndroid Build Coastguard Worker     }
4317*cf5a6c84SAndroid Build Coastguard Worker     if (toys.optc>1) {
4318*cf5a6c84SAndroid Build Coastguard Worker       toys.optargs++;
4319*cf5a6c84SAndroid Build Coastguard Worker       toys.optc--;
4320*cf5a6c84SAndroid Build Coastguard Worker     }
4321*cf5a6c84SAndroid Build Coastguard Worker     TT.options |= toys.optflags&0xff;
4322*cf5a6c84SAndroid Build Coastguard Worker   }
4323*cf5a6c84SAndroid Build Coastguard Worker 
4324*cf5a6c84SAndroid Build Coastguard Worker   // Create initial function context
4325*cf5a6c84SAndroid Build Coastguard Worker   call_function();
4326*cf5a6c84SAndroid Build Coastguard Worker   TT.ff->arg.v = toys.optargs;
4327*cf5a6c84SAndroid Build Coastguard Worker   TT.ff->arg.c = toys.optc;
4328*cf5a6c84SAndroid Build Coastguard Worker   TT.ff->ifs = " \t\n";
4329*cf5a6c84SAndroid Build Coastguard Worker 
4330*cf5a6c84SAndroid Build Coastguard Worker   // Set up environment variables.
4331*cf5a6c84SAndroid Build Coastguard Worker   // Note: can call run_command() which blanks argument sections of TT and this,
4332*cf5a6c84SAndroid Build Coastguard Worker   // so parse everything we need from shell command line before here.
4333*cf5a6c84SAndroid Build Coastguard Worker   if (CFG_TOYBOX_FORK || toys.stacktop) subshell_setup(); // returns
4334*cf5a6c84SAndroid Build Coastguard Worker   else nommu_reentry(); // does not return
4335*cf5a6c84SAndroid Build Coastguard Worker 
4336*cf5a6c84SAndroid Build Coastguard Worker   if (TT.options&FLAG_i) {
4337*cf5a6c84SAndroid Build Coastguard Worker     if (!getvar("PS1")) setvarval("PS1", getpid() ? "\\$ " : "# ");
4338*cf5a6c84SAndroid Build Coastguard Worker     // TODO Set up signal handlers and grab control of this tty.
4339*cf5a6c84SAndroid Build Coastguard Worker     // ^C SIGINT ^\ SIGQUIT ^Z SIGTSTP SIGTTIN SIGTTOU SIGCHLD
4340*cf5a6c84SAndroid Build Coastguard Worker     // setsid(), setpgid(), tcsetpgrp()...
4341*cf5a6c84SAndroid Build Coastguard Worker     xsignal(SIGINT, SIG_IGN);
4342*cf5a6c84SAndroid Build Coastguard Worker   }
4343*cf5a6c84SAndroid Build Coastguard Worker 
4344*cf5a6c84SAndroid Build Coastguard Worker   if (cc) ff = fmemopen(cc, strlen(cc), "r");
4345*cf5a6c84SAndroid Build Coastguard Worker   else if (TT.options&FLAG_s) ff = (TT.options&FLAG_i) ? 0 : stdin;
4346*cf5a6c84SAndroid Build Coastguard Worker   else if (!(ff = fpathopen(*toys.optargs))) perror_exit_raw(*toys.optargs);
4347*cf5a6c84SAndroid Build Coastguard Worker 
4348*cf5a6c84SAndroid Build Coastguard Worker   // Read and execute lines from file
4349*cf5a6c84SAndroid Build Coastguard Worker   if (do_source(cc ? : *toys.optargs, ff))
4350*cf5a6c84SAndroid Build Coastguard Worker     error_exit("%u:unfinished line"+3*!TT.LINENO, TT.LINENO);
4351*cf5a6c84SAndroid Build Coastguard Worker }
4352*cf5a6c84SAndroid Build Coastguard Worker 
4353*cf5a6c84SAndroid Build Coastguard Worker // TODO: ./blah.sh one two three: put one two three in scratch.arg
4354*cf5a6c84SAndroid Build Coastguard Worker 
4355*cf5a6c84SAndroid Build Coastguard Worker /********************* shell builtin functions *************************/
4356*cf5a6c84SAndroid Build Coastguard Worker 
4357*cf5a6c84SAndroid Build Coastguard Worker // Note: "break &" in bash breaks in the child, this breaks in the parent.
break_main(void)4358*cf5a6c84SAndroid Build Coastguard Worker void break_main(void)
4359*cf5a6c84SAndroid Build Coastguard Worker {
4360*cf5a6c84SAndroid Build Coastguard Worker   int i = *toys.optargs ? atolx_range(*toys.optargs, 1, INT_MAX) : 1;
4361*cf5a6c84SAndroid Build Coastguard Worker 
4362*cf5a6c84SAndroid Build Coastguard Worker   // Peel off encosing do blocks
4363*cf5a6c84SAndroid Build Coastguard Worker   while (i && TT.ff->blk->next)
4364*cf5a6c84SAndroid Build Coastguard Worker     if (TT.ff->blk->middle && !strcmp(*TT.ff->blk->middle->arg->v, "do")
4365*cf5a6c84SAndroid Build Coastguard Worker         && !--i && *toys.which->name=='c') TT.ff->pl = TT.ff->blk->start;
4366*cf5a6c84SAndroid Build Coastguard Worker     else TT.ff->pl = pop_block();
4367*cf5a6c84SAndroid Build Coastguard Worker }
4368*cf5a6c84SAndroid Build Coastguard Worker 
4369*cf5a6c84SAndroid Build Coastguard Worker #define FOR_cd
4370*cf5a6c84SAndroid Build Coastguard Worker #include "generated/flags.h"
cd_main(void)4371*cf5a6c84SAndroid Build Coastguard Worker void cd_main(void)
4372*cf5a6c84SAndroid Build Coastguard Worker {
4373*cf5a6c84SAndroid Build Coastguard Worker   char *from, *to = 0, *dd = *toys.optargs ? : (getvar("HOME") ? : "/"),
4374*cf5a6c84SAndroid Build Coastguard Worker        *pwd = FLAG(P) ? 0 : getvar("PWD"), *zap = 0;
4375*cf5a6c84SAndroid Build Coastguard Worker   struct stat st1, st2;
4376*cf5a6c84SAndroid Build Coastguard Worker 
4377*cf5a6c84SAndroid Build Coastguard Worker   // TODO: CDPATH? Really?
4378*cf5a6c84SAndroid Build Coastguard Worker 
4379*cf5a6c84SAndroid Build Coastguard Worker   // For cd - use $OLDPWD as destination directory
4380*cf5a6c84SAndroid Build Coastguard Worker   if (!strcmp(dd, "-") && (!(dd = getvar("OLDPWD")) || !*dd))
4381*cf5a6c84SAndroid Build Coastguard Worker     return perror_msg("No $OLDPWD");
4382*cf5a6c84SAndroid Build Coastguard Worker 
4383*cf5a6c84SAndroid Build Coastguard Worker   if (*dd == '/') pwd = 0;
4384*cf5a6c84SAndroid Build Coastguard Worker 
4385*cf5a6c84SAndroid Build Coastguard Worker   // Did $PWD move out from under us?
4386*cf5a6c84SAndroid Build Coastguard Worker   if (pwd && !stat(".", &st1))
4387*cf5a6c84SAndroid Build Coastguard Worker     if (stat(pwd, &st2) || st1.st_dev!=st2.st_dev || st1.st_ino!=st2.st_ino)
4388*cf5a6c84SAndroid Build Coastguard Worker       pwd = 0;
4389*cf5a6c84SAndroid Build Coastguard Worker 
4390*cf5a6c84SAndroid Build Coastguard Worker   // Handle logical relative path
4391*cf5a6c84SAndroid Build Coastguard Worker   if (pwd) {
4392*cf5a6c84SAndroid Build Coastguard Worker     zap = xmprintf("%s/%s", pwd, dd);
4393*cf5a6c84SAndroid Build Coastguard Worker 
4394*cf5a6c84SAndroid Build Coastguard Worker     // cancel out . and .. in the string
4395*cf5a6c84SAndroid Build Coastguard Worker     for (from = to = zap; *from;) {
4396*cf5a6c84SAndroid Build Coastguard Worker       if (*from=='/' && from[1]=='/') from++;
4397*cf5a6c84SAndroid Build Coastguard Worker       else if (*from!='/' || from[1]!='.') *to++ = *from++;
4398*cf5a6c84SAndroid Build Coastguard Worker       else if (!from[2] || from[2]=='/') from += 2;
4399*cf5a6c84SAndroid Build Coastguard Worker       else if (from[2]=='.' && (!from[3] || from[3]=='/')) {
4400*cf5a6c84SAndroid Build Coastguard Worker         from += 3;
4401*cf5a6c84SAndroid Build Coastguard Worker         while (to>zap && *--to != '/');
4402*cf5a6c84SAndroid Build Coastguard Worker       } else *to++ = *from++;
4403*cf5a6c84SAndroid Build Coastguard Worker     }
4404*cf5a6c84SAndroid Build Coastguard Worker     if (to == zap) to++;
4405*cf5a6c84SAndroid Build Coastguard Worker     if (to-zap>1 && to[-1]=='/') to--;
4406*cf5a6c84SAndroid Build Coastguard Worker     *to = 0;
4407*cf5a6c84SAndroid Build Coastguard Worker   }
4408*cf5a6c84SAndroid Build Coastguard Worker 
4409*cf5a6c84SAndroid Build Coastguard Worker   // If logical chdir doesn't work, fall back to physical
4410*cf5a6c84SAndroid Build Coastguard Worker   if (!zap || chdir(zap)) {
4411*cf5a6c84SAndroid Build Coastguard Worker     free(zap);
4412*cf5a6c84SAndroid Build Coastguard Worker     if (chdir(dd)) return perror_msg("%s", dd);
4413*cf5a6c84SAndroid Build Coastguard Worker     if (!(dd = getcwd(0, 0))) dd = xstrdup("(nowhere)");
4414*cf5a6c84SAndroid Build Coastguard Worker   } else dd = zap;
4415*cf5a6c84SAndroid Build Coastguard Worker 
4416*cf5a6c84SAndroid Build Coastguard Worker   if ((pwd = getvar("PWD"))) setvarval("OLDPWD", pwd);
4417*cf5a6c84SAndroid Build Coastguard Worker   setvarval("PWD", dd);
4418*cf5a6c84SAndroid Build Coastguard Worker   free(dd);
4419*cf5a6c84SAndroid Build Coastguard Worker 
4420*cf5a6c84SAndroid Build Coastguard Worker   if (!(TT.options&OPT_cd)) {
4421*cf5a6c84SAndroid Build Coastguard Worker     export("OLDPWD");
4422*cf5a6c84SAndroid Build Coastguard Worker     export("PWD");
4423*cf5a6c84SAndroid Build Coastguard Worker     TT.options |= OPT_cd;
4424*cf5a6c84SAndroid Build Coastguard Worker   }
4425*cf5a6c84SAndroid Build Coastguard Worker }
4426*cf5a6c84SAndroid Build Coastguard Worker 
continue_main(void)4427*cf5a6c84SAndroid Build Coastguard Worker void continue_main(void)
4428*cf5a6c84SAndroid Build Coastguard Worker {
4429*cf5a6c84SAndroid Build Coastguard Worker   break_main();
4430*cf5a6c84SAndroid Build Coastguard Worker }
4431*cf5a6c84SAndroid Build Coastguard Worker 
exit_main(void)4432*cf5a6c84SAndroid Build Coastguard Worker void exit_main(void)
4433*cf5a6c84SAndroid Build Coastguard Worker {
4434*cf5a6c84SAndroid Build Coastguard Worker   toys.exitval = *toys.optargs ? atoi(*toys.optargs) : 0;
4435*cf5a6c84SAndroid Build Coastguard Worker   toys.rebound = 0;
4436*cf5a6c84SAndroid Build Coastguard Worker   // TODO trap EXIT, sigatexit
4437*cf5a6c84SAndroid Build Coastguard Worker   xexit();
4438*cf5a6c84SAndroid Build Coastguard Worker }
4439*cf5a6c84SAndroid Build Coastguard Worker 
4440*cf5a6c84SAndroid Build Coastguard Worker // lib/args.c can't +prefix & "+o history" needs space so parse cmdline here
set_main(void)4441*cf5a6c84SAndroid Build Coastguard Worker void set_main(void)
4442*cf5a6c84SAndroid Build Coastguard Worker {
4443*cf5a6c84SAndroid Build Coastguard Worker   char *cc, *ostr[] = {"braceexpand", "noclobber", "xtrace"};
4444*cf5a6c84SAndroid Build Coastguard Worker   int ii, jj, kk, oo = 0, dd = 0;
4445*cf5a6c84SAndroid Build Coastguard Worker 
4446*cf5a6c84SAndroid Build Coastguard Worker   // display visible variables
4447*cf5a6c84SAndroid Build Coastguard Worker   if (!*toys.optargs) {
4448*cf5a6c84SAndroid Build Coastguard Worker     struct sh_vars **vv = visible_vars();
4449*cf5a6c84SAndroid Build Coastguard Worker 
4450*cf5a6c84SAndroid Build Coastguard Worker // TODO escape properly
4451*cf5a6c84SAndroid Build Coastguard Worker     for (ii = 0; vv[ii]; ii++)
4452*cf5a6c84SAndroid Build Coastguard Worker       if (!(vv[ii]->flags&VAR_WHITEOUT)) printf("%s\n", vv[ii]->str);
4453*cf5a6c84SAndroid Build Coastguard Worker     free(vv);
4454*cf5a6c84SAndroid Build Coastguard Worker 
4455*cf5a6c84SAndroid Build Coastguard Worker     return;
4456*cf5a6c84SAndroid Build Coastguard Worker   }
4457*cf5a6c84SAndroid Build Coastguard Worker 
4458*cf5a6c84SAndroid Build Coastguard Worker   // Handle options
4459*cf5a6c84SAndroid Build Coastguard Worker   for (ii = 0;; ii++) {
4460*cf5a6c84SAndroid Build Coastguard Worker     if ((cc = toys.optargs[ii]) && !(dd = stridx("-+", *cc)+1) && oo--) {
4461*cf5a6c84SAndroid Build Coastguard Worker       for (jj = 0; jj<ARRAY_LEN(ostr); jj++) if (!strcmp(cc, ostr[jj])) break;
4462*cf5a6c84SAndroid Build Coastguard Worker       if (jj != ARRAY_LEN(ostr)) {
4463*cf5a6c84SAndroid Build Coastguard Worker         if (dd==1) TT.options |= OPT_B<<kk;
4464*cf5a6c84SAndroid Build Coastguard Worker         else TT.options &= ~(OPT_B<<kk);
4465*cf5a6c84SAndroid Build Coastguard Worker 
4466*cf5a6c84SAndroid Build Coastguard Worker         continue;
4467*cf5a6c84SAndroid Build Coastguard Worker       }
4468*cf5a6c84SAndroid Build Coastguard Worker       error_exit("bad -o %s", cc);
4469*cf5a6c84SAndroid Build Coastguard Worker     }
4470*cf5a6c84SAndroid Build Coastguard Worker     if (oo>0) for (jj = 0; jj<ARRAY_LEN(ostr); jj++)
4471*cf5a6c84SAndroid Build Coastguard Worker       printf("%s\t%s\n", ostr[jj], TT.options&(OPT_B<<jj) ? "on" : "off");
4472*cf5a6c84SAndroid Build Coastguard Worker     oo = 0;
4473*cf5a6c84SAndroid Build Coastguard Worker     if (!cc || !dd) break;
4474*cf5a6c84SAndroid Build Coastguard Worker     for (jj = 1; cc[jj]; jj++) {
4475*cf5a6c84SAndroid Build Coastguard Worker       if (cc[jj] == 'o') oo++;
4476*cf5a6c84SAndroid Build Coastguard Worker       else if (-1 != (kk = stridx("BCxu", cc[jj]))) {
4477*cf5a6c84SAndroid Build Coastguard Worker         if (*cc == '-') TT.options |= OPT_B<<kk;
4478*cf5a6c84SAndroid Build Coastguard Worker         else TT.options &= ~(OPT_B<<kk);
4479*cf5a6c84SAndroid Build Coastguard Worker       } else error_exit("bad -%c", toys.optargs[ii][1]);
4480*cf5a6c84SAndroid Build Coastguard Worker     }
4481*cf5a6c84SAndroid Build Coastguard Worker   }
4482*cf5a6c84SAndroid Build Coastguard Worker 
4483*cf5a6c84SAndroid Build Coastguard Worker   // handle positional parameters
4484*cf5a6c84SAndroid Build Coastguard Worker   if (cc) {
4485*cf5a6c84SAndroid Build Coastguard Worker     struct arg_list *al, **head;
4486*cf5a6c84SAndroid Build Coastguard Worker     struct sh_arg *arg = &TT.ff->arg;
4487*cf5a6c84SAndroid Build Coastguard Worker 
4488*cf5a6c84SAndroid Build Coastguard Worker     // don't free memory that's already scheduled for deletion
4489*cf5a6c84SAndroid Build Coastguard Worker     for (al = *(head = &TT.ff->delete); al; al = *(head = &al->next))
4490*cf5a6c84SAndroid Build Coastguard Worker       if (al->arg == (void *)arg->v) break;
4491*cf5a6c84SAndroid Build Coastguard Worker 
4492*cf5a6c84SAndroid Build Coastguard Worker     // free last set's memory (if any) so it doesn't accumulate in loop
4493*cf5a6c84SAndroid Build Coastguard Worker     if (al) for (jj = arg->c+1; jj; jj--) {
4494*cf5a6c84SAndroid Build Coastguard Worker       *head = al->next;
4495*cf5a6c84SAndroid Build Coastguard Worker       free(al->arg);
4496*cf5a6c84SAndroid Build Coastguard Worker       free(al);
4497*cf5a6c84SAndroid Build Coastguard Worker     }
4498*cf5a6c84SAndroid Build Coastguard Worker 
4499*cf5a6c84SAndroid Build Coastguard Worker     while (toys.optargs[ii])
4500*cf5a6c84SAndroid Build Coastguard Worker       arg_add(arg, push_arg(&TT.ff->delete, strdup(toys.optargs[ii++])));
4501*cf5a6c84SAndroid Build Coastguard Worker     push_arg(&TT.ff->delete, arg->v);
4502*cf5a6c84SAndroid Build Coastguard Worker   }
4503*cf5a6c84SAndroid Build Coastguard Worker }
4504*cf5a6c84SAndroid Build Coastguard Worker 
4505*cf5a6c84SAndroid Build Coastguard Worker // TODO need test: unset clears var first and stops, function only if no var.
4506*cf5a6c84SAndroid Build Coastguard Worker #define FOR_unset
4507*cf5a6c84SAndroid Build Coastguard Worker #include "generated/flags.h"
4508*cf5a6c84SAndroid Build Coastguard Worker 
unset_main(void)4509*cf5a6c84SAndroid Build Coastguard Worker void unset_main(void)
4510*cf5a6c84SAndroid Build Coastguard Worker {
4511*cf5a6c84SAndroid Build Coastguard Worker   char **arg, *s;
4512*cf5a6c84SAndroid Build Coastguard Worker   int ii;
4513*cf5a6c84SAndroid Build Coastguard Worker 
4514*cf5a6c84SAndroid Build Coastguard Worker   for (arg = toys.optargs; *arg; arg++) {
4515*cf5a6c84SAndroid Build Coastguard Worker     s = varend(*arg);
4516*cf5a6c84SAndroid Build Coastguard Worker     if (s == *arg || *s) {
4517*cf5a6c84SAndroid Build Coastguard Worker       error_msg("bad '%s'", *arg);
4518*cf5a6c84SAndroid Build Coastguard Worker       continue;
4519*cf5a6c84SAndroid Build Coastguard Worker     }
4520*cf5a6c84SAndroid Build Coastguard Worker 
4521*cf5a6c84SAndroid Build Coastguard Worker     // TODO -n and name reference support
4522*cf5a6c84SAndroid Build Coastguard Worker     // unset variable
4523*cf5a6c84SAndroid Build Coastguard Worker     if (!FLAG(f) && unsetvar(*arg)) continue;
4524*cf5a6c84SAndroid Build Coastguard Worker     // unset function TODO binary search
4525*cf5a6c84SAndroid Build Coastguard Worker     for (ii = 0; ii<TT.funcslen; ii++)
4526*cf5a6c84SAndroid Build Coastguard Worker       if (!strcmp(*arg, TT.functions[ii]->name)) break;
4527*cf5a6c84SAndroid Build Coastguard Worker     if (ii != TT.funcslen) {
4528*cf5a6c84SAndroid Build Coastguard Worker       free_function(TT.functions[ii]);
4529*cf5a6c84SAndroid Build Coastguard Worker       memmove(TT.functions+ii, TT.functions+ii+1, TT.funcslen+1-ii);
4530*cf5a6c84SAndroid Build Coastguard Worker     }
4531*cf5a6c84SAndroid Build Coastguard Worker   }
4532*cf5a6c84SAndroid Build Coastguard Worker }
4533*cf5a6c84SAndroid Build Coastguard Worker 
4534*cf5a6c84SAndroid Build Coastguard Worker #define FOR_export
4535*cf5a6c84SAndroid Build Coastguard Worker #include "generated/flags.h"
4536*cf5a6c84SAndroid Build Coastguard Worker 
export_main(void)4537*cf5a6c84SAndroid Build Coastguard Worker void export_main(void)
4538*cf5a6c84SAndroid Build Coastguard Worker {
4539*cf5a6c84SAndroid Build Coastguard Worker   char **arg, *eq;
4540*cf5a6c84SAndroid Build Coastguard Worker 
4541*cf5a6c84SAndroid Build Coastguard Worker   // list existing variables?
4542*cf5a6c84SAndroid Build Coastguard Worker   if (!toys.optc) {
4543*cf5a6c84SAndroid Build Coastguard Worker     struct sh_vars **vv = visible_vars();
4544*cf5a6c84SAndroid Build Coastguard Worker     unsigned uu;
4545*cf5a6c84SAndroid Build Coastguard Worker 
4546*cf5a6c84SAndroid Build Coastguard Worker     for (uu = 0; vv[uu]; uu++) {
4547*cf5a6c84SAndroid Build Coastguard Worker       if ((vv[uu]->flags&(VAR_WHITEOUT|VAR_EXPORT))==VAR_EXPORT) {
4548*cf5a6c84SAndroid Build Coastguard Worker         xputs(eq = declarep(vv[uu]));
4549*cf5a6c84SAndroid Build Coastguard Worker         free(eq);
4550*cf5a6c84SAndroid Build Coastguard Worker       }
4551*cf5a6c84SAndroid Build Coastguard Worker     }
4552*cf5a6c84SAndroid Build Coastguard Worker     free(vv);
4553*cf5a6c84SAndroid Build Coastguard Worker 
4554*cf5a6c84SAndroid Build Coastguard Worker     return;
4555*cf5a6c84SAndroid Build Coastguard Worker   }
4556*cf5a6c84SAndroid Build Coastguard Worker 
4557*cf5a6c84SAndroid Build Coastguard Worker   // set/move variables
4558*cf5a6c84SAndroid Build Coastguard Worker   for (arg = toys.optargs; *arg; arg++) {
4559*cf5a6c84SAndroid Build Coastguard Worker     eq = varend(*arg);
4560*cf5a6c84SAndroid Build Coastguard Worker     if (eq == *arg || (*eq && eq[*eq=='+'] != '=')) {
4561*cf5a6c84SAndroid Build Coastguard Worker       error_msg("bad %s", *arg);
4562*cf5a6c84SAndroid Build Coastguard Worker       continue;
4563*cf5a6c84SAndroid Build Coastguard Worker     }
4564*cf5a6c84SAndroid Build Coastguard Worker 
4565*cf5a6c84SAndroid Build Coastguard Worker     if (FLAG(n)) set_varflags(*arg, 0, VAR_EXPORT);
4566*cf5a6c84SAndroid Build Coastguard Worker     else export(*arg);
4567*cf5a6c84SAndroid Build Coastguard Worker   }
4568*cf5a6c84SAndroid Build Coastguard Worker }
4569*cf5a6c84SAndroid Build Coastguard Worker 
4570*cf5a6c84SAndroid Build Coastguard Worker #define FOR_declare
4571*cf5a6c84SAndroid Build Coastguard Worker #include "generated/flags.h"
4572*cf5a6c84SAndroid Build Coastguard Worker 
declare_main(void)4573*cf5a6c84SAndroid Build Coastguard Worker void declare_main(void)
4574*cf5a6c84SAndroid Build Coastguard Worker {
4575*cf5a6c84SAndroid Build Coastguard Worker   unsigned uu, fl = toys.optflags&(FLAG(p)-1);
4576*cf5a6c84SAndroid Build Coastguard Worker   char *ss, **arg;
4577*cf5a6c84SAndroid Build Coastguard Worker // TODO: need a show_vars() to collate all the visible_vars() loop output
4578*cf5a6c84SAndroid Build Coastguard Worker // TODO: -g support including -gp
4579*cf5a6c84SAndroid Build Coastguard Worker // TODO: dump everything key=value and functions too
4580*cf5a6c84SAndroid Build Coastguard Worker   if (!toys.optc) {
4581*cf5a6c84SAndroid Build Coastguard Worker     struct sh_vars **vv = visible_vars();
4582*cf5a6c84SAndroid Build Coastguard Worker 
4583*cf5a6c84SAndroid Build Coastguard Worker     for (uu = 0; vv[uu]; uu++) {
4584*cf5a6c84SAndroid Build Coastguard Worker       if ((vv[uu]->flags&VAR_WHITEOUT) || (fl && !(vv[uu]->flags&fl))) continue;
4585*cf5a6c84SAndroid Build Coastguard Worker       xputs(ss = declarep(vv[uu]));
4586*cf5a6c84SAndroid Build Coastguard Worker       free(ss);
4587*cf5a6c84SAndroid Build Coastguard Worker     }
4588*cf5a6c84SAndroid Build Coastguard Worker     free(vv);
4589*cf5a6c84SAndroid Build Coastguard Worker   } else if (FLAG(p)) for (arg = toys.optargs; *arg; arg++) {
4590*cf5a6c84SAndroid Build Coastguard Worker     struct sh_vars *vv = *varend(ss = *arg) ? 0 : findvar(ss, 0);
4591*cf5a6c84SAndroid Build Coastguard Worker 
4592*cf5a6c84SAndroid Build Coastguard Worker     if (!vv) perror_msg("%s: not found", ss);
4593*cf5a6c84SAndroid Build Coastguard Worker     else {
4594*cf5a6c84SAndroid Build Coastguard Worker       xputs(ss = declarep(vv));
4595*cf5a6c84SAndroid Build Coastguard Worker       free(ss);
4596*cf5a6c84SAndroid Build Coastguard Worker     }
4597*cf5a6c84SAndroid Build Coastguard Worker   } else for (arg = toys.optargs; *arg; arg++) {
4598*cf5a6c84SAndroid Build Coastguard Worker     ss = varend(*arg);
4599*cf5a6c84SAndroid Build Coastguard Worker     if (ss == *arg || (*ss && ss[*ss=='+'] != '=')) {
4600*cf5a6c84SAndroid Build Coastguard Worker       error_msg("bad %s", *arg);
4601*cf5a6c84SAndroid Build Coastguard Worker       continue;
4602*cf5a6c84SAndroid Build Coastguard Worker     }
4603*cf5a6c84SAndroid Build Coastguard Worker     set_varflags(*arg, toys.optflags<<1, 0); // TODO +x unset
4604*cf5a6c84SAndroid Build Coastguard Worker   }
4605*cf5a6c84SAndroid Build Coastguard Worker }
4606*cf5a6c84SAndroid Build Coastguard Worker 
eval_main(void)4607*cf5a6c84SAndroid Build Coastguard Worker void eval_main(void)
4608*cf5a6c84SAndroid Build Coastguard Worker {
4609*cf5a6c84SAndroid Build Coastguard Worker   char *s;
4610*cf5a6c84SAndroid Build Coastguard Worker 
4611*cf5a6c84SAndroid Build Coastguard Worker   // borrow the $* expand infrastructure
4612*cf5a6c84SAndroid Build Coastguard Worker   call_function();
4613*cf5a6c84SAndroid Build Coastguard Worker   TT.ff->arg.v = toys.argv;
4614*cf5a6c84SAndroid Build Coastguard Worker   TT.ff->arg.c = toys.optc+1;
4615*cf5a6c84SAndroid Build Coastguard Worker   s = expand_one_arg("\"$*\"", SEMI_IFS);
4616*cf5a6c84SAndroid Build Coastguard Worker   TT.ff->arg.v = TT.ff->next->arg.v;
4617*cf5a6c84SAndroid Build Coastguard Worker   TT.ff->arg.c = TT.ff->next->arg.c;
4618*cf5a6c84SAndroid Build Coastguard Worker   do_source(0, fmemopen(s, strlen(s), "r"));
4619*cf5a6c84SAndroid Build Coastguard Worker   free(dlist_pop(&TT.ff));
4620*cf5a6c84SAndroid Build Coastguard Worker   free(s);
4621*cf5a6c84SAndroid Build Coastguard Worker }
4622*cf5a6c84SAndroid Build Coastguard Worker 
4623*cf5a6c84SAndroid Build Coastguard Worker #define FOR_exec
4624*cf5a6c84SAndroid Build Coastguard Worker #include "generated/flags.h"
4625*cf5a6c84SAndroid Build Coastguard Worker 
exec_main(void)4626*cf5a6c84SAndroid Build Coastguard Worker void exec_main(void)
4627*cf5a6c84SAndroid Build Coastguard Worker {
4628*cf5a6c84SAndroid Build Coastguard Worker   char *ee[1] = {0}, **old = environ;
4629*cf5a6c84SAndroid Build Coastguard Worker 
4630*cf5a6c84SAndroid Build Coastguard Worker   // discard redirects and return if nothing to exec
4631*cf5a6c84SAndroid Build Coastguard Worker   free(TT.pp->urd);
4632*cf5a6c84SAndroid Build Coastguard Worker   TT.pp->urd = 0;
4633*cf5a6c84SAndroid Build Coastguard Worker   if (!toys.optc) return;
4634*cf5a6c84SAndroid Build Coastguard Worker 
4635*cf5a6c84SAndroid Build Coastguard Worker   // exec, handling -acl
4636*cf5a6c84SAndroid Build Coastguard Worker   TT.isexec = *toys.optargs;
4637*cf5a6c84SAndroid Build Coastguard Worker   if (FLAG(c)) environ = ee;
4638*cf5a6c84SAndroid Build Coastguard Worker   if (TT.exec.a || FLAG(l))
4639*cf5a6c84SAndroid Build Coastguard Worker     *toys.optargs = xmprintf("%s%s", FLAG(l) ? "-" : "", TT.exec.a?:TT.isexec);
4640*cf5a6c84SAndroid Build Coastguard Worker   sh_exec(toys.optargs);
4641*cf5a6c84SAndroid Build Coastguard Worker 
4642*cf5a6c84SAndroid Build Coastguard Worker   // report error (usually ENOENT) and return
4643*cf5a6c84SAndroid Build Coastguard Worker   if (*toys.optargs != TT.isexec) free(*toys.optargs);
4644*cf5a6c84SAndroid Build Coastguard Worker   TT.isexec = 0;
4645*cf5a6c84SAndroid Build Coastguard Worker   toys.exitval = 127;
4646*cf5a6c84SAndroid Build Coastguard Worker   environ = old;
4647*cf5a6c84SAndroid Build Coastguard Worker }
4648*cf5a6c84SAndroid Build Coastguard Worker 
4649*cf5a6c84SAndroid Build Coastguard Worker // Return T.jobs index or -1 from identifier
4650*cf5a6c84SAndroid Build Coastguard Worker // Note, we don't return "ambiguous job spec", we return the first hit or -1.
4651*cf5a6c84SAndroid Build Coastguard Worker // TODO %% %+ %- %?ab
find_job(char * s)4652*cf5a6c84SAndroid Build Coastguard Worker int find_job(char *s)
4653*cf5a6c84SAndroid Build Coastguard Worker {
4654*cf5a6c84SAndroid Build Coastguard Worker   char *ss;
4655*cf5a6c84SAndroid Build Coastguard Worker   long ll = strtol(s, &ss, 10);
4656*cf5a6c84SAndroid Build Coastguard Worker   int i, j;
4657*cf5a6c84SAndroid Build Coastguard Worker 
4658*cf5a6c84SAndroid Build Coastguard Worker   if (!TT.jobs.c) return -1;
4659*cf5a6c84SAndroid Build Coastguard Worker   if (!*s || (!s[1] && strchr("%+-", *s))) {
4660*cf5a6c84SAndroid Build Coastguard Worker     int minus, plus = find_plus_minus(&minus);
4661*cf5a6c84SAndroid Build Coastguard Worker 
4662*cf5a6c84SAndroid Build Coastguard Worker     return (*s == '-') ? minus : plus;
4663*cf5a6c84SAndroid Build Coastguard Worker   }
4664*cf5a6c84SAndroid Build Coastguard Worker 
4665*cf5a6c84SAndroid Build Coastguard Worker   // Is this a %1 numeric jobspec?
4666*cf5a6c84SAndroid Build Coastguard Worker   if (s != ss && !*ss)
4667*cf5a6c84SAndroid Build Coastguard Worker     for (i = 0; i<TT.jobs.c; i++)
4668*cf5a6c84SAndroid Build Coastguard Worker       if (((struct sh_process *)TT.jobs.v[i])->job == ll) return i;
4669*cf5a6c84SAndroid Build Coastguard Worker 
4670*cf5a6c84SAndroid Build Coastguard Worker   // Match start of command or %?abc
4671*cf5a6c84SAndroid Build Coastguard Worker   for (i = 0; i<TT.jobs.c; i++) {
4672*cf5a6c84SAndroid Build Coastguard Worker     struct sh_process *pp = (void *)TT.jobs.v[i];
4673*cf5a6c84SAndroid Build Coastguard Worker 
4674*cf5a6c84SAndroid Build Coastguard Worker     if (strstart(&s, *pp->arg.v)) return i;
4675*cf5a6c84SAndroid Build Coastguard Worker     if (*s != '?' || !s[1]) continue;
4676*cf5a6c84SAndroid Build Coastguard Worker     for (j = 0; j<pp->arg.c; j++) if (strstr(pp->arg.v[j], s+1)) return i;
4677*cf5a6c84SAndroid Build Coastguard Worker   }
4678*cf5a6c84SAndroid Build Coastguard Worker 
4679*cf5a6c84SAndroid Build Coastguard Worker   return -1;
4680*cf5a6c84SAndroid Build Coastguard Worker }
4681*cf5a6c84SAndroid Build Coastguard Worker 
jobs_main(void)4682*cf5a6c84SAndroid Build Coastguard Worker void jobs_main(void)
4683*cf5a6c84SAndroid Build Coastguard Worker {
4684*cf5a6c84SAndroid Build Coastguard Worker   int i, j, minus, plus = find_plus_minus(&minus);
4685*cf5a6c84SAndroid Build Coastguard Worker   char *s;
4686*cf5a6c84SAndroid Build Coastguard Worker 
4687*cf5a6c84SAndroid Build Coastguard Worker // TODO -lnprs
4688*cf5a6c84SAndroid Build Coastguard Worker 
4689*cf5a6c84SAndroid Build Coastguard Worker   for (i = 0;;i++) {
4690*cf5a6c84SAndroid Build Coastguard Worker     if (toys.optc) {
4691*cf5a6c84SAndroid Build Coastguard Worker       if (!(s = toys.optargs[i])) break;
4692*cf5a6c84SAndroid Build Coastguard Worker       if ((j = find_job(s+('%' == *s))) == -1) {
4693*cf5a6c84SAndroid Build Coastguard Worker         perror_msg("%s: no such job", s);
4694*cf5a6c84SAndroid Build Coastguard Worker 
4695*cf5a6c84SAndroid Build Coastguard Worker         continue;
4696*cf5a6c84SAndroid Build Coastguard Worker       }
4697*cf5a6c84SAndroid Build Coastguard Worker     } else if ((j = i) >= TT.jobs.c) break;
4698*cf5a6c84SAndroid Build Coastguard Worker 
4699*cf5a6c84SAndroid Build Coastguard Worker     s = show_job((void *)TT.jobs.v[i], is_plus_minus(i, plus, minus));
4700*cf5a6c84SAndroid Build Coastguard Worker     printf("%s\n", s);
4701*cf5a6c84SAndroid Build Coastguard Worker     free(s);
4702*cf5a6c84SAndroid Build Coastguard Worker   }
4703*cf5a6c84SAndroid Build Coastguard Worker }
4704*cf5a6c84SAndroid Build Coastguard Worker 
4705*cf5a6c84SAndroid Build Coastguard Worker #define FOR_local
4706*cf5a6c84SAndroid Build Coastguard Worker #include "generated/flags.h"
4707*cf5a6c84SAndroid Build Coastguard Worker 
local_main(void)4708*cf5a6c84SAndroid Build Coastguard Worker void local_main(void)
4709*cf5a6c84SAndroid Build Coastguard Worker {
4710*cf5a6c84SAndroid Build Coastguard Worker   struct sh_fcall *ff, *ff2;
4711*cf5a6c84SAndroid Build Coastguard Worker   struct sh_vars *var;
4712*cf5a6c84SAndroid Build Coastguard Worker   char **arg, *eq;
4713*cf5a6c84SAndroid Build Coastguard Worker 
4714*cf5a6c84SAndroid Build Coastguard Worker   // find local variable context
4715*cf5a6c84SAndroid Build Coastguard Worker   for (ff = TT.ff;; ff = ff->next) {
4716*cf5a6c84SAndroid Build Coastguard Worker     if (ff == TT.ff->prev) return error_msg("not in function");
4717*cf5a6c84SAndroid Build Coastguard Worker     if (ff->vars) break;
4718*cf5a6c84SAndroid Build Coastguard Worker   }
4719*cf5a6c84SAndroid Build Coastguard Worker 
4720*cf5a6c84SAndroid Build Coastguard Worker   // list existing vars (todo:
4721*cf5a6c84SAndroid Build Coastguard Worker   if (!toys.optc) {
4722*cf5a6c84SAndroid Build Coastguard Worker     for (var = ff->vars; var; var++) xputs(var->str); // TODO escape
4723*cf5a6c84SAndroid Build Coastguard Worker     return;
4724*cf5a6c84SAndroid Build Coastguard Worker   }
4725*cf5a6c84SAndroid Build Coastguard Worker 
4726*cf5a6c84SAndroid Build Coastguard Worker   // set/move variables
4727*cf5a6c84SAndroid Build Coastguard Worker   for (arg = toys.optargs; *arg; arg++) {
4728*cf5a6c84SAndroid Build Coastguard Worker     if ((eq = varend(*arg)) == *arg || (*eq && *eq != '=')) {
4729*cf5a6c84SAndroid Build Coastguard Worker       error_msg("bad %s", *arg);
4730*cf5a6c84SAndroid Build Coastguard Worker       continue;
4731*cf5a6c84SAndroid Build Coastguard Worker     }
4732*cf5a6c84SAndroid Build Coastguard Worker 
4733*cf5a6c84SAndroid Build Coastguard Worker     if ((var = findvar(*arg, &ff2)) && ff == ff2 && !*eq) continue;
4734*cf5a6c84SAndroid Build Coastguard Worker     if (var && (var->flags&VAR_READONLY)) {
4735*cf5a6c84SAndroid Build Coastguard Worker       error_msg("%.*s: readonly variable", (int)(varend(*arg)-*arg), *arg);
4736*cf5a6c84SAndroid Build Coastguard Worker       continue;
4737*cf5a6c84SAndroid Build Coastguard Worker     }
4738*cf5a6c84SAndroid Build Coastguard Worker 
4739*cf5a6c84SAndroid Build Coastguard Worker     // Add local inheriting global status and setting whiteout if blank.
4740*cf5a6c84SAndroid Build Coastguard Worker     if (!var || ff!=ff2) {
4741*cf5a6c84SAndroid Build Coastguard Worker       int flags = var ? var->flags&VAR_EXPORT : 0;
4742*cf5a6c84SAndroid Build Coastguard Worker 
4743*cf5a6c84SAndroid Build Coastguard Worker       var = addvar(xmprintf("%s%s", *arg, *eq ? "" : "="), ff);
4744*cf5a6c84SAndroid Build Coastguard Worker       var->flags = flags|(VAR_WHITEOUT*!*eq);
4745*cf5a6c84SAndroid Build Coastguard Worker     }
4746*cf5a6c84SAndroid Build Coastguard Worker 
4747*cf5a6c84SAndroid Build Coastguard Worker     // TODO accept declare options to set more flags
4748*cf5a6c84SAndroid Build Coastguard Worker     // TODO, integer, uppercase take effect. Setvar?
4749*cf5a6c84SAndroid Build Coastguard Worker   }
4750*cf5a6c84SAndroid Build Coastguard Worker }
4751*cf5a6c84SAndroid Build Coastguard Worker 
return_main(void)4752*cf5a6c84SAndroid Build Coastguard Worker void return_main(void)
4753*cf5a6c84SAndroid Build Coastguard Worker {
4754*cf5a6c84SAndroid Build Coastguard Worker   struct sh_fcall *ff;
4755*cf5a6c84SAndroid Build Coastguard Worker   char *ss;
4756*cf5a6c84SAndroid Build Coastguard Worker 
4757*cf5a6c84SAndroid Build Coastguard Worker   if (*toys.optargs) {
4758*cf5a6c84SAndroid Build Coastguard Worker     toys.exitval = estrtol(*toys.optargs, &ss, 0);
4759*cf5a6c84SAndroid Build Coastguard Worker     if (errno || *ss) error_msg("NaN");
4760*cf5a6c84SAndroid Build Coastguard Worker   }
4761*cf5a6c84SAndroid Build Coastguard Worker 
4762*cf5a6c84SAndroid Build Coastguard Worker   // Do we have a non-transparent function context in the call stack?
4763*cf5a6c84SAndroid Build Coastguard Worker   for (ff = TT.ff; !ff->func; ff = ff->next)
4764*cf5a6c84SAndroid Build Coastguard Worker     if (ff == TT.ff->prev) return error_msg("not function or source");
4765*cf5a6c84SAndroid Build Coastguard Worker 
4766*cf5a6c84SAndroid Build Coastguard Worker   // Pop all blocks to start of function
4767*cf5a6c84SAndroid Build Coastguard Worker   for (ff = TT.ff;; ff = ff->next) {
4768*cf5a6c84SAndroid Build Coastguard Worker     while (TT.ff->blk->next) TT.ff->pl = pop_block();
4769*cf5a6c84SAndroid Build Coastguard Worker     if (ff->func) break;
4770*cf5a6c84SAndroid Build Coastguard Worker   }
4771*cf5a6c84SAndroid Build Coastguard Worker }
4772*cf5a6c84SAndroid Build Coastguard Worker 
shift_main(void)4773*cf5a6c84SAndroid Build Coastguard Worker void shift_main(void)
4774*cf5a6c84SAndroid Build Coastguard Worker {
4775*cf5a6c84SAndroid Build Coastguard Worker   long long by = 1;
4776*cf5a6c84SAndroid Build Coastguard Worker 
4777*cf5a6c84SAndroid Build Coastguard Worker   if (toys.optc) by = atolx(*toys.optargs);
4778*cf5a6c84SAndroid Build Coastguard Worker   by += TT.ff->shift;
4779*cf5a6c84SAndroid Build Coastguard Worker   if (by<0 || by>=TT.ff->arg.c) toys.exitval++;
4780*cf5a6c84SAndroid Build Coastguard Worker   else TT.ff->shift = by;
4781*cf5a6c84SAndroid Build Coastguard Worker }
4782*cf5a6c84SAndroid Build Coastguard Worker 
source_main(void)4783*cf5a6c84SAndroid Build Coastguard Worker void source_main(void)
4784*cf5a6c84SAndroid Build Coastguard Worker {
4785*cf5a6c84SAndroid Build Coastguard Worker   char *name = *toys.optargs;
4786*cf5a6c84SAndroid Build Coastguard Worker   FILE *ff = fpathopen(name);
4787*cf5a6c84SAndroid Build Coastguard Worker 
4788*cf5a6c84SAndroid Build Coastguard Worker   if (!ff) return perror_msg_raw(name);
4789*cf5a6c84SAndroid Build Coastguard Worker   // $0 is shell name, not source file name while running this
4790*cf5a6c84SAndroid Build Coastguard Worker // TODO add tests: sh -c "source input four five" one two three
4791*cf5a6c84SAndroid Build Coastguard Worker   *toys.optargs = *toys.argv;
4792*cf5a6c84SAndroid Build Coastguard Worker   ++TT.srclvl;
4793*cf5a6c84SAndroid Build Coastguard Worker   call_function();
4794*cf5a6c84SAndroid Build Coastguard Worker   TT.ff->func = (void *)1;
4795*cf5a6c84SAndroid Build Coastguard Worker   TT.ff->arg.v = toys.optargs;
4796*cf5a6c84SAndroid Build Coastguard Worker   TT.ff->arg.c = toys.optc;
4797*cf5a6c84SAndroid Build Coastguard Worker   TT.ff->oldlineno = TT.LINENO;
4798*cf5a6c84SAndroid Build Coastguard Worker   TT.LINENO = 0;
4799*cf5a6c84SAndroid Build Coastguard Worker   do_source(name, ff);
4800*cf5a6c84SAndroid Build Coastguard Worker   TT.LINENO = TT.ff->oldlineno;
4801*cf5a6c84SAndroid Build Coastguard Worker   // TODO: this doesn't do proper cleanup but isn't normal fcall either
4802*cf5a6c84SAndroid Build Coastguard Worker   free(dlist_pop(&TT.ff));
4803*cf5a6c84SAndroid Build Coastguard Worker   --TT.srclvl;
4804*cf5a6c84SAndroid Build Coastguard Worker }
4805*cf5a6c84SAndroid Build Coastguard Worker 
4806*cf5a6c84SAndroid Build Coastguard Worker #define FOR_wait
4807*cf5a6c84SAndroid Build Coastguard Worker #include "generated/flags.h"
4808*cf5a6c84SAndroid Build Coastguard Worker 
wait_main(void)4809*cf5a6c84SAndroid Build Coastguard Worker void wait_main(void)
4810*cf5a6c84SAndroid Build Coastguard Worker {
4811*cf5a6c84SAndroid Build Coastguard Worker   struct sh_process *pp;
4812*cf5a6c84SAndroid Build Coastguard Worker   int ii, jj;
4813*cf5a6c84SAndroid Build Coastguard Worker   long long ll;
4814*cf5a6c84SAndroid Build Coastguard Worker   char *s;
4815*cf5a6c84SAndroid Build Coastguard Worker 
4816*cf5a6c84SAndroid Build Coastguard Worker   // TODO does -o pipefail affect return code here
4817*cf5a6c84SAndroid Build Coastguard Worker   if (FLAG(n)) toys.exitval = free_process(wait_job(-1, 0));
4818*cf5a6c84SAndroid Build Coastguard Worker   else if (!toys.optc) while (TT.jobs.c) {
4819*cf5a6c84SAndroid Build Coastguard Worker     if (!(pp = wait_job(-1, 0))) break;
4820*cf5a6c84SAndroid Build Coastguard Worker   } else for (ii = 0; ii<toys.optc; ii++) {
4821*cf5a6c84SAndroid Build Coastguard Worker     ll = estrtol(toys.optargs[ii], &s, 10);
4822*cf5a6c84SAndroid Build Coastguard Worker     if (errno || *s) {
4823*cf5a6c84SAndroid Build Coastguard Worker       if (-1 == (jj = find_job(toys.optargs[ii]))) {
4824*cf5a6c84SAndroid Build Coastguard Worker         error_msg("%s: bad pid/job", toys.optargs[ii]);
4825*cf5a6c84SAndroid Build Coastguard Worker         continue;
4826*cf5a6c84SAndroid Build Coastguard Worker       }
4827*cf5a6c84SAndroid Build Coastguard Worker       ll = ((struct sh_process *)TT.jobs.v[jj])->pid;
4828*cf5a6c84SAndroid Build Coastguard Worker     }
4829*cf5a6c84SAndroid Build Coastguard Worker     if (!(pp = wait_job(ll, 0))) {
4830*cf5a6c84SAndroid Build Coastguard Worker       if (toys.signal) toys.exitval = 128+toys.signal;
4831*cf5a6c84SAndroid Build Coastguard Worker       break;
4832*cf5a6c84SAndroid Build Coastguard Worker     }
4833*cf5a6c84SAndroid Build Coastguard Worker     toys.exitval = free_process(pp);
4834*cf5a6c84SAndroid Build Coastguard Worker   }
4835*cf5a6c84SAndroid Build Coastguard Worker }
4836