xref: /plan9/sys/src/cmd/rc/exec.c (revision 4e3613ab15c331a9ada113286cc0f2a35bc0373d)
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
start(code * c,int pc,var * local)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*
newword(char * wd,word * next)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
pushword(char * wd)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
popword(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
freelist(word * w)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
pushlist(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
poplist(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
count(word * w)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
pushredir(int type,int from,int to)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*
newvar(char * name,var * next)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
main(int argc,char * argv[])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;
157*4e3613abSDavid du Colombier 	memset(bootstrap, 0, sizeof bootstrap);
1583e12c5d1SDavid du Colombier 	bootstrap[i++].i = 1;
1593e12c5d1SDavid du Colombier 	bootstrap[i++].f = Xmark;
1603e12c5d1SDavid du Colombier 	bootstrap[i++].f = Xword;
1613e12c5d1SDavid du Colombier 	bootstrap[i++].s="*";
1623e12c5d1SDavid du Colombier 	bootstrap[i++].f = Xassign;
1633e12c5d1SDavid du Colombier 	bootstrap[i++].f = Xmark;
1643e12c5d1SDavid du Colombier 	bootstrap[i++].f = Xmark;
1653e12c5d1SDavid du Colombier 	bootstrap[i++].f = Xword;
1663e12c5d1SDavid du Colombier 	bootstrap[i++].s="*";
1673e12c5d1SDavid du Colombier 	bootstrap[i++].f = Xdol;
1683e12c5d1SDavid du Colombier 	bootstrap[i++].f = Xword;
1699a747e4fSDavid du Colombier 	bootstrap[i++].s = rcmain;
1703e12c5d1SDavid du Colombier 	bootstrap[i++].f = Xword;
1713e12c5d1SDavid du Colombier 	bootstrap[i++].s=".";
1723e12c5d1SDavid du Colombier 	bootstrap[i++].f = Xsimple;
1733e12c5d1SDavid du Colombier 	bootstrap[i++].f = Xexit;
1743e12c5d1SDavid du Colombier 	bootstrap[i].i = 0;
1753e12c5d1SDavid du Colombier 	start(bootstrap, 1, (var *)0);
1763e12c5d1SDavid du Colombier 	/* prime bootstrap argv */
1773e12c5d1SDavid du Colombier 	pushlist();
1789a747e4fSDavid du Colombier 	argv0 = strdup(argv[0]);
1793e12c5d1SDavid du Colombier 	for(i = argc-1;i!=0;--i) pushword(argv[i]);
1803e12c5d1SDavid du Colombier 	for(;;){
181dc5a79c1SDavid du Colombier 		if(flag['r'])
182dc5a79c1SDavid du Colombier 			pfnc(err, runq);
1833e12c5d1SDavid du Colombier 		runq->pc++;
1843e12c5d1SDavid du Colombier 		(*runq->code[runq->pc-1].f)();
185dc5a79c1SDavid du Colombier 		if(ntrap)
186dc5a79c1SDavid du Colombier 			dotrap();
1873e12c5d1SDavid du Colombier 	}
1883e12c5d1SDavid du Colombier }
1893e12c5d1SDavid du Colombier /*
1903e12c5d1SDavid du Colombier  * Opcode routines
1913e12c5d1SDavid du Colombier  * Arguments on stack (...)
1923e12c5d1SDavid du Colombier  * Arguments in line [...]
1933e12c5d1SDavid du Colombier  * Code in line with jump around {...}
1943e12c5d1SDavid du Colombier  *
1953e12c5d1SDavid du Colombier  * Xappend(file)[fd]			open file to append
1963e12c5d1SDavid du Colombier  * Xassign(name, val)			assign val to name
1973e12c5d1SDavid du Colombier  * Xasync{... Xexit}			make thread for {}, no wait
1983e12c5d1SDavid du Colombier  * Xbackq{... Xreturn}			make thread for {}, push stdout
1993e12c5d1SDavid du Colombier  * Xbang				complement condition
2003e12c5d1SDavid du Colombier  * Xcase(pat, value){...}		exec code on match, leave (value) on
2013e12c5d1SDavid du Colombier  * 					stack
2023e12c5d1SDavid du Colombier  * Xclose[i]				close file descriptor
2033e12c5d1SDavid du Colombier  * Xconc(left, right)			concatenate, push results
2043e12c5d1SDavid du Colombier  * Xcount(name)				push var count
2053e12c5d1SDavid du Colombier  * Xdelfn(name)				delete function definition
206*4e3613abSDavid du Colombier  * Xdelhere
2073e12c5d1SDavid du Colombier  * Xdol(name)				get variable value
2083e12c5d1SDavid du Colombier  * Xdup[i j]				dup file descriptor
209*4e3613abSDavid du Colombier  * Xeflag
210*4e3613abSDavid du Colombier  * Xerror
2113e12c5d1SDavid du Colombier  * Xexit				rc exits with status
2123e12c5d1SDavid du Colombier  * Xfalse{...}				execute {} if false
2133e12c5d1SDavid du Colombier  * Xfn(name){... Xreturn}			define function
2143e12c5d1SDavid du Colombier  * Xfor(var, list){... Xreturn}		for loop
215*4e3613abSDavid du Colombier  * Xglob
216*4e3613abSDavid du Colombier  * Xif
217*4e3613abSDavid du Colombier  * Xifnot
2183e12c5d1SDavid du Colombier  * Xjump[addr]				goto
2193e12c5d1SDavid du Colombier  * Xlocal(name, val)			create local variable, assign value
2203e12c5d1SDavid du Colombier  * Xmark				mark stack
2213e12c5d1SDavid du Colombier  * Xmatch(pat, str)			match pattern, set status
2223e12c5d1SDavid du Colombier  * Xpipe[i j]{... Xreturn}{... Xreturn}	construct a pipe between 2 new threads,
2233e12c5d1SDavid du Colombier  * 					wait for both
2243e12c5d1SDavid du Colombier  * Xpipefd[type]{... Xreturn}		connect {} to pipe (input or output,
2253e12c5d1SDavid du Colombier  * 					depending on type), push /dev/fd/??
226*4e3613abSDavid du Colombier  * Xpipewait
2273e12c5d1SDavid du Colombier  * Xpopm(value)				pop value from stack
228*4e3613abSDavid du Colombier  * Xpopredir
229*4e3613abSDavid du Colombier  * Xrdcmds
230*4e3613abSDavid du Colombier  * Xrdfn
231119a69faSDavid du Colombier  * Xrdwr(file)[fd]			open file for reading and writing
2323e12c5d1SDavid du Colombier  * Xread(file)[fd]			open file to read
233*4e3613abSDavid du Colombier  * Xqdol(name)				concatenate variable components
2343e12c5d1SDavid du Colombier  * Xreturn				kill thread
235*4e3613abSDavid du Colombier  * Xsimple(args)			run command and wait
236*4e3613abSDavid du Colombier  * Xsub
2373e12c5d1SDavid du Colombier  * Xsubshell{... Xexit}			execute {} in a subshell and wait
2383e12c5d1SDavid du Colombier  * Xtrue{...}				execute {} if true
2393e12c5d1SDavid du Colombier  * Xunlocal				delete local variable
240*4e3613abSDavid du Colombier  * Xwastrue
2413e12c5d1SDavid du Colombier  * Xword[string]			push string
2423e12c5d1SDavid du Colombier  * Xwrite(file)[fd]			open file to write
2433e12c5d1SDavid du Colombier  */
244dc5a79c1SDavid du Colombier 
245dc5a79c1SDavid du Colombier void
Xappend(void)246dc5a79c1SDavid du Colombier Xappend(void)
247dc5a79c1SDavid du Colombier {
2483e12c5d1SDavid du Colombier 	char *file;
2493e12c5d1SDavid du Colombier 	int f;
2503e12c5d1SDavid du Colombier 	switch(count(runq->argv->words)){
251dc5a79c1SDavid du Colombier 	default:
252dc5a79c1SDavid du Colombier 		Xerror1(">> requires singleton");
253dc5a79c1SDavid du Colombier 		return;
254dc5a79c1SDavid du Colombier 	case 0:
255dc5a79c1SDavid du Colombier 		Xerror1(">> requires file");
256dc5a79c1SDavid du Colombier 		return;
257dc5a79c1SDavid du Colombier 	case 1:
258dc5a79c1SDavid du Colombier 		break;
2593e12c5d1SDavid du Colombier 	}
2603e12c5d1SDavid du Colombier 	file = runq->argv->words->word;
2613e12c5d1SDavid du Colombier 	if((f = open(file, 1))<0 && (f = Creat(file))<0){
2627dd7cddfSDavid du Colombier 		pfmt(err, "%s: ", file);
2637dd7cddfSDavid du Colombier 		Xerror("can't open");
2643e12c5d1SDavid du Colombier 		return;
2653e12c5d1SDavid du Colombier 	}
2663e12c5d1SDavid du Colombier 	Seek(f, 0L, 2);
2673e12c5d1SDavid du Colombier 	pushredir(ROPEN, f, runq->code[runq->pc].i);
2683e12c5d1SDavid du Colombier 	runq->pc++;
2693e12c5d1SDavid du Colombier 	poplist();
2703e12c5d1SDavid du Colombier }
271dc5a79c1SDavid du Colombier 
272dc5a79c1SDavid du Colombier void
Xsettrue(void)273dc5a79c1SDavid du Colombier Xsettrue(void)
274dc5a79c1SDavid du Colombier {
275219b2ee8SDavid du Colombier 	setstatus("");
276219b2ee8SDavid du Colombier }
277dc5a79c1SDavid du Colombier 
278dc5a79c1SDavid du Colombier void
Xbang(void)279dc5a79c1SDavid du Colombier Xbang(void)
280dc5a79c1SDavid du Colombier {
2813e12c5d1SDavid du Colombier 	setstatus(truestatus()?"false":"");
2823e12c5d1SDavid du Colombier }
283dc5a79c1SDavid du Colombier 
284dc5a79c1SDavid du Colombier void
Xclose(void)285dc5a79c1SDavid du Colombier Xclose(void)
286dc5a79c1SDavid du Colombier {
2873e12c5d1SDavid du Colombier 	pushredir(RCLOSE, runq->code[runq->pc].i, 0);
2883e12c5d1SDavid du Colombier 	runq->pc++;
2893e12c5d1SDavid du Colombier }
290dc5a79c1SDavid du Colombier 
291dc5a79c1SDavid du Colombier void
Xdup(void)292dc5a79c1SDavid du Colombier Xdup(void)
293dc5a79c1SDavid du Colombier {
2943e12c5d1SDavid du Colombier 	pushredir(RDUP, runq->code[runq->pc].i, runq->code[runq->pc+1].i);
2953e12c5d1SDavid du Colombier 	runq->pc+=2;
2963e12c5d1SDavid du Colombier }
297dc5a79c1SDavid du Colombier 
298dc5a79c1SDavid du Colombier void
Xeflag(void)299dc5a79c1SDavid du Colombier Xeflag(void)
300dc5a79c1SDavid du Colombier {
301219b2ee8SDavid du Colombier 	if(eflagok && !truestatus()) Xexit();
302219b2ee8SDavid du Colombier }
303dc5a79c1SDavid du Colombier 
304dc5a79c1SDavid du Colombier void
Xexit(void)305dc5a79c1SDavid du Colombier Xexit(void)
306dc5a79c1SDavid du Colombier {
3073e12c5d1SDavid du Colombier 	struct var *trapreq;
3083e12c5d1SDavid du Colombier 	struct word *starval;
3093e12c5d1SDavid du Colombier 	static int beenhere = 0;
3103e12c5d1SDavid du Colombier 	if(getpid()==mypid && !beenhere){
3113e12c5d1SDavid du Colombier 		trapreq = vlook("sigexit");
3123e12c5d1SDavid du Colombier 		if(trapreq->fn){
3133e12c5d1SDavid du Colombier 			beenhere = 1;
3143e12c5d1SDavid du Colombier 			--runq->pc;
315219b2ee8SDavid du Colombier 			starval = vlook("*")->val;
3163e12c5d1SDavid du Colombier 			start(trapreq->fn, trapreq->pc, (struct var *)0);
3173e12c5d1SDavid du Colombier 			runq->local = newvar(strdup("*"), runq->local);
3183e12c5d1SDavid du Colombier 			runq->local->val = copywords(starval, (struct word *)0);
3193e12c5d1SDavid du Colombier 			runq->local->changed = 1;
3203e12c5d1SDavid du Colombier 			runq->redir = runq->startredir = 0;
3213e12c5d1SDavid du Colombier 			return;
3223e12c5d1SDavid du Colombier 		}
3233e12c5d1SDavid du Colombier 	}
3243e12c5d1SDavid du Colombier 	Exit(getstatus());
3253e12c5d1SDavid du Colombier }
326dc5a79c1SDavid du Colombier 
327dc5a79c1SDavid du Colombier void
Xfalse(void)328dc5a79c1SDavid du Colombier Xfalse(void)
329dc5a79c1SDavid du Colombier {
3303e12c5d1SDavid du Colombier 	if(truestatus()) runq->pc = runq->code[runq->pc].i;
3313e12c5d1SDavid du Colombier 	else runq->pc++;
3323e12c5d1SDavid du Colombier }
3333e12c5d1SDavid du Colombier int ifnot;		/* dynamic if not flag */
334dc5a79c1SDavid du Colombier 
335dc5a79c1SDavid du Colombier void
Xifnot(void)336dc5a79c1SDavid du Colombier Xifnot(void)
337dc5a79c1SDavid du Colombier {
3383e12c5d1SDavid du Colombier 	if(ifnot)
3393e12c5d1SDavid du Colombier 		runq->pc++;
3403e12c5d1SDavid du Colombier 	else
3413e12c5d1SDavid du Colombier 		runq->pc = runq->code[runq->pc].i;
3423e12c5d1SDavid du Colombier }
343dc5a79c1SDavid du Colombier 
344dc5a79c1SDavid du Colombier void
Xjump(void)345dc5a79c1SDavid du Colombier Xjump(void)
346dc5a79c1SDavid du Colombier {
3473e12c5d1SDavid du Colombier 	runq->pc = runq->code[runq->pc].i;
3483e12c5d1SDavid du Colombier }
349dc5a79c1SDavid du Colombier 
350dc5a79c1SDavid du Colombier void
Xmark(void)351dc5a79c1SDavid du Colombier Xmark(void)
352dc5a79c1SDavid du Colombier {
3533e12c5d1SDavid du Colombier 	pushlist();
3543e12c5d1SDavid du Colombier }
355dc5a79c1SDavid du Colombier 
356dc5a79c1SDavid du Colombier void
Xpopm(void)357dc5a79c1SDavid du Colombier Xpopm(void)
358dc5a79c1SDavid du Colombier {
3593e12c5d1SDavid du Colombier 	poplist();
3603e12c5d1SDavid du Colombier }
361dc5a79c1SDavid du Colombier 
362dc5a79c1SDavid du Colombier void
Xread(void)363dc5a79c1SDavid du Colombier Xread(void)
364dc5a79c1SDavid du Colombier {
3653e12c5d1SDavid du Colombier 	char *file;
3663e12c5d1SDavid du Colombier 	int f;
3673e12c5d1SDavid du Colombier 	switch(count(runq->argv->words)){
368dc5a79c1SDavid du Colombier 	default:
369dc5a79c1SDavid du Colombier 		Xerror1("< requires singleton\n");
370dc5a79c1SDavid du Colombier 		return;
371dc5a79c1SDavid du Colombier 	case 0:
372dc5a79c1SDavid du Colombier 		Xerror1("< requires file\n");
373dc5a79c1SDavid du Colombier 		return;
374dc5a79c1SDavid du Colombier 	case 1:
375dc5a79c1SDavid du Colombier 		break;
3763e12c5d1SDavid du Colombier 	}
3773e12c5d1SDavid du Colombier 	file = runq->argv->words->word;
3783e12c5d1SDavid du Colombier 	if((f = open(file, 0))<0){
3797dd7cddfSDavid du Colombier 		pfmt(err, "%s: ", file);
3807dd7cddfSDavid du Colombier 		Xerror("can't open");
3813e12c5d1SDavid du Colombier 		return;
3823e12c5d1SDavid du Colombier 	}
3833e12c5d1SDavid du Colombier 	pushredir(ROPEN, f, runq->code[runq->pc].i);
3843e12c5d1SDavid du Colombier 	runq->pc++;
3853e12c5d1SDavid du Colombier 	poplist();
3863e12c5d1SDavid du Colombier }
387dc5a79c1SDavid du Colombier 
388dc5a79c1SDavid du Colombier void
Xrdwr(void)389119a69faSDavid du Colombier Xrdwr(void)
390119a69faSDavid du Colombier {
391119a69faSDavid du Colombier 	char *file;
392119a69faSDavid du Colombier 	int f;
393119a69faSDavid du Colombier 
394119a69faSDavid du Colombier 	switch(count(runq->argv->words)){
395119a69faSDavid du Colombier 	default:
396119a69faSDavid du Colombier 		Xerror1("<> requires singleton\n");
397119a69faSDavid du Colombier 		return;
398119a69faSDavid du Colombier 	case 0:
399119a69faSDavid du Colombier 		Xerror1("<> requires file\n");
400119a69faSDavid du Colombier 		return;
401119a69faSDavid du Colombier 	case 1:
402119a69faSDavid du Colombier 		break;
403119a69faSDavid du Colombier 	}
404119a69faSDavid du Colombier 	file = runq->argv->words->word;
405119a69faSDavid du Colombier 	if((f = open(file, ORDWR))<0){
406119a69faSDavid du Colombier 		pfmt(err, "%s: ", file);
407119a69faSDavid du Colombier 		Xerror("can't open");
408119a69faSDavid du Colombier 		return;
409119a69faSDavid du Colombier 	}
410119a69faSDavid du Colombier 	pushredir(ROPEN, f, runq->code[runq->pc].i);
411119a69faSDavid du Colombier 	runq->pc++;
412119a69faSDavid du Colombier 	poplist();
413119a69faSDavid du Colombier }
414119a69faSDavid du Colombier 
415119a69faSDavid du Colombier void
turfredir(void)416dc5a79c1SDavid du Colombier turfredir(void)
417dc5a79c1SDavid du Colombier {
4183e12c5d1SDavid du Colombier 	while(runq->redir!=runq->startredir)
4193e12c5d1SDavid du Colombier 		Xpopredir();
4203e12c5d1SDavid du Colombier }
421dc5a79c1SDavid du Colombier 
422dc5a79c1SDavid du Colombier void
Xpopredir(void)423dc5a79c1SDavid du Colombier Xpopredir(void)
424dc5a79c1SDavid du Colombier {
4253e12c5d1SDavid du Colombier 	struct redir *rp = runq->redir;
426dc5a79c1SDavid du Colombier 	if(rp==0)
427dc5a79c1SDavid du Colombier 		panic("turfredir null!", 0);
4283e12c5d1SDavid du Colombier 	runq->redir = rp->next;
429dc5a79c1SDavid du Colombier 	if(rp->type==ROPEN)
430dc5a79c1SDavid du Colombier 		close(rp->from);
4313e12c5d1SDavid du Colombier 	efree((char *)rp);
4323e12c5d1SDavid du Colombier }
433dc5a79c1SDavid du Colombier 
434dc5a79c1SDavid du Colombier void
Xreturn(void)435dc5a79c1SDavid du Colombier Xreturn(void)
436dc5a79c1SDavid du Colombier {
4373e12c5d1SDavid du Colombier 	struct thread *p = runq;
4383e12c5d1SDavid du Colombier 	turfredir();
4393e12c5d1SDavid du Colombier 	while(p->argv) poplist();
4403e12c5d1SDavid du Colombier 	codefree(p->code);
4413e12c5d1SDavid du Colombier 	runq = p->ret;
4423e12c5d1SDavid du Colombier 	efree((char *)p);
443dc5a79c1SDavid du Colombier 	if(runq==0)
444dc5a79c1SDavid du Colombier 		Exit(getstatus());
4453e12c5d1SDavid du Colombier }
446dc5a79c1SDavid du Colombier 
447dc5a79c1SDavid du Colombier void
Xtrue(void)448dc5a79c1SDavid du Colombier Xtrue(void)
449dc5a79c1SDavid du Colombier {
4503e12c5d1SDavid du Colombier 	if(truestatus()) runq->pc++;
4513e12c5d1SDavid du Colombier 	else runq->pc = runq->code[runq->pc].i;
4523e12c5d1SDavid du Colombier }
453dc5a79c1SDavid du Colombier 
454dc5a79c1SDavid du Colombier void
Xif(void)455dc5a79c1SDavid du Colombier Xif(void)
456dc5a79c1SDavid du Colombier {
4573e12c5d1SDavid du Colombier 	ifnot = 1;
4583e12c5d1SDavid du Colombier 	if(truestatus()) runq->pc++;
4593e12c5d1SDavid du Colombier 	else runq->pc = runq->code[runq->pc].i;
4603e12c5d1SDavid du Colombier }
461dc5a79c1SDavid du Colombier 
462dc5a79c1SDavid du Colombier void
Xwastrue(void)463dc5a79c1SDavid du Colombier Xwastrue(void)
464dc5a79c1SDavid du Colombier {
4653e12c5d1SDavid du Colombier 	ifnot = 0;
4663e12c5d1SDavid du Colombier }
467dc5a79c1SDavid du Colombier 
468dc5a79c1SDavid du Colombier void
Xword(void)469dc5a79c1SDavid du Colombier Xword(void)
470dc5a79c1SDavid du Colombier {
4713e12c5d1SDavid du Colombier 	pushword(runq->code[runq->pc++].s);
4723e12c5d1SDavid du Colombier }
473dc5a79c1SDavid du Colombier 
474dc5a79c1SDavid du Colombier void
Xwrite(void)475dc5a79c1SDavid du Colombier Xwrite(void)
476dc5a79c1SDavid du Colombier {
4773e12c5d1SDavid du Colombier 	char *file;
4783e12c5d1SDavid du Colombier 	int f;
4793e12c5d1SDavid du Colombier 	switch(count(runq->argv->words)){
480dc5a79c1SDavid du Colombier 	default:
481dc5a79c1SDavid du Colombier 		Xerror1("> requires singleton\n");
482dc5a79c1SDavid du Colombier 		return;
483dc5a79c1SDavid du Colombier 	case 0:
484dc5a79c1SDavid du Colombier 		Xerror1("> requires file\n");
485dc5a79c1SDavid du Colombier 		return;
486dc5a79c1SDavid du Colombier 	case 1:
487dc5a79c1SDavid du Colombier 		break;
4883e12c5d1SDavid du Colombier 	}
4893e12c5d1SDavid du Colombier 	file = runq->argv->words->word;
4903e12c5d1SDavid du Colombier 	if((f = Creat(file))<0){
4917dd7cddfSDavid du Colombier 		pfmt(err, "%s: ", file);
4927dd7cddfSDavid du Colombier 		Xerror("can't open");
4933e12c5d1SDavid du Colombier 		return;
4943e12c5d1SDavid du Colombier 	}
4953e12c5d1SDavid du Colombier 	pushredir(ROPEN, f, runq->code[runq->pc].i);
4963e12c5d1SDavid du Colombier 	runq->pc++;
4973e12c5d1SDavid du Colombier 	poplist();
4983e12c5d1SDavid du Colombier }
499dc5a79c1SDavid du Colombier 
500dc5a79c1SDavid du Colombier char*
list2str(word * words)501dc5a79c1SDavid du Colombier list2str(word *words)
502dc5a79c1SDavid du Colombier {
5033e12c5d1SDavid du Colombier 	char *value, *s, *t;
5043e12c5d1SDavid du Colombier 	int len = 0;
5053e12c5d1SDavid du Colombier 	word *ap;
5063e12c5d1SDavid du Colombier 	for(ap = words;ap;ap = ap->next)
5073e12c5d1SDavid du Colombier 		len+=1+strlen(ap->word);
5083e12c5d1SDavid du Colombier 	value = emalloc(len+1);
5093e12c5d1SDavid du Colombier 	s = value;
5103e12c5d1SDavid du Colombier 	for(ap = words;ap;ap = ap->next){
5113e12c5d1SDavid du Colombier 		for(t = ap->word;*t;) *s++=*t++;
5123e12c5d1SDavid du Colombier 		*s++=' ';
5133e12c5d1SDavid du Colombier 	}
514dc5a79c1SDavid du Colombier 	if(s==value)
515dc5a79c1SDavid du Colombier 		*s='\0';
5163e12c5d1SDavid du Colombier 	else s[-1]='\0';
5173e12c5d1SDavid du Colombier 	return value;
5183e12c5d1SDavid du Colombier }
519dc5a79c1SDavid du Colombier 
520dc5a79c1SDavid du Colombier void
Xmatch(void)521dc5a79c1SDavid du Colombier Xmatch(void)
522dc5a79c1SDavid du Colombier {
5233e12c5d1SDavid du Colombier 	word *p;
5243e12c5d1SDavid du Colombier 	char *subject;
5253e12c5d1SDavid du Colombier 	subject = list2str(runq->argv->words);
5263e12c5d1SDavid du Colombier 	setstatus("no match");
5273e12c5d1SDavid du Colombier 	for(p = runq->argv->next->words;p;p = p->next)
5283e12c5d1SDavid du Colombier 		if(match(subject, p->word, '\0')){
5293e12c5d1SDavid du Colombier 			setstatus("");
5303e12c5d1SDavid du Colombier 			break;
5313e12c5d1SDavid du Colombier 		}
5323e12c5d1SDavid du Colombier 	efree(subject);
5333e12c5d1SDavid du Colombier 	poplist();
5343e12c5d1SDavid du Colombier 	poplist();
5353e12c5d1SDavid du Colombier }
536dc5a79c1SDavid du Colombier 
537dc5a79c1SDavid du Colombier void
Xcase(void)538dc5a79c1SDavid du Colombier Xcase(void)
539dc5a79c1SDavid du Colombier {
5403e12c5d1SDavid du Colombier 	word *p;
5413e12c5d1SDavid du Colombier 	char *s;
5423e12c5d1SDavid du Colombier 	int ok = 0;
5433e12c5d1SDavid du Colombier 	s = list2str(runq->argv->next->words);
5443e12c5d1SDavid du Colombier 	for(p = runq->argv->words;p;p = p->next){
5453e12c5d1SDavid du Colombier 		if(match(s, p->word, '\0')){
5463e12c5d1SDavid du Colombier 			ok = 1;
5473e12c5d1SDavid du Colombier 			break;
5483e12c5d1SDavid du Colombier 		}
5493e12c5d1SDavid du Colombier 	}
5503e12c5d1SDavid du Colombier 	efree(s);
5513e12c5d1SDavid du Colombier 	if(ok)
5523e12c5d1SDavid du Colombier 		runq->pc++;
5533e12c5d1SDavid du Colombier 	else
5543e12c5d1SDavid du Colombier 		runq->pc = runq->code[runq->pc].i;
5553e12c5d1SDavid du Colombier 	poplist();
5563e12c5d1SDavid du Colombier }
557dc5a79c1SDavid du Colombier 
558dc5a79c1SDavid du Colombier word*
conclist(word * lp,word * rp,word * tail)559dc5a79c1SDavid du Colombier conclist(word *lp, word *rp, word *tail)
5603e12c5d1SDavid du Colombier {
5613e12c5d1SDavid du Colombier 	char *buf;
5623e12c5d1SDavid du Colombier 	word *v;
5633e12c5d1SDavid du Colombier 	if(lp->next || rp->next)
564276e7d6dSDavid du Colombier 		tail = conclist(lp->next==0? lp: lp->next,
565276e7d6dSDavid du Colombier 			rp->next==0? rp: rp->next, tail);
566276e7d6dSDavid du Colombier 	buf = emalloc(strlen(lp->word)+strlen((char *)rp->word)+1);
5673e12c5d1SDavid du Colombier 	strcpy(buf, lp->word);
5683e12c5d1SDavid du Colombier 	strcat(buf, rp->word);
5693e12c5d1SDavid du Colombier 	v = newword(buf, tail);
5703e12c5d1SDavid du Colombier 	efree(buf);
5713e12c5d1SDavid du Colombier 	return v;
5723e12c5d1SDavid du Colombier }
573dc5a79c1SDavid du Colombier 
574dc5a79c1SDavid du Colombier void
Xconc(void)575dc5a79c1SDavid du Colombier Xconc(void)
576dc5a79c1SDavid du Colombier {
5773e12c5d1SDavid du Colombier 	word *lp = runq->argv->words;
5783e12c5d1SDavid du Colombier 	word *rp = runq->argv->next->words;
5793e12c5d1SDavid du Colombier 	word *vp = runq->argv->next->next->words;
5803e12c5d1SDavid du Colombier 	int lc = count(lp), rc = count(rp);
5813e12c5d1SDavid du Colombier 	if(lc!=0 || rc!=0){
5823e12c5d1SDavid du Colombier 		if(lc==0 || rc==0){
5839a747e4fSDavid du Colombier 			Xerror1("null list in concatenation");
5843e12c5d1SDavid du Colombier 			return;
5853e12c5d1SDavid du Colombier 		}
5863e12c5d1SDavid du Colombier 		if(lc!=1 && rc!=1 && lc!=rc){
5879a747e4fSDavid du Colombier 			Xerror1("mismatched list lengths in concatenation");
5883e12c5d1SDavid du Colombier 			return;
5893e12c5d1SDavid du Colombier 		}
5903e12c5d1SDavid du Colombier 		vp = conclist(lp, rp, vp);
5913e12c5d1SDavid du Colombier 	}
5923e12c5d1SDavid du Colombier 	poplist();
5933e12c5d1SDavid du Colombier 	poplist();
5943e12c5d1SDavid du Colombier 	runq->argv->words = vp;
5953e12c5d1SDavid du Colombier }
596dc5a79c1SDavid du Colombier 
597dc5a79c1SDavid du Colombier void
Xassign(void)598dc5a79c1SDavid du Colombier Xassign(void)
599dc5a79c1SDavid du Colombier {
6003e12c5d1SDavid du Colombier 	var *v;
6013e12c5d1SDavid du Colombier 	if(count(runq->argv->words)!=1){
6029a747e4fSDavid du Colombier 		Xerror1("variable name not singleton!");
6033e12c5d1SDavid du Colombier 		return;
6043e12c5d1SDavid du Colombier 	}
6053e12c5d1SDavid du Colombier 	deglob(runq->argv->words->word);
6063e12c5d1SDavid du Colombier 	v = vlook(runq->argv->words->word);
6073e12c5d1SDavid du Colombier 	poplist();
6083e12c5d1SDavid du Colombier 	globlist();
6093e12c5d1SDavid du Colombier 	freewords(v->val);
6103e12c5d1SDavid du Colombier 	v->val = runq->argv->words;
6113e12c5d1SDavid du Colombier 	v->changed = 1;
6123e12c5d1SDavid du Colombier 	runq->argv->words = 0;
6133e12c5d1SDavid du Colombier 	poplist();
6143e12c5d1SDavid du Colombier }
6153e12c5d1SDavid du Colombier /*
6163e12c5d1SDavid du Colombier  * copy arglist a, adding the copy to the front of tail
6173e12c5d1SDavid du Colombier  */
618dc5a79c1SDavid du Colombier 
619dc5a79c1SDavid du Colombier word*
copywords(word * a,word * tail)620dc5a79c1SDavid du Colombier copywords(word *a, word *tail)
6213e12c5d1SDavid du Colombier {
6223e12c5d1SDavid du Colombier 	word *v = 0, **end;
6233e12c5d1SDavid du Colombier 	for(end=&v;a;a = a->next,end=&(*end)->next)
6243e12c5d1SDavid du Colombier 		*end = newword(a->word, 0);
6253e12c5d1SDavid du Colombier 	*end = tail;
6263e12c5d1SDavid du Colombier 	return v;
6273e12c5d1SDavid du Colombier }
628dc5a79c1SDavid du Colombier 
629dc5a79c1SDavid du Colombier void
Xdol(void)630dc5a79c1SDavid du Colombier Xdol(void)
631dc5a79c1SDavid du Colombier {
6323e12c5d1SDavid du Colombier 	word *a, *star;
6333e12c5d1SDavid du Colombier 	char *s, *t;
6343e12c5d1SDavid du Colombier 	int n;
6353e12c5d1SDavid du Colombier 	if(count(runq->argv->words)!=1){
6369a747e4fSDavid du Colombier 		Xerror1("variable name not singleton!");
6373e12c5d1SDavid du Colombier 		return;
6383e12c5d1SDavid du Colombier 	}
6393e12c5d1SDavid du Colombier 	s = runq->argv->words->word;
6403e12c5d1SDavid du Colombier 	deglob(s);
6413e12c5d1SDavid du Colombier 	n = 0;
64299eb86a7SDavid du Colombier 	for(t = s;'0'<=*t && *t<='9';t++) n = n*10+*t-'0';
6433e12c5d1SDavid du Colombier 	a = runq->argv->next->words;
6443e12c5d1SDavid du Colombier 	if(n==0 || *t)
6453e12c5d1SDavid du Colombier 		a = copywords(vlook(s)->val, a);
6463e12c5d1SDavid du Colombier 	else{
6473e12c5d1SDavid du Colombier 		star = vlook("*")->val;
6483e12c5d1SDavid du Colombier 		if(star && 1<=n && n<=count(star)){
64999eb86a7SDavid du Colombier 			while(--n) star = star->next;
6503e12c5d1SDavid du Colombier 			a = newword(star->word, a);
6513e12c5d1SDavid du Colombier 		}
6523e12c5d1SDavid du Colombier 	}
6533e12c5d1SDavid du Colombier 	poplist();
6543e12c5d1SDavid du Colombier 	runq->argv->words = a;
6553e12c5d1SDavid du Colombier }
656dc5a79c1SDavid du Colombier 
657dc5a79c1SDavid du Colombier void
Xqdol(void)658dc5a79c1SDavid du Colombier Xqdol(void)
659dc5a79c1SDavid du Colombier {
6603e12c5d1SDavid du Colombier 	word *a, *p;
6613e12c5d1SDavid du Colombier 	char *s;
6623e12c5d1SDavid du Colombier 	int n;
6633e12c5d1SDavid du Colombier 	if(count(runq->argv->words)!=1){
6649a747e4fSDavid du Colombier 		Xerror1("variable name not singleton!");
6653e12c5d1SDavid du Colombier 		return;
6663e12c5d1SDavid du Colombier 	}
6673e12c5d1SDavid du Colombier 	s = runq->argv->words->word;
6683e12c5d1SDavid du Colombier 	deglob(s);
6693e12c5d1SDavid du Colombier 	a = vlook(s)->val;
6703e12c5d1SDavid du Colombier 	poplist();
6713e12c5d1SDavid du Colombier 	n = count(a);
6723e12c5d1SDavid du Colombier 	if(n==0){
6733e12c5d1SDavid du Colombier 		pushword("");
6743e12c5d1SDavid du Colombier 		return;
6753e12c5d1SDavid du Colombier 	}
6763e12c5d1SDavid du Colombier 	for(p = a;p;p = p->next) n+=strlen(p->word);
6773e12c5d1SDavid du Colombier 	s = emalloc(n);
6783e12c5d1SDavid du Colombier 	if(a){
6793e12c5d1SDavid du Colombier 		strcpy(s, a->word);
6803e12c5d1SDavid du Colombier 		for(p = a->next;p;p = p->next){
6813e12c5d1SDavid du Colombier 			strcat(s, " ");
6823e12c5d1SDavid du Colombier 			strcat(s, p->word);
6833e12c5d1SDavid du Colombier 		}
6843e12c5d1SDavid du Colombier 	}
6853e12c5d1SDavid du Colombier 	else
6863e12c5d1SDavid du Colombier 		s[0]='\0';
6873e12c5d1SDavid du Colombier 	pushword(s);
6883e12c5d1SDavid du Colombier 	efree(s);
6893e12c5d1SDavid du Colombier }
690dc5a79c1SDavid du Colombier 
691dc5a79c1SDavid du Colombier word*
copynwords(word * a,word * tail,int n)6925e061cc0SDavid du Colombier copynwords(word *a, word *tail, int n)
6935e061cc0SDavid du Colombier {
6945e061cc0SDavid du Colombier 	word *v, **end;
6955e061cc0SDavid du Colombier 
6965e061cc0SDavid du Colombier 	v = 0;
6975e061cc0SDavid du Colombier 	end = &v;
6985e061cc0SDavid du Colombier 	while(n-- > 0){
6995e061cc0SDavid du Colombier 		*end = newword(a->word, 0);
7005e061cc0SDavid du Colombier 		end = &(*end)->next;
7015e061cc0SDavid du Colombier 		a = a->next;
7025e061cc0SDavid du Colombier 	}
7035e061cc0SDavid du Colombier 	*end = tail;
7045e061cc0SDavid du Colombier 	return v;
7055e061cc0SDavid du Colombier }
7065e061cc0SDavid du Colombier 
7075e061cc0SDavid du Colombier word*
subwords(word * val,int len,word * sub,word * a)708dc5a79c1SDavid du Colombier subwords(word *val, int len, word *sub, word *a)
7093e12c5d1SDavid du Colombier {
7105e061cc0SDavid du Colombier 	int n, m;
7113e12c5d1SDavid du Colombier 	char *s;
712dc5a79c1SDavid du Colombier 	if(!sub)
713dc5a79c1SDavid du Colombier 		return a;
7143e12c5d1SDavid du Colombier 	a = subwords(val, len, sub->next, a);
7153e12c5d1SDavid du Colombier 	s = sub->word;
7163e12c5d1SDavid du Colombier 	deglob(s);
7175e061cc0SDavid du Colombier 	m = 0;
7183e12c5d1SDavid du Colombier 	n = 0;
7195e061cc0SDavid du Colombier 	while('0'<=*s && *s<='9')
7205e061cc0SDavid du Colombier 		n = n*10+ *s++ -'0';
7215e061cc0SDavid du Colombier 	if(*s == '-'){
7225e061cc0SDavid du Colombier 		if(*++s == 0)
7235e061cc0SDavid du Colombier 			m = len - n;
7245e061cc0SDavid du Colombier 		else{
7255e061cc0SDavid du Colombier 			while('0'<=*s && *s<='9')
7265e061cc0SDavid du Colombier 				m = m*10+ *s++ -'0';
7275e061cc0SDavid du Colombier 			m -= n;
7285e061cc0SDavid du Colombier 		}
7295e061cc0SDavid du Colombier 	}
7305e061cc0SDavid du Colombier 	if(n<1 || n>len || m<0)
731dc5a79c1SDavid du Colombier 		return a;
7325e061cc0SDavid du Colombier 	if(n+m>len)
7335e061cc0SDavid du Colombier 		m = len-n;
7345e061cc0SDavid du Colombier 	while(--n > 0)
7355e061cc0SDavid du Colombier 		val = val->next;
7365e061cc0SDavid du Colombier 	return copynwords(val, a, m+1);
7373e12c5d1SDavid du Colombier }
738dc5a79c1SDavid du Colombier 
739dc5a79c1SDavid du Colombier void
Xsub(void)740dc5a79c1SDavid du Colombier Xsub(void)
741dc5a79c1SDavid du Colombier {
7423e12c5d1SDavid du Colombier 	word *a, *v;
7433e12c5d1SDavid du Colombier 	char *s;
7443e12c5d1SDavid du Colombier 	if(count(runq->argv->next->words)!=1){
7459a747e4fSDavid du Colombier 		Xerror1("variable name not singleton!");
7463e12c5d1SDavid du Colombier 		return;
7473e12c5d1SDavid du Colombier 	}
7483e12c5d1SDavid du Colombier 	s = runq->argv->next->words->word;
7493e12c5d1SDavid du Colombier 	deglob(s);
7503e12c5d1SDavid du Colombier 	a = runq->argv->next->next->words;
7513e12c5d1SDavid du Colombier 	v = vlook(s)->val;
7523e12c5d1SDavid du Colombier 	a = subwords(v, count(v), runq->argv->words, a);
7533e12c5d1SDavid du Colombier 	poplist();
7543e12c5d1SDavid du Colombier 	poplist();
7553e12c5d1SDavid du Colombier 	runq->argv->words = a;
7563e12c5d1SDavid du Colombier }
757dc5a79c1SDavid du Colombier 
758dc5a79c1SDavid du Colombier void
Xcount(void)759dc5a79c1SDavid du Colombier Xcount(void)
760dc5a79c1SDavid du Colombier {
7613e12c5d1SDavid du Colombier 	word *a;
7623e12c5d1SDavid du Colombier 	char *s, *t;
7633e12c5d1SDavid du Colombier 	int n;
7643e12c5d1SDavid du Colombier 	char num[12];
7653e12c5d1SDavid du Colombier 	if(count(runq->argv->words)!=1){
7669a747e4fSDavid du Colombier 		Xerror1("variable name not singleton!");
7673e12c5d1SDavid du Colombier 		return;
7683e12c5d1SDavid du Colombier 	}
7693e12c5d1SDavid du Colombier 	s = runq->argv->words->word;
7703e12c5d1SDavid du Colombier 	deglob(s);
7713e12c5d1SDavid du Colombier 	n = 0;
7723e12c5d1SDavid du Colombier 	for(t = s;'0'<=*t && *t<='9';t++) n = n*10+*t-'0';
7733e12c5d1SDavid du Colombier 	if(n==0 || *t){
7743e12c5d1SDavid du Colombier 		a = vlook(s)->val;
775dc5a79c1SDavid du Colombier 		inttoascii(num, count(a));
7763e12c5d1SDavid du Colombier 	}
7773e12c5d1SDavid du Colombier 	else{
7783e12c5d1SDavid du Colombier 		a = vlook("*")->val;
779dc5a79c1SDavid du Colombier 		inttoascii(num, a && 1<=n && n<=count(a)?1:0);
7803e12c5d1SDavid du Colombier 	}
7813e12c5d1SDavid du Colombier 	poplist();
7823e12c5d1SDavid du Colombier 	pushword(num);
7833e12c5d1SDavid du Colombier }
784dc5a79c1SDavid du Colombier 
785dc5a79c1SDavid du Colombier void
Xlocal(void)786dc5a79c1SDavid du Colombier Xlocal(void)
787dc5a79c1SDavid du Colombier {
7883e12c5d1SDavid du Colombier 	if(count(runq->argv->words)!=1){
7899a747e4fSDavid du Colombier 		Xerror1("variable name must be singleton\n");
7903e12c5d1SDavid du Colombier 		return;
7913e12c5d1SDavid du Colombier 	}
7923e12c5d1SDavid du Colombier 	deglob(runq->argv->words->word);
7933e12c5d1SDavid du Colombier 	runq->local = newvar(strdup(runq->argv->words->word), runq->local);
7943e12c5d1SDavid du Colombier 	poplist();
795fed0fa9eSDavid du Colombier 	globlist();
796fed0fa9eSDavid du Colombier 	runq->local->val = runq->argv->words;
797fed0fa9eSDavid du Colombier 	runq->local->changed = 1;
798fed0fa9eSDavid du Colombier 	runq->argv->words = 0;
7993e12c5d1SDavid du Colombier 	poplist();
8003e12c5d1SDavid du Colombier }
801dc5a79c1SDavid du Colombier 
802dc5a79c1SDavid du Colombier void
Xunlocal(void)803dc5a79c1SDavid du Colombier Xunlocal(void)
804dc5a79c1SDavid du Colombier {
8053e12c5d1SDavid du Colombier 	var *v = runq->local, *hid;
806dc5a79c1SDavid du Colombier 	if(v==0)
807dc5a79c1SDavid du Colombier 		panic("Xunlocal: no locals!", 0);
8083e12c5d1SDavid du Colombier 	runq->local = v->next;
8093e12c5d1SDavid du Colombier 	hid = vlook(v->name);
8103e12c5d1SDavid du Colombier 	hid->changed = 1;
8113e12c5d1SDavid du Colombier 	efree(v->name);
8123e12c5d1SDavid du Colombier 	freewords(v->val);
8133e12c5d1SDavid du Colombier 	efree((char *)v);
8143e12c5d1SDavid du Colombier }
815dc5a79c1SDavid du Colombier 
816dc5a79c1SDavid du Colombier void
freewords(word * w)817dc5a79c1SDavid du Colombier freewords(word *w)
8183e12c5d1SDavid du Colombier {
8193e12c5d1SDavid du Colombier 	word *nw;
8203e12c5d1SDavid du Colombier 	while(w){
8213e12c5d1SDavid du Colombier 		efree(w->word);
8223e12c5d1SDavid du Colombier 		nw = w->next;
8233e12c5d1SDavid du Colombier 		efree((char *)w);
8243e12c5d1SDavid du Colombier 		w = nw;
8253e12c5d1SDavid du Colombier 	}
8263e12c5d1SDavid du Colombier }
827dc5a79c1SDavid du Colombier 
828dc5a79c1SDavid du Colombier void
Xfn(void)829dc5a79c1SDavid du Colombier Xfn(void)
830dc5a79c1SDavid du Colombier {
8313e12c5d1SDavid du Colombier 	var *v;
8323e12c5d1SDavid du Colombier 	word *a;
8333e12c5d1SDavid du Colombier 	int end;
8343e12c5d1SDavid du Colombier 	end = runq->code[runq->pc].i;
835fed0fa9eSDavid du Colombier 	globlist();
8363e12c5d1SDavid du Colombier 	for(a = runq->argv->words;a;a = a->next){
8373e12c5d1SDavid du Colombier 		v = gvlook(a->word);
838dc5a79c1SDavid du Colombier 		if(v->fn)
839dc5a79c1SDavid du Colombier 			codefree(v->fn);
8403e12c5d1SDavid du Colombier 		v->fn = codecopy(runq->code);
8413e12c5d1SDavid du Colombier 		v->pc = runq->pc+2;
8423e12c5d1SDavid du Colombier 		v->fnchanged = 1;
8433e12c5d1SDavid du Colombier 	}
8443e12c5d1SDavid du Colombier 	runq->pc = end;
8453e12c5d1SDavid du Colombier 	poplist();
8463e12c5d1SDavid du Colombier }
847dc5a79c1SDavid du Colombier 
848dc5a79c1SDavid du Colombier void
Xdelfn(void)849dc5a79c1SDavid du Colombier Xdelfn(void)
850dc5a79c1SDavid du Colombier {
8513e12c5d1SDavid du Colombier 	var *v;
8523e12c5d1SDavid du Colombier 	word *a;
8533e12c5d1SDavid du Colombier 	for(a = runq->argv->words;a;a = a->next){
8543e12c5d1SDavid du Colombier 		v = gvlook(a->word);
855dc5a79c1SDavid du Colombier 		if(v->fn)
856dc5a79c1SDavid du Colombier 			codefree(v->fn);
8573e12c5d1SDavid du Colombier 		v->fn = 0;
8583e12c5d1SDavid du Colombier 		v->fnchanged = 1;
8593e12c5d1SDavid du Colombier 	}
8603e12c5d1SDavid du Colombier 	poplist();
8613e12c5d1SDavid du Colombier }
862dc5a79c1SDavid du Colombier 
863dc5a79c1SDavid du Colombier char*
concstatus(char * s,char * t)864dc5a79c1SDavid du Colombier concstatus(char *s, char *t)
8653e12c5d1SDavid du Colombier {
8663e12c5d1SDavid du Colombier 	static char v[NSTATUS+1];
8673e12c5d1SDavid du Colombier 	int n = strlen(s);
8683e12c5d1SDavid du Colombier 	strncpy(v, s, NSTATUS);
8693e12c5d1SDavid du Colombier 	if(n<NSTATUS){
8703e12c5d1SDavid du Colombier 		v[n]='|';
8713e12c5d1SDavid du Colombier 		strncpy(v+n+1, t, NSTATUS-n-1);
8723e12c5d1SDavid du Colombier 	}
8733e12c5d1SDavid du Colombier 	v[NSTATUS]='\0';
8743e12c5d1SDavid du Colombier 	return v;
8753e12c5d1SDavid du Colombier }
876dc5a79c1SDavid du Colombier 
877dc5a79c1SDavid du Colombier void
Xpipewait(void)878dc5a79c1SDavid du Colombier Xpipewait(void)
879dc5a79c1SDavid du Colombier {
8803e12c5d1SDavid du Colombier 	char status[NSTATUS+1];
8813e12c5d1SDavid du Colombier 	if(runq->pid==-1)
8823e12c5d1SDavid du Colombier 		setstatus(concstatus(runq->status, getstatus()));
8833e12c5d1SDavid du Colombier 	else{
8843e12c5d1SDavid du Colombier 		strncpy(status, getstatus(), NSTATUS);
8853e12c5d1SDavid du Colombier 		status[NSTATUS]='\0';
8863e12c5d1SDavid du Colombier 		Waitfor(runq->pid, 1);
8873e12c5d1SDavid du Colombier 		runq->pid=-1;
8883e12c5d1SDavid du Colombier 		setstatus(concstatus(getstatus(), status));
8893e12c5d1SDavid du Colombier 	}
8903e12c5d1SDavid du Colombier }
891dc5a79c1SDavid du Colombier 
892dc5a79c1SDavid du Colombier void
Xrdcmds(void)893dc5a79c1SDavid du Colombier Xrdcmds(void)
894dc5a79c1SDavid du Colombier {
8953e12c5d1SDavid du Colombier 	struct thread *p = runq;
8963e12c5d1SDavid du Colombier 	word *prompt;
8973e12c5d1SDavid du Colombier 	flush(err);
8983e12c5d1SDavid du Colombier 	nerror = 0;
8993e12c5d1SDavid du Colombier 	if(flag['s'] && !truestatus())
9003e12c5d1SDavid du Colombier 		pfmt(err, "status=%v\n", vlook("status")->val);
9013e12c5d1SDavid du Colombier 	if(runq->iflag){
9023e12c5d1SDavid du Colombier 		prompt = vlook("prompt")->val;
9033e12c5d1SDavid du Colombier 		if(prompt)
9043e12c5d1SDavid du Colombier 			promptstr = prompt->word;
9053e12c5d1SDavid du Colombier 		else
9063e12c5d1SDavid du Colombier 			promptstr="% ";
9073e12c5d1SDavid du Colombier 	}
9083e12c5d1SDavid du Colombier 	Noerror();
9093e12c5d1SDavid du Colombier 	if(yyparse()){
9103e12c5d1SDavid du Colombier 		if(!p->iflag || p->eof && !Eintr()){
911dc5a79c1SDavid du Colombier 			if(p->cmdfile)
912dc5a79c1SDavid du Colombier 				efree(p->cmdfile);
9133e12c5d1SDavid du Colombier 			closeio(p->cmdfd);
9143e12c5d1SDavid du Colombier 			Xreturn();	/* should this be omitted? */
9153e12c5d1SDavid du Colombier 		}
9163e12c5d1SDavid du Colombier 		else{
9173e12c5d1SDavid du Colombier 			if(Eintr()){
9183e12c5d1SDavid du Colombier 				pchr(err, '\n');
9193e12c5d1SDavid du Colombier 				p->eof = 0;
9203e12c5d1SDavid du Colombier 			}
9213e12c5d1SDavid du Colombier 			--p->pc;	/* go back for next command */
9223e12c5d1SDavid du Colombier 		}
9233e12c5d1SDavid du Colombier 	}
9243e12c5d1SDavid du Colombier 	else{
9257dd7cddfSDavid du Colombier 		ntrap = 0;	/* avoid double-interrupts during blocked writes */
9263e12c5d1SDavid du Colombier 		--p->pc;	/* re-execute Xrdcmds after codebuf runs */
9273e12c5d1SDavid du Colombier 		start(codebuf, 1, runq->local);
9283e12c5d1SDavid du Colombier 	}
9293e12c5d1SDavid du Colombier 	freenodes();
9303e12c5d1SDavid du Colombier }
931dc5a79c1SDavid du Colombier 
932dc5a79c1SDavid du Colombier void
Xerror(char * s)933dc5a79c1SDavid du Colombier Xerror(char *s)
9343e12c5d1SDavid du Colombier {
9359a747e4fSDavid du Colombier 	if(strcmp(argv0, "rc")==0 || strcmp(argv0, "/bin/rc")==0)
9369a747e4fSDavid du Colombier 		pfmt(err, "rc: %s: %r\n", s);
9379a747e4fSDavid du Colombier 	else
9389a747e4fSDavid du Colombier 		pfmt(err, "rc (%s): %s: %r\n", argv0, s);
9399a747e4fSDavid du Colombier 	flush(err);
940d3907fe5SDavid du Colombier 	setstatus("error");
9419a747e4fSDavid du Colombier 	while(!runq->iflag) Xreturn();
9429a747e4fSDavid du Colombier }
943dc5a79c1SDavid du Colombier 
944dc5a79c1SDavid du Colombier void
Xerror1(char * s)945dc5a79c1SDavid du Colombier Xerror1(char *s)
9469a747e4fSDavid du Colombier {
9479a747e4fSDavid du Colombier 	if(strcmp(argv0, "rc")==0 || strcmp(argv0, "/bin/rc")==0)
9483e12c5d1SDavid du Colombier 		pfmt(err, "rc: %s\n", s);
9499a747e4fSDavid du Colombier 	else
9509a747e4fSDavid du Colombier 		pfmt(err, "rc (%s): %s\n", argv0, s);
9513e12c5d1SDavid du Colombier 	flush(err);
952d3907fe5SDavid du Colombier 	setstatus("error");
9533e12c5d1SDavid du Colombier 	while(!runq->iflag) Xreturn();
9543e12c5d1SDavid du Colombier }
955dc5a79c1SDavid du Colombier 
956dc5a79c1SDavid du Colombier void
setstatus(char * s)957dc5a79c1SDavid du Colombier setstatus(char *s)
9583e12c5d1SDavid du Colombier {
9593e12c5d1SDavid du Colombier 	setvar("status", newword(s, (word *)0));
9603e12c5d1SDavid du Colombier }
961dc5a79c1SDavid du Colombier 
962dc5a79c1SDavid du Colombier char*
getstatus(void)963dc5a79c1SDavid du Colombier getstatus(void)
964dc5a79c1SDavid du Colombier {
9653e12c5d1SDavid du Colombier 	var *status = vlook("status");
9663e12c5d1SDavid du Colombier 	return status->val?status->val->word:"";
9673e12c5d1SDavid du Colombier }
968dc5a79c1SDavid du Colombier 
969dc5a79c1SDavid du Colombier int
truestatus(void)970dc5a79c1SDavid du Colombier truestatus(void)
971dc5a79c1SDavid du Colombier {
9723e12c5d1SDavid du Colombier 	char *s;
9733e12c5d1SDavid du Colombier 	for(s = getstatus();*s;s++)
974dc5a79c1SDavid du Colombier 		if(*s!='|' && *s!='0')
975dc5a79c1SDavid du Colombier 			return 0;
9763e12c5d1SDavid du Colombier 	return 1;
9773e12c5d1SDavid du Colombier }
978dc5a79c1SDavid du Colombier 
979dc5a79c1SDavid du Colombier void
Xdelhere(void)980dc5a79c1SDavid du Colombier Xdelhere(void)
981dc5a79c1SDavid du Colombier {
9823e12c5d1SDavid du Colombier 	Unlink(runq->code[runq->pc++].s);
9833e12c5d1SDavid du Colombier }
984dc5a79c1SDavid du Colombier 
985dc5a79c1SDavid du Colombier void
Xfor(void)986dc5a79c1SDavid du Colombier Xfor(void)
987dc5a79c1SDavid du Colombier {
9883e12c5d1SDavid du Colombier 	if(runq->argv->words==0){
9893e12c5d1SDavid du Colombier 		poplist();
9903e12c5d1SDavid du Colombier 		runq->pc = runq->code[runq->pc].i;
9913e12c5d1SDavid du Colombier 	}
9923e12c5d1SDavid du Colombier 	else{
9933e12c5d1SDavid du Colombier 		freelist(runq->local->val);
9943e12c5d1SDavid du Colombier 		runq->local->val = runq->argv->words;
9953e12c5d1SDavid du Colombier 		runq->local->changed = 1;
9963e12c5d1SDavid du Colombier 		runq->argv->words = runq->argv->words->next;
9973e12c5d1SDavid du Colombier 		runq->local->val->next = 0;
9983e12c5d1SDavid du Colombier 		runq->pc++;
9993e12c5d1SDavid du Colombier 	}
10003e12c5d1SDavid du Colombier }
1001dc5a79c1SDavid du Colombier 
1002dc5a79c1SDavid du Colombier void
Xglob(void)1003dc5a79c1SDavid du Colombier Xglob(void)
1004dc5a79c1SDavid du Colombier {
10053e12c5d1SDavid du Colombier 	globlist();
10063e12c5d1SDavid du Colombier }
1007