xref: /plan9/sys/src/cmd/rc/exec.c (revision 9a747e4fd48b9f4522c70c07e8f882a15030f964)
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  */
9*9a747e4fSDavid du Colombier char *argv0="rc";
103e12c5d1SDavid du Colombier void start(code *c, int pc, var *local)
113e12c5d1SDavid du Colombier {
123e12c5d1SDavid du Colombier 	struct thread *p=new(struct thread);
133e12c5d1SDavid du Colombier 	p->code=codecopy(c);
143e12c5d1SDavid du Colombier 	p->pc=pc;
153e12c5d1SDavid du Colombier 	p->argv=0;
163e12c5d1SDavid du Colombier 	p->redir=p->startredir=runq?runq->redir:0;
173e12c5d1SDavid du Colombier 	p->local=local;
183e12c5d1SDavid du Colombier 	p->cmdfile=0;
193e12c5d1SDavid du Colombier 	p->cmdfd=0;
203e12c5d1SDavid du Colombier 	p->eof=0;
213e12c5d1SDavid du Colombier 	p->iflag=0;
223e12c5d1SDavid du Colombier 	p->lineno=1;
233e12c5d1SDavid du Colombier 	p->ret=runq;
243e12c5d1SDavid du Colombier 	runq=p;
253e12c5d1SDavid du Colombier }
263e12c5d1SDavid du Colombier word *newword(char *wd, word *next)
273e12c5d1SDavid du Colombier {
283e12c5d1SDavid du Colombier 	word *p=new(word);
293e12c5d1SDavid du Colombier 	p->word=strdup(wd);
303e12c5d1SDavid du Colombier 	p->next=next;
313e12c5d1SDavid du Colombier 	return p;
323e12c5d1SDavid du Colombier }
333e12c5d1SDavid du Colombier void pushword(char *wd)
343e12c5d1SDavid du Colombier {
353e12c5d1SDavid du Colombier 	if(runq->argv==0) panic("pushword but no argv!", 0);
363e12c5d1SDavid du Colombier 	runq->argv->words=newword(wd, runq->argv->words);
373e12c5d1SDavid du Colombier }
383e12c5d1SDavid du Colombier void popword(void){
393e12c5d1SDavid du Colombier 	word *p;
403e12c5d1SDavid du Colombier 	if(runq->argv==0) panic("popword but no argv!", 0);
413e12c5d1SDavid du Colombier 	p=runq->argv->words;
423e12c5d1SDavid du Colombier 	if(p==0) panic("popword but no word!", 0);
433e12c5d1SDavid du Colombier 	runq->argv->words=p->next;
443e12c5d1SDavid du Colombier 	efree(p->word);
453e12c5d1SDavid du Colombier 	efree((char *)p);
463e12c5d1SDavid du Colombier }
473e12c5d1SDavid du Colombier void freelist(word *w)
483e12c5d1SDavid du Colombier {
493e12c5d1SDavid du Colombier 	word *nw;
503e12c5d1SDavid du Colombier 	while(w){
513e12c5d1SDavid du Colombier 		nw=w->next;
523e12c5d1SDavid du Colombier 		efree(w->word);
533e12c5d1SDavid du Colombier 		efree((char *)w);
543e12c5d1SDavid du Colombier 		w=nw;
553e12c5d1SDavid du Colombier 	}
563e12c5d1SDavid du Colombier }
573e12c5d1SDavid du Colombier void pushlist(void){
583e12c5d1SDavid du Colombier 	list *p=new(list);
593e12c5d1SDavid du Colombier 	p->next=runq->argv;
603e12c5d1SDavid du Colombier 	p->words=0;
613e12c5d1SDavid du Colombier 	runq->argv=p;
623e12c5d1SDavid du Colombier }
633e12c5d1SDavid du Colombier void poplist(void){
643e12c5d1SDavid du Colombier 	list *p=runq->argv;
653e12c5d1SDavid du Colombier 	if(p==0) panic("poplist but no argv", 0);
663e12c5d1SDavid du Colombier 	freelist(p->words);
673e12c5d1SDavid du Colombier 	runq->argv=p->next;
683e12c5d1SDavid du Colombier 	efree((char *)p);
693e12c5d1SDavid du Colombier }
703e12c5d1SDavid du Colombier int count(word *w)
713e12c5d1SDavid du Colombier {
723e12c5d1SDavid du Colombier 	int n;
733e12c5d1SDavid du Colombier 	for(n=0;w;n++) w=w->next;
743e12c5d1SDavid du Colombier 	return n;
753e12c5d1SDavid du Colombier }
763e12c5d1SDavid du Colombier void pushredir(int type, int from, int to){
773e12c5d1SDavid du Colombier 	redir * rp=new(redir);
783e12c5d1SDavid du Colombier 	rp->type=type;
793e12c5d1SDavid du Colombier 	rp->from=from;
803e12c5d1SDavid du Colombier 	rp->to=to;
813e12c5d1SDavid du Colombier 	rp->next=runq->redir;
823e12c5d1SDavid du Colombier 	runq->redir=rp;
833e12c5d1SDavid du Colombier }
843e12c5d1SDavid du Colombier var *newvar(char *name, var *next)
853e12c5d1SDavid du Colombier {
863e12c5d1SDavid du Colombier 	var *v=new(var);
873e12c5d1SDavid du Colombier 	v->name=name;
883e12c5d1SDavid du Colombier 	v->val=0;
893e12c5d1SDavid du Colombier 	v->fn=0;
903e12c5d1SDavid du Colombier 	v->changed=0;
913e12c5d1SDavid du Colombier 	v->fnchanged=0;
923e12c5d1SDavid du Colombier 	v->next=next;
933e12c5d1SDavid du Colombier 	return v;
943e12c5d1SDavid du Colombier }
953e12c5d1SDavid du Colombier /*
963e12c5d1SDavid du Colombier  * get command line flags, initialize keywords & traps.
973e12c5d1SDavid du Colombier  * get values from environment.
983e12c5d1SDavid du Colombier  * set $pid, $cflag, $*
993e12c5d1SDavid du Colombier  * fabricate bootstrap code and start it (*=(argv);. /usr/lib/rcmain $*)
1003e12c5d1SDavid du Colombier  * start interpreting code
1013e12c5d1SDavid du Colombier  */
1027dd7cddfSDavid du Colombier void main(int argc, char *argv[])
1033e12c5d1SDavid du Colombier {
1043e12c5d1SDavid du Colombier 	code bootstrap[17];
105*9a747e4fSDavid du Colombier 	char num[12], *rcmain;
1063e12c5d1SDavid du Colombier 	int i;
107*9a747e4fSDavid du Colombier 	argc=getflags(argc, argv, "srdiIlxepvVc:1m:1[command]", 1);
1083e12c5d1SDavid du Colombier 	if(argc==-1) usage("[file [arg ...]]");
1093e12c5d1SDavid du Colombier 	if(argv[0][0]=='-') flag['l']=flagset;
1103e12c5d1SDavid du Colombier 	if(flag['I']) flag['i'] = 0;
1117dd7cddfSDavid du Colombier 	else if(flag['i']==0 && argc==1 && Isatty(0)) flag['i'] = flagset;
112*9a747e4fSDavid du Colombier 	rcmain=flag['m']?flag['m'][0]:Rcmain;
1133e12c5d1SDavid du Colombier 	err=openfd(2);
1143e12c5d1SDavid du Colombier 	kinit();
1153e12c5d1SDavid du Colombier 	Trapinit();
1163e12c5d1SDavid du Colombier 	Vinit();
1173e12c5d1SDavid du Colombier 	itoa(num, mypid=getpid());
1183e12c5d1SDavid du Colombier 	setvar("pid", newword(num, (word *)0));
1193e12c5d1SDavid du Colombier 	setvar("cflag", flag['c']?newword(flag['c'][0], (word *)0)
1203e12c5d1SDavid du Colombier 				:(word *)0);
121219b2ee8SDavid du Colombier 	setvar("rcname", newword(argv[0], (word *)0));
1223e12c5d1SDavid du Colombier 	i=0;
1233e12c5d1SDavid du Colombier 	bootstrap[i++].i=1;
1243e12c5d1SDavid du Colombier 	bootstrap[i++].f=Xmark;
1253e12c5d1SDavid du Colombier 	bootstrap[i++].f=Xword;
1263e12c5d1SDavid du Colombier 	bootstrap[i++].s="*";
1273e12c5d1SDavid du Colombier 	bootstrap[i++].f=Xassign;
1283e12c5d1SDavid du Colombier 	bootstrap[i++].f=Xmark;
1293e12c5d1SDavid du Colombier 	bootstrap[i++].f=Xmark;
1303e12c5d1SDavid du Colombier 	bootstrap[i++].f=Xword;
1313e12c5d1SDavid du Colombier 	bootstrap[i++].s="*";
1323e12c5d1SDavid du Colombier 	bootstrap[i++].f=Xdol;
1333e12c5d1SDavid du Colombier 	bootstrap[i++].f=Xword;
134*9a747e4fSDavid du Colombier 	bootstrap[i++].s=rcmain;
1353e12c5d1SDavid du Colombier 	bootstrap[i++].f=Xword;
1363e12c5d1SDavid du Colombier 	bootstrap[i++].s=".";
1373e12c5d1SDavid du Colombier 	bootstrap[i++].f=Xsimple;
1383e12c5d1SDavid du Colombier 	bootstrap[i++].f=Xexit;
1393e12c5d1SDavid du Colombier 	bootstrap[i].i=0;
1403e12c5d1SDavid du Colombier 	start(bootstrap, 1, (var *)0);
1413e12c5d1SDavid du Colombier 	/* prime bootstrap argv */
1423e12c5d1SDavid du Colombier 	pushlist();
143*9a747e4fSDavid du Colombier 	argv0 = strdup(argv[0]);
1443e12c5d1SDavid du Colombier 	for(i=argc-1;i!=0;--i) pushword(argv[i]);
1453e12c5d1SDavid du Colombier 	for(;;){
1463e12c5d1SDavid du Colombier 		if(flag['r']) pfnc(err, runq);
1473e12c5d1SDavid du Colombier 		runq->pc++;
1483e12c5d1SDavid du Colombier 		(*runq->code[runq->pc-1].f)();
1493e12c5d1SDavid du Colombier 		if(ntrap) dotrap();
1503e12c5d1SDavid du Colombier 	}
1513e12c5d1SDavid du Colombier }
1523e12c5d1SDavid du Colombier /*
1533e12c5d1SDavid du Colombier  * Opcode routines
1543e12c5d1SDavid du Colombier  * Arguments on stack (...)
1553e12c5d1SDavid du Colombier  * Arguments in line [...]
1563e12c5d1SDavid du Colombier  * Code in line with jump around {...}
1573e12c5d1SDavid du Colombier  *
1583e12c5d1SDavid du Colombier  * Xappend(file)[fd]			open file to append
1593e12c5d1SDavid du Colombier  * Xassign(name, val)			assign val to name
1603e12c5d1SDavid du Colombier  * Xasync{... Xexit}			make thread for {}, no wait
1613e12c5d1SDavid du Colombier  * Xbackq{... Xreturn}			make thread for {}, push stdout
1623e12c5d1SDavid du Colombier  * Xbang				complement condition
1633e12c5d1SDavid du Colombier  * Xcase(pat, value){...}		exec code on match, leave (value) on
1643e12c5d1SDavid du Colombier  * 					stack
1653e12c5d1SDavid du Colombier  * Xclose[i]				close file descriptor
1663e12c5d1SDavid du Colombier  * Xconc(left, right)			concatenate, push results
1673e12c5d1SDavid du Colombier  * Xcount(name)				push var count
1683e12c5d1SDavid du Colombier  * Xdelfn(name)				delete function definition
1693e12c5d1SDavid du Colombier  * Xdeltraps(names)			delete named traps
1703e12c5d1SDavid du Colombier  * Xdol(name)				get variable value
1713e12c5d1SDavid du Colombier  * Xqdol(name)				concatenate variable components
1723e12c5d1SDavid du Colombier  * Xdup[i j]				dup file descriptor
1733e12c5d1SDavid du Colombier  * Xexit				rc exits with status
1743e12c5d1SDavid du Colombier  * Xfalse{...}				execute {} if false
1753e12c5d1SDavid du Colombier  * Xfn(name){... Xreturn}			define function
1763e12c5d1SDavid du Colombier  * Xfor(var, list){... Xreturn}		for loop
1773e12c5d1SDavid du Colombier  * Xjump[addr]				goto
1783e12c5d1SDavid du Colombier  * Xlocal(name, val)			create local variable, assign value
1793e12c5d1SDavid du Colombier  * Xmark				mark stack
1803e12c5d1SDavid du Colombier  * Xmatch(pat, str)			match pattern, set status
1813e12c5d1SDavid du Colombier  * Xpipe[i j]{... Xreturn}{... Xreturn}	construct a pipe between 2 new threads,
1823e12c5d1SDavid du Colombier  * 					wait for both
1833e12c5d1SDavid du Colombier  * Xpipefd[type]{... Xreturn}		connect {} to pipe (input or output,
1843e12c5d1SDavid du Colombier  * 					depending on type), push /dev/fd/??
1853e12c5d1SDavid du Colombier  * Xpopm(value)				pop value from stack
1863e12c5d1SDavid du Colombier  * Xread(file)[fd]			open file to read
1873e12c5d1SDavid du Colombier  * Xsettraps(names){... Xreturn}		define trap functions
1883e12c5d1SDavid du Colombier  * Xshowtraps				print trap list
1893e12c5d1SDavid du Colombier  * Xsimple(args)			run command and wait
1903e12c5d1SDavid du Colombier  * Xreturn				kill thread
1913e12c5d1SDavid du Colombier  * Xsubshell{... Xexit}			execute {} in a subshell and wait
1923e12c5d1SDavid du Colombier  * Xtrue{...}				execute {} if true
1933e12c5d1SDavid du Colombier  * Xunlocal				delete local variable
1943e12c5d1SDavid du Colombier  * Xword[string]			push string
1953e12c5d1SDavid du Colombier  * Xwrite(file)[fd]			open file to write
1963e12c5d1SDavid du Colombier  */
1973e12c5d1SDavid du Colombier void Xappend(void){
1983e12c5d1SDavid du Colombier 	char *file;
1993e12c5d1SDavid du Colombier 	int f;
2003e12c5d1SDavid du Colombier 	switch(count(runq->argv->words)){
201*9a747e4fSDavid du Colombier 	default: Xerror1(">> requires singleton"); return;
202*9a747e4fSDavid du Colombier 	case 0: Xerror1(">> requires file"); return;
2033e12c5d1SDavid du Colombier 	case 1: break;
2043e12c5d1SDavid du Colombier 	}
2053e12c5d1SDavid du Colombier 	file=runq->argv->words->word;
2063e12c5d1SDavid du Colombier 	if((f=open(file, 1))<0 && (f=Creat(file))<0){
2077dd7cddfSDavid du Colombier 		pfmt(err, "%s: ", file);
2087dd7cddfSDavid du Colombier 		Xerror("can't open");
2093e12c5d1SDavid du Colombier 		return;
2103e12c5d1SDavid du Colombier 	}
2113e12c5d1SDavid du Colombier 	Seek(f, 0L, 2);
2123e12c5d1SDavid du Colombier 	pushredir(ROPEN, f, runq->code[runq->pc].i);
2133e12c5d1SDavid du Colombier 	runq->pc++;
2143e12c5d1SDavid du Colombier 	poplist();
2153e12c5d1SDavid du Colombier }
2163e12c5d1SDavid du Colombier void Xasync(void){
2173e12c5d1SDavid du Colombier 	int null=open("/dev/null", 0);
2183e12c5d1SDavid du Colombier 	int pid;
2193e12c5d1SDavid du Colombier 	char npid[10];
2203e12c5d1SDavid du Colombier 	if(null<0){
2217dd7cddfSDavid du Colombier 		Xerror("Can't open /dev/null\n");
2223e12c5d1SDavid du Colombier 		return;
2233e12c5d1SDavid du Colombier 	}
224219b2ee8SDavid du Colombier 	switch(pid=rfork(RFFDG|RFPROC|RFNOTEG)){
2253e12c5d1SDavid du Colombier 	case -1:
2263e12c5d1SDavid du Colombier 		close(null);
2277dd7cddfSDavid du Colombier 		Xerror("try again");
2283e12c5d1SDavid du Colombier 		break;
2293e12c5d1SDavid du Colombier 	case 0:
2303e12c5d1SDavid du Colombier 		pushredir(ROPEN, null, 0);
2313e12c5d1SDavid du Colombier 		start(runq->code, runq->pc+1, runq->local);
2323e12c5d1SDavid du Colombier 		runq->ret=0;
2333e12c5d1SDavid du Colombier 		break;
2343e12c5d1SDavid du Colombier 	default:
2353e12c5d1SDavid du Colombier 		close(null);
2363e12c5d1SDavid du Colombier 		runq->pc=runq->code[runq->pc].i;
2373e12c5d1SDavid du Colombier 		itoa(npid, pid);
2383e12c5d1SDavid du Colombier 		setvar("apid", newword(npid, (word *)0));
2393e12c5d1SDavid du Colombier 		break;
2403e12c5d1SDavid du Colombier 	}
2413e12c5d1SDavid du Colombier }
242219b2ee8SDavid du Colombier void Xsettrue(void){
243219b2ee8SDavid du Colombier 	setstatus("");
244219b2ee8SDavid du Colombier }
2453e12c5d1SDavid du Colombier void Xbang(void){
2463e12c5d1SDavid du Colombier 	setstatus(truestatus()?"false":"");
2473e12c5d1SDavid du Colombier }
2483e12c5d1SDavid du Colombier void Xclose(void){
2493e12c5d1SDavid du Colombier 	pushredir(RCLOSE, runq->code[runq->pc].i, 0);
2503e12c5d1SDavid du Colombier 	runq->pc++;
2513e12c5d1SDavid du Colombier }
2523e12c5d1SDavid du Colombier void Xdup(void){
2533e12c5d1SDavid du Colombier 	pushredir(RDUP, runq->code[runq->pc].i, runq->code[runq->pc+1].i);
2543e12c5d1SDavid du Colombier 	runq->pc+=2;
2553e12c5d1SDavid du Colombier }
256219b2ee8SDavid du Colombier void Xeflag(void){
257219b2ee8SDavid du Colombier 	if(eflagok && !truestatus()) Xexit();
258219b2ee8SDavid du Colombier }
2593e12c5d1SDavid du Colombier void Xexit(void){
2603e12c5d1SDavid du Colombier 	struct var *trapreq;
2613e12c5d1SDavid du Colombier 	struct word *starval;
2623e12c5d1SDavid du Colombier 	static int beenhere=0;
2633e12c5d1SDavid du Colombier 	if(getpid()==mypid && !beenhere){
2643e12c5d1SDavid du Colombier 		trapreq=vlook("sigexit");
2653e12c5d1SDavid du Colombier 		if(trapreq->fn){
2663e12c5d1SDavid du Colombier 			beenhere=1;
2673e12c5d1SDavid du Colombier 			--runq->pc;
268219b2ee8SDavid du Colombier 			starval=vlook("*")->val;
2693e12c5d1SDavid du Colombier 			start(trapreq->fn, trapreq->pc, (struct var *)0);
2703e12c5d1SDavid du Colombier 			runq->local=newvar(strdup("*"), runq->local);
2713e12c5d1SDavid du Colombier 			runq->local->val=copywords(starval, (struct word *)0);
2723e12c5d1SDavid du Colombier 			runq->local->changed=1;
2733e12c5d1SDavid du Colombier 			runq->redir=runq->startredir=0;
2743e12c5d1SDavid du Colombier 			return;
2753e12c5d1SDavid du Colombier 		}
2763e12c5d1SDavid du Colombier 	}
2773e12c5d1SDavid du Colombier 	Exit(getstatus());
2783e12c5d1SDavid du Colombier }
2793e12c5d1SDavid du Colombier void Xfalse(void){
2803e12c5d1SDavid du Colombier 	if(truestatus()) runq->pc=runq->code[runq->pc].i;
2813e12c5d1SDavid du Colombier 	else runq->pc++;
2823e12c5d1SDavid du Colombier }
2833e12c5d1SDavid du Colombier int ifnot;		/* dynamic if not flag */
2843e12c5d1SDavid du Colombier void Xifnot(void){
2853e12c5d1SDavid du Colombier 	if(ifnot)
2863e12c5d1SDavid du Colombier 		runq->pc++;
2873e12c5d1SDavid du Colombier 	else
2883e12c5d1SDavid du Colombier 		runq->pc=runq->code[runq->pc].i;
2893e12c5d1SDavid du Colombier }
2903e12c5d1SDavid du Colombier void Xjump(void){
2913e12c5d1SDavid du Colombier 	runq->pc=runq->code[runq->pc].i;
2923e12c5d1SDavid du Colombier }
2933e12c5d1SDavid du Colombier void Xmark(void){
2943e12c5d1SDavid du Colombier 	pushlist();
2953e12c5d1SDavid du Colombier }
2963e12c5d1SDavid du Colombier void Xpopm(void){
2973e12c5d1SDavid du Colombier 	poplist();
2983e12c5d1SDavid du Colombier }
2993e12c5d1SDavid du Colombier void Xread(void){
3003e12c5d1SDavid du Colombier 	char *file;
3013e12c5d1SDavid du Colombier 	int f;
3023e12c5d1SDavid du Colombier 	switch(count(runq->argv->words)){
303*9a747e4fSDavid du Colombier 	default: Xerror1("< requires singleton\n"); return;
304*9a747e4fSDavid du Colombier 	case 0: Xerror1("< requires file\n"); return;
3053e12c5d1SDavid du Colombier 	case 1: break;
3063e12c5d1SDavid du Colombier 	}
3073e12c5d1SDavid du Colombier 	file=runq->argv->words->word;
3083e12c5d1SDavid du Colombier 	if((f=open(file, 0))<0){
3097dd7cddfSDavid du Colombier 		pfmt(err, "%s: ", file);
3107dd7cddfSDavid du Colombier 		Xerror("can't open");
3113e12c5d1SDavid du Colombier 		return;
3123e12c5d1SDavid du Colombier 	}
3133e12c5d1SDavid du Colombier 	pushredir(ROPEN, f, runq->code[runq->pc].i);
3143e12c5d1SDavid du Colombier 	runq->pc++;
3153e12c5d1SDavid du Colombier 	poplist();
3163e12c5d1SDavid du Colombier }
3173e12c5d1SDavid du Colombier void turfredir(void){
3183e12c5d1SDavid du Colombier 	while(runq->redir!=runq->startredir)
3193e12c5d1SDavid du Colombier 		Xpopredir();
3203e12c5d1SDavid du Colombier }
3213e12c5d1SDavid du Colombier void Xpopredir(void){
3223e12c5d1SDavid du Colombier 	struct redir *rp=runq->redir;
3233e12c5d1SDavid du Colombier 	if(rp==0) panic("turfredir null!", 0);
3243e12c5d1SDavid du Colombier 	runq->redir=rp->next;
3253e12c5d1SDavid du Colombier 	if(rp->type==ROPEN) close(rp->from);
3263e12c5d1SDavid du Colombier 	efree((char *)rp);
3273e12c5d1SDavid du Colombier }
3283e12c5d1SDavid du Colombier void Xreturn(void){
3293e12c5d1SDavid du Colombier 	struct thread *p=runq;
3303e12c5d1SDavid du Colombier 	turfredir();
3313e12c5d1SDavid du Colombier 	while(p->argv) poplist();
3323e12c5d1SDavid du Colombier 	codefree(p->code);
3333e12c5d1SDavid du Colombier 	runq=p->ret;
3343e12c5d1SDavid du Colombier 	efree((char *)p);
3353e12c5d1SDavid du Colombier 	if(runq==0) Exit(getstatus());
3363e12c5d1SDavid du Colombier }
3373e12c5d1SDavid du Colombier void Xtrue(void){
3383e12c5d1SDavid du Colombier 	if(truestatus()) runq->pc++;
3393e12c5d1SDavid du Colombier 	else runq->pc=runq->code[runq->pc].i;
3403e12c5d1SDavid du Colombier }
3413e12c5d1SDavid du Colombier void Xif(void){
3423e12c5d1SDavid du Colombier 	ifnot=1;
3433e12c5d1SDavid du Colombier 	if(truestatus()) runq->pc++;
3443e12c5d1SDavid du Colombier 	else runq->pc=runq->code[runq->pc].i;
3453e12c5d1SDavid du Colombier }
3463e12c5d1SDavid du Colombier void Xwastrue(void){
3473e12c5d1SDavid du Colombier 	ifnot=0;
3483e12c5d1SDavid du Colombier }
3493e12c5d1SDavid du Colombier void Xword(void){
3503e12c5d1SDavid du Colombier 	pushword(runq->code[runq->pc++].s);
3513e12c5d1SDavid du Colombier }
3523e12c5d1SDavid du Colombier void Xwrite(void){
3533e12c5d1SDavid du Colombier 	char *file;
3543e12c5d1SDavid du Colombier 	int f;
3553e12c5d1SDavid du Colombier 	switch(count(runq->argv->words)){
356*9a747e4fSDavid du Colombier 	default: Xerror1("> requires singleton\n"); return;
357*9a747e4fSDavid du Colombier 	case 0: Xerror1("> requires file\n"); return;
3583e12c5d1SDavid du Colombier 	case 1: break;
3593e12c5d1SDavid du Colombier 	}
3603e12c5d1SDavid du Colombier 	file=runq->argv->words->word;
3613e12c5d1SDavid du Colombier 	if((f=Creat(file))<0){
3627dd7cddfSDavid du Colombier 		pfmt(err, "%s: ", file);
3637dd7cddfSDavid du Colombier 		Xerror("can't open");
3643e12c5d1SDavid du Colombier 		return;
3653e12c5d1SDavid du Colombier 	}
3663e12c5d1SDavid du Colombier 	pushredir(ROPEN, f, runq->code[runq->pc].i);
3673e12c5d1SDavid du Colombier 	runq->pc++;
3683e12c5d1SDavid du Colombier 	poplist();
3693e12c5d1SDavid du Colombier }
3703e12c5d1SDavid du Colombier char *list2str(word *words){
3713e12c5d1SDavid du Colombier 	char *value, *s, *t;
3723e12c5d1SDavid du Colombier 	int len=0;
3733e12c5d1SDavid du Colombier 	word *ap;
3743e12c5d1SDavid du Colombier 	for(ap=words;ap;ap=ap->next)
3753e12c5d1SDavid du Colombier 		len+=1+strlen(ap->word);
3763e12c5d1SDavid du Colombier 	value=emalloc(len+1);
3773e12c5d1SDavid du Colombier 	s=value;
3783e12c5d1SDavid du Colombier 	for(ap=words;ap;ap=ap->next){
3793e12c5d1SDavid du Colombier 		for(t=ap->word;*t;) *s++=*t++;
3803e12c5d1SDavid du Colombier 		*s++=' ';
3813e12c5d1SDavid du Colombier 	}
3823e12c5d1SDavid du Colombier 	if(s==value) *s='\0';
3833e12c5d1SDavid du Colombier 	else s[-1]='\0';
3843e12c5d1SDavid du Colombier 	return value;
3853e12c5d1SDavid du Colombier }
3863e12c5d1SDavid du Colombier void Xmatch(void){
3873e12c5d1SDavid du Colombier 	word *p;
3883e12c5d1SDavid du Colombier 	char *subject;
3893e12c5d1SDavid du Colombier 	subject=list2str(runq->argv->words);
3903e12c5d1SDavid du Colombier 	setstatus("no match");
3913e12c5d1SDavid du Colombier 	for(p=runq->argv->next->words;p;p=p->next)
3923e12c5d1SDavid du Colombier 		if(match(subject, p->word, '\0')){
3933e12c5d1SDavid du Colombier 			setstatus("");
3943e12c5d1SDavid du Colombier 			break;
3953e12c5d1SDavid du Colombier 		}
3963e12c5d1SDavid du Colombier 	efree(subject);
3973e12c5d1SDavid du Colombier 	poplist();
3983e12c5d1SDavid du Colombier 	poplist();
3993e12c5d1SDavid du Colombier }
4003e12c5d1SDavid du Colombier void Xcase(void){
4013e12c5d1SDavid du Colombier 	word *p;
4023e12c5d1SDavid du Colombier 	char *s;
4033e12c5d1SDavid du Colombier 	int ok=0;
4043e12c5d1SDavid du Colombier 	s=list2str(runq->argv->next->words);
4053e12c5d1SDavid du Colombier 	for(p=runq->argv->words;p;p=p->next){
4063e12c5d1SDavid du Colombier 		if(match(s, p->word, '\0')){
4073e12c5d1SDavid du Colombier 			ok=1;
4083e12c5d1SDavid du Colombier 			break;
4093e12c5d1SDavid du Colombier 		}
4103e12c5d1SDavid du Colombier 	}
4113e12c5d1SDavid du Colombier 	efree(s);
4123e12c5d1SDavid du Colombier 	if(ok)
4133e12c5d1SDavid du Colombier 		runq->pc++;
4143e12c5d1SDavid du Colombier 	else
4153e12c5d1SDavid du Colombier 		runq->pc=runq->code[runq->pc].i;
4163e12c5d1SDavid du Colombier 	poplist();
4173e12c5d1SDavid du Colombier }
4183e12c5d1SDavid du Colombier word *conclist(word *lp, word *rp, word *tail)
4193e12c5d1SDavid du Colombier {
4203e12c5d1SDavid du Colombier 	char *buf;
4213e12c5d1SDavid du Colombier 	word *v;
4223e12c5d1SDavid du Colombier 	if(lp->next || rp->next)
4233e12c5d1SDavid du Colombier 		tail=conclist(lp->next==0?lp:lp->next, rp->next==0?rp:rp->next,
4243e12c5d1SDavid du Colombier 			tail);
4253e12c5d1SDavid du Colombier 	buf=emalloc(strlen(lp->word)+strlen(rp->word)+1);
4263e12c5d1SDavid du Colombier 	strcpy(buf, lp->word);
4273e12c5d1SDavid du Colombier 	strcat(buf, rp->word);
4283e12c5d1SDavid du Colombier 	v=newword(buf, tail);
4293e12c5d1SDavid du Colombier 	efree(buf);
4303e12c5d1SDavid du Colombier 	return v;
4313e12c5d1SDavid du Colombier }
4323e12c5d1SDavid du Colombier void Xconc(void){
4333e12c5d1SDavid du Colombier 	word *lp=runq->argv->words;
4343e12c5d1SDavid du Colombier 	word *rp=runq->argv->next->words;
4353e12c5d1SDavid du Colombier 	word *vp=runq->argv->next->next->words;
4363e12c5d1SDavid du Colombier 	int lc=count(lp), rc=count(rp);
4373e12c5d1SDavid du Colombier 	if(lc!=0 || rc!=0){
4383e12c5d1SDavid du Colombier 		if(lc==0 || rc==0){
439*9a747e4fSDavid du Colombier 			Xerror1("null list in concatenation");
4403e12c5d1SDavid du Colombier 			return;
4413e12c5d1SDavid du Colombier 		}
4423e12c5d1SDavid du Colombier 		if(lc!=1 && rc!=1 && lc!=rc){
443*9a747e4fSDavid du Colombier 			Xerror1("mismatched list lengths in concatenation");
4443e12c5d1SDavid du Colombier 			return;
4453e12c5d1SDavid du Colombier 		}
4463e12c5d1SDavid du Colombier 		vp=conclist(lp, rp, vp);
4473e12c5d1SDavid du Colombier 	}
4483e12c5d1SDavid du Colombier 	poplist();
4493e12c5d1SDavid du Colombier 	poplist();
4503e12c5d1SDavid du Colombier 	runq->argv->words=vp;
4513e12c5d1SDavid du Colombier }
4523e12c5d1SDavid du Colombier void Xassign(void){
4533e12c5d1SDavid du Colombier 	var *v;
4543e12c5d1SDavid du Colombier 	if(count(runq->argv->words)!=1){
455*9a747e4fSDavid du Colombier 		Xerror1("variable name not singleton!");
4563e12c5d1SDavid du Colombier 		return;
4573e12c5d1SDavid du Colombier 	}
4583e12c5d1SDavid du Colombier 	deglob(runq->argv->words->word);
4593e12c5d1SDavid du Colombier 	v=vlook(runq->argv->words->word);
4603e12c5d1SDavid du Colombier 	poplist();
4613e12c5d1SDavid du Colombier 	globlist();
4623e12c5d1SDavid du Colombier 	freewords(v->val);
4633e12c5d1SDavid du Colombier 	v->val=runq->argv->words;
4643e12c5d1SDavid du Colombier 	v->changed=1;
4653e12c5d1SDavid du Colombier 	runq->argv->words=0;
4663e12c5d1SDavid du Colombier 	poplist();
4673e12c5d1SDavid du Colombier }
4683e12c5d1SDavid du Colombier /*
4693e12c5d1SDavid du Colombier  * copy arglist a, adding the copy to the front of tail
4703e12c5d1SDavid du Colombier  */
4713e12c5d1SDavid du Colombier word *copywords(word *a, word *tail)
4723e12c5d1SDavid du Colombier {
4733e12c5d1SDavid du Colombier 	word *v=0, **end;
4743e12c5d1SDavid du Colombier 	for(end=&v;a;a=a->next,end=&(*end)->next)
4753e12c5d1SDavid du Colombier 		*end=newword(a->word, 0);
4763e12c5d1SDavid du Colombier 	*end=tail;
4773e12c5d1SDavid du Colombier 	return v;
4783e12c5d1SDavid du Colombier }
4793e12c5d1SDavid du Colombier void Xdol(void){
4803e12c5d1SDavid du Colombier 	word *a, *star;
4813e12c5d1SDavid du Colombier 	char *s, *t;
4823e12c5d1SDavid du Colombier 	int n;
4833e12c5d1SDavid du Colombier 	if(count(runq->argv->words)!=1){
484*9a747e4fSDavid du Colombier 		Xerror1("variable name not singleton!");
4853e12c5d1SDavid du Colombier 		return;
4863e12c5d1SDavid du Colombier 	}
4873e12c5d1SDavid du Colombier 	s=runq->argv->words->word;
4883e12c5d1SDavid du Colombier 	deglob(s);
4893e12c5d1SDavid du Colombier 	n=0;
4903e12c5d1SDavid du Colombier 	for(t=s;'0'<=*t && *t<='9';t++) n=n*10+*t-'0';
4913e12c5d1SDavid du Colombier 	a=runq->argv->next->words;
4923e12c5d1SDavid du Colombier 	if(n==0 || *t)
4933e12c5d1SDavid du Colombier 		a=copywords(vlook(s)->val, a);
4943e12c5d1SDavid du Colombier 	else{
4953e12c5d1SDavid du Colombier 		star=vlook("*")->val;
4963e12c5d1SDavid du Colombier 		if(star && 1<=n && n<=count(star)){
4973e12c5d1SDavid du Colombier 			while(--n) star=star->next;
4983e12c5d1SDavid du Colombier 			a=newword(star->word, a);
4993e12c5d1SDavid du Colombier 		}
5003e12c5d1SDavid du Colombier 	}
5013e12c5d1SDavid du Colombier 	poplist();
5023e12c5d1SDavid du Colombier 	runq->argv->words=a;
5033e12c5d1SDavid du Colombier }
5043e12c5d1SDavid du Colombier void Xqdol(void){
5053e12c5d1SDavid du Colombier 	word *a, *p;
5063e12c5d1SDavid du Colombier 	char *s;
5073e12c5d1SDavid du Colombier 	int n;
5083e12c5d1SDavid du Colombier 	if(count(runq->argv->words)!=1){
509*9a747e4fSDavid du Colombier 		Xerror1("variable name not singleton!");
5103e12c5d1SDavid du Colombier 		return;
5113e12c5d1SDavid du Colombier 	}
5123e12c5d1SDavid du Colombier 	s=runq->argv->words->word;
5133e12c5d1SDavid du Colombier 	deglob(s);
5143e12c5d1SDavid du Colombier 	a=vlook(s)->val;
5153e12c5d1SDavid du Colombier 	poplist();
5163e12c5d1SDavid du Colombier 	n=count(a);
5173e12c5d1SDavid du Colombier 	if(n==0){
5183e12c5d1SDavid du Colombier 		pushword("");
5193e12c5d1SDavid du Colombier 		return;
5203e12c5d1SDavid du Colombier 	}
5213e12c5d1SDavid du Colombier 	for(p=a;p;p=p->next) n+=strlen(p->word);
5223e12c5d1SDavid du Colombier 	s=emalloc(n);
5233e12c5d1SDavid du Colombier 	if(a){
5243e12c5d1SDavid du Colombier 		strcpy(s, a->word);
5253e12c5d1SDavid du Colombier 		for(p=a->next;p;p=p->next){
5263e12c5d1SDavid du Colombier 			strcat(s, " ");
5273e12c5d1SDavid du Colombier 			strcat(s, p->word);
5283e12c5d1SDavid du Colombier 		}
5293e12c5d1SDavid du Colombier 	}
5303e12c5d1SDavid du Colombier 	else
5313e12c5d1SDavid du Colombier 		s[0]='\0';
5323e12c5d1SDavid du Colombier 	pushword(s);
5333e12c5d1SDavid du Colombier 	efree(s);
5343e12c5d1SDavid du Colombier }
5353e12c5d1SDavid du Colombier word *subwords(word *val, int len, word *sub, word *a)
5363e12c5d1SDavid du Colombier {
5373e12c5d1SDavid du Colombier 	int n;
5383e12c5d1SDavid du Colombier 	char *s;
5393e12c5d1SDavid du Colombier 	if(!sub) return a;
5403e12c5d1SDavid du Colombier 	a=subwords(val, len, sub->next, a);
5413e12c5d1SDavid du Colombier 	s=sub->word;
5423e12c5d1SDavid du Colombier 	deglob(s);
5433e12c5d1SDavid du Colombier 	n=0;
5443e12c5d1SDavid du Colombier 	while('0'<=*s && *s<='9') n=n*10+ *s++ -'0';
5453e12c5d1SDavid du Colombier 	if(n<1 || len<n) return a;
5463e12c5d1SDavid du Colombier 	for(;n!=1;--n) val=val->next;
5473e12c5d1SDavid du Colombier 	return newword(val->word, a);
5483e12c5d1SDavid du Colombier }
5493e12c5d1SDavid du Colombier void Xsub(void){
5503e12c5d1SDavid du Colombier 	word *a, *v;
5513e12c5d1SDavid du Colombier 	char *s;
5523e12c5d1SDavid du Colombier 	if(count(runq->argv->next->words)!=1){
553*9a747e4fSDavid du Colombier 		Xerror1("variable name not singleton!");
5543e12c5d1SDavid du Colombier 		return;
5553e12c5d1SDavid du Colombier 	}
5563e12c5d1SDavid du Colombier 	s=runq->argv->next->words->word;
5573e12c5d1SDavid du Colombier 	deglob(s);
5583e12c5d1SDavid du Colombier 	a=runq->argv->next->next->words;
5593e12c5d1SDavid du Colombier 	v=vlook(s)->val;
5603e12c5d1SDavid du Colombier 	a=subwords(v, count(v), runq->argv->words, a);
5613e12c5d1SDavid du Colombier 	poplist();
5623e12c5d1SDavid du Colombier 	poplist();
5633e12c5d1SDavid du Colombier 	runq->argv->words=a;
5643e12c5d1SDavid du Colombier }
5653e12c5d1SDavid du Colombier void Xcount(void){
5663e12c5d1SDavid du Colombier 	word *a;
5673e12c5d1SDavid du Colombier 	char *s, *t;
5683e12c5d1SDavid du Colombier 	int n;
5693e12c5d1SDavid du Colombier 	char num[12];
5703e12c5d1SDavid du Colombier 	if(count(runq->argv->words)!=1){
571*9a747e4fSDavid du Colombier 		Xerror1("variable name not singleton!");
5723e12c5d1SDavid du Colombier 		return;
5733e12c5d1SDavid du Colombier 	}
5743e12c5d1SDavid du Colombier 	s=runq->argv->words->word;
5753e12c5d1SDavid du Colombier 	deglob(s);
5763e12c5d1SDavid du Colombier 	n=0;
5773e12c5d1SDavid du Colombier 	for(t=s;'0'<=*t && *t<='9';t++) n=n*10+*t-'0';
5783e12c5d1SDavid du Colombier 	if(n==0 || *t){
5793e12c5d1SDavid du Colombier 		a=vlook(s)->val;
5803e12c5d1SDavid du Colombier 		itoa(num, count(a));
5813e12c5d1SDavid du Colombier 	}
5823e12c5d1SDavid du Colombier 	else{
5833e12c5d1SDavid du Colombier 		a=vlook("*")->val;
5843e12c5d1SDavid du Colombier 		itoa(num, a && 1<=n && n<=count(a)?1:0);
5853e12c5d1SDavid du Colombier 	}
5863e12c5d1SDavid du Colombier 	poplist();
5873e12c5d1SDavid du Colombier 	pushword(num);
5883e12c5d1SDavid du Colombier }
5893e12c5d1SDavid du Colombier void Xlocal(void){
5903e12c5d1SDavid du Colombier 	if(count(runq->argv->words)!=1){
591*9a747e4fSDavid du Colombier 		Xerror1("variable name must be singleton\n");
5923e12c5d1SDavid du Colombier 		return;
5933e12c5d1SDavid du Colombier 	}
5943e12c5d1SDavid du Colombier 	deglob(runq->argv->words->word);
5953e12c5d1SDavid du Colombier 	runq->local=newvar(strdup(runq->argv->words->word), runq->local);
5963e12c5d1SDavid du Colombier 	runq->local->val=copywords(runq->argv->next->words, (word *)0);
5973e12c5d1SDavid du Colombier 	runq->local->changed=1;
5983e12c5d1SDavid du Colombier 	poplist();
5993e12c5d1SDavid du Colombier 	poplist();
6003e12c5d1SDavid du Colombier }
6013e12c5d1SDavid du Colombier void Xunlocal(void){
6023e12c5d1SDavid du Colombier 	var *v=runq->local, *hid;
6033e12c5d1SDavid du Colombier 	if(v==0) panic("Xunlocal: no locals!", 0);
6043e12c5d1SDavid du Colombier 	runq->local=v->next;
6053e12c5d1SDavid du Colombier 	hid=vlook(v->name);
6063e12c5d1SDavid du Colombier 	hid->changed=1;
6073e12c5d1SDavid du Colombier 	efree(v->name);
6083e12c5d1SDavid du Colombier 	freewords(v->val);
6093e12c5d1SDavid du Colombier 	efree((char *)v);
6103e12c5d1SDavid du Colombier }
6113e12c5d1SDavid du Colombier void freewords(word *w)
6123e12c5d1SDavid du Colombier {
6133e12c5d1SDavid du Colombier 	word *nw;
6143e12c5d1SDavid du Colombier 	while(w){
6153e12c5d1SDavid du Colombier 		efree(w->word);
6163e12c5d1SDavid du Colombier 		nw=w->next;
6173e12c5d1SDavid du Colombier 		efree((char *)w);
6183e12c5d1SDavid du Colombier 		w=nw;
6193e12c5d1SDavid du Colombier 	}
6203e12c5d1SDavid du Colombier }
6213e12c5d1SDavid du Colombier void Xfn(void){
6223e12c5d1SDavid du Colombier 	var *v;
6233e12c5d1SDavid du Colombier 	word *a;
6243e12c5d1SDavid du Colombier 	int end;
6253e12c5d1SDavid du Colombier 	end=runq->code[runq->pc].i;
6263e12c5d1SDavid du Colombier 	for(a=runq->argv->words;a;a=a->next){
6273e12c5d1SDavid du Colombier 		v=gvlook(a->word);
6283e12c5d1SDavid du Colombier 		if(v->fn) codefree(v->fn);
6293e12c5d1SDavid du Colombier 		v->fn=codecopy(runq->code);
6303e12c5d1SDavid du Colombier 		v->pc=runq->pc+2;
6313e12c5d1SDavid du Colombier 		v->fnchanged=1;
6323e12c5d1SDavid du Colombier 	}
6333e12c5d1SDavid du Colombier 	runq->pc=end;
6343e12c5d1SDavid du Colombier 	poplist();
6353e12c5d1SDavid du Colombier }
6363e12c5d1SDavid du Colombier void Xdelfn(void){
6373e12c5d1SDavid du Colombier 	var *v;
6383e12c5d1SDavid du Colombier 	word *a;
6393e12c5d1SDavid du Colombier 	for(a=runq->argv->words;a;a=a->next){
6403e12c5d1SDavid du Colombier 		v=gvlook(a->word);
6413e12c5d1SDavid du Colombier 		if(v->fn) codefree(v->fn);
6423e12c5d1SDavid du Colombier 		v->fn=0;
6433e12c5d1SDavid du Colombier 		v->fnchanged=1;
6443e12c5d1SDavid du Colombier 	}
6453e12c5d1SDavid du Colombier 	poplist();
6463e12c5d1SDavid du Colombier }
6473e12c5d1SDavid du Colombier void Xpipe(void){
6483e12c5d1SDavid du Colombier 	struct thread *p=runq;
6493e12c5d1SDavid du Colombier 	int pc=p->pc, forkid;
6503e12c5d1SDavid du Colombier 	int lfd=p->code[pc++].i;
6513e12c5d1SDavid du Colombier 	int rfd=p->code[pc++].i;
6523e12c5d1SDavid du Colombier 	int pfd[2];
6533e12c5d1SDavid du Colombier 	if(pipe(pfd)<0){
6547dd7cddfSDavid du Colombier 		Xerror("can't get pipe");
6553e12c5d1SDavid du Colombier 		return;
6563e12c5d1SDavid du Colombier 	}
6573e12c5d1SDavid du Colombier 	switch(forkid=fork()){
6583e12c5d1SDavid du Colombier 	case -1:
6597dd7cddfSDavid du Colombier 		Xerror("try again");
6603e12c5d1SDavid du Colombier 		break;
6613e12c5d1SDavid du Colombier 	case 0:
6623e12c5d1SDavid du Colombier 		start(p->code, pc+2, runq->local);
6633e12c5d1SDavid du Colombier 		runq->ret=0;
6643e12c5d1SDavid du Colombier 		close(pfd[PRD]);
6653e12c5d1SDavid du Colombier 		pushredir(ROPEN, pfd[PWR], lfd);
6663e12c5d1SDavid du Colombier 		break;
6673e12c5d1SDavid du Colombier 	default:
6683e12c5d1SDavid du Colombier 		start(p->code, p->code[pc].i, runq->local);
6693e12c5d1SDavid du Colombier 		close(pfd[PWR]);
6703e12c5d1SDavid du Colombier 		pushredir(ROPEN, pfd[PRD], rfd);
6713e12c5d1SDavid du Colombier 		p->pc=p->code[pc+1].i;
6723e12c5d1SDavid du Colombier 		p->pid=forkid;
6733e12c5d1SDavid du Colombier 		break;
6743e12c5d1SDavid du Colombier 	}
6753e12c5d1SDavid du Colombier }
6763e12c5d1SDavid du Colombier char *concstatus(char *s, char *t)
6773e12c5d1SDavid du Colombier {
6783e12c5d1SDavid du Colombier 	static char v[NSTATUS+1];
6793e12c5d1SDavid du Colombier 	int n=strlen(s);
6803e12c5d1SDavid du Colombier 	strncpy(v, s, NSTATUS);
6813e12c5d1SDavid du Colombier 	if(n<NSTATUS){
6823e12c5d1SDavid du Colombier 		v[n]='|';
6833e12c5d1SDavid du Colombier 		strncpy(v+n+1, t, NSTATUS-n-1);
6843e12c5d1SDavid du Colombier 	}
6853e12c5d1SDavid du Colombier 	v[NSTATUS]='\0';
6863e12c5d1SDavid du Colombier 	return v;
6873e12c5d1SDavid du Colombier }
6883e12c5d1SDavid du Colombier void Xpipewait(void){
6893e12c5d1SDavid du Colombier 	char status[NSTATUS+1];
6903e12c5d1SDavid du Colombier 	if(runq->pid==-1)
6913e12c5d1SDavid du Colombier 		setstatus(concstatus(runq->status, getstatus()));
6923e12c5d1SDavid du Colombier 	else{
6933e12c5d1SDavid du Colombier 		strncpy(status, getstatus(), NSTATUS);
6943e12c5d1SDavid du Colombier 		status[NSTATUS]='\0';
6953e12c5d1SDavid du Colombier 		Waitfor(runq->pid, 1);
6963e12c5d1SDavid du Colombier 		runq->pid=-1;
6973e12c5d1SDavid du Colombier 		setstatus(concstatus(getstatus(), status));
6983e12c5d1SDavid du Colombier 	}
6993e12c5d1SDavid du Colombier }
7003e12c5d1SDavid du Colombier void Xrdcmds(void){
7013e12c5d1SDavid du Colombier 	struct thread *p=runq;
7023e12c5d1SDavid du Colombier 	word *prompt;
7033e12c5d1SDavid du Colombier 	flush(err);
7043e12c5d1SDavid du Colombier 	nerror=0;
7053e12c5d1SDavid du Colombier 	if(flag['s'] && !truestatus())
7063e12c5d1SDavid du Colombier 		pfmt(err, "status=%v\n", vlook("status")->val);
7073e12c5d1SDavid du Colombier 	if(runq->iflag){
7083e12c5d1SDavid du Colombier 		prompt=vlook("prompt")->val;
7093e12c5d1SDavid du Colombier 		if(prompt)
7103e12c5d1SDavid du Colombier 			promptstr=prompt->word;
7113e12c5d1SDavid du Colombier 		else
7123e12c5d1SDavid du Colombier 			promptstr="% ";
7133e12c5d1SDavid du Colombier 	}
7143e12c5d1SDavid du Colombier 	Noerror();
7153e12c5d1SDavid du Colombier 	if(yyparse()){
7163e12c5d1SDavid du Colombier 		if(!p->iflag || p->eof && !Eintr()){
7173e12c5d1SDavid du Colombier 			if(p->cmdfile) efree(p->cmdfile);
7183e12c5d1SDavid du Colombier 			closeio(p->cmdfd);
7193e12c5d1SDavid du Colombier 			Xreturn();	/* should this be omitted? */
7203e12c5d1SDavid du Colombier 		}
7213e12c5d1SDavid du Colombier 		else{
7223e12c5d1SDavid du Colombier 			if(Eintr()){
7233e12c5d1SDavid du Colombier 				pchr(err, '\n');
7243e12c5d1SDavid du Colombier 				p->eof=0;
7253e12c5d1SDavid du Colombier 			}
7263e12c5d1SDavid du Colombier 			--p->pc;	/* go back for next command */
7273e12c5d1SDavid du Colombier 		}
7283e12c5d1SDavid du Colombier 	}
7293e12c5d1SDavid du Colombier 	else{
7307dd7cddfSDavid du Colombier 		ntrap = 0;	/* avoid double-interrupts during blocked writes */
7313e12c5d1SDavid du Colombier 		--p->pc;	/* re-execute Xrdcmds after codebuf runs */
7323e12c5d1SDavid du Colombier 		start(codebuf, 1, runq->local);
7333e12c5d1SDavid du Colombier 	}
7343e12c5d1SDavid du Colombier 	freenodes();
7353e12c5d1SDavid du Colombier }
7363e12c5d1SDavid du Colombier void Xerror(char *s)
7373e12c5d1SDavid du Colombier {
738*9a747e4fSDavid du Colombier 	if(strcmp(argv0, "rc")==0 || strcmp(argv0, "/bin/rc")==0)
739*9a747e4fSDavid du Colombier 		pfmt(err, "rc: %s: %r\n", s);
740*9a747e4fSDavid du Colombier 	else
741*9a747e4fSDavid du Colombier 		pfmt(err, "rc (%s): %s: %r\n", argv0, s);
742*9a747e4fSDavid du Colombier 	flush(err);
743*9a747e4fSDavid du Colombier 	while(!runq->iflag) Xreturn();
744*9a747e4fSDavid du Colombier }
745*9a747e4fSDavid du Colombier void Xerror1(char *s)
746*9a747e4fSDavid du Colombier {
747*9a747e4fSDavid du Colombier 	if(strcmp(argv0, "rc")==0 || strcmp(argv0, "/bin/rc")==0)
7483e12c5d1SDavid du Colombier 		pfmt(err, "rc: %s\n", s);
749*9a747e4fSDavid du Colombier 	else
750*9a747e4fSDavid du Colombier 		pfmt(err, "rc (%s): %s\n", argv0, s);
7513e12c5d1SDavid du Colombier 	flush(err);
7523e12c5d1SDavid du Colombier 	while(!runq->iflag) Xreturn();
7533e12c5d1SDavid du Colombier }
7543e12c5d1SDavid du Colombier void Xbackq(void){
7553e12c5d1SDavid du Colombier 	char wd[8193];
7563e12c5d1SDavid du Colombier 	int c;
7573e12c5d1SDavid du Colombier 	char *s, *ewd=&wd[8192], *stop;
7583e12c5d1SDavid du Colombier 	struct io *f;
7593e12c5d1SDavid du Colombier 	var *ifs=vlook("ifs");
7603e12c5d1SDavid du Colombier 	word *v, *nextv;
7613e12c5d1SDavid du Colombier 	int pfd[2];
7623e12c5d1SDavid du Colombier 	int pid;
7633e12c5d1SDavid du Colombier 	stop=ifs->val?ifs->val->word:"";
7643e12c5d1SDavid du Colombier 	if(pipe(pfd)<0){
7653e12c5d1SDavid du Colombier 		Xerror("can't make pipe");
7663e12c5d1SDavid du Colombier 		return;
7673e12c5d1SDavid du Colombier 	}
7683e12c5d1SDavid du Colombier 	switch(pid=fork()){
7693e12c5d1SDavid du Colombier 	case -1: Xerror("try again");
7703e12c5d1SDavid du Colombier 		close(pfd[PRD]);
7713e12c5d1SDavid du Colombier 		close(pfd[PWR]);
7723e12c5d1SDavid du Colombier 		return;
7733e12c5d1SDavid du Colombier 	case 0:
7743e12c5d1SDavid du Colombier 		close(pfd[PRD]);
7753e12c5d1SDavid du Colombier 		start(runq->code, runq->pc+1, runq->local);
7763e12c5d1SDavid du Colombier 		pushredir(ROPEN, pfd[PWR], 1);
7773e12c5d1SDavid du Colombier 		return;
7783e12c5d1SDavid du Colombier 	default:
7793e12c5d1SDavid du Colombier 		close(pfd[PWR]);
7803e12c5d1SDavid du Colombier 		f=openfd(pfd[PRD]);
7813e12c5d1SDavid du Colombier 		s=wd;
7823e12c5d1SDavid du Colombier 		v=0;
7833e12c5d1SDavid du Colombier 		while((c=rchr(f))!=EOF){
7843e12c5d1SDavid du Colombier 			if(strchr(stop, c) || s==ewd){
7853e12c5d1SDavid du Colombier 				if(s!=wd){
7863e12c5d1SDavid du Colombier 					*s='\0';
7873e12c5d1SDavid du Colombier 					v=newword(wd, v);
7883e12c5d1SDavid du Colombier 					s=wd;
7893e12c5d1SDavid du Colombier 				}
7903e12c5d1SDavid du Colombier 			}
7913e12c5d1SDavid du Colombier 			else *s++=c;
7923e12c5d1SDavid du Colombier 		}
7933e12c5d1SDavid du Colombier 		if(s!=wd){
7943e12c5d1SDavid du Colombier 			*s='\0';
7953e12c5d1SDavid du Colombier 			v=newword(wd, v);
7963e12c5d1SDavid du Colombier 		}
7973e12c5d1SDavid du Colombier 		closeio(f);
7983e12c5d1SDavid du Colombier 		Waitfor(pid, 0);
7993e12c5d1SDavid du Colombier 		/* v points to reversed arglist -- reverse it onto argv */
8003e12c5d1SDavid du Colombier 		while(v){
8013e12c5d1SDavid du Colombier 			nextv=v->next;
8023e12c5d1SDavid du Colombier 			v->next=runq->argv->words;
8033e12c5d1SDavid du Colombier 			runq->argv->words=v;
8043e12c5d1SDavid du Colombier 			v=nextv;
8053e12c5d1SDavid du Colombier 		}
8063e12c5d1SDavid du Colombier 		runq->pc=runq->code[runq->pc].i;
8073e12c5d1SDavid du Colombier 		return;
8083e12c5d1SDavid du Colombier 	}
8093e12c5d1SDavid du Colombier }
8103e12c5d1SDavid du Colombier /*
8113e12c5d1SDavid du Colombier  * Who should wait for the exit from the fork?
8123e12c5d1SDavid du Colombier  */
8133e12c5d1SDavid du Colombier void Xpipefd(void){
8143e12c5d1SDavid du Colombier 	struct thread *p=runq;
8153e12c5d1SDavid du Colombier 	int pc=p->pc;
8163e12c5d1SDavid du Colombier 	char name[40];
8173e12c5d1SDavid du Colombier 	int pfd[2];
8183e12c5d1SDavid du Colombier 	int sidefd, mainfd;
8193e12c5d1SDavid du Colombier 	if(pipe(pfd)<0){
8203e12c5d1SDavid du Colombier 		Xerror("can't get pipe");
8213e12c5d1SDavid du Colombier 		return;
8223e12c5d1SDavid du Colombier 	}
8233e12c5d1SDavid du Colombier 	if(p->code[pc].i==READ){
8243e12c5d1SDavid du Colombier 		sidefd=pfd[PWR];
8253e12c5d1SDavid du Colombier 		mainfd=pfd[PRD];
8263e12c5d1SDavid du Colombier 	}
8273e12c5d1SDavid du Colombier 	else{
8283e12c5d1SDavid du Colombier 		sidefd=pfd[PRD];
8293e12c5d1SDavid du Colombier 		mainfd=pfd[PWR];
8303e12c5d1SDavid du Colombier 	}
8313e12c5d1SDavid du Colombier 	switch(fork()){
8323e12c5d1SDavid du Colombier 	case -1:
8333e12c5d1SDavid du Colombier 		Xerror("try again");
8343e12c5d1SDavid du Colombier 		break;
8353e12c5d1SDavid du Colombier 	case 0:
8363e12c5d1SDavid du Colombier 		start(p->code, pc+2, runq->local);
8373e12c5d1SDavid du Colombier 		close(mainfd);
8383e12c5d1SDavid du Colombier 		pushredir(ROPEN, sidefd, p->code[pc].i==READ?1:0);
8393e12c5d1SDavid du Colombier 		runq->ret=0;
8403e12c5d1SDavid du Colombier 		break;
8413e12c5d1SDavid du Colombier 	default:
8423e12c5d1SDavid du Colombier 		close(sidefd);
8433e12c5d1SDavid du Colombier 		pushredir(ROPEN, mainfd, mainfd);	/* isn't this a noop? */
8443e12c5d1SDavid du Colombier 		strcpy(name, Fdprefix);
8453e12c5d1SDavid du Colombier 		itoa(name+strlen(name), mainfd);
8463e12c5d1SDavid du Colombier 		pushword(name);
8473e12c5d1SDavid du Colombier 		p->pc=p->code[pc+1].i;
8483e12c5d1SDavid du Colombier 		break;
8493e12c5d1SDavid du Colombier 	}
8503e12c5d1SDavid du Colombier }
8513e12c5d1SDavid du Colombier void Xsubshell(void){
8523e12c5d1SDavid du Colombier 	int pid;
8533e12c5d1SDavid du Colombier 	switch(pid=fork()){
8543e12c5d1SDavid du Colombier 	case -1:
8553e12c5d1SDavid du Colombier 		Xerror("try again");
8563e12c5d1SDavid du Colombier 		break;
8573e12c5d1SDavid du Colombier 	case 0:
8583e12c5d1SDavid du Colombier 		start(runq->code, runq->pc+1, runq->local);
8593e12c5d1SDavid du Colombier 		runq->ret=0;
8603e12c5d1SDavid du Colombier 		break;
8613e12c5d1SDavid du Colombier 	default:
8623e12c5d1SDavid du Colombier 		Waitfor(pid, 1);
8633e12c5d1SDavid du Colombier 		runq->pc=runq->code[runq->pc].i;
8643e12c5d1SDavid du Colombier 		break;
8653e12c5d1SDavid du Colombier 	}
8663e12c5d1SDavid du Colombier }
8673e12c5d1SDavid du Colombier void setstatus(char *s)
8683e12c5d1SDavid du Colombier {
8693e12c5d1SDavid du Colombier 	setvar("status", newword(s, (word *)0));
8703e12c5d1SDavid du Colombier }
8713e12c5d1SDavid du Colombier char *getstatus(void){
8723e12c5d1SDavid du Colombier 	var *status=vlook("status");
8733e12c5d1SDavid du Colombier 	return status->val?status->val->word:"";
8743e12c5d1SDavid du Colombier }
8753e12c5d1SDavid du Colombier int truestatus(void){
8763e12c5d1SDavid du Colombier 	char *s;
8773e12c5d1SDavid du Colombier 	for(s=getstatus();*s;s++)
8783e12c5d1SDavid du Colombier 		if(*s!='|' && *s!='0') return 0;
8793e12c5d1SDavid du Colombier 	return 1;
8803e12c5d1SDavid du Colombier }
8813e12c5d1SDavid du Colombier void Xdelhere(void){
8823e12c5d1SDavid du Colombier 	Unlink(runq->code[runq->pc++].s);
8833e12c5d1SDavid du Colombier }
8843e12c5d1SDavid du Colombier void Xfor(void){
8853e12c5d1SDavid du Colombier 	if(runq->argv->words==0){
8863e12c5d1SDavid du Colombier 		poplist();
8873e12c5d1SDavid du Colombier 		runq->pc=runq->code[runq->pc].i;
8883e12c5d1SDavid du Colombier 	}
8893e12c5d1SDavid du Colombier 	else{
8903e12c5d1SDavid du Colombier 		freelist(runq->local->val);
8913e12c5d1SDavid du Colombier 		runq->local->val=runq->argv->words;
8923e12c5d1SDavid du Colombier 		runq->local->changed=1;
8933e12c5d1SDavid du Colombier 		runq->argv->words=runq->argv->words->next;
8943e12c5d1SDavid du Colombier 		runq->local->val->next=0;
8953e12c5d1SDavid du Colombier 		runq->pc++;
8963e12c5d1SDavid du Colombier 	}
8973e12c5d1SDavid du Colombier }
8983e12c5d1SDavid du Colombier void Xglob(void){
8993e12c5d1SDavid du Colombier 	globlist();
9003e12c5d1SDavid du Colombier }
901