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