xref: /plan9/sys/src/cmd/rc/exec.c (revision fed0fa9e146ce97377041b76bdecad7bcff8a240)
13e12c5d1SDavid du Colombier #include "rc.h"
23e12c5d1SDavid du Colombier #include "getflags.h"
33e12c5d1SDavid du Colombier #include "exec.h"
43e12c5d1SDavid du Colombier #include "io.h"
53e12c5d1SDavid du Colombier #include "fns.h"
63e12c5d1SDavid du Colombier /*
73e12c5d1SDavid du Colombier  * Start executing the given code at the given pc with the given redirection
83e12c5d1SDavid du Colombier  */
99a747e4fSDavid du Colombier char *argv0="rc";
10dc5a79c1SDavid du Colombier 
11dc5a79c1SDavid du Colombier void
12dc5a79c1SDavid du Colombier start(code *c, int pc, var *local)
133e12c5d1SDavid du Colombier {
143e12c5d1SDavid du Colombier 	struct thread *p = new(struct thread);
15dc5a79c1SDavid du Colombier 
163e12c5d1SDavid du Colombier 	p->code = codecopy(c);
173e12c5d1SDavid du Colombier 	p->pc = pc;
183e12c5d1SDavid du Colombier 	p->argv = 0;
193e12c5d1SDavid du Colombier 	p->redir = p->startredir = runq?runq->redir:0;
203e12c5d1SDavid du Colombier 	p->local = local;
213e12c5d1SDavid du Colombier 	p->cmdfile = 0;
223e12c5d1SDavid du Colombier 	p->cmdfd = 0;
233e12c5d1SDavid du Colombier 	p->eof = 0;
243e12c5d1SDavid du Colombier 	p->iflag = 0;
253e12c5d1SDavid du Colombier 	p->lineno = 1;
263e12c5d1SDavid du Colombier 	p->ret = runq;
273e12c5d1SDavid du Colombier 	runq = p;
283e12c5d1SDavid du Colombier }
29dc5a79c1SDavid du Colombier 
30dc5a79c1SDavid du Colombier word*
31dc5a79c1SDavid du Colombier newword(char *wd, word *next)
323e12c5d1SDavid du Colombier {
333e12c5d1SDavid du Colombier 	word *p = new(word);
343e12c5d1SDavid du Colombier 	p->word = strdup(wd);
353e12c5d1SDavid du Colombier 	p->next = next;
363e12c5d1SDavid du Colombier 	return p;
373e12c5d1SDavid du Colombier }
38dc5a79c1SDavid du Colombier 
39dc5a79c1SDavid du Colombier void
40dc5a79c1SDavid du Colombier pushword(char *wd)
413e12c5d1SDavid du Colombier {
42dc5a79c1SDavid du Colombier 	if(runq->argv==0)
43dc5a79c1SDavid du Colombier 		panic("pushword but no argv!", 0);
443e12c5d1SDavid du Colombier 	runq->argv->words = newword(wd, runq->argv->words);
453e12c5d1SDavid du Colombier }
46dc5a79c1SDavid du Colombier 
47dc5a79c1SDavid du Colombier void
48dc5a79c1SDavid du Colombier popword(void)
49dc5a79c1SDavid du Colombier {
503e12c5d1SDavid du Colombier 	word *p;
51dc5a79c1SDavid du Colombier 	if(runq->argv==0)
52dc5a79c1SDavid du Colombier 		panic("popword but no argv!", 0);
533e12c5d1SDavid du Colombier 	p = runq->argv->words;
54dc5a79c1SDavid du Colombier 	if(p==0)
55dc5a79c1SDavid du Colombier 		panic("popword but no word!", 0);
563e12c5d1SDavid du Colombier 	runq->argv->words = p->next;
573e12c5d1SDavid du Colombier 	efree(p->word);
583e12c5d1SDavid du Colombier 	efree((char *)p);
593e12c5d1SDavid du Colombier }
60dc5a79c1SDavid du Colombier 
61dc5a79c1SDavid du Colombier void
62dc5a79c1SDavid du Colombier freelist(word *w)
633e12c5d1SDavid du Colombier {
643e12c5d1SDavid du Colombier 	word *nw;
653e12c5d1SDavid du Colombier 	while(w){
663e12c5d1SDavid du Colombier 		nw = w->next;
673e12c5d1SDavid du Colombier 		efree(w->word);
683e12c5d1SDavid du Colombier 		efree((char *)w);
693e12c5d1SDavid du Colombier 		w = nw;
703e12c5d1SDavid du Colombier 	}
713e12c5d1SDavid du Colombier }
72dc5a79c1SDavid du Colombier 
73dc5a79c1SDavid du Colombier void
74dc5a79c1SDavid du Colombier pushlist(void)
75dc5a79c1SDavid du Colombier {
763e12c5d1SDavid du Colombier 	list *p = new(list);
773e12c5d1SDavid du Colombier 	p->next = runq->argv;
783e12c5d1SDavid du Colombier 	p->words = 0;
793e12c5d1SDavid du Colombier 	runq->argv = p;
803e12c5d1SDavid du Colombier }
81dc5a79c1SDavid du Colombier 
82dc5a79c1SDavid du Colombier void
83dc5a79c1SDavid du Colombier poplist(void)
84dc5a79c1SDavid du Colombier {
853e12c5d1SDavid du Colombier 	list *p = runq->argv;
86dc5a79c1SDavid du Colombier 	if(p==0)
87dc5a79c1SDavid du Colombier 		panic("poplist but no argv", 0);
883e12c5d1SDavid du Colombier 	freelist(p->words);
893e12c5d1SDavid du Colombier 	runq->argv = p->next;
903e12c5d1SDavid du Colombier 	efree((char *)p);
913e12c5d1SDavid du Colombier }
92dc5a79c1SDavid du Colombier 
93dc5a79c1SDavid du Colombier int
94dc5a79c1SDavid du Colombier count(word *w)
953e12c5d1SDavid du Colombier {
963e12c5d1SDavid du Colombier 	int n;
973e12c5d1SDavid du Colombier 	for(n = 0;w;n++) w = w->next;
983e12c5d1SDavid du Colombier 	return n;
993e12c5d1SDavid du Colombier }
100dc5a79c1SDavid du Colombier 
101dc5a79c1SDavid du Colombier void
102dc5a79c1SDavid du Colombier pushredir(int type, int from, int to)
103dc5a79c1SDavid du Colombier {
1043e12c5d1SDavid du Colombier 	redir * rp = new(redir);
1053e12c5d1SDavid du Colombier 	rp->type = type;
1063e12c5d1SDavid du Colombier 	rp->from = from;
1073e12c5d1SDavid du Colombier 	rp->to = to;
1083e12c5d1SDavid du Colombier 	rp->next = runq->redir;
1093e12c5d1SDavid du Colombier 	runq->redir = rp;
1103e12c5d1SDavid du Colombier }
111dc5a79c1SDavid du Colombier 
112dc5a79c1SDavid du Colombier var*
113dc5a79c1SDavid du Colombier newvar(char *name, var *next)
1143e12c5d1SDavid du Colombier {
1153e12c5d1SDavid du Colombier 	var *v = new(var);
1163e12c5d1SDavid du Colombier 	v->name = name;
1173e12c5d1SDavid du Colombier 	v->val = 0;
1183e12c5d1SDavid du Colombier 	v->fn = 0;
1193e12c5d1SDavid du Colombier 	v->changed = 0;
1203e12c5d1SDavid du Colombier 	v->fnchanged = 0;
1213e12c5d1SDavid du Colombier 	v->next = next;
1223e12c5d1SDavid du Colombier 	return v;
1233e12c5d1SDavid du Colombier }
1243e12c5d1SDavid du Colombier /*
1253e12c5d1SDavid du Colombier  * get command line flags, initialize keywords & traps.
1263e12c5d1SDavid du Colombier  * get values from environment.
1273e12c5d1SDavid du Colombier  * set $pid, $cflag, $*
1283e12c5d1SDavid du Colombier  * fabricate bootstrap code and start it (*=(argv);. /usr/lib/rcmain $*)
1293e12c5d1SDavid du Colombier  * start interpreting code
1303e12c5d1SDavid du Colombier  */
131dc5a79c1SDavid du Colombier 
132dc5a79c1SDavid du Colombier void
133dc5a79c1SDavid du Colombier main(int argc, char *argv[])
1343e12c5d1SDavid du Colombier {
1353e12c5d1SDavid du Colombier 	code bootstrap[17];
1369a747e4fSDavid du Colombier 	char num[12], *rcmain;
1373e12c5d1SDavid du Colombier 	int i;
138dc5a79c1SDavid du Colombier 	argc = getflags(argc, argv, "SsrdiIlxepvVc:1m:1[command]", 1);
139dc5a79c1SDavid du Colombier 	if(argc==-1)
140dc5a79c1SDavid du Colombier 		usage("[file [arg ...]]");
141dc5a79c1SDavid du Colombier 	if(argv[0][0]=='-')
142dc5a79c1SDavid du Colombier 		flag['l'] = flagset;
143dc5a79c1SDavid du Colombier 	if(flag['I'])
144dc5a79c1SDavid du Colombier 		flag['i'] = 0;
1457dd7cddfSDavid du Colombier 	else if(flag['i']==0 && argc==1 && Isatty(0)) flag['i'] = flagset;
1469a747e4fSDavid du Colombier 	rcmain = flag['m']?flag['m'][0]:Rcmain;
1473e12c5d1SDavid du Colombier 	err = openfd(2);
1483e12c5d1SDavid du Colombier 	kinit();
1493e12c5d1SDavid du Colombier 	Trapinit();
1503e12c5d1SDavid du Colombier 	Vinit();
151dc5a79c1SDavid du Colombier 	inttoascii(num, mypid = getpid());
1523e12c5d1SDavid du Colombier 	setvar("pid", newword(num, (word *)0));
1533e12c5d1SDavid du Colombier 	setvar("cflag", flag['c']?newword(flag['c'][0], (word *)0)
1543e12c5d1SDavid du Colombier 				:(word *)0);
155219b2ee8SDavid du Colombier 	setvar("rcname", newword(argv[0], (word *)0));
1563e12c5d1SDavid du Colombier 	i = 0;
1573e12c5d1SDavid du Colombier 	bootstrap[i++].i = 1;
1583e12c5d1SDavid du Colombier 	bootstrap[i++].f = Xmark;
1593e12c5d1SDavid du Colombier 	bootstrap[i++].f = Xword;
1603e12c5d1SDavid du Colombier 	bootstrap[i++].s="*";
1613e12c5d1SDavid du Colombier 	bootstrap[i++].f = Xassign;
1623e12c5d1SDavid du Colombier 	bootstrap[i++].f = Xmark;
1633e12c5d1SDavid du Colombier 	bootstrap[i++].f = Xmark;
1643e12c5d1SDavid du Colombier 	bootstrap[i++].f = Xword;
1653e12c5d1SDavid du Colombier 	bootstrap[i++].s="*";
1663e12c5d1SDavid du Colombier 	bootstrap[i++].f = Xdol;
1673e12c5d1SDavid du Colombier 	bootstrap[i++].f = Xword;
1689a747e4fSDavid du Colombier 	bootstrap[i++].s = rcmain;
1693e12c5d1SDavid du Colombier 	bootstrap[i++].f = Xword;
1703e12c5d1SDavid du Colombier 	bootstrap[i++].s=".";
1713e12c5d1SDavid du Colombier 	bootstrap[i++].f = Xsimple;
1723e12c5d1SDavid du Colombier 	bootstrap[i++].f = Xexit;
1733e12c5d1SDavid du Colombier 	bootstrap[i].i = 0;
1743e12c5d1SDavid du Colombier 	start(bootstrap, 1, (var *)0);
1753e12c5d1SDavid du Colombier 	/* prime bootstrap argv */
1763e12c5d1SDavid du Colombier 	pushlist();
1779a747e4fSDavid du Colombier 	argv0 = strdup(argv[0]);
1783e12c5d1SDavid du Colombier 	for(i = argc-1;i!=0;--i) pushword(argv[i]);
1793e12c5d1SDavid du Colombier 	for(;;){
180dc5a79c1SDavid du Colombier 		if(flag['r'])
181dc5a79c1SDavid du Colombier 			pfnc(err, runq);
1823e12c5d1SDavid du Colombier 		runq->pc++;
1833e12c5d1SDavid du Colombier 		(*runq->code[runq->pc-1].f)();
184dc5a79c1SDavid du Colombier 		if(ntrap)
185dc5a79c1SDavid du Colombier 			dotrap();
1863e12c5d1SDavid du Colombier 	}
1873e12c5d1SDavid du Colombier }
1883e12c5d1SDavid du Colombier /*
1893e12c5d1SDavid du Colombier  * Opcode routines
1903e12c5d1SDavid du Colombier  * Arguments on stack (...)
1913e12c5d1SDavid du Colombier  * Arguments in line [...]
1923e12c5d1SDavid du Colombier  * Code in line with jump around {...}
1933e12c5d1SDavid du Colombier  *
1943e12c5d1SDavid du Colombier  * Xappend(file)[fd]			open file to append
1953e12c5d1SDavid du Colombier  * Xassign(name, val)			assign val to name
1963e12c5d1SDavid du Colombier  * Xasync{... Xexit}			make thread for {}, no wait
1973e12c5d1SDavid du Colombier  * Xbackq{... Xreturn}			make thread for {}, push stdout
1983e12c5d1SDavid du Colombier  * Xbang				complement condition
1993e12c5d1SDavid du Colombier  * Xcase(pat, value){...}		exec code on match, leave (value) on
2003e12c5d1SDavid du Colombier  * 					stack
2013e12c5d1SDavid du Colombier  * Xclose[i]				close file descriptor
2023e12c5d1SDavid du Colombier  * Xconc(left, right)			concatenate, push results
2033e12c5d1SDavid du Colombier  * Xcount(name)				push var count
2043e12c5d1SDavid du Colombier  * Xdelfn(name)				delete function definition
2053e12c5d1SDavid du Colombier  * Xdeltraps(names)			delete named traps
2063e12c5d1SDavid du Colombier  * Xdol(name)				get variable value
2073e12c5d1SDavid du Colombier  * Xqdol(name)				concatenate variable components
2083e12c5d1SDavid du Colombier  * Xdup[i j]				dup file descriptor
2093e12c5d1SDavid du Colombier  * Xexit				rc exits with status
2103e12c5d1SDavid du Colombier  * Xfalse{...}				execute {} if false
2113e12c5d1SDavid du Colombier  * Xfn(name){... Xreturn}			define function
2123e12c5d1SDavid du Colombier  * Xfor(var, list){... Xreturn}		for loop
2133e12c5d1SDavid du Colombier  * Xjump[addr]				goto
2143e12c5d1SDavid du Colombier  * Xlocal(name, val)			create local variable, assign value
2153e12c5d1SDavid du Colombier  * Xmark				mark stack
2163e12c5d1SDavid du Colombier  * Xmatch(pat, str)			match pattern, set status
2173e12c5d1SDavid du Colombier  * Xpipe[i j]{... Xreturn}{... Xreturn}	construct a pipe between 2 new threads,
2183e12c5d1SDavid du Colombier  * 					wait for both
2193e12c5d1SDavid du Colombier  * Xpipefd[type]{... Xreturn}		connect {} to pipe (input or output,
2203e12c5d1SDavid du Colombier  * 					depending on type), push /dev/fd/??
2213e12c5d1SDavid du Colombier  * Xpopm(value)				pop value from stack
222119a69faSDavid du Colombier  * Xrdwr(file)[fd]			open file for reading and writing
2233e12c5d1SDavid du Colombier  * Xread(file)[fd]			open file to read
2243e12c5d1SDavid du Colombier  * Xsettraps(names){... Xreturn}		define trap functions
2253e12c5d1SDavid du Colombier  * Xshowtraps				print trap list
2263e12c5d1SDavid du Colombier  * Xsimple(args)			run command and wait
2273e12c5d1SDavid du Colombier  * Xreturn				kill thread
2283e12c5d1SDavid du Colombier  * Xsubshell{... Xexit}			execute {} in a subshell and wait
2293e12c5d1SDavid du Colombier  * Xtrue{...}				execute {} if true
2303e12c5d1SDavid du Colombier  * Xunlocal				delete local variable
2313e12c5d1SDavid du Colombier  * Xword[string]			push string
2323e12c5d1SDavid du Colombier  * Xwrite(file)[fd]			open file to write
2333e12c5d1SDavid du Colombier  */
234dc5a79c1SDavid du Colombier 
235dc5a79c1SDavid du Colombier void
236dc5a79c1SDavid du Colombier Xappend(void)
237dc5a79c1SDavid du Colombier {
2383e12c5d1SDavid du Colombier 	char *file;
2393e12c5d1SDavid du Colombier 	int f;
2403e12c5d1SDavid du Colombier 	switch(count(runq->argv->words)){
241dc5a79c1SDavid du Colombier 	default:
242dc5a79c1SDavid du Colombier 		Xerror1(">> requires singleton");
243dc5a79c1SDavid du Colombier 		return;
244dc5a79c1SDavid du Colombier 	case 0:
245dc5a79c1SDavid du Colombier 		Xerror1(">> requires file");
246dc5a79c1SDavid du Colombier 		return;
247dc5a79c1SDavid du Colombier 	case 1:
248dc5a79c1SDavid du Colombier 		break;
2493e12c5d1SDavid du Colombier 	}
2503e12c5d1SDavid du Colombier 	file = runq->argv->words->word;
2513e12c5d1SDavid du Colombier 	if((f = open(file, 1))<0 && (f = Creat(file))<0){
2527dd7cddfSDavid du Colombier 		pfmt(err, "%s: ", file);
2537dd7cddfSDavid du Colombier 		Xerror("can't open");
2543e12c5d1SDavid du Colombier 		return;
2553e12c5d1SDavid du Colombier 	}
2563e12c5d1SDavid du Colombier 	Seek(f, 0L, 2);
2573e12c5d1SDavid du Colombier 	pushredir(ROPEN, f, runq->code[runq->pc].i);
2583e12c5d1SDavid du Colombier 	runq->pc++;
2593e12c5d1SDavid du Colombier 	poplist();
2603e12c5d1SDavid du Colombier }
261dc5a79c1SDavid du Colombier 
262dc5a79c1SDavid du Colombier void
263dc5a79c1SDavid du Colombier Xsettrue(void)
264dc5a79c1SDavid du Colombier {
265219b2ee8SDavid du Colombier 	setstatus("");
266219b2ee8SDavid du Colombier }
267dc5a79c1SDavid du Colombier 
268dc5a79c1SDavid du Colombier void
269dc5a79c1SDavid du Colombier Xbang(void)
270dc5a79c1SDavid du Colombier {
2713e12c5d1SDavid du Colombier 	setstatus(truestatus()?"false":"");
2723e12c5d1SDavid du Colombier }
273dc5a79c1SDavid du Colombier 
274dc5a79c1SDavid du Colombier void
275dc5a79c1SDavid du Colombier Xclose(void)
276dc5a79c1SDavid du Colombier {
2773e12c5d1SDavid du Colombier 	pushredir(RCLOSE, runq->code[runq->pc].i, 0);
2783e12c5d1SDavid du Colombier 	runq->pc++;
2793e12c5d1SDavid du Colombier }
280dc5a79c1SDavid du Colombier 
281dc5a79c1SDavid du Colombier void
282dc5a79c1SDavid du Colombier Xdup(void)
283dc5a79c1SDavid du Colombier {
2843e12c5d1SDavid du Colombier 	pushredir(RDUP, runq->code[runq->pc].i, runq->code[runq->pc+1].i);
2853e12c5d1SDavid du Colombier 	runq->pc+=2;
2863e12c5d1SDavid du Colombier }
287dc5a79c1SDavid du Colombier 
288dc5a79c1SDavid du Colombier void
289dc5a79c1SDavid du Colombier Xeflag(void)
290dc5a79c1SDavid du Colombier {
291219b2ee8SDavid du Colombier 	if(eflagok && !truestatus()) Xexit();
292219b2ee8SDavid du Colombier }
293dc5a79c1SDavid du Colombier 
294dc5a79c1SDavid du Colombier void
295dc5a79c1SDavid du Colombier Xexit(void)
296dc5a79c1SDavid du Colombier {
2973e12c5d1SDavid du Colombier 	struct var *trapreq;
2983e12c5d1SDavid du Colombier 	struct word *starval;
2993e12c5d1SDavid du Colombier 	static int beenhere = 0;
3003e12c5d1SDavid du Colombier 	if(getpid()==mypid && !beenhere){
3013e12c5d1SDavid du Colombier 		trapreq = vlook("sigexit");
3023e12c5d1SDavid du Colombier 		if(trapreq->fn){
3033e12c5d1SDavid du Colombier 			beenhere = 1;
3043e12c5d1SDavid du Colombier 			--runq->pc;
305219b2ee8SDavid du Colombier 			starval = vlook("*")->val;
3063e12c5d1SDavid du Colombier 			start(trapreq->fn, trapreq->pc, (struct var *)0);
3073e12c5d1SDavid du Colombier 			runq->local = newvar(strdup("*"), runq->local);
3083e12c5d1SDavid du Colombier 			runq->local->val = copywords(starval, (struct word *)0);
3093e12c5d1SDavid du Colombier 			runq->local->changed = 1;
3103e12c5d1SDavid du Colombier 			runq->redir = runq->startredir = 0;
3113e12c5d1SDavid du Colombier 			return;
3123e12c5d1SDavid du Colombier 		}
3133e12c5d1SDavid du Colombier 	}
3143e12c5d1SDavid du Colombier 	Exit(getstatus());
3153e12c5d1SDavid du Colombier }
316dc5a79c1SDavid du Colombier 
317dc5a79c1SDavid du Colombier void
318dc5a79c1SDavid du Colombier Xfalse(void)
319dc5a79c1SDavid du Colombier {
3203e12c5d1SDavid du Colombier 	if(truestatus()) runq->pc = runq->code[runq->pc].i;
3213e12c5d1SDavid du Colombier 	else runq->pc++;
3223e12c5d1SDavid du Colombier }
3233e12c5d1SDavid du Colombier int ifnot;		/* dynamic if not flag */
324dc5a79c1SDavid du Colombier 
325dc5a79c1SDavid du Colombier void
326dc5a79c1SDavid du Colombier Xifnot(void)
327dc5a79c1SDavid du Colombier {
3283e12c5d1SDavid du Colombier 	if(ifnot)
3293e12c5d1SDavid du Colombier 		runq->pc++;
3303e12c5d1SDavid du Colombier 	else
3313e12c5d1SDavid du Colombier 		runq->pc = runq->code[runq->pc].i;
3323e12c5d1SDavid du Colombier }
333dc5a79c1SDavid du Colombier 
334dc5a79c1SDavid du Colombier void
335dc5a79c1SDavid du Colombier Xjump(void)
336dc5a79c1SDavid du Colombier {
3373e12c5d1SDavid du Colombier 	runq->pc = runq->code[runq->pc].i;
3383e12c5d1SDavid du Colombier }
339dc5a79c1SDavid du Colombier 
340dc5a79c1SDavid du Colombier void
341dc5a79c1SDavid du Colombier Xmark(void)
342dc5a79c1SDavid du Colombier {
3433e12c5d1SDavid du Colombier 	pushlist();
3443e12c5d1SDavid du Colombier }
345dc5a79c1SDavid du Colombier 
346dc5a79c1SDavid du Colombier void
347dc5a79c1SDavid du Colombier Xpopm(void)
348dc5a79c1SDavid du Colombier {
3493e12c5d1SDavid du Colombier 	poplist();
3503e12c5d1SDavid du Colombier }
351dc5a79c1SDavid du Colombier 
352dc5a79c1SDavid du Colombier void
353dc5a79c1SDavid du Colombier Xread(void)
354dc5a79c1SDavid du Colombier {
3553e12c5d1SDavid du Colombier 	char *file;
3563e12c5d1SDavid du Colombier 	int f;
3573e12c5d1SDavid du Colombier 	switch(count(runq->argv->words)){
358dc5a79c1SDavid du Colombier 	default:
359dc5a79c1SDavid du Colombier 		Xerror1("< requires singleton\n");
360dc5a79c1SDavid du Colombier 		return;
361dc5a79c1SDavid du Colombier 	case 0:
362dc5a79c1SDavid du Colombier 		Xerror1("< requires file\n");
363dc5a79c1SDavid du Colombier 		return;
364dc5a79c1SDavid du Colombier 	case 1:
365dc5a79c1SDavid du Colombier 		break;
3663e12c5d1SDavid du Colombier 	}
3673e12c5d1SDavid du Colombier 	file = runq->argv->words->word;
3683e12c5d1SDavid du Colombier 	if((f = open(file, 0))<0){
3697dd7cddfSDavid du Colombier 		pfmt(err, "%s: ", file);
3707dd7cddfSDavid du Colombier 		Xerror("can't open");
3713e12c5d1SDavid du Colombier 		return;
3723e12c5d1SDavid du Colombier 	}
3733e12c5d1SDavid du Colombier 	pushredir(ROPEN, f, runq->code[runq->pc].i);
3743e12c5d1SDavid du Colombier 	runq->pc++;
3753e12c5d1SDavid du Colombier 	poplist();
3763e12c5d1SDavid du Colombier }
377dc5a79c1SDavid du Colombier 
378dc5a79c1SDavid du Colombier void
379119a69faSDavid du Colombier Xrdwr(void)
380119a69faSDavid du Colombier {
381119a69faSDavid du Colombier 	char *file;
382119a69faSDavid du Colombier 	int f;
383119a69faSDavid du Colombier 
384119a69faSDavid du Colombier 	switch(count(runq->argv->words)){
385119a69faSDavid du Colombier 	default:
386119a69faSDavid du Colombier 		Xerror1("<> requires singleton\n");
387119a69faSDavid du Colombier 		return;
388119a69faSDavid du Colombier 	case 0:
389119a69faSDavid du Colombier 		Xerror1("<> requires file\n");
390119a69faSDavid du Colombier 		return;
391119a69faSDavid du Colombier 	case 1:
392119a69faSDavid du Colombier 		break;
393119a69faSDavid du Colombier 	}
394119a69faSDavid du Colombier 	file = runq->argv->words->word;
395119a69faSDavid du Colombier 	if((f = open(file, ORDWR))<0){
396119a69faSDavid du Colombier 		pfmt(err, "%s: ", file);
397119a69faSDavid du Colombier 		Xerror("can't open");
398119a69faSDavid du Colombier 		return;
399119a69faSDavid du Colombier 	}
400119a69faSDavid du Colombier 	pushredir(ROPEN, f, runq->code[runq->pc].i);
401119a69faSDavid du Colombier 	runq->pc++;
402119a69faSDavid du Colombier 	poplist();
403119a69faSDavid du Colombier }
404119a69faSDavid du Colombier 
405119a69faSDavid du Colombier void
406dc5a79c1SDavid du Colombier turfredir(void)
407dc5a79c1SDavid du Colombier {
4083e12c5d1SDavid du Colombier 	while(runq->redir!=runq->startredir)
4093e12c5d1SDavid du Colombier 		Xpopredir();
4103e12c5d1SDavid du Colombier }
411dc5a79c1SDavid du Colombier 
412dc5a79c1SDavid du Colombier void
413dc5a79c1SDavid du Colombier Xpopredir(void)
414dc5a79c1SDavid du Colombier {
4153e12c5d1SDavid du Colombier 	struct redir *rp = runq->redir;
416dc5a79c1SDavid du Colombier 	if(rp==0)
417dc5a79c1SDavid du Colombier 		panic("turfredir null!", 0);
4183e12c5d1SDavid du Colombier 	runq->redir = rp->next;
419dc5a79c1SDavid du Colombier 	if(rp->type==ROPEN)
420dc5a79c1SDavid du Colombier 		close(rp->from);
4213e12c5d1SDavid du Colombier 	efree((char *)rp);
4223e12c5d1SDavid du Colombier }
423dc5a79c1SDavid du Colombier 
424dc5a79c1SDavid du Colombier void
425dc5a79c1SDavid du Colombier Xreturn(void)
426dc5a79c1SDavid du Colombier {
4273e12c5d1SDavid du Colombier 	struct thread *p = runq;
4283e12c5d1SDavid du Colombier 	turfredir();
4293e12c5d1SDavid du Colombier 	while(p->argv) poplist();
4303e12c5d1SDavid du Colombier 	codefree(p->code);
4313e12c5d1SDavid du Colombier 	runq = p->ret;
4323e12c5d1SDavid du Colombier 	efree((char *)p);
433dc5a79c1SDavid du Colombier 	if(runq==0)
434dc5a79c1SDavid du Colombier 		Exit(getstatus());
4353e12c5d1SDavid du Colombier }
436dc5a79c1SDavid du Colombier 
437dc5a79c1SDavid du Colombier void
438dc5a79c1SDavid du Colombier Xtrue(void)
439dc5a79c1SDavid du Colombier {
4403e12c5d1SDavid du Colombier 	if(truestatus()) runq->pc++;
4413e12c5d1SDavid du Colombier 	else runq->pc = runq->code[runq->pc].i;
4423e12c5d1SDavid du Colombier }
443dc5a79c1SDavid du Colombier 
444dc5a79c1SDavid du Colombier void
445dc5a79c1SDavid du Colombier Xif(void)
446dc5a79c1SDavid du Colombier {
4473e12c5d1SDavid du Colombier 	ifnot = 1;
4483e12c5d1SDavid du Colombier 	if(truestatus()) runq->pc++;
4493e12c5d1SDavid du Colombier 	else runq->pc = runq->code[runq->pc].i;
4503e12c5d1SDavid du Colombier }
451dc5a79c1SDavid du Colombier 
452dc5a79c1SDavid du Colombier void
453dc5a79c1SDavid du Colombier Xwastrue(void)
454dc5a79c1SDavid du Colombier {
4553e12c5d1SDavid du Colombier 	ifnot = 0;
4563e12c5d1SDavid du Colombier }
457dc5a79c1SDavid du Colombier 
458dc5a79c1SDavid du Colombier void
459dc5a79c1SDavid du Colombier Xword(void)
460dc5a79c1SDavid du Colombier {
4613e12c5d1SDavid du Colombier 	pushword(runq->code[runq->pc++].s);
4623e12c5d1SDavid du Colombier }
463dc5a79c1SDavid du Colombier 
464dc5a79c1SDavid du Colombier void
465dc5a79c1SDavid du Colombier Xwrite(void)
466dc5a79c1SDavid du Colombier {
4673e12c5d1SDavid du Colombier 	char *file;
4683e12c5d1SDavid du Colombier 	int f;
4693e12c5d1SDavid du Colombier 	switch(count(runq->argv->words)){
470dc5a79c1SDavid du Colombier 	default:
471dc5a79c1SDavid du Colombier 		Xerror1("> requires singleton\n");
472dc5a79c1SDavid du Colombier 		return;
473dc5a79c1SDavid du Colombier 	case 0:
474dc5a79c1SDavid du Colombier 		Xerror1("> requires file\n");
475dc5a79c1SDavid du Colombier 		return;
476dc5a79c1SDavid du Colombier 	case 1:
477dc5a79c1SDavid du Colombier 		break;
4783e12c5d1SDavid du Colombier 	}
4793e12c5d1SDavid du Colombier 	file = runq->argv->words->word;
4803e12c5d1SDavid du Colombier 	if((f = Creat(file))<0){
4817dd7cddfSDavid du Colombier 		pfmt(err, "%s: ", file);
4827dd7cddfSDavid du Colombier 		Xerror("can't open");
4833e12c5d1SDavid du Colombier 		return;
4843e12c5d1SDavid du Colombier 	}
4853e12c5d1SDavid du Colombier 	pushredir(ROPEN, f, runq->code[runq->pc].i);
4863e12c5d1SDavid du Colombier 	runq->pc++;
4873e12c5d1SDavid du Colombier 	poplist();
4883e12c5d1SDavid du Colombier }
489dc5a79c1SDavid du Colombier 
490dc5a79c1SDavid du Colombier char*
491dc5a79c1SDavid du Colombier list2str(word *words)
492dc5a79c1SDavid du Colombier {
4933e12c5d1SDavid du Colombier 	char *value, *s, *t;
4943e12c5d1SDavid du Colombier 	int len = 0;
4953e12c5d1SDavid du Colombier 	word *ap;
4963e12c5d1SDavid du Colombier 	for(ap = words;ap;ap = ap->next)
4973e12c5d1SDavid du Colombier 		len+=1+strlen(ap->word);
4983e12c5d1SDavid du Colombier 	value = emalloc(len+1);
4993e12c5d1SDavid du Colombier 	s = value;
5003e12c5d1SDavid du Colombier 	for(ap = words;ap;ap = ap->next){
5013e12c5d1SDavid du Colombier 		for(t = ap->word;*t;) *s++=*t++;
5023e12c5d1SDavid du Colombier 		*s++=' ';
5033e12c5d1SDavid du Colombier 	}
504dc5a79c1SDavid du Colombier 	if(s==value)
505dc5a79c1SDavid du Colombier 		*s='\0';
5063e12c5d1SDavid du Colombier 	else s[-1]='\0';
5073e12c5d1SDavid du Colombier 	return value;
5083e12c5d1SDavid du Colombier }
509dc5a79c1SDavid du Colombier 
510dc5a79c1SDavid du Colombier void
511dc5a79c1SDavid du Colombier Xmatch(void)
512dc5a79c1SDavid du Colombier {
5133e12c5d1SDavid du Colombier 	word *p;
5143e12c5d1SDavid du Colombier 	char *subject;
5153e12c5d1SDavid du Colombier 	subject = list2str(runq->argv->words);
5163e12c5d1SDavid du Colombier 	setstatus("no match");
5173e12c5d1SDavid du Colombier 	for(p = runq->argv->next->words;p;p = p->next)
5183e12c5d1SDavid du Colombier 		if(match(subject, p->word, '\0')){
5193e12c5d1SDavid du Colombier 			setstatus("");
5203e12c5d1SDavid du Colombier 			break;
5213e12c5d1SDavid du Colombier 		}
5223e12c5d1SDavid du Colombier 	efree(subject);
5233e12c5d1SDavid du Colombier 	poplist();
5243e12c5d1SDavid du Colombier 	poplist();
5253e12c5d1SDavid du Colombier }
526dc5a79c1SDavid du Colombier 
527dc5a79c1SDavid du Colombier void
528dc5a79c1SDavid du Colombier Xcase(void)
529dc5a79c1SDavid du Colombier {
5303e12c5d1SDavid du Colombier 	word *p;
5313e12c5d1SDavid du Colombier 	char *s;
5323e12c5d1SDavid du Colombier 	int ok = 0;
5333e12c5d1SDavid du Colombier 	s = list2str(runq->argv->next->words);
5343e12c5d1SDavid du Colombier 	for(p = runq->argv->words;p;p = p->next){
5353e12c5d1SDavid du Colombier 		if(match(s, p->word, '\0')){
5363e12c5d1SDavid du Colombier 			ok = 1;
5373e12c5d1SDavid du Colombier 			break;
5383e12c5d1SDavid du Colombier 		}
5393e12c5d1SDavid du Colombier 	}
5403e12c5d1SDavid du Colombier 	efree(s);
5413e12c5d1SDavid du Colombier 	if(ok)
5423e12c5d1SDavid du Colombier 		runq->pc++;
5433e12c5d1SDavid du Colombier 	else
5443e12c5d1SDavid du Colombier 		runq->pc = runq->code[runq->pc].i;
5453e12c5d1SDavid du Colombier 	poplist();
5463e12c5d1SDavid du Colombier }
547dc5a79c1SDavid du Colombier 
548dc5a79c1SDavid du Colombier word*
549dc5a79c1SDavid du Colombier conclist(word *lp, word *rp, word *tail)
5503e12c5d1SDavid du Colombier {
5513e12c5d1SDavid du Colombier 	char *buf;
5523e12c5d1SDavid du Colombier 	word *v;
5533e12c5d1SDavid du Colombier 	if(lp->next || rp->next)
554276e7d6dSDavid du Colombier 		tail = conclist(lp->next==0? lp: lp->next,
555276e7d6dSDavid du Colombier 			rp->next==0? rp: rp->next, tail);
556276e7d6dSDavid du Colombier 	buf = emalloc(strlen(lp->word)+strlen((char *)rp->word)+1);
5573e12c5d1SDavid du Colombier 	strcpy(buf, lp->word);
5583e12c5d1SDavid du Colombier 	strcat(buf, rp->word);
5593e12c5d1SDavid du Colombier 	v = newword(buf, tail);
5603e12c5d1SDavid du Colombier 	efree(buf);
5613e12c5d1SDavid du Colombier 	return v;
5623e12c5d1SDavid du Colombier }
563dc5a79c1SDavid du Colombier 
564dc5a79c1SDavid du Colombier void
565dc5a79c1SDavid du Colombier Xconc(void)
566dc5a79c1SDavid du Colombier {
5673e12c5d1SDavid du Colombier 	word *lp = runq->argv->words;
5683e12c5d1SDavid du Colombier 	word *rp = runq->argv->next->words;
5693e12c5d1SDavid du Colombier 	word *vp = runq->argv->next->next->words;
5703e12c5d1SDavid du Colombier 	int lc = count(lp), rc = count(rp);
5713e12c5d1SDavid du Colombier 	if(lc!=0 || rc!=0){
5723e12c5d1SDavid du Colombier 		if(lc==0 || rc==0){
5739a747e4fSDavid du Colombier 			Xerror1("null list in concatenation");
5743e12c5d1SDavid du Colombier 			return;
5753e12c5d1SDavid du Colombier 		}
5763e12c5d1SDavid du Colombier 		if(lc!=1 && rc!=1 && lc!=rc){
5779a747e4fSDavid du Colombier 			Xerror1("mismatched list lengths in concatenation");
5783e12c5d1SDavid du Colombier 			return;
5793e12c5d1SDavid du Colombier 		}
5803e12c5d1SDavid du Colombier 		vp = conclist(lp, rp, vp);
5813e12c5d1SDavid du Colombier 	}
5823e12c5d1SDavid du Colombier 	poplist();
5833e12c5d1SDavid du Colombier 	poplist();
5843e12c5d1SDavid du Colombier 	runq->argv->words = vp;
5853e12c5d1SDavid du Colombier }
586dc5a79c1SDavid du Colombier 
587dc5a79c1SDavid du Colombier void
588dc5a79c1SDavid du Colombier Xassign(void)
589dc5a79c1SDavid du Colombier {
5903e12c5d1SDavid du Colombier 	var *v;
5913e12c5d1SDavid du Colombier 	if(count(runq->argv->words)!=1){
5929a747e4fSDavid du Colombier 		Xerror1("variable name not singleton!");
5933e12c5d1SDavid du Colombier 		return;
5943e12c5d1SDavid du Colombier 	}
5953e12c5d1SDavid du Colombier 	deglob(runq->argv->words->word);
5963e12c5d1SDavid du Colombier 	v = vlook(runq->argv->words->word);
5973e12c5d1SDavid du Colombier 	poplist();
5983e12c5d1SDavid du Colombier 	globlist();
5993e12c5d1SDavid du Colombier 	freewords(v->val);
6003e12c5d1SDavid du Colombier 	v->val = runq->argv->words;
6013e12c5d1SDavid du Colombier 	v->changed = 1;
6023e12c5d1SDavid du Colombier 	runq->argv->words = 0;
6033e12c5d1SDavid du Colombier 	poplist();
6043e12c5d1SDavid du Colombier }
6053e12c5d1SDavid du Colombier /*
6063e12c5d1SDavid du Colombier  * copy arglist a, adding the copy to the front of tail
6073e12c5d1SDavid du Colombier  */
608dc5a79c1SDavid du Colombier 
609dc5a79c1SDavid du Colombier word*
610dc5a79c1SDavid du Colombier copywords(word *a, word *tail)
6113e12c5d1SDavid du Colombier {
6123e12c5d1SDavid du Colombier 	word *v = 0, **end;
6133e12c5d1SDavid du Colombier 	for(end=&v;a;a = a->next,end=&(*end)->next)
6143e12c5d1SDavid du Colombier 		*end = newword(a->word, 0);
6153e12c5d1SDavid du Colombier 	*end = tail;
6163e12c5d1SDavid du Colombier 	return v;
6173e12c5d1SDavid du Colombier }
618dc5a79c1SDavid du Colombier 
619dc5a79c1SDavid du Colombier void
620dc5a79c1SDavid du Colombier Xdol(void)
621dc5a79c1SDavid du Colombier {
6223e12c5d1SDavid du Colombier 	word *a, *star;
6233e12c5d1SDavid du Colombier 	char *s, *t;
6243e12c5d1SDavid du Colombier 	int n;
6253e12c5d1SDavid du Colombier 	if(count(runq->argv->words)!=1){
6269a747e4fSDavid du Colombier 		Xerror1("variable name not singleton!");
6273e12c5d1SDavid du Colombier 		return;
6283e12c5d1SDavid du Colombier 	}
6293e12c5d1SDavid du Colombier 	s = runq->argv->words->word;
6303e12c5d1SDavid du Colombier 	deglob(s);
6313e12c5d1SDavid du Colombier 	n = 0;
63299eb86a7SDavid du Colombier 	for(t = s;'0'<=*t && *t<='9';t++) n = n*10+*t-'0';
6333e12c5d1SDavid du Colombier 	a = runq->argv->next->words;
6343e12c5d1SDavid du Colombier 	if(n==0 || *t)
6353e12c5d1SDavid du Colombier 		a = copywords(vlook(s)->val, a);
6363e12c5d1SDavid du Colombier 	else{
6373e12c5d1SDavid du Colombier 		star = vlook("*")->val;
6383e12c5d1SDavid du Colombier 		if(star && 1<=n && n<=count(star)){
63999eb86a7SDavid du Colombier 			while(--n) star = star->next;
6403e12c5d1SDavid du Colombier 			a = newword(star->word, a);
6413e12c5d1SDavid du Colombier 		}
6423e12c5d1SDavid du Colombier 	}
6433e12c5d1SDavid du Colombier 	poplist();
6443e12c5d1SDavid du Colombier 	runq->argv->words = a;
6453e12c5d1SDavid du Colombier }
646dc5a79c1SDavid du Colombier 
647dc5a79c1SDavid du Colombier void
648dc5a79c1SDavid du Colombier Xqdol(void)
649dc5a79c1SDavid du Colombier {
6503e12c5d1SDavid du Colombier 	word *a, *p;
6513e12c5d1SDavid du Colombier 	char *s;
6523e12c5d1SDavid du Colombier 	int n;
6533e12c5d1SDavid du Colombier 	if(count(runq->argv->words)!=1){
6549a747e4fSDavid du Colombier 		Xerror1("variable name not singleton!");
6553e12c5d1SDavid du Colombier 		return;
6563e12c5d1SDavid du Colombier 	}
6573e12c5d1SDavid du Colombier 	s = runq->argv->words->word;
6583e12c5d1SDavid du Colombier 	deglob(s);
6593e12c5d1SDavid du Colombier 	a = vlook(s)->val;
6603e12c5d1SDavid du Colombier 	poplist();
6613e12c5d1SDavid du Colombier 	n = count(a);
6623e12c5d1SDavid du Colombier 	if(n==0){
6633e12c5d1SDavid du Colombier 		pushword("");
6643e12c5d1SDavid du Colombier 		return;
6653e12c5d1SDavid du Colombier 	}
6663e12c5d1SDavid du Colombier 	for(p = a;p;p = p->next) n+=strlen(p->word);
6673e12c5d1SDavid du Colombier 	s = emalloc(n);
6683e12c5d1SDavid du Colombier 	if(a){
6693e12c5d1SDavid du Colombier 		strcpy(s, a->word);
6703e12c5d1SDavid du Colombier 		for(p = a->next;p;p = p->next){
6713e12c5d1SDavid du Colombier 			strcat(s, " ");
6723e12c5d1SDavid du Colombier 			strcat(s, p->word);
6733e12c5d1SDavid du Colombier 		}
6743e12c5d1SDavid du Colombier 	}
6753e12c5d1SDavid du Colombier 	else
6763e12c5d1SDavid du Colombier 		s[0]='\0';
6773e12c5d1SDavid du Colombier 	pushword(s);
6783e12c5d1SDavid du Colombier 	efree(s);
6793e12c5d1SDavid du Colombier }
680dc5a79c1SDavid du Colombier 
681dc5a79c1SDavid du Colombier word*
682dc5a79c1SDavid du Colombier subwords(word *val, int len, word *sub, word *a)
6833e12c5d1SDavid du Colombier {
6843e12c5d1SDavid du Colombier 	int n;
6853e12c5d1SDavid du Colombier 	char *s;
686dc5a79c1SDavid du Colombier 	if(!sub)
687dc5a79c1SDavid du Colombier 		return a;
6883e12c5d1SDavid du Colombier 	a = subwords(val, len, sub->next, a);
6893e12c5d1SDavid du Colombier 	s = sub->word;
6903e12c5d1SDavid du Colombier 	deglob(s);
6913e12c5d1SDavid du Colombier 	n = 0;
69299eb86a7SDavid du Colombier 	while('0'<=*s && *s<='9') n = n*10+ *s++ -'0';
693dc5a79c1SDavid du Colombier 	if(n<1 || len<n)
694dc5a79c1SDavid du Colombier 		return a;
69599eb86a7SDavid du Colombier 	for(;n!=1;--n) val = val->next;
6963e12c5d1SDavid du Colombier 	return newword(val->word, a);
6973e12c5d1SDavid du Colombier }
698dc5a79c1SDavid du Colombier 
699dc5a79c1SDavid du Colombier void
700dc5a79c1SDavid du Colombier Xsub(void)
701dc5a79c1SDavid du Colombier {
7023e12c5d1SDavid du Colombier 	word *a, *v;
7033e12c5d1SDavid du Colombier 	char *s;
7043e12c5d1SDavid du Colombier 	if(count(runq->argv->next->words)!=1){
7059a747e4fSDavid du Colombier 		Xerror1("variable name not singleton!");
7063e12c5d1SDavid du Colombier 		return;
7073e12c5d1SDavid du Colombier 	}
7083e12c5d1SDavid du Colombier 	s = runq->argv->next->words->word;
7093e12c5d1SDavid du Colombier 	deglob(s);
7103e12c5d1SDavid du Colombier 	a = runq->argv->next->next->words;
7113e12c5d1SDavid du Colombier 	v = vlook(s)->val;
7123e12c5d1SDavid du Colombier 	a = subwords(v, count(v), runq->argv->words, a);
7133e12c5d1SDavid du Colombier 	poplist();
7143e12c5d1SDavid du Colombier 	poplist();
7153e12c5d1SDavid du Colombier 	runq->argv->words = a;
7163e12c5d1SDavid du Colombier }
717dc5a79c1SDavid du Colombier 
718dc5a79c1SDavid du Colombier void
719dc5a79c1SDavid du Colombier Xcount(void)
720dc5a79c1SDavid du Colombier {
7213e12c5d1SDavid du Colombier 	word *a;
7223e12c5d1SDavid du Colombier 	char *s, *t;
7233e12c5d1SDavid du Colombier 	int n;
7243e12c5d1SDavid du Colombier 	char num[12];
7253e12c5d1SDavid du Colombier 	if(count(runq->argv->words)!=1){
7269a747e4fSDavid du Colombier 		Xerror1("variable name not singleton!");
7273e12c5d1SDavid du Colombier 		return;
7283e12c5d1SDavid du Colombier 	}
7293e12c5d1SDavid du Colombier 	s = runq->argv->words->word;
7303e12c5d1SDavid du Colombier 	deglob(s);
7313e12c5d1SDavid du Colombier 	n = 0;
7323e12c5d1SDavid du Colombier 	for(t = s;'0'<=*t && *t<='9';t++) n = n*10+*t-'0';
7333e12c5d1SDavid du Colombier 	if(n==0 || *t){
7343e12c5d1SDavid du Colombier 		a = vlook(s)->val;
735dc5a79c1SDavid du Colombier 		inttoascii(num, count(a));
7363e12c5d1SDavid du Colombier 	}
7373e12c5d1SDavid du Colombier 	else{
7383e12c5d1SDavid du Colombier 		a = vlook("*")->val;
739dc5a79c1SDavid du Colombier 		inttoascii(num, a && 1<=n && n<=count(a)?1:0);
7403e12c5d1SDavid du Colombier 	}
7413e12c5d1SDavid du Colombier 	poplist();
7423e12c5d1SDavid du Colombier 	pushword(num);
7433e12c5d1SDavid du Colombier }
744dc5a79c1SDavid du Colombier 
745dc5a79c1SDavid du Colombier void
746dc5a79c1SDavid du Colombier Xlocal(void)
747dc5a79c1SDavid du Colombier {
7483e12c5d1SDavid du Colombier 	if(count(runq->argv->words)!=1){
7499a747e4fSDavid du Colombier 		Xerror1("variable name must be singleton\n");
7503e12c5d1SDavid du Colombier 		return;
7513e12c5d1SDavid du Colombier 	}
7523e12c5d1SDavid du Colombier 	deglob(runq->argv->words->word);
7533e12c5d1SDavid du Colombier 	runq->local = newvar(strdup(runq->argv->words->word), runq->local);
7543e12c5d1SDavid du Colombier 	poplist();
755*fed0fa9eSDavid du Colombier 	globlist();
756*fed0fa9eSDavid du Colombier 	runq->local->val = runq->argv->words;
757*fed0fa9eSDavid du Colombier 	runq->local->changed = 1;
758*fed0fa9eSDavid du Colombier 	runq->argv->words = 0;
7593e12c5d1SDavid du Colombier 	poplist();
7603e12c5d1SDavid du Colombier }
761dc5a79c1SDavid du Colombier 
762dc5a79c1SDavid du Colombier void
763dc5a79c1SDavid du Colombier Xunlocal(void)
764dc5a79c1SDavid du Colombier {
7653e12c5d1SDavid du Colombier 	var *v = runq->local, *hid;
766dc5a79c1SDavid du Colombier 	if(v==0)
767dc5a79c1SDavid du Colombier 		panic("Xunlocal: no locals!", 0);
7683e12c5d1SDavid du Colombier 	runq->local = v->next;
7693e12c5d1SDavid du Colombier 	hid = vlook(v->name);
7703e12c5d1SDavid du Colombier 	hid->changed = 1;
7713e12c5d1SDavid du Colombier 	efree(v->name);
7723e12c5d1SDavid du Colombier 	freewords(v->val);
7733e12c5d1SDavid du Colombier 	efree((char *)v);
7743e12c5d1SDavid du Colombier }
775dc5a79c1SDavid du Colombier 
776dc5a79c1SDavid du Colombier void
777dc5a79c1SDavid du Colombier freewords(word *w)
7783e12c5d1SDavid du Colombier {
7793e12c5d1SDavid du Colombier 	word *nw;
7803e12c5d1SDavid du Colombier 	while(w){
7813e12c5d1SDavid du Colombier 		efree(w->word);
7823e12c5d1SDavid du Colombier 		nw = w->next;
7833e12c5d1SDavid du Colombier 		efree((char *)w);
7843e12c5d1SDavid du Colombier 		w = nw;
7853e12c5d1SDavid du Colombier 	}
7863e12c5d1SDavid du Colombier }
787dc5a79c1SDavid du Colombier 
788dc5a79c1SDavid du Colombier void
789dc5a79c1SDavid du Colombier Xfn(void)
790dc5a79c1SDavid du Colombier {
7913e12c5d1SDavid du Colombier 	var *v;
7923e12c5d1SDavid du Colombier 	word *a;
7933e12c5d1SDavid du Colombier 	int end;
7943e12c5d1SDavid du Colombier 	end = runq->code[runq->pc].i;
795*fed0fa9eSDavid du Colombier 	globlist();
7963e12c5d1SDavid du Colombier 	for(a = runq->argv->words;a;a = a->next){
7973e12c5d1SDavid du Colombier 		v = gvlook(a->word);
798dc5a79c1SDavid du Colombier 		if(v->fn)
799dc5a79c1SDavid du Colombier 			codefree(v->fn);
8003e12c5d1SDavid du Colombier 		v->fn = codecopy(runq->code);
8013e12c5d1SDavid du Colombier 		v->pc = runq->pc+2;
8023e12c5d1SDavid du Colombier 		v->fnchanged = 1;
8033e12c5d1SDavid du Colombier 	}
8043e12c5d1SDavid du Colombier 	runq->pc = end;
8053e12c5d1SDavid du Colombier 	poplist();
8063e12c5d1SDavid du Colombier }
807dc5a79c1SDavid du Colombier 
808dc5a79c1SDavid du Colombier void
809dc5a79c1SDavid du Colombier Xdelfn(void)
810dc5a79c1SDavid du Colombier {
8113e12c5d1SDavid du Colombier 	var *v;
8123e12c5d1SDavid du Colombier 	word *a;
8133e12c5d1SDavid du Colombier 	for(a = runq->argv->words;a;a = a->next){
8143e12c5d1SDavid du Colombier 		v = gvlook(a->word);
815dc5a79c1SDavid du Colombier 		if(v->fn)
816dc5a79c1SDavid du Colombier 			codefree(v->fn);
8173e12c5d1SDavid du Colombier 		v->fn = 0;
8183e12c5d1SDavid du Colombier 		v->fnchanged = 1;
8193e12c5d1SDavid du Colombier 	}
8203e12c5d1SDavid du Colombier 	poplist();
8213e12c5d1SDavid du Colombier }
822dc5a79c1SDavid du Colombier 
823dc5a79c1SDavid du Colombier char*
824dc5a79c1SDavid du Colombier concstatus(char *s, char *t)
8253e12c5d1SDavid du Colombier {
8263e12c5d1SDavid du Colombier 	static char v[NSTATUS+1];
8273e12c5d1SDavid du Colombier 	int n = strlen(s);
8283e12c5d1SDavid du Colombier 	strncpy(v, s, NSTATUS);
8293e12c5d1SDavid du Colombier 	if(n<NSTATUS){
8303e12c5d1SDavid du Colombier 		v[n]='|';
8313e12c5d1SDavid du Colombier 		strncpy(v+n+1, t, NSTATUS-n-1);
8323e12c5d1SDavid du Colombier 	}
8333e12c5d1SDavid du Colombier 	v[NSTATUS]='\0';
8343e12c5d1SDavid du Colombier 	return v;
8353e12c5d1SDavid du Colombier }
836dc5a79c1SDavid du Colombier 
837dc5a79c1SDavid du Colombier void
838dc5a79c1SDavid du Colombier Xpipewait(void)
839dc5a79c1SDavid du Colombier {
8403e12c5d1SDavid du Colombier 	char status[NSTATUS+1];
8413e12c5d1SDavid du Colombier 	if(runq->pid==-1)
8423e12c5d1SDavid du Colombier 		setstatus(concstatus(runq->status, getstatus()));
8433e12c5d1SDavid du Colombier 	else{
8443e12c5d1SDavid du Colombier 		strncpy(status, getstatus(), NSTATUS);
8453e12c5d1SDavid du Colombier 		status[NSTATUS]='\0';
8463e12c5d1SDavid du Colombier 		Waitfor(runq->pid, 1);
8473e12c5d1SDavid du Colombier 		runq->pid=-1;
8483e12c5d1SDavid du Colombier 		setstatus(concstatus(getstatus(), status));
8493e12c5d1SDavid du Colombier 	}
8503e12c5d1SDavid du Colombier }
851dc5a79c1SDavid du Colombier 
852dc5a79c1SDavid du Colombier void
853dc5a79c1SDavid du Colombier Xrdcmds(void)
854dc5a79c1SDavid du Colombier {
8553e12c5d1SDavid du Colombier 	struct thread *p = runq;
8563e12c5d1SDavid du Colombier 	word *prompt;
8573e12c5d1SDavid du Colombier 	flush(err);
8583e12c5d1SDavid du Colombier 	nerror = 0;
8593e12c5d1SDavid du Colombier 	if(flag['s'] && !truestatus())
8603e12c5d1SDavid du Colombier 		pfmt(err, "status=%v\n", vlook("status")->val);
8613e12c5d1SDavid du Colombier 	if(runq->iflag){
8623e12c5d1SDavid du Colombier 		prompt = vlook("prompt")->val;
8633e12c5d1SDavid du Colombier 		if(prompt)
8643e12c5d1SDavid du Colombier 			promptstr = prompt->word;
8653e12c5d1SDavid du Colombier 		else
8663e12c5d1SDavid du Colombier 			promptstr="% ";
8673e12c5d1SDavid du Colombier 	}
8683e12c5d1SDavid du Colombier 	Noerror();
8693e12c5d1SDavid du Colombier 	if(yyparse()){
8703e12c5d1SDavid du Colombier 		if(!p->iflag || p->eof && !Eintr()){
871dc5a79c1SDavid du Colombier 			if(p->cmdfile)
872dc5a79c1SDavid du Colombier 				efree(p->cmdfile);
8733e12c5d1SDavid du Colombier 			closeio(p->cmdfd);
8743e12c5d1SDavid du Colombier 			Xreturn();	/* should this be omitted? */
8753e12c5d1SDavid du Colombier 		}
8763e12c5d1SDavid du Colombier 		else{
8773e12c5d1SDavid du Colombier 			if(Eintr()){
8783e12c5d1SDavid du Colombier 				pchr(err, '\n');
8793e12c5d1SDavid du Colombier 				p->eof = 0;
8803e12c5d1SDavid du Colombier 			}
8813e12c5d1SDavid du Colombier 			--p->pc;	/* go back for next command */
8823e12c5d1SDavid du Colombier 		}
8833e12c5d1SDavid du Colombier 	}
8843e12c5d1SDavid du Colombier 	else{
8857dd7cddfSDavid du Colombier 		ntrap = 0;	/* avoid double-interrupts during blocked writes */
8863e12c5d1SDavid du Colombier 		--p->pc;	/* re-execute Xrdcmds after codebuf runs */
8873e12c5d1SDavid du Colombier 		start(codebuf, 1, runq->local);
8883e12c5d1SDavid du Colombier 	}
8893e12c5d1SDavid du Colombier 	freenodes();
8903e12c5d1SDavid du Colombier }
891dc5a79c1SDavid du Colombier 
892dc5a79c1SDavid du Colombier void
893dc5a79c1SDavid du Colombier Xerror(char *s)
8943e12c5d1SDavid du Colombier {
8959a747e4fSDavid du Colombier 	if(strcmp(argv0, "rc")==0 || strcmp(argv0, "/bin/rc")==0)
8969a747e4fSDavid du Colombier 		pfmt(err, "rc: %s: %r\n", s);
8979a747e4fSDavid du Colombier 	else
8989a747e4fSDavid du Colombier 		pfmt(err, "rc (%s): %s: %r\n", argv0, s);
8999a747e4fSDavid du Colombier 	flush(err);
900d3907fe5SDavid du Colombier 	setstatus("error");
9019a747e4fSDavid du Colombier 	while(!runq->iflag) Xreturn();
9029a747e4fSDavid du Colombier }
903dc5a79c1SDavid du Colombier 
904dc5a79c1SDavid du Colombier void
905dc5a79c1SDavid du Colombier Xerror1(char *s)
9069a747e4fSDavid du Colombier {
9079a747e4fSDavid du Colombier 	if(strcmp(argv0, "rc")==0 || strcmp(argv0, "/bin/rc")==0)
9083e12c5d1SDavid du Colombier 		pfmt(err, "rc: %s\n", s);
9099a747e4fSDavid du Colombier 	else
9109a747e4fSDavid du Colombier 		pfmt(err, "rc (%s): %s\n", argv0, s);
9113e12c5d1SDavid du Colombier 	flush(err);
912d3907fe5SDavid du Colombier 	setstatus("error");
9133e12c5d1SDavid du Colombier 	while(!runq->iflag) Xreturn();
9143e12c5d1SDavid du Colombier }
915dc5a79c1SDavid du Colombier 
916dc5a79c1SDavid du Colombier void
917dc5a79c1SDavid du Colombier setstatus(char *s)
9183e12c5d1SDavid du Colombier {
9193e12c5d1SDavid du Colombier 	setvar("status", newword(s, (word *)0));
9203e12c5d1SDavid du Colombier }
921dc5a79c1SDavid du Colombier 
922dc5a79c1SDavid du Colombier char*
923dc5a79c1SDavid du Colombier getstatus(void)
924dc5a79c1SDavid du Colombier {
9253e12c5d1SDavid du Colombier 	var *status = vlook("status");
9263e12c5d1SDavid du Colombier 	return status->val?status->val->word:"";
9273e12c5d1SDavid du Colombier }
928dc5a79c1SDavid du Colombier 
929dc5a79c1SDavid du Colombier int
930dc5a79c1SDavid du Colombier truestatus(void)
931dc5a79c1SDavid du Colombier {
9323e12c5d1SDavid du Colombier 	char *s;
9333e12c5d1SDavid du Colombier 	for(s = getstatus();*s;s++)
934dc5a79c1SDavid du Colombier 		if(*s!='|' && *s!='0')
935dc5a79c1SDavid du Colombier 			return 0;
9363e12c5d1SDavid du Colombier 	return 1;
9373e12c5d1SDavid du Colombier }
938dc5a79c1SDavid du Colombier 
939dc5a79c1SDavid du Colombier void
940dc5a79c1SDavid du Colombier Xdelhere(void)
941dc5a79c1SDavid du Colombier {
9423e12c5d1SDavid du Colombier 	Unlink(runq->code[runq->pc++].s);
9433e12c5d1SDavid du Colombier }
944dc5a79c1SDavid du Colombier 
945dc5a79c1SDavid du Colombier void
946dc5a79c1SDavid du Colombier Xfor(void)
947dc5a79c1SDavid du Colombier {
9483e12c5d1SDavid du Colombier 	if(runq->argv->words==0){
9493e12c5d1SDavid du Colombier 		poplist();
9503e12c5d1SDavid du Colombier 		runq->pc = runq->code[runq->pc].i;
9513e12c5d1SDavid du Colombier 	}
9523e12c5d1SDavid du Colombier 	else{
9533e12c5d1SDavid du Colombier 		freelist(runq->local->val);
9543e12c5d1SDavid du Colombier 		runq->local->val = runq->argv->words;
9553e12c5d1SDavid du Colombier 		runq->local->changed = 1;
9563e12c5d1SDavid du Colombier 		runq->argv->words = runq->argv->words->next;
9573e12c5d1SDavid du Colombier 		runq->local->val->next = 0;
9583e12c5d1SDavid du Colombier 		runq->pc++;
9593e12c5d1SDavid du Colombier 	}
9603e12c5d1SDavid du Colombier }
961dc5a79c1SDavid du Colombier 
962dc5a79c1SDavid du Colombier void
963dc5a79c1SDavid du Colombier Xglob(void)
964dc5a79c1SDavid du Colombier {
9653e12c5d1SDavid du Colombier 	globlist();
9663e12c5d1SDavid du Colombier }
967