xref: /plan9-contrib/sys/src/cmd/rc/exec.c (revision 4446a870cd0cc88dde8a2b5b72feb64f4ae5b744)
13e12c5d1SDavid du Colombier #include "rc.h"
23e12c5d1SDavid du Colombier #include "exec.h"
33e12c5d1SDavid du Colombier #include "io.h"
43e12c5d1SDavid du Colombier #include "fns.h"
5c6df1444SDavid du Colombier 
6c6df1444SDavid du Colombier char flagset[] = "<flag>";	/* anything non-nil will do */
7c6df1444SDavid du Colombier char *flag[NFLAG];
8c6df1444SDavid du Colombier 
93e12c5d1SDavid du Colombier /*
103e12c5d1SDavid du Colombier  * Start executing the given code at the given pc with the given redirection
113e12c5d1SDavid du Colombier  */
12c6df1444SDavid du Colombier char *argv0;
13dc5a79c1SDavid du Colombier 
14dc5a79c1SDavid du Colombier void
start(code * c,int pc,var * local)15dc5a79c1SDavid du Colombier start(code *c, int pc, var *local)
163e12c5d1SDavid du Colombier {
173e12c5d1SDavid du Colombier 	struct thread *p = new(struct thread);
18dc5a79c1SDavid du Colombier 
193e12c5d1SDavid du Colombier 	p->code = codecopy(c);
203e12c5d1SDavid du Colombier 	p->pc = pc;
213e12c5d1SDavid du Colombier 	p->argv = 0;
223e12c5d1SDavid du Colombier 	p->redir = p->startredir = runq?runq->redir:0;
233e12c5d1SDavid du Colombier 	p->local = local;
243e12c5d1SDavid du Colombier 	p->cmdfile = 0;
253e12c5d1SDavid du Colombier 	p->cmdfd = 0;
263e12c5d1SDavid du Colombier 	p->eof = 0;
273e12c5d1SDavid du Colombier 	p->iflag = 0;
283e12c5d1SDavid du Colombier 	p->lineno = 1;
293e12c5d1SDavid du Colombier 	p->ret = runq;
303e12c5d1SDavid du Colombier 	runq = p;
313e12c5d1SDavid du Colombier }
32dc5a79c1SDavid du Colombier 
33dc5a79c1SDavid du Colombier word*
newword(char * wd,word * next)34dc5a79c1SDavid du Colombier newword(char *wd, word *next)
353e12c5d1SDavid du Colombier {
363e12c5d1SDavid du Colombier 	word *p = new(word);
373e12c5d1SDavid du Colombier 	p->word = strdup(wd);
383e12c5d1SDavid du Colombier 	p->next = next;
393e12c5d1SDavid du Colombier 	return p;
403e12c5d1SDavid du Colombier }
41dc5a79c1SDavid du Colombier 
42dc5a79c1SDavid du Colombier void
pushword(char * wd)43dc5a79c1SDavid du Colombier pushword(char *wd)
443e12c5d1SDavid du Colombier {
45dc5a79c1SDavid du Colombier 	if(runq->argv==0)
46dc5a79c1SDavid du Colombier 		panic("pushword but no argv!", 0);
473e12c5d1SDavid du Colombier 	runq->argv->words = newword(wd, runq->argv->words);
483e12c5d1SDavid du Colombier }
49dc5a79c1SDavid du Colombier 
50dc5a79c1SDavid du Colombier void
popword(void)51dc5a79c1SDavid du Colombier popword(void)
52dc5a79c1SDavid du Colombier {
533e12c5d1SDavid du Colombier 	word *p;
54dc5a79c1SDavid du Colombier 	if(runq->argv==0)
55dc5a79c1SDavid du Colombier 		panic("popword but no argv!", 0);
563e12c5d1SDavid du Colombier 	p = runq->argv->words;
57dc5a79c1SDavid du Colombier 	if(p==0)
58dc5a79c1SDavid du Colombier 		panic("popword but no word!", 0);
593e12c5d1SDavid du Colombier 	runq->argv->words = p->next;
603e12c5d1SDavid du Colombier 	efree(p->word);
613e12c5d1SDavid du Colombier 	efree((char *)p);
623e12c5d1SDavid du Colombier }
63dc5a79c1SDavid du Colombier 
64dc5a79c1SDavid du Colombier void
freelist(word * w)65dc5a79c1SDavid du Colombier freelist(word *w)
663e12c5d1SDavid du Colombier {
673e12c5d1SDavid du Colombier 	word *nw;
683e12c5d1SDavid du Colombier 	while(w){
693e12c5d1SDavid du Colombier 		nw = w->next;
703e12c5d1SDavid du Colombier 		efree(w->word);
713e12c5d1SDavid du Colombier 		efree((char *)w);
723e12c5d1SDavid du Colombier 		w = nw;
733e12c5d1SDavid du Colombier 	}
743e12c5d1SDavid du Colombier }
75dc5a79c1SDavid du Colombier 
76dc5a79c1SDavid du Colombier void
pushlist(void)77dc5a79c1SDavid du Colombier pushlist(void)
78dc5a79c1SDavid du Colombier {
793e12c5d1SDavid du Colombier 	list *p = new(list);
803e12c5d1SDavid du Colombier 	p->next = runq->argv;
813e12c5d1SDavid du Colombier 	p->words = 0;
823e12c5d1SDavid du Colombier 	runq->argv = p;
833e12c5d1SDavid du Colombier }
84dc5a79c1SDavid du Colombier 
85dc5a79c1SDavid du Colombier void
poplist(void)86dc5a79c1SDavid du Colombier poplist(void)
87dc5a79c1SDavid du Colombier {
883e12c5d1SDavid du Colombier 	list *p = runq->argv;
89dc5a79c1SDavid du Colombier 	if(p==0)
90dc5a79c1SDavid du Colombier 		panic("poplist but no argv", 0);
913e12c5d1SDavid du Colombier 	freelist(p->words);
923e12c5d1SDavid du Colombier 	runq->argv = p->next;
933e12c5d1SDavid du Colombier 	efree((char *)p);
943e12c5d1SDavid du Colombier }
95dc5a79c1SDavid du Colombier 
96dc5a79c1SDavid du Colombier int
count(word * w)97dc5a79c1SDavid du Colombier count(word *w)
983e12c5d1SDavid du Colombier {
993e12c5d1SDavid du Colombier 	int n;
1003e12c5d1SDavid du Colombier 	for(n = 0;w;n++) w = w->next;
1013e12c5d1SDavid du Colombier 	return n;
1023e12c5d1SDavid du Colombier }
103dc5a79c1SDavid du Colombier 
104dc5a79c1SDavid du Colombier void
pushredir(int type,int from,int to)105dc5a79c1SDavid du Colombier pushredir(int type, int from, int to)
106dc5a79c1SDavid du Colombier {
1073e12c5d1SDavid du Colombier 	redir * rp = new(redir);
1083e12c5d1SDavid du Colombier 	rp->type = type;
1093e12c5d1SDavid du Colombier 	rp->from = from;
1103e12c5d1SDavid du Colombier 	rp->to = to;
1113e12c5d1SDavid du Colombier 	rp->next = runq->redir;
1123e12c5d1SDavid du Colombier 	runq->redir = rp;
1133e12c5d1SDavid du Colombier }
114dc5a79c1SDavid du Colombier 
115*4446a870SDavid du Colombier void
shuffleredir(void)116*4446a870SDavid du Colombier shuffleredir(void)
117*4446a870SDavid du Colombier {
118*4446a870SDavid du Colombier 	redir **rr, *rp;
119*4446a870SDavid du Colombier 
120*4446a870SDavid du Colombier 	rp = runq->redir;
121*4446a870SDavid du Colombier 	if(rp==0)
122*4446a870SDavid du Colombier 		return;
123*4446a870SDavid du Colombier 	runq->redir = rp->next;
124*4446a870SDavid du Colombier 	rp->next = runq->startredir;
125*4446a870SDavid du Colombier 	for(rr = &runq->redir; *rr != rp->next; rr = &((*rr)->next))
126*4446a870SDavid du Colombier 		;
127*4446a870SDavid du Colombier 	*rr = rp;
128*4446a870SDavid du Colombier }
129*4446a870SDavid du Colombier 
130dc5a79c1SDavid du Colombier var*
newvar(char * name,var * next)131dc5a79c1SDavid du Colombier newvar(char *name, var *next)
1323e12c5d1SDavid du Colombier {
1333e12c5d1SDavid du Colombier 	var *v = new(var);
134c6df1444SDavid du Colombier 
135c6df1444SDavid du Colombier 	assert(name != nil);
1363e12c5d1SDavid du Colombier 	v->name = name;
1373e12c5d1SDavid du Colombier 	v->val = 0;
1383e12c5d1SDavid du Colombier 	v->fn = 0;
1393e12c5d1SDavid du Colombier 	v->changed = 0;
1403e12c5d1SDavid du Colombier 	v->fnchanged = 0;
1413e12c5d1SDavid du Colombier 	v->next = next;
1423e12c5d1SDavid du Colombier 	return v;
1433e12c5d1SDavid du Colombier }
144c6df1444SDavid du Colombier 
145c6df1444SDavid du Colombier /* fabricate bootstrap code (*=(argv);. /rc/lib/rcmain $*; exit) */
146c6df1444SDavid du Colombier static void
loadboot(code * base,int nel,char * rcmain)147c6df1444SDavid du Colombier loadboot(code *base, int nel, char *rcmain)
148c6df1444SDavid du Colombier {
149c6df1444SDavid du Colombier 	code *bs;
150c6df1444SDavid du Colombier 
151c6df1444SDavid du Colombier 	bs = base;
152c6df1444SDavid du Colombier 	bs++->i = 1;			/* reference count */
153c6df1444SDavid du Colombier 	bs++->f = Xmark;		/* "* = $*" */
154c6df1444SDavid du Colombier 	bs++->f = Xword;
155c6df1444SDavid du Colombier 	bs++->s="*";
156c6df1444SDavid du Colombier 	bs++->f = Xassign;
157c6df1444SDavid du Colombier 	bs++->f = Xmark;
158c6df1444SDavid du Colombier 	bs++->f = Xmark;
159c6df1444SDavid du Colombier 	bs++->f = Xword;
160c6df1444SDavid du Colombier 	bs++->s="*";
161c6df1444SDavid du Colombier 	bs++->f = Xdol;
162c6df1444SDavid du Colombier 	bs++->f = Xword;
163c6df1444SDavid du Colombier 	bs++->s = rcmain;		/* ". /rc/lib/rcmain $*" */
164c6df1444SDavid du Colombier 	bs++->f = Xword;
165c6df1444SDavid du Colombier 	bs++->s=".";
166c6df1444SDavid du Colombier 	bs++->f = Xsimple;
167c6df1444SDavid du Colombier 	bs++->f = Xexit;		/* exit */
168c6df1444SDavid du Colombier 	bs++->i = 0;			/* not reached */
169c6df1444SDavid du Colombier 	if (bs > base + nel)
170c6df1444SDavid du Colombier 		panic("bootstrap array too small", 0);
171c6df1444SDavid du Colombier }
172c6df1444SDavid du Colombier 
173c6df1444SDavid du Colombier void
usage(void)174c6df1444SDavid du Colombier usage(void)
175c6df1444SDavid du Colombier {
176c6df1444SDavid du Colombier 	pfmt(err, "Usage: rc [-srdiIlxepvV] [-c arg] [-m command] "
177c6df1444SDavid du Colombier 		"[file [arg ...]]\n");
178c6df1444SDavid du Colombier 	Exit("bad flags");
179c6df1444SDavid du Colombier }
180c6df1444SDavid du Colombier 
1813e12c5d1SDavid du Colombier /*
1823e12c5d1SDavid du Colombier  * get command line flags, initialize keywords & traps.
1833e12c5d1SDavid du Colombier  * get values from environment.
1843e12c5d1SDavid du Colombier  * set $pid, $cflag, $*
185c6df1444SDavid du Colombier  * fabricate bootstrap code and start it
1863e12c5d1SDavid du Colombier  * start interpreting code
1873e12c5d1SDavid du Colombier  */
188dc5a79c1SDavid du Colombier void
main(int argc,char * argv[])189dc5a79c1SDavid du Colombier main(int argc, char *argv[])
1903e12c5d1SDavid du Colombier {
1913e12c5d1SDavid du Colombier 	code bootstrap[17];
192c6df1444SDavid du Colombier 	char num[12];
1933e12c5d1SDavid du Colombier 	int i;
194c6df1444SDavid du Colombier 
195c6df1444SDavid du Colombier 	err = openfd(2);
196c6df1444SDavid du Colombier 	ARGBEGIN {
197c6df1444SDavid du Colombier 	case 'd': case 'e': case 'i': case 'l':
198c6df1444SDavid du Colombier 	case 'p': case 'r': case 's': case 'v':
199c6df1444SDavid du Colombier 	case 'x': case 'I': case 'V':
200c6df1444SDavid du Colombier 		flag[ARGC()] = flagset;
201c6df1444SDavid du Colombier 		break;
202c6df1444SDavid du Colombier 	case 'c':
203c6df1444SDavid du Colombier 	case 'm':
204c6df1444SDavid du Colombier 		if (flag[ARGC()])
205c6df1444SDavid du Colombier 			usage();
206c6df1444SDavid du Colombier 		flag[ARGC()] = EARGF(usage());
207c6df1444SDavid du Colombier 		break;
208c6df1444SDavid du Colombier 	default:
209c6df1444SDavid du Colombier 		usage();
210c6df1444SDavid du Colombier 		break;
211c6df1444SDavid du Colombier 	} ARGEND
212c6df1444SDavid du Colombier 	if(argc < 0)
213c6df1444SDavid du Colombier 		usage();
214c6df1444SDavid du Colombier 	if(argv0 == nil)
215c6df1444SDavid du Colombier 		argv0 = "rc";
216c6df1444SDavid du Colombier 	if(argv0[0]=='-')			/* login shell? */
217dc5a79c1SDavid du Colombier 		flag['l'] = flagset;
218dc5a79c1SDavid du Colombier 	if(flag['I'])
219dc5a79c1SDavid du Colombier 		flag['i'] = 0;
220c6df1444SDavid du Colombier 	else if(flag['i']==0 && argc==0 && Isatty(0))
221c6df1444SDavid du Colombier 		flag['i'] = flagset;		/* force interactive */
222c6df1444SDavid du Colombier 
2233e12c5d1SDavid du Colombier 	kinit();
2243e12c5d1SDavid du Colombier 	Trapinit();
2253e12c5d1SDavid du Colombier 	Vinit();
226dc5a79c1SDavid du Colombier 	inttoascii(num, mypid = getpid());
2273e12c5d1SDavid du Colombier 	setvar("pid", newword(num, (word *)0));
228c6df1444SDavid du Colombier 	setvar("cflag", flag['c']? newword(flag['c'], (word *)0): (word *)0);
229c6df1444SDavid du Colombier 	setvar("rcname", newword(argv0, (word *)0));
230c6df1444SDavid du Colombier 
231c6df1444SDavid du Colombier 	loadboot(bootstrap, nelem(bootstrap), (flag['m']? flag['m']: Rcmain));
2323e12c5d1SDavid du Colombier 	start(bootstrap, 1, (var *)0);
2333e12c5d1SDavid du Colombier 	/* prime bootstrap argv */
2343e12c5d1SDavid du Colombier 	pushlist();
235c6df1444SDavid du Colombier 	for(i = argc-1; i >= 0; --i)
236c6df1444SDavid du Colombier 		pushword(argv[i]);
2373e12c5d1SDavid du Colombier 	for(;;){
238dc5a79c1SDavid du Colombier 		if(flag['r'])
239dc5a79c1SDavid du Colombier 			pfnc(err, runq);
2403e12c5d1SDavid du Colombier 		runq->pc++;
2413e12c5d1SDavid du Colombier 		(*runq->code[runq->pc-1].f)();
242dc5a79c1SDavid du Colombier 		if(ntrap)
243dc5a79c1SDavid du Colombier 			dotrap();
2443e12c5d1SDavid du Colombier 	}
2453e12c5d1SDavid du Colombier }
246c6df1444SDavid du Colombier 
2473e12c5d1SDavid du Colombier /*
2483e12c5d1SDavid du Colombier  * Opcode routines
2493e12c5d1SDavid du Colombier  * Arguments on stack (...)
2503e12c5d1SDavid du Colombier  * Arguments in line [...]
2513e12c5d1SDavid du Colombier  * Code in line with jump around {...}
2523e12c5d1SDavid du Colombier  *
2533e12c5d1SDavid du Colombier  * Xappend(file)[fd]			open file to append
2543e12c5d1SDavid du Colombier  * Xassign(name, val)			assign val to name
2553e12c5d1SDavid du Colombier  * Xasync{... Xexit}			make thread for {}, no wait
256dbee7877SDavid du Colombier  * Xbackq(split){... Xreturn}		make thread for {}, push stdout
2573e12c5d1SDavid du Colombier  * Xbang				complement condition
2583e12c5d1SDavid du Colombier  * Xcase(pat, value){...}		exec code on match, leave (value) on
2593e12c5d1SDavid du Colombier  * 					stack
2603e12c5d1SDavid du Colombier  * Xclose[i]				close file descriptor
2613e12c5d1SDavid du Colombier  * Xconc(left, right)			concatenate, push results
2623e12c5d1SDavid du Colombier  * Xcount(name)				push var count
2633e12c5d1SDavid du Colombier  * Xdelfn(name)				delete function definition
2644e3613abSDavid du Colombier  * Xdelhere
2653e12c5d1SDavid du Colombier  * Xdol(name)				get variable value
2663e12c5d1SDavid du Colombier  * Xdup[i j]				dup file descriptor
2674e3613abSDavid du Colombier  * Xeflag
2684e3613abSDavid du Colombier  * Xerror
2693e12c5d1SDavid du Colombier  * Xexit				rc exits with status
2703e12c5d1SDavid du Colombier  * Xfalse{...}				execute {} if false
2713e12c5d1SDavid du Colombier  * Xfn(name){... Xreturn}			define function
2723e12c5d1SDavid du Colombier  * Xfor(var, list){... Xreturn}		for loop
2734e3613abSDavid du Colombier  * Xglob
2744e3613abSDavid du Colombier  * Xif
2754e3613abSDavid du Colombier  * Xifnot
2763e12c5d1SDavid du Colombier  * Xjump[addr]				goto
2773e12c5d1SDavid du Colombier  * Xlocal(name, val)			create local variable, assign value
2783e12c5d1SDavid du Colombier  * Xmark				mark stack
2793e12c5d1SDavid du Colombier  * Xmatch(pat, str)			match pattern, set status
2803e12c5d1SDavid du Colombier  * Xpipe[i j]{... Xreturn}{... Xreturn}	construct a pipe between 2 new threads,
2813e12c5d1SDavid du Colombier  * 					wait for both
2823e12c5d1SDavid du Colombier  * Xpipefd[type]{... Xreturn}		connect {} to pipe (input or output,
2833e12c5d1SDavid du Colombier  * 					depending on type), push /dev/fd/??
2844e3613abSDavid du Colombier  * Xpipewait
2853e12c5d1SDavid du Colombier  * Xpopm(value)				pop value from stack
2864e3613abSDavid du Colombier  * Xpopredir
287c6df1444SDavid du Colombier  * Xqdol(name)				concatenate variable components
2884e3613abSDavid du Colombier  * Xrdcmds
2894e3613abSDavid du Colombier  * Xrdfn
290119a69faSDavid du Colombier  * Xrdwr(file)[fd]			open file for reading and writing
2913e12c5d1SDavid du Colombier  * Xread(file)[fd]			open file to read
2923e12c5d1SDavid du Colombier  * Xreturn				kill thread
2934e3613abSDavid du Colombier  * Xsimple(args)			run command and wait
294c6df1444SDavid du Colombier  * Xsettrue
2954e3613abSDavid du Colombier  * Xsub
2963e12c5d1SDavid du Colombier  * Xsubshell{... Xexit}			execute {} in a subshell and wait
2973e12c5d1SDavid du Colombier  * Xtrue{...}				execute {} if true
2983e12c5d1SDavid du Colombier  * Xunlocal				delete local variable
2994e3613abSDavid du Colombier  * Xwastrue
3003e12c5d1SDavid du Colombier  * Xword[string]			push string
3013e12c5d1SDavid du Colombier  * Xwrite(file)[fd]			open file to write
3023e12c5d1SDavid du Colombier  */
303dc5a79c1SDavid du Colombier 
304dc5a79c1SDavid du Colombier void
Xappend(void)305dc5a79c1SDavid du Colombier Xappend(void)
306dc5a79c1SDavid du Colombier {
3073e12c5d1SDavid du Colombier 	char *file;
3083e12c5d1SDavid du Colombier 	int f;
3093e12c5d1SDavid du Colombier 	switch(count(runq->argv->words)){
310dc5a79c1SDavid du Colombier 	default:
311dc5a79c1SDavid du Colombier 		Xerror1(">> requires singleton");
312dc5a79c1SDavid du Colombier 		return;
313dc5a79c1SDavid du Colombier 	case 0:
314dc5a79c1SDavid du Colombier 		Xerror1(">> requires file");
315dc5a79c1SDavid du Colombier 		return;
316dc5a79c1SDavid du Colombier 	case 1:
317dc5a79c1SDavid du Colombier 		break;
3183e12c5d1SDavid du Colombier 	}
3193e12c5d1SDavid du Colombier 	file = runq->argv->words->word;
3203e12c5d1SDavid du Colombier 	if((f = open(file, 1))<0 && (f = Creat(file))<0){
3217dd7cddfSDavid du Colombier 		pfmt(err, "%s: ", file);
3227dd7cddfSDavid du Colombier 		Xerror("can't open");
3233e12c5d1SDavid du Colombier 		return;
3243e12c5d1SDavid du Colombier 	}
325c6df1444SDavid du Colombier 	seek(f, 0, 2);
3263e12c5d1SDavid du Colombier 	pushredir(ROPEN, f, runq->code[runq->pc].i);
3273e12c5d1SDavid du Colombier 	runq->pc++;
3283e12c5d1SDavid du Colombier 	poplist();
3293e12c5d1SDavid du Colombier }
330dc5a79c1SDavid du Colombier 
331dc5a79c1SDavid du Colombier void
Xsettrue(void)332dc5a79c1SDavid du Colombier Xsettrue(void)
333dc5a79c1SDavid du Colombier {
334219b2ee8SDavid du Colombier 	setstatus("");
335219b2ee8SDavid du Colombier }
336dc5a79c1SDavid du Colombier 
337dc5a79c1SDavid du Colombier void
Xbang(void)338dc5a79c1SDavid du Colombier Xbang(void)
339dc5a79c1SDavid du Colombier {
3403e12c5d1SDavid du Colombier 	setstatus(truestatus()?"false":"");
3413e12c5d1SDavid du Colombier }
342dc5a79c1SDavid du Colombier 
343dc5a79c1SDavid du Colombier void
Xclose(void)344dc5a79c1SDavid du Colombier Xclose(void)
345dc5a79c1SDavid du Colombier {
3463e12c5d1SDavid du Colombier 	pushredir(RCLOSE, runq->code[runq->pc].i, 0);
3473e12c5d1SDavid du Colombier 	runq->pc++;
3483e12c5d1SDavid du Colombier }
349dc5a79c1SDavid du Colombier 
350dc5a79c1SDavid du Colombier void
Xdup(void)351dc5a79c1SDavid du Colombier Xdup(void)
352dc5a79c1SDavid du Colombier {
3533e12c5d1SDavid du Colombier 	pushredir(RDUP, runq->code[runq->pc].i, runq->code[runq->pc+1].i);
3543e12c5d1SDavid du Colombier 	runq->pc+=2;
3553e12c5d1SDavid du Colombier }
356dc5a79c1SDavid du Colombier 
357dc5a79c1SDavid du Colombier void
Xeflag(void)358dc5a79c1SDavid du Colombier Xeflag(void)
359dc5a79c1SDavid du Colombier {
360219b2ee8SDavid du Colombier 	if(eflagok && !truestatus()) Xexit();
361219b2ee8SDavid du Colombier }
362dc5a79c1SDavid du Colombier 
363dc5a79c1SDavid du Colombier void
Xexit(void)364dc5a79c1SDavid du Colombier Xexit(void)
365dc5a79c1SDavid du Colombier {
3663e12c5d1SDavid du Colombier 	struct var *trapreq;
3673e12c5d1SDavid du Colombier 	struct word *starval;
3683e12c5d1SDavid du Colombier 	static int beenhere = 0;
3693e12c5d1SDavid du Colombier 	if(getpid()==mypid && !beenhere){
3703e12c5d1SDavid du Colombier 		trapreq = vlook("sigexit");
3713e12c5d1SDavid du Colombier 		if(trapreq->fn){
3723e12c5d1SDavid du Colombier 			beenhere = 1;
3733e12c5d1SDavid du Colombier 			--runq->pc;
374219b2ee8SDavid du Colombier 			starval = vlook("*")->val;
3753e12c5d1SDavid du Colombier 			start(trapreq->fn, trapreq->pc, (struct var *)0);
3763e12c5d1SDavid du Colombier 			runq->local = newvar(strdup("*"), runq->local);
3773e12c5d1SDavid du Colombier 			runq->local->val = copywords(starval, (struct word *)0);
3783e12c5d1SDavid du Colombier 			runq->local->changed = 1;
3793e12c5d1SDavid du Colombier 			runq->redir = runq->startredir = 0;
3803e12c5d1SDavid du Colombier 			return;
3813e12c5d1SDavid du Colombier 		}
3823e12c5d1SDavid du Colombier 	}
3833e12c5d1SDavid du Colombier 	Exit(getstatus());
3843e12c5d1SDavid du Colombier }
385dc5a79c1SDavid du Colombier 
386dc5a79c1SDavid du Colombier void
Xfalse(void)387dc5a79c1SDavid du Colombier Xfalse(void)
388dc5a79c1SDavid du Colombier {
3893e12c5d1SDavid du Colombier 	if(truestatus()) runq->pc = runq->code[runq->pc].i;
3903e12c5d1SDavid du Colombier 	else runq->pc++;
3913e12c5d1SDavid du Colombier }
3923e12c5d1SDavid du Colombier int ifnot;		/* dynamic if not flag */
393dc5a79c1SDavid du Colombier 
394dc5a79c1SDavid du Colombier void
Xifnot(void)395dc5a79c1SDavid du Colombier Xifnot(void)
396dc5a79c1SDavid du Colombier {
3973e12c5d1SDavid du Colombier 	if(ifnot)
3983e12c5d1SDavid du Colombier 		runq->pc++;
3993e12c5d1SDavid du Colombier 	else
4003e12c5d1SDavid du Colombier 		runq->pc = runq->code[runq->pc].i;
4013e12c5d1SDavid du Colombier }
402dc5a79c1SDavid du Colombier 
403dc5a79c1SDavid du Colombier void
Xjump(void)404dc5a79c1SDavid du Colombier Xjump(void)
405dc5a79c1SDavid du Colombier {
4063e12c5d1SDavid du Colombier 	runq->pc = runq->code[runq->pc].i;
4073e12c5d1SDavid du Colombier }
408dc5a79c1SDavid du Colombier 
409dc5a79c1SDavid du Colombier void
Xmark(void)410dc5a79c1SDavid du Colombier Xmark(void)
411dc5a79c1SDavid du Colombier {
4123e12c5d1SDavid du Colombier 	pushlist();
4133e12c5d1SDavid du Colombier }
414dc5a79c1SDavid du Colombier 
415dc5a79c1SDavid du Colombier void
Xpopm(void)416dc5a79c1SDavid du Colombier Xpopm(void)
417dc5a79c1SDavid du Colombier {
4183e12c5d1SDavid du Colombier 	poplist();
4193e12c5d1SDavid du Colombier }
420dc5a79c1SDavid du Colombier 
421dc5a79c1SDavid du Colombier void
Xread(void)422dc5a79c1SDavid du Colombier Xread(void)
423dc5a79c1SDavid du Colombier {
4243e12c5d1SDavid du Colombier 	char *file;
4253e12c5d1SDavid du Colombier 	int f;
4263e12c5d1SDavid du Colombier 	switch(count(runq->argv->words)){
427dc5a79c1SDavid du Colombier 	default:
428dc5a79c1SDavid du Colombier 		Xerror1("< requires singleton\n");
429dc5a79c1SDavid du Colombier 		return;
430dc5a79c1SDavid du Colombier 	case 0:
431dc5a79c1SDavid du Colombier 		Xerror1("< requires file\n");
432dc5a79c1SDavid du Colombier 		return;
433dc5a79c1SDavid du Colombier 	case 1:
434dc5a79c1SDavid du Colombier 		break;
4353e12c5d1SDavid du Colombier 	}
4363e12c5d1SDavid du Colombier 	file = runq->argv->words->word;
4373e12c5d1SDavid du Colombier 	if((f = open(file, 0))<0){
4387dd7cddfSDavid du Colombier 		pfmt(err, "%s: ", file);
4397dd7cddfSDavid du Colombier 		Xerror("can't open");
4403e12c5d1SDavid du Colombier 		return;
4413e12c5d1SDavid du Colombier 	}
4423e12c5d1SDavid du Colombier 	pushredir(ROPEN, f, runq->code[runq->pc].i);
4433e12c5d1SDavid du Colombier 	runq->pc++;
4443e12c5d1SDavid du Colombier 	poplist();
4453e12c5d1SDavid du Colombier }
446dc5a79c1SDavid du Colombier 
447dc5a79c1SDavid du Colombier void
Xrdwr(void)448119a69faSDavid du Colombier Xrdwr(void)
449119a69faSDavid du Colombier {
450119a69faSDavid du Colombier 	char *file;
451119a69faSDavid du Colombier 	int f;
452119a69faSDavid du Colombier 
453119a69faSDavid du Colombier 	switch(count(runq->argv->words)){
454119a69faSDavid du Colombier 	default:
455119a69faSDavid du Colombier 		Xerror1("<> requires singleton\n");
456119a69faSDavid du Colombier 		return;
457119a69faSDavid du Colombier 	case 0:
458119a69faSDavid du Colombier 		Xerror1("<> requires file\n");
459119a69faSDavid du Colombier 		return;
460119a69faSDavid du Colombier 	case 1:
461119a69faSDavid du Colombier 		break;
462119a69faSDavid du Colombier 	}
463119a69faSDavid du Colombier 	file = runq->argv->words->word;
464119a69faSDavid du Colombier 	if((f = open(file, ORDWR))<0){
465119a69faSDavid du Colombier 		pfmt(err, "%s: ", file);
466119a69faSDavid du Colombier 		Xerror("can't open");
467119a69faSDavid du Colombier 		return;
468119a69faSDavid du Colombier 	}
469119a69faSDavid du Colombier 	pushredir(ROPEN, f, runq->code[runq->pc].i);
470119a69faSDavid du Colombier 	runq->pc++;
471119a69faSDavid du Colombier 	poplist();
472119a69faSDavid du Colombier }
473119a69faSDavid du Colombier 
474119a69faSDavid du Colombier void
turfredir(void)475dc5a79c1SDavid du Colombier turfredir(void)
476dc5a79c1SDavid du Colombier {
4773e12c5d1SDavid du Colombier 	while(runq->redir!=runq->startredir)
4783e12c5d1SDavid du Colombier 		Xpopredir();
4793e12c5d1SDavid du Colombier }
480dc5a79c1SDavid du Colombier 
481dc5a79c1SDavid du Colombier void
Xpopredir(void)482dc5a79c1SDavid du Colombier Xpopredir(void)
483dc5a79c1SDavid du Colombier {
4843e12c5d1SDavid du Colombier 	struct redir *rp = runq->redir;
485dc5a79c1SDavid du Colombier 	if(rp==0)
486dc5a79c1SDavid du Colombier 		panic("turfredir null!", 0);
4873e12c5d1SDavid du Colombier 	runq->redir = rp->next;
488dc5a79c1SDavid du Colombier 	if(rp->type==ROPEN)
489dc5a79c1SDavid du Colombier 		close(rp->from);
4903e12c5d1SDavid du Colombier 	efree((char *)rp);
4913e12c5d1SDavid du Colombier }
492dc5a79c1SDavid du Colombier 
493dc5a79c1SDavid du Colombier void
Xreturn(void)494dc5a79c1SDavid du Colombier Xreturn(void)
495dc5a79c1SDavid du Colombier {
4963e12c5d1SDavid du Colombier 	struct thread *p = runq;
4973e12c5d1SDavid du Colombier 	turfredir();
4983e12c5d1SDavid du Colombier 	while(p->argv) poplist();
4993e12c5d1SDavid du Colombier 	codefree(p->code);
5003e12c5d1SDavid du Colombier 	runq = p->ret;
5013e12c5d1SDavid du Colombier 	efree((char *)p);
502dc5a79c1SDavid du Colombier 	if(runq==0)
503dc5a79c1SDavid du Colombier 		Exit(getstatus());
5043e12c5d1SDavid du Colombier }
505dc5a79c1SDavid du Colombier 
506dc5a79c1SDavid du Colombier void
Xtrue(void)507dc5a79c1SDavid du Colombier Xtrue(void)
508dc5a79c1SDavid du Colombier {
5093e12c5d1SDavid du Colombier 	if(truestatus()) runq->pc++;
5103e12c5d1SDavid du Colombier 	else runq->pc = runq->code[runq->pc].i;
5113e12c5d1SDavid du Colombier }
512dc5a79c1SDavid du Colombier 
513dc5a79c1SDavid du Colombier void
Xif(void)514dc5a79c1SDavid du Colombier Xif(void)
515dc5a79c1SDavid du Colombier {
5163e12c5d1SDavid du Colombier 	ifnot = 1;
5173e12c5d1SDavid du Colombier 	if(truestatus()) runq->pc++;
5183e12c5d1SDavid du Colombier 	else runq->pc = runq->code[runq->pc].i;
5193e12c5d1SDavid du Colombier }
520dc5a79c1SDavid du Colombier 
521dc5a79c1SDavid du Colombier void
Xwastrue(void)522dc5a79c1SDavid du Colombier Xwastrue(void)
523dc5a79c1SDavid du Colombier {
5243e12c5d1SDavid du Colombier 	ifnot = 0;
5253e12c5d1SDavid du Colombier }
526dc5a79c1SDavid du Colombier 
527dc5a79c1SDavid du Colombier void
Xword(void)528dc5a79c1SDavid du Colombier Xword(void)
529dc5a79c1SDavid du Colombier {
5303e12c5d1SDavid du Colombier 	pushword(runq->code[runq->pc++].s);
5313e12c5d1SDavid du Colombier }
532dc5a79c1SDavid du Colombier 
533dc5a79c1SDavid du Colombier void
Xwrite(void)534dc5a79c1SDavid du Colombier Xwrite(void)
535dc5a79c1SDavid du Colombier {
5363e12c5d1SDavid du Colombier 	char *file;
5373e12c5d1SDavid du Colombier 	int f;
5383e12c5d1SDavid du Colombier 	switch(count(runq->argv->words)){
539dc5a79c1SDavid du Colombier 	default:
540dc5a79c1SDavid du Colombier 		Xerror1("> requires singleton\n");
541dc5a79c1SDavid du Colombier 		return;
542dc5a79c1SDavid du Colombier 	case 0:
543dc5a79c1SDavid du Colombier 		Xerror1("> requires file\n");
544dc5a79c1SDavid du Colombier 		return;
545dc5a79c1SDavid du Colombier 	case 1:
546dc5a79c1SDavid du Colombier 		break;
5473e12c5d1SDavid du Colombier 	}
5483e12c5d1SDavid du Colombier 	file = runq->argv->words->word;
5493e12c5d1SDavid du Colombier 	if((f = Creat(file))<0){
5507dd7cddfSDavid du Colombier 		pfmt(err, "%s: ", file);
5517dd7cddfSDavid du Colombier 		Xerror("can't open");
5523e12c5d1SDavid du Colombier 		return;
5533e12c5d1SDavid du Colombier 	}
5543e12c5d1SDavid du Colombier 	pushredir(ROPEN, f, runq->code[runq->pc].i);
5553e12c5d1SDavid du Colombier 	runq->pc++;
5563e12c5d1SDavid du Colombier 	poplist();
5573e12c5d1SDavid du Colombier }
558dc5a79c1SDavid du Colombier 
559dc5a79c1SDavid du Colombier char*
list2str(word * words)560dc5a79c1SDavid du Colombier list2str(word *words)
561dc5a79c1SDavid du Colombier {
5623e12c5d1SDavid du Colombier 	char *value, *s, *t;
5633e12c5d1SDavid du Colombier 	int len = 0;
5643e12c5d1SDavid du Colombier 	word *ap;
5653e12c5d1SDavid du Colombier 	for(ap = words;ap;ap = ap->next)
5663e12c5d1SDavid du Colombier 		len+=1+strlen(ap->word);
5673e12c5d1SDavid du Colombier 	value = emalloc(len+1);
5683e12c5d1SDavid du Colombier 	s = value;
5693e12c5d1SDavid du Colombier 	for(ap = words;ap;ap = ap->next){
5703e12c5d1SDavid du Colombier 		for(t = ap->word;*t;) *s++=*t++;
5713e12c5d1SDavid du Colombier 		*s++=' ';
5723e12c5d1SDavid du Colombier 	}
573dc5a79c1SDavid du Colombier 	if(s==value)
574dc5a79c1SDavid du Colombier 		*s='\0';
5753e12c5d1SDavid du Colombier 	else s[-1]='\0';
5763e12c5d1SDavid du Colombier 	return value;
5773e12c5d1SDavid du Colombier }
578dc5a79c1SDavid du Colombier 
579dc5a79c1SDavid du Colombier void
Xmatch(void)580dc5a79c1SDavid du Colombier Xmatch(void)
581dc5a79c1SDavid du Colombier {
5823e12c5d1SDavid du Colombier 	word *p;
5833e12c5d1SDavid du Colombier 	char *subject;
5843e12c5d1SDavid du Colombier 	subject = list2str(runq->argv->words);
5853e12c5d1SDavid du Colombier 	setstatus("no match");
5863e12c5d1SDavid du Colombier 	for(p = runq->argv->next->words;p;p = p->next)
5873e12c5d1SDavid du Colombier 		if(match(subject, p->word, '\0')){
5883e12c5d1SDavid du Colombier 			setstatus("");
5893e12c5d1SDavid du Colombier 			break;
5903e12c5d1SDavid du Colombier 		}
5913e12c5d1SDavid du Colombier 	efree(subject);
5923e12c5d1SDavid du Colombier 	poplist();
5933e12c5d1SDavid du Colombier 	poplist();
5943e12c5d1SDavid du Colombier }
595dc5a79c1SDavid du Colombier 
596dc5a79c1SDavid du Colombier void
Xcase(void)597dc5a79c1SDavid du Colombier Xcase(void)
598dc5a79c1SDavid du Colombier {
5993e12c5d1SDavid du Colombier 	word *p;
6003e12c5d1SDavid du Colombier 	char *s;
6013e12c5d1SDavid du Colombier 	int ok = 0;
6023e12c5d1SDavid du Colombier 	s = list2str(runq->argv->next->words);
6033e12c5d1SDavid du Colombier 	for(p = runq->argv->words;p;p = p->next){
6043e12c5d1SDavid du Colombier 		if(match(s, p->word, '\0')){
6053e12c5d1SDavid du Colombier 			ok = 1;
6063e12c5d1SDavid du Colombier 			break;
6073e12c5d1SDavid du Colombier 		}
6083e12c5d1SDavid du Colombier 	}
6093e12c5d1SDavid du Colombier 	efree(s);
6103e12c5d1SDavid du Colombier 	if(ok)
6113e12c5d1SDavid du Colombier 		runq->pc++;
6123e12c5d1SDavid du Colombier 	else
6133e12c5d1SDavid du Colombier 		runq->pc = runq->code[runq->pc].i;
6143e12c5d1SDavid du Colombier 	poplist();
6153e12c5d1SDavid du Colombier }
616dc5a79c1SDavid du Colombier 
617dc5a79c1SDavid du Colombier word*
conclist(word * lp,word * rp,word * tail)618dc5a79c1SDavid du Colombier conclist(word *lp, word *rp, word *tail)
6193e12c5d1SDavid du Colombier {
6203e12c5d1SDavid du Colombier 	char *buf;
6213e12c5d1SDavid du Colombier 	word *v;
6223e12c5d1SDavid du Colombier 	if(lp->next || rp->next)
623276e7d6dSDavid du Colombier 		tail = conclist(lp->next==0? lp: lp->next,
624276e7d6dSDavid du Colombier 			rp->next==0? rp: rp->next, tail);
625276e7d6dSDavid du Colombier 	buf = emalloc(strlen(lp->word)+strlen((char *)rp->word)+1);
6263e12c5d1SDavid du Colombier 	strcpy(buf, lp->word);
6273e12c5d1SDavid du Colombier 	strcat(buf, rp->word);
6283e12c5d1SDavid du Colombier 	v = newword(buf, tail);
6293e12c5d1SDavid du Colombier 	efree(buf);
6303e12c5d1SDavid du Colombier 	return v;
6313e12c5d1SDavid du Colombier }
632dc5a79c1SDavid du Colombier 
633dc5a79c1SDavid du Colombier void
Xconc(void)634dc5a79c1SDavid du Colombier Xconc(void)
635dc5a79c1SDavid du Colombier {
6363e12c5d1SDavid du Colombier 	word *lp = runq->argv->words;
6373e12c5d1SDavid du Colombier 	word *rp = runq->argv->next->words;
6383e12c5d1SDavid du Colombier 	word *vp = runq->argv->next->next->words;
6393e12c5d1SDavid du Colombier 	int lc = count(lp), rc = count(rp);
6403e12c5d1SDavid du Colombier 	if(lc!=0 || rc!=0){
6413e12c5d1SDavid du Colombier 		if(lc==0 || rc==0){
6429a747e4fSDavid du Colombier 			Xerror1("null list in concatenation");
6433e12c5d1SDavid du Colombier 			return;
6443e12c5d1SDavid du Colombier 		}
6453e12c5d1SDavid du Colombier 		if(lc!=1 && rc!=1 && lc!=rc){
6469a747e4fSDavid du Colombier 			Xerror1("mismatched list lengths in concatenation");
6473e12c5d1SDavid du Colombier 			return;
6483e12c5d1SDavid du Colombier 		}
6493e12c5d1SDavid du Colombier 		vp = conclist(lp, rp, vp);
6503e12c5d1SDavid du Colombier 	}
6513e12c5d1SDavid du Colombier 	poplist();
6523e12c5d1SDavid du Colombier 	poplist();
6533e12c5d1SDavid du Colombier 	runq->argv->words = vp;
6543e12c5d1SDavid du Colombier }
655dc5a79c1SDavid du Colombier 
656dc5a79c1SDavid du Colombier void
Xassign(void)657dc5a79c1SDavid du Colombier Xassign(void)
658dc5a79c1SDavid du Colombier {
6593e12c5d1SDavid du Colombier 	var *v;
6603e12c5d1SDavid du Colombier 	if(count(runq->argv->words)!=1){
6619a747e4fSDavid du Colombier 		Xerror1("variable name not singleton!");
6623e12c5d1SDavid du Colombier 		return;
6633e12c5d1SDavid du Colombier 	}
6643e12c5d1SDavid du Colombier 	deglob(runq->argv->words->word);
6653e12c5d1SDavid du Colombier 	v = vlook(runq->argv->words->word);
6663e12c5d1SDavid du Colombier 	poplist();
6673e12c5d1SDavid du Colombier 	globlist();
6683e12c5d1SDavid du Colombier 	freewords(v->val);
6693e12c5d1SDavid du Colombier 	v->val = runq->argv->words;
6703e12c5d1SDavid du Colombier 	v->changed = 1;
6713e12c5d1SDavid du Colombier 	runq->argv->words = 0;
6723e12c5d1SDavid du Colombier 	poplist();
6733e12c5d1SDavid du Colombier }
6743e12c5d1SDavid du Colombier /*
6753e12c5d1SDavid du Colombier  * copy arglist a, adding the copy to the front of tail
6763e12c5d1SDavid du Colombier  */
677dc5a79c1SDavid du Colombier 
678dc5a79c1SDavid du Colombier word*
copywords(word * a,word * tail)679dc5a79c1SDavid du Colombier copywords(word *a, word *tail)
6803e12c5d1SDavid du Colombier {
6813e12c5d1SDavid du Colombier 	word *v = 0, **end;
6823e12c5d1SDavid du Colombier 	for(end=&v;a;a = a->next,end=&(*end)->next)
6833e12c5d1SDavid du Colombier 		*end = newword(a->word, 0);
6843e12c5d1SDavid du Colombier 	*end = tail;
6853e12c5d1SDavid du Colombier 	return v;
6863e12c5d1SDavid du Colombier }
687dc5a79c1SDavid du Colombier 
688dc5a79c1SDavid du Colombier void
Xdol(void)689dc5a79c1SDavid du Colombier Xdol(void)
690dc5a79c1SDavid du Colombier {
6913e12c5d1SDavid du Colombier 	word *a, *star;
6923e12c5d1SDavid du Colombier 	char *s, *t;
6933e12c5d1SDavid du Colombier 	int n;
6943e12c5d1SDavid du Colombier 	if(count(runq->argv->words)!=1){
6959a747e4fSDavid du Colombier 		Xerror1("variable name not singleton!");
6963e12c5d1SDavid du Colombier 		return;
6973e12c5d1SDavid du Colombier 	}
6983e12c5d1SDavid du Colombier 	s = runq->argv->words->word;
6993e12c5d1SDavid du Colombier 	deglob(s);
7003e12c5d1SDavid du Colombier 	n = 0;
70199eb86a7SDavid du Colombier 	for(t = s;'0'<=*t && *t<='9';t++) n = n*10+*t-'0';
7023e12c5d1SDavid du Colombier 	a = runq->argv->next->words;
7033e12c5d1SDavid du Colombier 	if(n==0 || *t)
7043e12c5d1SDavid du Colombier 		a = copywords(vlook(s)->val, a);
7053e12c5d1SDavid du Colombier 	else{
7063e12c5d1SDavid du Colombier 		star = vlook("*")->val;
7073e12c5d1SDavid du Colombier 		if(star && 1<=n && n<=count(star)){
70899eb86a7SDavid du Colombier 			while(--n) star = star->next;
7093e12c5d1SDavid du Colombier 			a = newword(star->word, a);
7103e12c5d1SDavid du Colombier 		}
7113e12c5d1SDavid du Colombier 	}
7123e12c5d1SDavid du Colombier 	poplist();
7133e12c5d1SDavid du Colombier 	runq->argv->words = a;
7143e12c5d1SDavid du Colombier }
715dc5a79c1SDavid du Colombier 
716dc5a79c1SDavid du Colombier void
Xqdol(void)717dc5a79c1SDavid du Colombier Xqdol(void)
718dc5a79c1SDavid du Colombier {
7193e12c5d1SDavid du Colombier 	word *a, *p;
7203e12c5d1SDavid du Colombier 	char *s;
7213e12c5d1SDavid du Colombier 	int n;
7223e12c5d1SDavid du Colombier 	if(count(runq->argv->words)!=1){
7239a747e4fSDavid du Colombier 		Xerror1("variable name not singleton!");
7243e12c5d1SDavid du Colombier 		return;
7253e12c5d1SDavid du Colombier 	}
7263e12c5d1SDavid du Colombier 	s = runq->argv->words->word;
7273e12c5d1SDavid du Colombier 	deglob(s);
7283e12c5d1SDavid du Colombier 	a = vlook(s)->val;
7293e12c5d1SDavid du Colombier 	poplist();
7303e12c5d1SDavid du Colombier 	n = count(a);
7313e12c5d1SDavid du Colombier 	if(n==0){
7323e12c5d1SDavid du Colombier 		pushword("");
7333e12c5d1SDavid du Colombier 		return;
7343e12c5d1SDavid du Colombier 	}
7353e12c5d1SDavid du Colombier 	for(p = a;p;p = p->next) n+=strlen(p->word);
7363e12c5d1SDavid du Colombier 	s = emalloc(n);
7373e12c5d1SDavid du Colombier 	if(a){
7383e12c5d1SDavid du Colombier 		strcpy(s, a->word);
7393e12c5d1SDavid du Colombier 		for(p = a->next;p;p = p->next){
7403e12c5d1SDavid du Colombier 			strcat(s, " ");
7413e12c5d1SDavid du Colombier 			strcat(s, p->word);
7423e12c5d1SDavid du Colombier 		}
7433e12c5d1SDavid du Colombier 	}
7443e12c5d1SDavid du Colombier 	else
7453e12c5d1SDavid du Colombier 		s[0]='\0';
7463e12c5d1SDavid du Colombier 	pushword(s);
7473e12c5d1SDavid du Colombier 	efree(s);
7483e12c5d1SDavid du Colombier }
749dc5a79c1SDavid du Colombier 
750dc5a79c1SDavid du Colombier word*
copynwords(word * a,word * tail,int n)7515e061cc0SDavid du Colombier copynwords(word *a, word *tail, int n)
7525e061cc0SDavid du Colombier {
7535e061cc0SDavid du Colombier 	word *v, **end;
7545e061cc0SDavid du Colombier 
7555e061cc0SDavid du Colombier 	v = 0;
7565e061cc0SDavid du Colombier 	end = &v;
7575e061cc0SDavid du Colombier 	while(n-- > 0){
7585e061cc0SDavid du Colombier 		*end = newword(a->word, 0);
7595e061cc0SDavid du Colombier 		end = &(*end)->next;
7605e061cc0SDavid du Colombier 		a = a->next;
7615e061cc0SDavid du Colombier 	}
7625e061cc0SDavid du Colombier 	*end = tail;
7635e061cc0SDavid du Colombier 	return v;
7645e061cc0SDavid du Colombier }
7655e061cc0SDavid du Colombier 
7665e061cc0SDavid du Colombier word*
subwords(word * val,int len,word * sub,word * a)767dc5a79c1SDavid du Colombier subwords(word *val, int len, word *sub, word *a)
7683e12c5d1SDavid du Colombier {
7695e061cc0SDavid du Colombier 	int n, m;
7703e12c5d1SDavid du Colombier 	char *s;
771dc5a79c1SDavid du Colombier 	if(!sub)
772dc5a79c1SDavid du Colombier 		return a;
7733e12c5d1SDavid du Colombier 	a = subwords(val, len, sub->next, a);
7743e12c5d1SDavid du Colombier 	s = sub->word;
7753e12c5d1SDavid du Colombier 	deglob(s);
7765e061cc0SDavid du Colombier 	m = 0;
7773e12c5d1SDavid du Colombier 	n = 0;
7785e061cc0SDavid du Colombier 	while('0'<=*s && *s<='9')
7795e061cc0SDavid du Colombier 		n = n*10+ *s++ -'0';
7805e061cc0SDavid du Colombier 	if(*s == '-'){
7815e061cc0SDavid du Colombier 		if(*++s == 0)
7825e061cc0SDavid du Colombier 			m = len - n;
7835e061cc0SDavid du Colombier 		else{
7845e061cc0SDavid du Colombier 			while('0'<=*s && *s<='9')
7855e061cc0SDavid du Colombier 				m = m*10+ *s++ -'0';
7865e061cc0SDavid du Colombier 			m -= n;
7875e061cc0SDavid du Colombier 		}
7885e061cc0SDavid du Colombier 	}
7895e061cc0SDavid du Colombier 	if(n<1 || n>len || m<0)
790dc5a79c1SDavid du Colombier 		return a;
7915e061cc0SDavid du Colombier 	if(n+m>len)
7925e061cc0SDavid du Colombier 		m = len-n;
7935e061cc0SDavid du Colombier 	while(--n > 0)
7945e061cc0SDavid du Colombier 		val = val->next;
7955e061cc0SDavid du Colombier 	return copynwords(val, a, m+1);
7963e12c5d1SDavid du Colombier }
797dc5a79c1SDavid du Colombier 
798dc5a79c1SDavid du Colombier void
Xsub(void)799dc5a79c1SDavid du Colombier Xsub(void)
800dc5a79c1SDavid du Colombier {
8013e12c5d1SDavid du Colombier 	word *a, *v;
8023e12c5d1SDavid du Colombier 	char *s;
8033e12c5d1SDavid du Colombier 	if(count(runq->argv->next->words)!=1){
8049a747e4fSDavid du Colombier 		Xerror1("variable name not singleton!");
8053e12c5d1SDavid du Colombier 		return;
8063e12c5d1SDavid du Colombier 	}
8073e12c5d1SDavid du Colombier 	s = runq->argv->next->words->word;
8083e12c5d1SDavid du Colombier 	deglob(s);
8093e12c5d1SDavid du Colombier 	a = runq->argv->next->next->words;
8103e12c5d1SDavid du Colombier 	v = vlook(s)->val;
8113e12c5d1SDavid du Colombier 	a = subwords(v, count(v), runq->argv->words, a);
8123e12c5d1SDavid du Colombier 	poplist();
8133e12c5d1SDavid du Colombier 	poplist();
8143e12c5d1SDavid du Colombier 	runq->argv->words = a;
8153e12c5d1SDavid du Colombier }
816dc5a79c1SDavid du Colombier 
817dc5a79c1SDavid du Colombier void
Xcount(void)818dc5a79c1SDavid du Colombier Xcount(void)
819dc5a79c1SDavid du Colombier {
8203e12c5d1SDavid du Colombier 	word *a;
8213e12c5d1SDavid du Colombier 	char *s, *t;
8223e12c5d1SDavid du Colombier 	int n;
8233e12c5d1SDavid du Colombier 	char num[12];
8243e12c5d1SDavid du Colombier 	if(count(runq->argv->words)!=1){
8259a747e4fSDavid du Colombier 		Xerror1("variable name not singleton!");
8263e12c5d1SDavid du Colombier 		return;
8273e12c5d1SDavid du Colombier 	}
8283e12c5d1SDavid du Colombier 	s = runq->argv->words->word;
8293e12c5d1SDavid du Colombier 	deglob(s);
8303e12c5d1SDavid du Colombier 	n = 0;
8313e12c5d1SDavid du Colombier 	for(t = s;'0'<=*t && *t<='9';t++) n = n*10+*t-'0';
8323e12c5d1SDavid du Colombier 	if(n==0 || *t){
8333e12c5d1SDavid du Colombier 		a = vlook(s)->val;
834dc5a79c1SDavid du Colombier 		inttoascii(num, count(a));
8353e12c5d1SDavid du Colombier 	}
8363e12c5d1SDavid du Colombier 	else{
8373e12c5d1SDavid du Colombier 		a = vlook("*")->val;
838dc5a79c1SDavid du Colombier 		inttoascii(num, a && 1<=n && n<=count(a)?1:0);
8393e12c5d1SDavid du Colombier 	}
8403e12c5d1SDavid du Colombier 	poplist();
8413e12c5d1SDavid du Colombier 	pushword(num);
8423e12c5d1SDavid du Colombier }
843dc5a79c1SDavid du Colombier 
844dc5a79c1SDavid du Colombier void
Xlocal(void)845dc5a79c1SDavid du Colombier Xlocal(void)
846dc5a79c1SDavid du Colombier {
8473e12c5d1SDavid du Colombier 	if(count(runq->argv->words)!=1){
8489a747e4fSDavid du Colombier 		Xerror1("variable name must be singleton\n");
8493e12c5d1SDavid du Colombier 		return;
8503e12c5d1SDavid du Colombier 	}
8513e12c5d1SDavid du Colombier 	deglob(runq->argv->words->word);
8523e12c5d1SDavid du Colombier 	runq->local = newvar(strdup(runq->argv->words->word), runq->local);
8533e12c5d1SDavid du Colombier 	poplist();
854fed0fa9eSDavid du Colombier 	globlist();
855fed0fa9eSDavid du Colombier 	runq->local->val = runq->argv->words;
856fed0fa9eSDavid du Colombier 	runq->local->changed = 1;
857fed0fa9eSDavid du Colombier 	runq->argv->words = 0;
8583e12c5d1SDavid du Colombier 	poplist();
8593e12c5d1SDavid du Colombier }
860dc5a79c1SDavid du Colombier 
861dc5a79c1SDavid du Colombier void
Xunlocal(void)862dc5a79c1SDavid du Colombier Xunlocal(void)
863dc5a79c1SDavid du Colombier {
8643e12c5d1SDavid du Colombier 	var *v = runq->local, *hid;
865dc5a79c1SDavid du Colombier 	if(v==0)
866dc5a79c1SDavid du Colombier 		panic("Xunlocal: no locals!", 0);
8673e12c5d1SDavid du Colombier 	runq->local = v->next;
8683e12c5d1SDavid du Colombier 	hid = vlook(v->name);
8693e12c5d1SDavid du Colombier 	hid->changed = 1;
8703e12c5d1SDavid du Colombier 	efree(v->name);
8713e12c5d1SDavid du Colombier 	freewords(v->val);
8723e12c5d1SDavid du Colombier 	efree((char *)v);
8733e12c5d1SDavid du Colombier }
874dc5a79c1SDavid du Colombier 
875dc5a79c1SDavid du Colombier void
freewords(word * w)876dc5a79c1SDavid du Colombier freewords(word *w)
8773e12c5d1SDavid du Colombier {
8783e12c5d1SDavid du Colombier 	word *nw;
8793e12c5d1SDavid du Colombier 	while(w){
8803e12c5d1SDavid du Colombier 		efree(w->word);
8813e12c5d1SDavid du Colombier 		nw = w->next;
8823e12c5d1SDavid du Colombier 		efree((char *)w);
8833e12c5d1SDavid du Colombier 		w = nw;
8843e12c5d1SDavid du Colombier 	}
8853e12c5d1SDavid du Colombier }
886dc5a79c1SDavid du Colombier 
887dc5a79c1SDavid du Colombier void
Xfn(void)888dc5a79c1SDavid du Colombier Xfn(void)
889dc5a79c1SDavid du Colombier {
8903e12c5d1SDavid du Colombier 	var *v;
8913e12c5d1SDavid du Colombier 	word *a;
8923e12c5d1SDavid du Colombier 	int end;
8933e12c5d1SDavid du Colombier 	end = runq->code[runq->pc].i;
894fed0fa9eSDavid du Colombier 	globlist();
8953e12c5d1SDavid du Colombier 	for(a = runq->argv->words;a;a = a->next){
8963e12c5d1SDavid du Colombier 		v = gvlook(a->word);
897dc5a79c1SDavid du Colombier 		if(v->fn)
898dc5a79c1SDavid du Colombier 			codefree(v->fn);
8993e12c5d1SDavid du Colombier 		v->fn = codecopy(runq->code);
9003e12c5d1SDavid du Colombier 		v->pc = runq->pc+2;
9013e12c5d1SDavid du Colombier 		v->fnchanged = 1;
9023e12c5d1SDavid du Colombier 	}
9033e12c5d1SDavid du Colombier 	runq->pc = end;
9043e12c5d1SDavid du Colombier 	poplist();
9053e12c5d1SDavid du Colombier }
906dc5a79c1SDavid du Colombier 
907dc5a79c1SDavid du Colombier void
Xdelfn(void)908dc5a79c1SDavid du Colombier Xdelfn(void)
909dc5a79c1SDavid du Colombier {
9103e12c5d1SDavid du Colombier 	var *v;
9113e12c5d1SDavid du Colombier 	word *a;
9123e12c5d1SDavid du Colombier 	for(a = runq->argv->words;a;a = a->next){
9133e12c5d1SDavid du Colombier 		v = gvlook(a->word);
914dc5a79c1SDavid du Colombier 		if(v->fn)
915dc5a79c1SDavid du Colombier 			codefree(v->fn);
9163e12c5d1SDavid du Colombier 		v->fn = 0;
9173e12c5d1SDavid du Colombier 		v->fnchanged = 1;
9183e12c5d1SDavid du Colombier 	}
9193e12c5d1SDavid du Colombier 	poplist();
9203e12c5d1SDavid du Colombier }
921dc5a79c1SDavid du Colombier 
922dc5a79c1SDavid du Colombier char*
concstatus(char * s,char * t)923dc5a79c1SDavid du Colombier concstatus(char *s, char *t)
9243e12c5d1SDavid du Colombier {
9253e12c5d1SDavid du Colombier 	static char v[NSTATUS+1];
9263e12c5d1SDavid du Colombier 	int n = strlen(s);
9273e12c5d1SDavid du Colombier 	strncpy(v, s, NSTATUS);
9283e12c5d1SDavid du Colombier 	if(n<NSTATUS){
9293e12c5d1SDavid du Colombier 		v[n]='|';
9303e12c5d1SDavid du Colombier 		strncpy(v+n+1, t, NSTATUS-n-1);
9313e12c5d1SDavid du Colombier 	}
9323e12c5d1SDavid du Colombier 	v[NSTATUS]='\0';
9333e12c5d1SDavid du Colombier 	return v;
9343e12c5d1SDavid du Colombier }
935dc5a79c1SDavid du Colombier 
936dc5a79c1SDavid du Colombier void
Xpipewait(void)937dc5a79c1SDavid du Colombier Xpipewait(void)
938dc5a79c1SDavid du Colombier {
9393e12c5d1SDavid du Colombier 	char status[NSTATUS+1];
9403e12c5d1SDavid du Colombier 	if(runq->pid==-1)
9413e12c5d1SDavid du Colombier 		setstatus(concstatus(runq->status, getstatus()));
9423e12c5d1SDavid du Colombier 	else{
9433e12c5d1SDavid du Colombier 		strncpy(status, getstatus(), NSTATUS);
9443e12c5d1SDavid du Colombier 		status[NSTATUS]='\0';
9453e12c5d1SDavid du Colombier 		Waitfor(runq->pid, 1);
9463e12c5d1SDavid du Colombier 		runq->pid=-1;
9473e12c5d1SDavid du Colombier 		setstatus(concstatus(getstatus(), status));
9483e12c5d1SDavid du Colombier 	}
9493e12c5d1SDavid du Colombier }
950dc5a79c1SDavid du Colombier 
951dc5a79c1SDavid du Colombier void
Xrdcmds(void)952dc5a79c1SDavid du Colombier Xrdcmds(void)
953dc5a79c1SDavid du Colombier {
9543e12c5d1SDavid du Colombier 	struct thread *p = runq;
9553e12c5d1SDavid du Colombier 	word *prompt;
9563e12c5d1SDavid du Colombier 	flush(err);
9573e12c5d1SDavid du Colombier 	nerror = 0;
9583e12c5d1SDavid du Colombier 	if(flag['s'] && !truestatus())
9593e12c5d1SDavid du Colombier 		pfmt(err, "status=%v\n", vlook("status")->val);
9603e12c5d1SDavid du Colombier 	if(runq->iflag){
9613e12c5d1SDavid du Colombier 		prompt = vlook("prompt")->val;
9623e12c5d1SDavid du Colombier 		if(prompt)
9633e12c5d1SDavid du Colombier 			promptstr = prompt->word;
9643e12c5d1SDavid du Colombier 		else
9653e12c5d1SDavid du Colombier 			promptstr="% ";
9663e12c5d1SDavid du Colombier 	}
9673e12c5d1SDavid du Colombier 	Noerror();
9683e12c5d1SDavid du Colombier 	if(yyparse()){
9693e12c5d1SDavid du Colombier 		if(!p->iflag || p->eof && !Eintr()){
970dc5a79c1SDavid du Colombier 			if(p->cmdfile)
971dc5a79c1SDavid du Colombier 				efree(p->cmdfile);
9723e12c5d1SDavid du Colombier 			closeio(p->cmdfd);
9733e12c5d1SDavid du Colombier 			Xreturn();	/* should this be omitted? */
9743e12c5d1SDavid du Colombier 		}
9753e12c5d1SDavid du Colombier 		else{
9763e12c5d1SDavid du Colombier 			if(Eintr()){
9773e12c5d1SDavid du Colombier 				pchr(err, '\n');
9783e12c5d1SDavid du Colombier 				p->eof = 0;
9793e12c5d1SDavid du Colombier 			}
9803e12c5d1SDavid du Colombier 			--p->pc;	/* go back for next command */
9813e12c5d1SDavid du Colombier 		}
9823e12c5d1SDavid du Colombier 	}
9833e12c5d1SDavid du Colombier 	else{
9847dd7cddfSDavid du Colombier 		ntrap = 0;	/* avoid double-interrupts during blocked writes */
9853e12c5d1SDavid du Colombier 		--p->pc;	/* re-execute Xrdcmds after codebuf runs */
9863e12c5d1SDavid du Colombier 		start(codebuf, 1, runq->local);
9873e12c5d1SDavid du Colombier 	}
9883e12c5d1SDavid du Colombier 	freenodes();
9893e12c5d1SDavid du Colombier }
990dc5a79c1SDavid du Colombier 
991dc5a79c1SDavid du Colombier void
pargv0(io * f)992c6df1444SDavid du Colombier pargv0(io *f)
9933e12c5d1SDavid du Colombier {
9949a747e4fSDavid du Colombier 	if(strcmp(argv0, "rc")==0 || strcmp(argv0, "/bin/rc")==0)
995c6df1444SDavid du Colombier 		pfmt(f, "rc: ");
9969a747e4fSDavid du Colombier 	else
997c6df1444SDavid du Colombier 		pfmt(f, "rc (%s): ", argv0);
998c6df1444SDavid du Colombier }
999c6df1444SDavid du Colombier 
1000c6df1444SDavid du Colombier void
hisfault(io * f)1001c6df1444SDavid du Colombier hisfault(io *f)
1002c6df1444SDavid du Colombier {
1003c6df1444SDavid du Colombier 	thread *t;
1004c6df1444SDavid du Colombier 
1005c6df1444SDavid du Colombier 	for(t = runq; !t->cmdfile && t->ret != 0; t = t->ret)
1006c6df1444SDavid du Colombier 		;
1007c6df1444SDavid du Colombier 	if(t->cmdfile && !t->iflag)
1008c6df1444SDavid du Colombier 		pfmt(f, "%s:%d ", t->cmdfile, t->lineno);
1009c6df1444SDavid du Colombier }
1010c6df1444SDavid du Colombier 
1011c6df1444SDavid du Colombier void
Xerror(char * s)1012c6df1444SDavid du Colombier Xerror(char *s)
1013c6df1444SDavid du Colombier {
1014c6df1444SDavid du Colombier 	io *msg = openstr();
1015c6df1444SDavid du Colombier 
1016c6df1444SDavid du Colombier 	pargv0(msg);
1017c6df1444SDavid du Colombier 	hisfault(msg);		/* capture errstr before another sys call */
1018c6df1444SDavid du Colombier 	pfmt(err, "%s%s: %r\n", (char *)msg->strp, s);
1019c6df1444SDavid du Colombier 	closeio(msg);
10209a747e4fSDavid du Colombier 	flush(err);
1021d3907fe5SDavid du Colombier 	setstatus("error");
10229a747e4fSDavid du Colombier 	while(!runq->iflag) Xreturn();
10239a747e4fSDavid du Colombier }
1024dc5a79c1SDavid du Colombier 
1025dc5a79c1SDavid du Colombier void
Xerror1(char * s)1026c6df1444SDavid du Colombier Xerror1(char *s)			/* omit errstr */
10279a747e4fSDavid du Colombier {
1028c6df1444SDavid du Colombier 	pargv0(err);
1029c6df1444SDavid du Colombier 	hisfault(err);
1030c6df1444SDavid du Colombier 	pfmt(err, "%s\n", s);
10313e12c5d1SDavid du Colombier 	flush(err);
1032d3907fe5SDavid du Colombier 	setstatus("error");
10333e12c5d1SDavid du Colombier 	while(!runq->iflag) Xreturn();
10343e12c5d1SDavid du Colombier }
1035dc5a79c1SDavid du Colombier 
1036dc5a79c1SDavid du Colombier void
setstatus(char * s)1037dc5a79c1SDavid du Colombier setstatus(char *s)
10383e12c5d1SDavid du Colombier {
10393e12c5d1SDavid du Colombier 	setvar("status", newword(s, (word *)0));
10403e12c5d1SDavid du Colombier }
1041dc5a79c1SDavid du Colombier 
1042dc5a79c1SDavid du Colombier char*
getstatus(void)1043dc5a79c1SDavid du Colombier getstatus(void)
1044dc5a79c1SDavid du Colombier {
10453e12c5d1SDavid du Colombier 	var *status = vlook("status");
10463e12c5d1SDavid du Colombier 	return status->val?status->val->word:"";
10473e12c5d1SDavid du Colombier }
1048dc5a79c1SDavid du Colombier 
1049dc5a79c1SDavid du Colombier int
truestatus(void)1050dc5a79c1SDavid du Colombier truestatus(void)
1051dc5a79c1SDavid du Colombier {
10523e12c5d1SDavid du Colombier 	char *s;
10533e12c5d1SDavid du Colombier 	for(s = getstatus();*s;s++)
1054dc5a79c1SDavid du Colombier 		if(*s!='|' && *s!='0')
1055dc5a79c1SDavid du Colombier 			return 0;
10563e12c5d1SDavid du Colombier 	return 1;
10573e12c5d1SDavid du Colombier }
1058dc5a79c1SDavid du Colombier 
1059dc5a79c1SDavid du Colombier void
Xdelhere(void)1060dc5a79c1SDavid du Colombier Xdelhere(void)
1061dc5a79c1SDavid du Colombier {
10623e12c5d1SDavid du Colombier 	Unlink(runq->code[runq->pc++].s);
10633e12c5d1SDavid du Colombier }
1064dc5a79c1SDavid du Colombier 
1065dc5a79c1SDavid du Colombier void
Xfor(void)1066dc5a79c1SDavid du Colombier Xfor(void)
1067dc5a79c1SDavid du Colombier {
10683e12c5d1SDavid du Colombier 	if(runq->argv->words==0){
10693e12c5d1SDavid du Colombier 		poplist();
10703e12c5d1SDavid du Colombier 		runq->pc = runq->code[runq->pc].i;
10713e12c5d1SDavid du Colombier 	}
10723e12c5d1SDavid du Colombier 	else{
10733e12c5d1SDavid du Colombier 		freelist(runq->local->val);
10743e12c5d1SDavid du Colombier 		runq->local->val = runq->argv->words;
10753e12c5d1SDavid du Colombier 		runq->local->changed = 1;
10763e12c5d1SDavid du Colombier 		runq->argv->words = runq->argv->words->next;
10773e12c5d1SDavid du Colombier 		runq->local->val->next = 0;
10783e12c5d1SDavid du Colombier 		runq->pc++;
10793e12c5d1SDavid du Colombier 	}
10803e12c5d1SDavid du Colombier }
1081dc5a79c1SDavid du Colombier 
1082dc5a79c1SDavid du Colombier void
Xglob(void)1083dc5a79c1SDavid du Colombier Xglob(void)
1084dc5a79c1SDavid du Colombier {
10853e12c5d1SDavid du Colombier 	globlist();
10863e12c5d1SDavid du Colombier }
1087