xref: /inferno-os/appl/tiny/sh.b (revision 37da2899f40661e3e9631e497da8dc59b971cbd0)
1*37da2899SCharles.Forsythimplement Sh;
2*37da2899SCharles.Forsyth
3*37da2899SCharles.Forsythinclude "sys.m";
4*37da2899SCharles.Forsyth	sys: Sys;
5*37da2899SCharles.Forsyth	FD: import Sys;
6*37da2899SCharles.Forsyth
7*37da2899SCharles.Forsythinclude "draw.m";
8*37da2899SCharles.Forsyth	Context: import Draw;
9*37da2899SCharles.Forsyth
10*37da2899SCharles.Forsythinclude "filepat.m";
11*37da2899SCharles.Forsyth	filepat: Filepat;
12*37da2899SCharles.Forsyth	nofilepat := 0;			# true if load Filepat has failed.
13*37da2899SCharles.Forsyth
14*37da2899SCharles.Forsythinclude "bufio.m";
15*37da2899SCharles.Forsyth	bufio: Bufio;
16*37da2899SCharles.Forsyth	Iobuf: import bufio;
17*37da2899SCharles.Forsyth
18*37da2899SCharles.Forsythinclude "env.m";
19*37da2899SCharles.Forsyth	env: Env;
20*37da2899SCharles.Forsyth
21*37da2899SCharles.Forsythstdin: ref FD;
22*37da2899SCharles.Forsythstderr: ref FD;
23*37da2899SCharles.Forsythwaitfd: ref FD;
24*37da2899SCharles.Forsyth
25*37da2899SCharles.ForsythQuoted: con '\uFFF0';
26*37da2899SCharles.ForsythstringQuoted: con "\uFFF0";
27*37da2899SCharles.Forsyth
28*37da2899SCharles.ForsythSh: module
29*37da2899SCharles.Forsyth{
30*37da2899SCharles.Forsyth	init: fn(ctxt: ref Context, argv: list of string);
31*37da2899SCharles.Forsyth};
32*37da2899SCharles.Forsyth
33*37da2899SCharles.ForsythCommand: adt
34*37da2899SCharles.Forsyth{
35*37da2899SCharles.Forsyth	args: list of string;
36*37da2899SCharles.Forsyth	inf, outf: string;
37*37da2899SCharles.Forsyth	append: int;
38*37da2899SCharles.Forsyth};
39*37da2899SCharles.Forsyth
40*37da2899SCharles.ForsythAsync, Seq: con iota;
41*37da2899SCharles.Forsyth
42*37da2899SCharles.ForsythPipeline: adt
43*37da2899SCharles.Forsyth{
44*37da2899SCharles.Forsyth	cmds: list of ref Command;
45*37da2899SCharles.Forsyth	term: int;
46*37da2899SCharles.Forsyth};
47*37da2899SCharles.Forsyth
48*37da2899SCharles.Forsythusage()
49*37da2899SCharles.Forsyth{
50*37da2899SCharles.Forsyth	sys->fprint(stderr, "Usage: sh [-n] [-c cmd] [file]\n");
51*37da2899SCharles.Forsyth}
52*37da2899SCharles.Forsyth
53*37da2899SCharles.Forsythinit(ctxt: ref Context, argv: list of string)
54*37da2899SCharles.Forsyth{
55*37da2899SCharles.Forsyth	n: int;
56*37da2899SCharles.Forsyth	arg: list of string;
57*37da2899SCharles.Forsyth	buf := array[1024] of byte;
58*37da2899SCharles.Forsyth
59*37da2899SCharles.Forsyth	sys = load Sys Sys->PATH;
60*37da2899SCharles.Forsyth	env = load Env Env->PATH;
61*37da2899SCharles.Forsyth
62*37da2899SCharles.Forsyth	stderr = sys->fildes(2);
63*37da2899SCharles.Forsyth
64*37da2899SCharles.Forsyth	waitfd = sys->open("#p/"+string sys->pctl(0, nil)+"/wait", sys->OREAD);
65*37da2899SCharles.Forsyth	if(waitfd == nil){
66*37da2899SCharles.Forsyth		sys->fprint(stderr, "sh: open wait: %r\n");
67*37da2899SCharles.Forsyth		return;
68*37da2899SCharles.Forsyth	}
69*37da2899SCharles.Forsyth
70*37da2899SCharles.Forsyth	eflag := nflag := lflag := 0;
71*37da2899SCharles.Forsyth	cmd: string;
72*37da2899SCharles.Forsyth	if(argv != nil)
73*37da2899SCharles.Forsyth		argv = tl argv;
74*37da2899SCharles.Forsyth	for(; argv != nil && len hd argv && (hd argv)[0]=='-'; argv = tl argv)
75*37da2899SCharles.Forsyth		case hd argv {
76*37da2899SCharles.Forsyth		"-e" =>
77*37da2899SCharles.Forsyth			eflag = 1;
78*37da2899SCharles.Forsyth		"-n" =>
79*37da2899SCharles.Forsyth			nflag = 1;
80*37da2899SCharles.Forsyth		"-l" =>
81*37da2899SCharles.Forsyth			lflag = 1;
82*37da2899SCharles.Forsyth		"-c" =>
83*37da2899SCharles.Forsyth			argv = tl argv;
84*37da2899SCharles.Forsyth			if(len argv != 1){
85*37da2899SCharles.Forsyth				usage();
86*37da2899SCharles.Forsyth				return;
87*37da2899SCharles.Forsyth			}
88*37da2899SCharles.Forsyth			cmd = hd argv;
89*37da2899SCharles.Forsyth		* =>
90*37da2899SCharles.Forsyth			usage();
91*37da2899SCharles.Forsyth			return;
92*37da2899SCharles.Forsyth		}
93*37da2899SCharles.Forsyth
94*37da2899SCharles.Forsyth	if (lflag)
95*37da2899SCharles.Forsyth		startup(ctxt);
96*37da2899SCharles.Forsyth
97*37da2899SCharles.Forsyth	if(eflag == 0)
98*37da2899SCharles.Forsyth		sys->pctl(sys->FORKENV, nil);
99*37da2899SCharles.Forsyth	if(nflag == 0)
100*37da2899SCharles.Forsyth		sys->pctl(sys->FORKNS, nil);
101*37da2899SCharles.Forsyth	if(cmd != nil){
102*37da2899SCharles.Forsyth		arg = tokenize(cmd+"\n");
103*37da2899SCharles.Forsyth		if(arg != nil)
104*37da2899SCharles.Forsyth			runit(ctxt, parseit(arg));
105*37da2899SCharles.Forsyth		return;
106*37da2899SCharles.Forsyth	}
107*37da2899SCharles.Forsyth	if(argv != nil){
108*37da2899SCharles.Forsyth		script(ctxt, hd argv);
109*37da2899SCharles.Forsyth		return;
110*37da2899SCharles.Forsyth	}
111*37da2899SCharles.Forsyth
112*37da2899SCharles.Forsyth	stdin = sys->fildes(0);
113*37da2899SCharles.Forsyth
114*37da2899SCharles.Forsyth	prompt := sysname() + "$ ";
115*37da2899SCharles.Forsyth	for(;;){
116*37da2899SCharles.Forsyth		sys->print("%s", prompt);
117*37da2899SCharles.Forsyth		n = sys->read(stdin, buf, len buf);
118*37da2899SCharles.Forsyth		if(n <= 0)
119*37da2899SCharles.Forsyth			break;
120*37da2899SCharles.Forsyth		arg = tokenize(string buf[0:n]);
121*37da2899SCharles.Forsyth		if(arg != nil)
122*37da2899SCharles.Forsyth			runit(ctxt, parseit(arg));
123*37da2899SCharles.Forsyth	}
124*37da2899SCharles.Forsyth}
125*37da2899SCharles.Forsyth
126*37da2899SCharles.Forsythrev(arg: list of string): list of string
127*37da2899SCharles.Forsyth{
128*37da2899SCharles.Forsyth	ret: list of string;
129*37da2899SCharles.Forsyth
130*37da2899SCharles.Forsyth	while(arg != nil){
131*37da2899SCharles.Forsyth		ret = hd arg :: ret;
132*37da2899SCharles.Forsyth		arg = tl arg;
133*37da2899SCharles.Forsyth	}
134*37da2899SCharles.Forsyth	return ret;
135*37da2899SCharles.Forsyth}
136*37da2899SCharles.Forsyth
137*37da2899SCharles.Forsythwaitfor(pid: int)
138*37da2899SCharles.Forsyth{
139*37da2899SCharles.Forsyth	if(pid <= 0)
140*37da2899SCharles.Forsyth		return;
141*37da2899SCharles.Forsyth	buf := array[sys->WAITLEN] of byte;
142*37da2899SCharles.Forsyth	status := "";
143*37da2899SCharles.Forsyth	for(;;){
144*37da2899SCharles.Forsyth		n := sys->read(waitfd, buf, len buf);
145*37da2899SCharles.Forsyth		if(n < 0){
146*37da2899SCharles.Forsyth			sys->fprint(stderr, "sh: read wait: %r\n");
147*37da2899SCharles.Forsyth			return;
148*37da2899SCharles.Forsyth		}
149*37da2899SCharles.Forsyth		status = string buf[0:n];
150*37da2899SCharles.Forsyth		if(status[len status-1] != ':')
151*37da2899SCharles.Forsyth			sys->fprint(stderr, "%s\n", status);
152*37da2899SCharles.Forsyth		who := int status;
153*37da2899SCharles.Forsyth		if(who != 0){
154*37da2899SCharles.Forsyth			if(who == pid)
155*37da2899SCharles.Forsyth				return;
156*37da2899SCharles.Forsyth		}
157*37da2899SCharles.Forsyth	}
158*37da2899SCharles.Forsyth}
159*37da2899SCharles.Forsyth
160*37da2899SCharles.Forsythmkprog(ctxt: ref Context, arg: list of string, infd, outfd: ref Sys->FD, waitpid: chan of int)
161*37da2899SCharles.Forsyth{
162*37da2899SCharles.Forsyth	fds := list of {0, 1, 2};
163*37da2899SCharles.Forsyth	if(infd != nil)
164*37da2899SCharles.Forsyth		fds = infd.fd :: fds;
165*37da2899SCharles.Forsyth	if(outfd != nil)
166*37da2899SCharles.Forsyth		fds = outfd.fd :: fds;
167*37da2899SCharles.Forsyth	pid := sys->pctl(sys->NEWFD, fds);
168*37da2899SCharles.Forsyth	console := sys->fildes(2);
169*37da2899SCharles.Forsyth
170*37da2899SCharles.Forsyth	if(infd != nil){
171*37da2899SCharles.Forsyth		sys->dup(infd.fd, 0);
172*37da2899SCharles.Forsyth		infd = nil;
173*37da2899SCharles.Forsyth	}
174*37da2899SCharles.Forsyth	if(outfd != nil){
175*37da2899SCharles.Forsyth		sys->dup(outfd.fd, 1);
176*37da2899SCharles.Forsyth		outfd = nil;
177*37da2899SCharles.Forsyth	}
178*37da2899SCharles.Forsyth
179*37da2899SCharles.Forsyth	waitpid <-= pid;
180*37da2899SCharles.Forsyth
181*37da2899SCharles.Forsyth	if(pid < 0 || arg == nil)
182*37da2899SCharles.Forsyth		return;
183*37da2899SCharles.Forsyth
184*37da2899SCharles.Forsyth	{
185*37da2899SCharles.Forsyth		exec(ctxt, arg, console);
186*37da2899SCharles.Forsyth	}exception{
187*37da2899SCharles.Forsyth	"fail:*" =>
188*37da2899SCharles.Forsyth		#sys->fprint(console, "%s:%s\n", hd arg, e.name[5:]);
189*37da2899SCharles.Forsyth		exit;
190*37da2899SCharles.Forsyth	"write on closed pipe" =>
191*37da2899SCharles.Forsyth		#sys->fprint(console, "%s: %s\n", hd arg, e.name);
192*37da2899SCharles.Forsyth		exit;
193*37da2899SCharles.Forsyth	}
194*37da2899SCharles.Forsyth}
195*37da2899SCharles.Forsyth
196*37da2899SCharles.Forsythexec(ctxt: ref Context, args: list of string, console: ref Sys->FD)
197*37da2899SCharles.Forsyth{
198*37da2899SCharles.Forsyth	if (args == nil)
199*37da2899SCharles.Forsyth		return;
200*37da2899SCharles.Forsyth	cmd := hd args;
201*37da2899SCharles.Forsyth	file := cmd;
202*37da2899SCharles.Forsyth
203*37da2899SCharles.Forsyth	if(len file<4 || file[len file-4:]!=".dis")
204*37da2899SCharles.Forsyth		file += ".dis";
205*37da2899SCharles.Forsyth
206*37da2899SCharles.Forsyth	c := load Sh file;
207*37da2899SCharles.Forsyth	if(c == nil) {
208*37da2899SCharles.Forsyth		err := sys->sprint("%r");
209*37da2899SCharles.Forsyth		if(err != "permission denied" && err != "access permission denied" && file[0]!='/' && file[0:2]!="./"){
210*37da2899SCharles.Forsyth			c = load Sh "/dis/"+file;
211*37da2899SCharles.Forsyth			if(c == nil)
212*37da2899SCharles.Forsyth				err = sys->sprint("%r");
213*37da2899SCharles.Forsyth		}
214*37da2899SCharles.Forsyth		if(c == nil){
215*37da2899SCharles.Forsyth			sys->fprint(console, "%s: %s\n", cmd, err);
216*37da2899SCharles.Forsyth			return;
217*37da2899SCharles.Forsyth		}
218*37da2899SCharles.Forsyth	}
219*37da2899SCharles.Forsyth
220*37da2899SCharles.Forsyth	c->init(ctxt, args);
221*37da2899SCharles.Forsyth}
222*37da2899SCharles.Forsyth
223*37da2899SCharles.Forsythscript(ctxt: ref Context, src: string)
224*37da2899SCharles.Forsyth{
225*37da2899SCharles.Forsyth	bufio = load Bufio Bufio->PATH;
226*37da2899SCharles.Forsyth	if(bufio == nil){
227*37da2899SCharles.Forsyth		sys->fprint(stderr, "sh: load bufio: %r\n");
228*37da2899SCharles.Forsyth		return;
229*37da2899SCharles.Forsyth	}
230*37da2899SCharles.Forsyth
231*37da2899SCharles.Forsyth	f := bufio->open(src, Bufio->OREAD);
232*37da2899SCharles.Forsyth	if(f == nil){
233*37da2899SCharles.Forsyth		sys->fprint(stderr, "sh: open %s: %r\n", src);
234*37da2899SCharles.Forsyth		return;
235*37da2899SCharles.Forsyth	}
236*37da2899SCharles.Forsyth	for(;;){
237*37da2899SCharles.Forsyth		s := f.gets('\n');
238*37da2899SCharles.Forsyth		if(s == nil)
239*37da2899SCharles.Forsyth			break;
240*37da2899SCharles.Forsyth		arg := tokenize(s);
241*37da2899SCharles.Forsyth		if(arg != nil)
242*37da2899SCharles.Forsyth			runit(ctxt, parseit(arg));
243*37da2899SCharles.Forsyth	}
244*37da2899SCharles.Forsyth}
245*37da2899SCharles.Forsyth
246*37da2899SCharles.Forsythsysname(): string
247*37da2899SCharles.Forsyth{
248*37da2899SCharles.Forsyth	fd := sys->open("#c/sysname", sys->OREAD);
249*37da2899SCharles.Forsyth	if(fd == nil)
250*37da2899SCharles.Forsyth		return "anon";
251*37da2899SCharles.Forsyth	buf := array[128] of byte;
252*37da2899SCharles.Forsyth	n := sys->read(fd, buf, len buf);
253*37da2899SCharles.Forsyth	if(n < 0)
254*37da2899SCharles.Forsyth		return "anon";
255*37da2899SCharles.Forsyth	return string buf[0:n];
256*37da2899SCharles.Forsyth}
257*37da2899SCharles.Forsyth
258*37da2899SCharles.Forsyth# Lexer.
259*37da2899SCharles.Forsyth
260*37da2899SCharles.Forsythtokenize(s: string): list of string
261*37da2899SCharles.Forsyth{
262*37da2899SCharles.Forsyth	tok: list of string;
263*37da2899SCharles.Forsyth	token := "";
264*37da2899SCharles.Forsyth	instring := 0;
265*37da2899SCharles.Forsyth
266*37da2899SCharles.Forsythloop:
267*37da2899SCharles.Forsyth	for(i:=0; i<len s; i++) {
268*37da2899SCharles.Forsyth		if(instring) {
269*37da2899SCharles.Forsyth			if(s[i] != '\'')
270*37da2899SCharles.Forsyth				token = addchar(token, s[i]);
271*37da2899SCharles.Forsyth			else if(i == len s-1 || s[i+1] != '\'') {
272*37da2899SCharles.Forsyth				if(i == len s-1 || s[i+1] == ' ' || s[i+1] == '\t' || s[i+1] == '\n'){
273*37da2899SCharles.Forsyth					tok = token :: tok;
274*37da2899SCharles.Forsyth					token = "";
275*37da2899SCharles.Forsyth				}
276*37da2899SCharles.Forsyth				instring = 0;
277*37da2899SCharles.Forsyth			} else {
278*37da2899SCharles.Forsyth				token[len token] = '\'';
279*37da2899SCharles.Forsyth				i++;
280*37da2899SCharles.Forsyth			}
281*37da2899SCharles.Forsyth			continue;
282*37da2899SCharles.Forsyth		}
283*37da2899SCharles.Forsyth		case s[i] {
284*37da2899SCharles.Forsyth		' ' or '\t' or '\n' or '#' or
285*37da2899SCharles.Forsyth		'\'' or '|' or '&' or ';' or
286*37da2899SCharles.Forsyth		'>' or '<' or '\r' =>
287*37da2899SCharles.Forsyth			if(token != "" && s[i]!='\''){
288*37da2899SCharles.Forsyth				tok = token :: tok;
289*37da2899SCharles.Forsyth				token = "";
290*37da2899SCharles.Forsyth			}
291*37da2899SCharles.Forsyth			case s[i] {
292*37da2899SCharles.Forsyth			'#' =>
293*37da2899SCharles.Forsyth				break loop;
294*37da2899SCharles.Forsyth			'\'' =>
295*37da2899SCharles.Forsyth				instring = 1;
296*37da2899SCharles.Forsyth			'>' =>
297*37da2899SCharles.Forsyth				ss := "";
298*37da2899SCharles.Forsyth				ss[0] = s[i];
299*37da2899SCharles.Forsyth				if(i<len s-1 && s[i+1]==s[i])
300*37da2899SCharles.Forsyth					ss[1] = s[i++];
301*37da2899SCharles.Forsyth				tok = ss :: tok;
302*37da2899SCharles.Forsyth			'|' or '&' or ';' or '<' =>
303*37da2899SCharles.Forsyth				ss := "";
304*37da2899SCharles.Forsyth				ss[0] = s[i];
305*37da2899SCharles.Forsyth				tok = ss :: tok;
306*37da2899SCharles.Forsyth			}
307*37da2899SCharles.Forsyth		* =>
308*37da2899SCharles.Forsyth			token[len token] = s[i];
309*37da2899SCharles.Forsyth		}
310*37da2899SCharles.Forsyth	}
311*37da2899SCharles.Forsyth	if(instring){
312*37da2899SCharles.Forsyth		sys->fprint(stderr, "sh: unmatched quote\n");
313*37da2899SCharles.Forsyth		return nil;
314*37da2899SCharles.Forsyth	}
315*37da2899SCharles.Forsyth	return rev(tok);
316*37da2899SCharles.Forsyth}
317*37da2899SCharles.Forsyth
318*37da2899SCharles.Forsythismeta(char: int): int
319*37da2899SCharles.Forsyth{
320*37da2899SCharles.Forsyth	case char {
321*37da2899SCharles.Forsyth	'*'  or '[' or '?' or
322*37da2899SCharles.Forsyth	'#'  or '\'' or '|' or
323*37da2899SCharles.Forsyth	'&' or ';' or '>' or
324*37da2899SCharles.Forsyth	'<'  =>
325*37da2899SCharles.Forsyth		return 1;
326*37da2899SCharles.Forsyth	}
327*37da2899SCharles.Forsyth	return 0;
328*37da2899SCharles.Forsyth}
329*37da2899SCharles.Forsyth
330*37da2899SCharles.Forsythaddchar(token: string, char: int): string
331*37da2899SCharles.Forsyth{
332*37da2899SCharles.Forsyth	if(ismeta(char) && (len token==0 || token[0]!=Quoted))
333*37da2899SCharles.Forsyth		token = stringQuoted + token;
334*37da2899SCharles.Forsyth	token[len token] = char;
335*37da2899SCharles.Forsyth	return token;
336*37da2899SCharles.Forsyth}
337*37da2899SCharles.Forsyth
338*37da2899SCharles.Forsyth# Parser.
339*37da2899SCharles.Forsyth
340*37da2899SCharles.Forsythgetcommand(words: list of string): (ref Command, list of string)
341*37da2899SCharles.Forsyth{
342*37da2899SCharles.Forsyth	args: list of string;
343*37da2899SCharles.Forsyth	word: string;
344*37da2899SCharles.Forsyth	si, so: string;
345*37da2899SCharles.Forsyth	append := 0;
346*37da2899SCharles.Forsyth
347*37da2899SCharles.Forsythgather:
348*37da2899SCharles.Forsyth	do {
349*37da2899SCharles.Forsyth		word = hd words;
350*37da2899SCharles.Forsyth
351*37da2899SCharles.Forsyth		case word {
352*37da2899SCharles.Forsyth		">" or ">>" =>
353*37da2899SCharles.Forsyth			if(so != nil)
354*37da2899SCharles.Forsyth				return (nil, nil);
355*37da2899SCharles.Forsyth
356*37da2899SCharles.Forsyth			words = tl words;
357*37da2899SCharles.Forsyth
358*37da2899SCharles.Forsyth			if(words == nil)
359*37da2899SCharles.Forsyth				return (nil, nil);
360*37da2899SCharles.Forsyth
361*37da2899SCharles.Forsyth			so = hd words;
362*37da2899SCharles.Forsyth			if(len so>0 && so[0]==Quoted)
363*37da2899SCharles.Forsyth				so = so[1:];
364*37da2899SCharles.Forsyth			if(word == ">>")
365*37da2899SCharles.Forsyth				append = 1;
366*37da2899SCharles.Forsyth		"<" =>
367*37da2899SCharles.Forsyth			if(si != nil)
368*37da2899SCharles.Forsyth				return (nil, nil);
369*37da2899SCharles.Forsyth
370*37da2899SCharles.Forsyth			words = tl words;
371*37da2899SCharles.Forsyth
372*37da2899SCharles.Forsyth			if(words == nil)
373*37da2899SCharles.Forsyth				return (nil, nil);
374*37da2899SCharles.Forsyth
375*37da2899SCharles.Forsyth			si = hd words;
376*37da2899SCharles.Forsyth			if(len si>0 && si[0]==Quoted)
377*37da2899SCharles.Forsyth				si = si[1:];
378*37da2899SCharles.Forsyth		"|" or ";" or "&" =>
379*37da2899SCharles.Forsyth			break gather;
380*37da2899SCharles.Forsyth		* =>
381*37da2899SCharles.Forsyth			files := doexpand(word);
382*37da2899SCharles.Forsyth			while(files != nil){
383*37da2899SCharles.Forsyth				args = hd files :: args;
384*37da2899SCharles.Forsyth				files = tl files;
385*37da2899SCharles.Forsyth			}
386*37da2899SCharles.Forsyth		}
387*37da2899SCharles.Forsyth
388*37da2899SCharles.Forsyth		words = tl words;
389*37da2899SCharles.Forsyth	} while (words != nil);
390*37da2899SCharles.Forsyth
391*37da2899SCharles.Forsyth	return (ref Command(rev(args), si, so, append), words);
392*37da2899SCharles.Forsyth}
393*37da2899SCharles.Forsyth
394*37da2899SCharles.Forsythdoexpand(file: string): list of string
395*37da2899SCharles.Forsyth{
396*37da2899SCharles.Forsyth	if(file == nil)
397*37da2899SCharles.Forsyth		return file :: nil;
398*37da2899SCharles.Forsyth	if(len file>0 && file[0]==Quoted)
399*37da2899SCharles.Forsyth		return file[1:] :: nil;
400*37da2899SCharles.Forsyth	if (nofilepat)
401*37da2899SCharles.Forsyth		return file :: nil;
402*37da2899SCharles.Forsyth	for(i:=0; i<len file; i++)
403*37da2899SCharles.Forsyth		if(file[i]=='*' || file[i]=='[' || file[i]=='?'){
404*37da2899SCharles.Forsyth			if(filepat == nil) {
405*37da2899SCharles.Forsyth				if ((filepat = load Filepat Filepat->PATH) == nil) {
406*37da2899SCharles.Forsyth					sys->fprint(stderr, "sh: warning: cannot load %s: %r\n",
407*37da2899SCharles.Forsyth							Filepat->PATH);
408*37da2899SCharles.Forsyth					nofilepat = 1;
409*37da2899SCharles.Forsyth					return file :: nil;
410*37da2899SCharles.Forsyth				}
411*37da2899SCharles.Forsyth			}
412*37da2899SCharles.Forsyth			files := filepat->expand(file);
413*37da2899SCharles.Forsyth			if(files != nil)
414*37da2899SCharles.Forsyth				return files;
415*37da2899SCharles.Forsyth			break;
416*37da2899SCharles.Forsyth		}
417*37da2899SCharles.Forsyth	return file :: nil;
418*37da2899SCharles.Forsyth}
419*37da2899SCharles.Forsyth
420*37da2899SCharles.Forsythrevc(arg: list of ref Command): list of ref Command
421*37da2899SCharles.Forsyth{
422*37da2899SCharles.Forsyth	ret: list of ref Command;
423*37da2899SCharles.Forsyth	while(arg != nil) {
424*37da2899SCharles.Forsyth		ret = hd arg :: ret;
425*37da2899SCharles.Forsyth		arg = tl arg;
426*37da2899SCharles.Forsyth	}
427*37da2899SCharles.Forsyth	return ret;
428*37da2899SCharles.Forsyth}
429*37da2899SCharles.Forsyth
430*37da2899SCharles.Forsythgetpipe(words: list of string): (ref Pipeline, list of string)
431*37da2899SCharles.Forsyth{
432*37da2899SCharles.Forsyth	cmds: list of ref Command;
433*37da2899SCharles.Forsyth	cur: ref Command;
434*37da2899SCharles.Forsyth	word: string;
435*37da2899SCharles.Forsyth
436*37da2899SCharles.Forsyth	term := Seq;
437*37da2899SCharles.Forsythgather:
438*37da2899SCharles.Forsyth	while(words != nil) {
439*37da2899SCharles.Forsyth		word = hd words;
440*37da2899SCharles.Forsyth
441*37da2899SCharles.Forsyth		if(word == "|")
442*37da2899SCharles.Forsyth			return (nil, nil);
443*37da2899SCharles.Forsyth
444*37da2899SCharles.Forsyth		(cur, words) = getcommand(words);
445*37da2899SCharles.Forsyth
446*37da2899SCharles.Forsyth		if(cur == nil)
447*37da2899SCharles.Forsyth			return (nil, nil);
448*37da2899SCharles.Forsyth
449*37da2899SCharles.Forsyth		cmds = cur :: cmds;
450*37da2899SCharles.Forsyth
451*37da2899SCharles.Forsyth		if(words == nil)
452*37da2899SCharles.Forsyth			break gather;
453*37da2899SCharles.Forsyth
454*37da2899SCharles.Forsyth		word = hd words;
455*37da2899SCharles.Forsyth		words = tl words;
456*37da2899SCharles.Forsyth
457*37da2899SCharles.Forsyth		case word {
458*37da2899SCharles.Forsyth		";" =>
459*37da2899SCharles.Forsyth			break gather;
460*37da2899SCharles.Forsyth		"&" =>
461*37da2899SCharles.Forsyth			term = Async;
462*37da2899SCharles.Forsyth			break gather;
463*37da2899SCharles.Forsyth		"|" =>
464*37da2899SCharles.Forsyth			continue gather;
465*37da2899SCharles.Forsyth		}
466*37da2899SCharles.Forsyth		return (nil, nil);
467*37da2899SCharles.Forsyth	}
468*37da2899SCharles.Forsyth
469*37da2899SCharles.Forsyth	if(word == "|")
470*37da2899SCharles.Forsyth		return (nil, nil);
471*37da2899SCharles.Forsyth
472*37da2899SCharles.Forsyth	return (ref Pipeline(revc(cmds), term), words);
473*37da2899SCharles.Forsyth}
474*37da2899SCharles.Forsyth
475*37da2899SCharles.Forsythrevp(arg: list of ref Pipeline): list of ref Pipeline
476*37da2899SCharles.Forsyth{
477*37da2899SCharles.Forsyth	ret: list of ref Pipeline;
478*37da2899SCharles.Forsyth
479*37da2899SCharles.Forsyth	while(arg != nil) {
480*37da2899SCharles.Forsyth		ret = hd arg :: ret;
481*37da2899SCharles.Forsyth		arg = tl arg;
482*37da2899SCharles.Forsyth	}
483*37da2899SCharles.Forsyth	return ret;
484*37da2899SCharles.Forsyth}
485*37da2899SCharles.Forsyth
486*37da2899SCharles.Forsythparseit(words: list of string): list of ref Pipeline
487*37da2899SCharles.Forsyth{
488*37da2899SCharles.Forsyth	ret: list of ref Pipeline;
489*37da2899SCharles.Forsyth	cur: ref Pipeline;
490*37da2899SCharles.Forsyth
491*37da2899SCharles.Forsyth	while(words != nil) {
492*37da2899SCharles.Forsyth		(cur, words) = getpipe(words);
493*37da2899SCharles.Forsyth		if(cur == nil){
494*37da2899SCharles.Forsyth			sys->fprint(stderr, "sh: syntax error\n");
495*37da2899SCharles.Forsyth			return nil;
496*37da2899SCharles.Forsyth		}
497*37da2899SCharles.Forsyth		ret = cur :: ret;
498*37da2899SCharles.Forsyth	}
499*37da2899SCharles.Forsyth	return revp(ret);
500*37da2899SCharles.Forsyth}
501*37da2899SCharles.Forsyth
502*37da2899SCharles.Forsyth# Runner.
503*37da2899SCharles.Forsyth
504*37da2899SCharles.Forsythrunpipeline(ctx: ref Context, pipeline: ref Pipeline)
505*37da2899SCharles.Forsyth{
506*37da2899SCharles.Forsyth	if(pipeline.term == Async)
507*37da2899SCharles.Forsyth		sys->pctl(sys->NEWPGRP, nil);
508*37da2899SCharles.Forsyth	pid := startpipeline(ctx, pipeline);
509*37da2899SCharles.Forsyth	if(pid < 0)
510*37da2899SCharles.Forsyth		return;
511*37da2899SCharles.Forsyth	if(pipeline.term == Seq)
512*37da2899SCharles.Forsyth		waitfor(pid);
513*37da2899SCharles.Forsyth}
514*37da2899SCharles.Forsyth
515*37da2899SCharles.Forsythstartpipeline(ctx: ref Context, pipeline: ref Pipeline): int
516*37da2899SCharles.Forsyth{
517*37da2899SCharles.Forsyth	pid := 0;
518*37da2899SCharles.Forsyth	cmds := pipeline.cmds;
519*37da2899SCharles.Forsyth	first := 1;
520*37da2899SCharles.Forsyth	inpipe, outpipe: ref Sys->FD;
521*37da2899SCharles.Forsyth	while(cmds != nil) {
522*37da2899SCharles.Forsyth		last := tl cmds == nil;
523*37da2899SCharles.Forsyth		cmd := hd cmds;
524*37da2899SCharles.Forsyth
525*37da2899SCharles.Forsyth		infd: ref Sys->FD;
526*37da2899SCharles.Forsyth		if(!first)
527*37da2899SCharles.Forsyth			infd = inpipe;
528*37da2899SCharles.Forsyth		else if(cmd.inf != nil){
529*37da2899SCharles.Forsyth			infd = sys->open(cmd.inf, Sys->OREAD);
530*37da2899SCharles.Forsyth			if(infd == nil){
531*37da2899SCharles.Forsyth				sys->fprint(stderr, "sh: can't open %s: %r\n", cmd.inf);
532*37da2899SCharles.Forsyth				return -1;
533*37da2899SCharles.Forsyth			}
534*37da2899SCharles.Forsyth		}
535*37da2899SCharles.Forsyth
536*37da2899SCharles.Forsyth		outfd: ref Sys->FD;
537*37da2899SCharles.Forsyth		if(!last){
538*37da2899SCharles.Forsyth			fds := array[2] of ref Sys->FD;
539*37da2899SCharles.Forsyth			if(sys->pipe(fds) < 0){
540*37da2899SCharles.Forsyth				sys->fprint(stderr, "sh: can't make pipe: %r\n");
541*37da2899SCharles.Forsyth				return -1;
542*37da2899SCharles.Forsyth			}
543*37da2899SCharles.Forsyth			outpipe = fds[0];
544*37da2899SCharles.Forsyth			outfd = fds[1];
545*37da2899SCharles.Forsyth			fds = nil;
546*37da2899SCharles.Forsyth		}else if(cmd.outf != nil){
547*37da2899SCharles.Forsyth			if(cmd.append){
548*37da2899SCharles.Forsyth				outfd = sys->open(cmd.outf, Sys->OWRITE);
549*37da2899SCharles.Forsyth				if(outfd != nil)
550*37da2899SCharles.Forsyth					sys->seek(outfd, big 0, Sys->SEEKEND);
551*37da2899SCharles.Forsyth			}
552*37da2899SCharles.Forsyth			if(outfd == nil)
553*37da2899SCharles.Forsyth				outfd = sys->create(cmd.outf, Sys->OWRITE, 8r666);
554*37da2899SCharles.Forsyth			if(outfd == nil){
555*37da2899SCharles.Forsyth				sys->fprint(stderr, "sh: can't open %s: %r\n", cmd.outf);
556*37da2899SCharles.Forsyth				return -1;
557*37da2899SCharles.Forsyth			}
558*37da2899SCharles.Forsyth		}
559*37da2899SCharles.Forsyth
560*37da2899SCharles.Forsyth		rpid := chan of int;
561*37da2899SCharles.Forsyth		spawn mkprog(ctx, cmd.args, infd, outfd, rpid);
562*37da2899SCharles.Forsyth		pid = <-rpid;
563*37da2899SCharles.Forsyth		infd = nil;
564*37da2899SCharles.Forsyth		outfd = nil;
565*37da2899SCharles.Forsyth
566*37da2899SCharles.Forsyth		inpipe = outpipe;
567*37da2899SCharles.Forsyth		outpipe = nil;
568*37da2899SCharles.Forsyth
569*37da2899SCharles.Forsyth		first = 0;
570*37da2899SCharles.Forsyth		cmds = tl cmds;
571*37da2899SCharles.Forsyth	}
572*37da2899SCharles.Forsyth	return pid;
573*37da2899SCharles.Forsyth}
574*37da2899SCharles.Forsyth
575*37da2899SCharles.Forsythrunit(ctx: ref Context, pipes: list of ref Pipeline)
576*37da2899SCharles.Forsyth{
577*37da2899SCharles.Forsyth	while(pipes != nil) {
578*37da2899SCharles.Forsyth		pipeline := hd pipes;
579*37da2899SCharles.Forsyth		pipes = tl pipes;
580*37da2899SCharles.Forsyth		if(pipeline.term == Seq)
581*37da2899SCharles.Forsyth			runpipeline(ctx, pipeline);
582*37da2899SCharles.Forsyth		else
583*37da2899SCharles.Forsyth			spawn runpipeline(ctx, pipeline);
584*37da2899SCharles.Forsyth	}
585*37da2899SCharles.Forsyth}
586*37da2899SCharles.Forsyth
587*37da2899SCharles.Forsythstrchr(s: string, c: int): int
588*37da2899SCharles.Forsyth{
589*37da2899SCharles.Forsyth	ln := len s;
590*37da2899SCharles.Forsyth	for (i := 0; i < ln; i++)
591*37da2899SCharles.Forsyth		if (s[i] == c)
592*37da2899SCharles.Forsyth			return i;
593*37da2899SCharles.Forsyth	return -1;
594*37da2899SCharles.Forsyth}
595*37da2899SCharles.Forsyth
596*37da2899SCharles.Forsyth# PROFILE: con "/lib/profile";
597*37da2899SCharles.ForsythPROFILE: con "/lib/infernoinit";
598*37da2899SCharles.Forsyth
599*37da2899SCharles.Forsythstartup(ctxt: ref Context)
600*37da2899SCharles.Forsyth{
601*37da2899SCharles.Forsyth	if (env == nil)
602*37da2899SCharles.Forsyth		return;
603*37da2899SCharles.Forsyth	# if (env->getenv("home") != nil)
604*37da2899SCharles.Forsyth	#	return;
605*37da2899SCharles.Forsyth	home := gethome();
606*37da2899SCharles.Forsyth	env->setenv("home", home);
607*37da2899SCharles.Forsyth	escript(ctxt, PROFILE);
608*37da2899SCharles.Forsyth	escript(ctxt, home + PROFILE);
609*37da2899SCharles.Forsyth}
610*37da2899SCharles.Forsyth
611*37da2899SCharles.Forsythescript(ctxt: ref Context, file: string)
612*37da2899SCharles.Forsyth{
613*37da2899SCharles.Forsyth	fd := sys->open(file, Sys->OREAD);
614*37da2899SCharles.Forsyth	if (fd != nil)
615*37da2899SCharles.Forsyth		script(ctxt, file);
616*37da2899SCharles.Forsyth}
617*37da2899SCharles.Forsyth
618*37da2899SCharles.Forsythgethome(): string
619*37da2899SCharles.Forsyth{
620*37da2899SCharles.Forsyth	fd := sys->open("/dev/user", sys->OREAD);
621*37da2899SCharles.Forsyth  	if(fd == nil)
622*37da2899SCharles.Forsyth    		return "/";
623*37da2899SCharles.Forsyth  	buf := array[128] of byte;
624*37da2899SCharles.Forsyth  	n := sys->read(fd, buf, len buf);
625*37da2899SCharles.Forsyth  	if(n < 0)
626*37da2899SCharles.Forsyth    		return "/";
627*37da2899SCharles.Forsyth  	return "/usr/" + string buf[0:n];
628*37da2899SCharles.Forsyth}
629