xref: /plan9/sys/src/cmd/rc/exec.c (revision 4e3613ab15c331a9ada113286cc0f2a35bc0373d)
1 #include "rc.h"
2 #include "getflags.h"
3 #include "exec.h"
4 #include "io.h"
5 #include "fns.h"
6 /*
7  * Start executing the given code at the given pc with the given redirection
8  */
9 char *argv0="rc";
10 
11 void
start(code * c,int pc,var * local)12 start(code *c, int pc, var *local)
13 {
14 	struct thread *p = new(struct thread);
15 
16 	p->code = codecopy(c);
17 	p->pc = pc;
18 	p->argv = 0;
19 	p->redir = p->startredir = runq?runq->redir:0;
20 	p->local = local;
21 	p->cmdfile = 0;
22 	p->cmdfd = 0;
23 	p->eof = 0;
24 	p->iflag = 0;
25 	p->lineno = 1;
26 	p->ret = runq;
27 	runq = p;
28 }
29 
30 word*
newword(char * wd,word * next)31 newword(char *wd, word *next)
32 {
33 	word *p = new(word);
34 	p->word = strdup(wd);
35 	p->next = next;
36 	return p;
37 }
38 
39 void
pushword(char * wd)40 pushword(char *wd)
41 {
42 	if(runq->argv==0)
43 		panic("pushword but no argv!", 0);
44 	runq->argv->words = newword(wd, runq->argv->words);
45 }
46 
47 void
popword(void)48 popword(void)
49 {
50 	word *p;
51 	if(runq->argv==0)
52 		panic("popword but no argv!", 0);
53 	p = runq->argv->words;
54 	if(p==0)
55 		panic("popword but no word!", 0);
56 	runq->argv->words = p->next;
57 	efree(p->word);
58 	efree((char *)p);
59 }
60 
61 void
freelist(word * w)62 freelist(word *w)
63 {
64 	word *nw;
65 	while(w){
66 		nw = w->next;
67 		efree(w->word);
68 		efree((char *)w);
69 		w = nw;
70 	}
71 }
72 
73 void
pushlist(void)74 pushlist(void)
75 {
76 	list *p = new(list);
77 	p->next = runq->argv;
78 	p->words = 0;
79 	runq->argv = p;
80 }
81 
82 void
poplist(void)83 poplist(void)
84 {
85 	list *p = runq->argv;
86 	if(p==0)
87 		panic("poplist but no argv", 0);
88 	freelist(p->words);
89 	runq->argv = p->next;
90 	efree((char *)p);
91 }
92 
93 int
count(word * w)94 count(word *w)
95 {
96 	int n;
97 	for(n = 0;w;n++) w = w->next;
98 	return n;
99 }
100 
101 void
pushredir(int type,int from,int to)102 pushredir(int type, int from, int to)
103 {
104 	redir * rp = new(redir);
105 	rp->type = type;
106 	rp->from = from;
107 	rp->to = to;
108 	rp->next = runq->redir;
109 	runq->redir = rp;
110 }
111 
112 var*
newvar(char * name,var * next)113 newvar(char *name, var *next)
114 {
115 	var *v = new(var);
116 	v->name = name;
117 	v->val = 0;
118 	v->fn = 0;
119 	v->changed = 0;
120 	v->fnchanged = 0;
121 	v->next = next;
122 	return v;
123 }
124 /*
125  * get command line flags, initialize keywords & traps.
126  * get values from environment.
127  * set $pid, $cflag, $*
128  * fabricate bootstrap code and start it (*=(argv);. /usr/lib/rcmain $*)
129  * start interpreting code
130  */
131 
132 void
main(int argc,char * argv[])133 main(int argc, char *argv[])
134 {
135 	code bootstrap[17];
136 	char num[12], *rcmain;
137 	int i;
138 	argc = getflags(argc, argv, "SsrdiIlxepvVc:1m:1[command]", 1);
139 	if(argc==-1)
140 		usage("[file [arg ...]]");
141 	if(argv[0][0]=='-')
142 		flag['l'] = flagset;
143 	if(flag['I'])
144 		flag['i'] = 0;
145 	else if(flag['i']==0 && argc==1 && Isatty(0)) flag['i'] = flagset;
146 	rcmain = flag['m']?flag['m'][0]:Rcmain;
147 	err = openfd(2);
148 	kinit();
149 	Trapinit();
150 	Vinit();
151 	inttoascii(num, mypid = getpid());
152 	setvar("pid", newword(num, (word *)0));
153 	setvar("cflag", flag['c']?newword(flag['c'][0], (word *)0)
154 				:(word *)0);
155 	setvar("rcname", newword(argv[0], (word *)0));
156 	i = 0;
157 	memset(bootstrap, 0, sizeof bootstrap);
158 	bootstrap[i++].i = 1;
159 	bootstrap[i++].f = Xmark;
160 	bootstrap[i++].f = Xword;
161 	bootstrap[i++].s="*";
162 	bootstrap[i++].f = Xassign;
163 	bootstrap[i++].f = Xmark;
164 	bootstrap[i++].f = Xmark;
165 	bootstrap[i++].f = Xword;
166 	bootstrap[i++].s="*";
167 	bootstrap[i++].f = Xdol;
168 	bootstrap[i++].f = Xword;
169 	bootstrap[i++].s = rcmain;
170 	bootstrap[i++].f = Xword;
171 	bootstrap[i++].s=".";
172 	bootstrap[i++].f = Xsimple;
173 	bootstrap[i++].f = Xexit;
174 	bootstrap[i].i = 0;
175 	start(bootstrap, 1, (var *)0);
176 	/* prime bootstrap argv */
177 	pushlist();
178 	argv0 = strdup(argv[0]);
179 	for(i = argc-1;i!=0;--i) pushword(argv[i]);
180 	for(;;){
181 		if(flag['r'])
182 			pfnc(err, runq);
183 		runq->pc++;
184 		(*runq->code[runq->pc-1].f)();
185 		if(ntrap)
186 			dotrap();
187 	}
188 }
189 /*
190  * Opcode routines
191  * Arguments on stack (...)
192  * Arguments in line [...]
193  * Code in line with jump around {...}
194  *
195  * Xappend(file)[fd]			open file to append
196  * Xassign(name, val)			assign val to name
197  * Xasync{... Xexit}			make thread for {}, no wait
198  * Xbackq{... Xreturn}			make thread for {}, push stdout
199  * Xbang				complement condition
200  * Xcase(pat, value){...}		exec code on match, leave (value) on
201  * 					stack
202  * Xclose[i]				close file descriptor
203  * Xconc(left, right)			concatenate, push results
204  * Xcount(name)				push var count
205  * Xdelfn(name)				delete function definition
206  * Xdelhere
207  * Xdol(name)				get variable value
208  * Xdup[i j]				dup file descriptor
209  * Xeflag
210  * Xerror
211  * Xexit				rc exits with status
212  * Xfalse{...}				execute {} if false
213  * Xfn(name){... Xreturn}			define function
214  * Xfor(var, list){... Xreturn}		for loop
215  * Xglob
216  * Xif
217  * Xifnot
218  * Xjump[addr]				goto
219  * Xlocal(name, val)			create local variable, assign value
220  * Xmark				mark stack
221  * Xmatch(pat, str)			match pattern, set status
222  * Xpipe[i j]{... Xreturn}{... Xreturn}	construct a pipe between 2 new threads,
223  * 					wait for both
224  * Xpipefd[type]{... Xreturn}		connect {} to pipe (input or output,
225  * 					depending on type), push /dev/fd/??
226  * Xpipewait
227  * Xpopm(value)				pop value from stack
228  * Xpopredir
229  * Xrdcmds
230  * Xrdfn
231  * Xrdwr(file)[fd]			open file for reading and writing
232  * Xread(file)[fd]			open file to read
233  * Xqdol(name)				concatenate variable components
234  * Xreturn				kill thread
235  * Xsimple(args)			run command and wait
236  * Xsub
237  * Xsubshell{... Xexit}			execute {} in a subshell and wait
238  * Xtrue{...}				execute {} if true
239  * Xunlocal				delete local variable
240  * Xwastrue
241  * Xword[string]			push string
242  * Xwrite(file)[fd]			open file to write
243  */
244 
245 void
Xappend(void)246 Xappend(void)
247 {
248 	char *file;
249 	int f;
250 	switch(count(runq->argv->words)){
251 	default:
252 		Xerror1(">> requires singleton");
253 		return;
254 	case 0:
255 		Xerror1(">> requires file");
256 		return;
257 	case 1:
258 		break;
259 	}
260 	file = runq->argv->words->word;
261 	if((f = open(file, 1))<0 && (f = Creat(file))<0){
262 		pfmt(err, "%s: ", file);
263 		Xerror("can't open");
264 		return;
265 	}
266 	Seek(f, 0L, 2);
267 	pushredir(ROPEN, f, runq->code[runq->pc].i);
268 	runq->pc++;
269 	poplist();
270 }
271 
272 void
Xsettrue(void)273 Xsettrue(void)
274 {
275 	setstatus("");
276 }
277 
278 void
Xbang(void)279 Xbang(void)
280 {
281 	setstatus(truestatus()?"false":"");
282 }
283 
284 void
Xclose(void)285 Xclose(void)
286 {
287 	pushredir(RCLOSE, runq->code[runq->pc].i, 0);
288 	runq->pc++;
289 }
290 
291 void
Xdup(void)292 Xdup(void)
293 {
294 	pushredir(RDUP, runq->code[runq->pc].i, runq->code[runq->pc+1].i);
295 	runq->pc+=2;
296 }
297 
298 void
Xeflag(void)299 Xeflag(void)
300 {
301 	if(eflagok && !truestatus()) Xexit();
302 }
303 
304 void
Xexit(void)305 Xexit(void)
306 {
307 	struct var *trapreq;
308 	struct word *starval;
309 	static int beenhere = 0;
310 	if(getpid()==mypid && !beenhere){
311 		trapreq = vlook("sigexit");
312 		if(trapreq->fn){
313 			beenhere = 1;
314 			--runq->pc;
315 			starval = vlook("*")->val;
316 			start(trapreq->fn, trapreq->pc, (struct var *)0);
317 			runq->local = newvar(strdup("*"), runq->local);
318 			runq->local->val = copywords(starval, (struct word *)0);
319 			runq->local->changed = 1;
320 			runq->redir = runq->startredir = 0;
321 			return;
322 		}
323 	}
324 	Exit(getstatus());
325 }
326 
327 void
Xfalse(void)328 Xfalse(void)
329 {
330 	if(truestatus()) runq->pc = runq->code[runq->pc].i;
331 	else runq->pc++;
332 }
333 int ifnot;		/* dynamic if not flag */
334 
335 void
Xifnot(void)336 Xifnot(void)
337 {
338 	if(ifnot)
339 		runq->pc++;
340 	else
341 		runq->pc = runq->code[runq->pc].i;
342 }
343 
344 void
Xjump(void)345 Xjump(void)
346 {
347 	runq->pc = runq->code[runq->pc].i;
348 }
349 
350 void
Xmark(void)351 Xmark(void)
352 {
353 	pushlist();
354 }
355 
356 void
Xpopm(void)357 Xpopm(void)
358 {
359 	poplist();
360 }
361 
362 void
Xread(void)363 Xread(void)
364 {
365 	char *file;
366 	int f;
367 	switch(count(runq->argv->words)){
368 	default:
369 		Xerror1("< requires singleton\n");
370 		return;
371 	case 0:
372 		Xerror1("< requires file\n");
373 		return;
374 	case 1:
375 		break;
376 	}
377 	file = runq->argv->words->word;
378 	if((f = open(file, 0))<0){
379 		pfmt(err, "%s: ", file);
380 		Xerror("can't open");
381 		return;
382 	}
383 	pushredir(ROPEN, f, runq->code[runq->pc].i);
384 	runq->pc++;
385 	poplist();
386 }
387 
388 void
Xrdwr(void)389 Xrdwr(void)
390 {
391 	char *file;
392 	int f;
393 
394 	switch(count(runq->argv->words)){
395 	default:
396 		Xerror1("<> requires singleton\n");
397 		return;
398 	case 0:
399 		Xerror1("<> requires file\n");
400 		return;
401 	case 1:
402 		break;
403 	}
404 	file = runq->argv->words->word;
405 	if((f = open(file, ORDWR))<0){
406 		pfmt(err, "%s: ", file);
407 		Xerror("can't open");
408 		return;
409 	}
410 	pushredir(ROPEN, f, runq->code[runq->pc].i);
411 	runq->pc++;
412 	poplist();
413 }
414 
415 void
turfredir(void)416 turfredir(void)
417 {
418 	while(runq->redir!=runq->startredir)
419 		Xpopredir();
420 }
421 
422 void
Xpopredir(void)423 Xpopredir(void)
424 {
425 	struct redir *rp = runq->redir;
426 	if(rp==0)
427 		panic("turfredir null!", 0);
428 	runq->redir = rp->next;
429 	if(rp->type==ROPEN)
430 		close(rp->from);
431 	efree((char *)rp);
432 }
433 
434 void
Xreturn(void)435 Xreturn(void)
436 {
437 	struct thread *p = runq;
438 	turfredir();
439 	while(p->argv) poplist();
440 	codefree(p->code);
441 	runq = p->ret;
442 	efree((char *)p);
443 	if(runq==0)
444 		Exit(getstatus());
445 }
446 
447 void
Xtrue(void)448 Xtrue(void)
449 {
450 	if(truestatus()) runq->pc++;
451 	else runq->pc = runq->code[runq->pc].i;
452 }
453 
454 void
Xif(void)455 Xif(void)
456 {
457 	ifnot = 1;
458 	if(truestatus()) runq->pc++;
459 	else runq->pc = runq->code[runq->pc].i;
460 }
461 
462 void
Xwastrue(void)463 Xwastrue(void)
464 {
465 	ifnot = 0;
466 }
467 
468 void
Xword(void)469 Xword(void)
470 {
471 	pushword(runq->code[runq->pc++].s);
472 }
473 
474 void
Xwrite(void)475 Xwrite(void)
476 {
477 	char *file;
478 	int f;
479 	switch(count(runq->argv->words)){
480 	default:
481 		Xerror1("> requires singleton\n");
482 		return;
483 	case 0:
484 		Xerror1("> requires file\n");
485 		return;
486 	case 1:
487 		break;
488 	}
489 	file = runq->argv->words->word;
490 	if((f = Creat(file))<0){
491 		pfmt(err, "%s: ", file);
492 		Xerror("can't open");
493 		return;
494 	}
495 	pushredir(ROPEN, f, runq->code[runq->pc].i);
496 	runq->pc++;
497 	poplist();
498 }
499 
500 char*
list2str(word * words)501 list2str(word *words)
502 {
503 	char *value, *s, *t;
504 	int len = 0;
505 	word *ap;
506 	for(ap = words;ap;ap = ap->next)
507 		len+=1+strlen(ap->word);
508 	value = emalloc(len+1);
509 	s = value;
510 	for(ap = words;ap;ap = ap->next){
511 		for(t = ap->word;*t;) *s++=*t++;
512 		*s++=' ';
513 	}
514 	if(s==value)
515 		*s='\0';
516 	else s[-1]='\0';
517 	return value;
518 }
519 
520 void
Xmatch(void)521 Xmatch(void)
522 {
523 	word *p;
524 	char *subject;
525 	subject = list2str(runq->argv->words);
526 	setstatus("no match");
527 	for(p = runq->argv->next->words;p;p = p->next)
528 		if(match(subject, p->word, '\0')){
529 			setstatus("");
530 			break;
531 		}
532 	efree(subject);
533 	poplist();
534 	poplist();
535 }
536 
537 void
Xcase(void)538 Xcase(void)
539 {
540 	word *p;
541 	char *s;
542 	int ok = 0;
543 	s = list2str(runq->argv->next->words);
544 	for(p = runq->argv->words;p;p = p->next){
545 		if(match(s, p->word, '\0')){
546 			ok = 1;
547 			break;
548 		}
549 	}
550 	efree(s);
551 	if(ok)
552 		runq->pc++;
553 	else
554 		runq->pc = runq->code[runq->pc].i;
555 	poplist();
556 }
557 
558 word*
conclist(word * lp,word * rp,word * tail)559 conclist(word *lp, word *rp, word *tail)
560 {
561 	char *buf;
562 	word *v;
563 	if(lp->next || rp->next)
564 		tail = conclist(lp->next==0? lp: lp->next,
565 			rp->next==0? rp: rp->next, tail);
566 	buf = emalloc(strlen(lp->word)+strlen((char *)rp->word)+1);
567 	strcpy(buf, lp->word);
568 	strcat(buf, rp->word);
569 	v = newword(buf, tail);
570 	efree(buf);
571 	return v;
572 }
573 
574 void
Xconc(void)575 Xconc(void)
576 {
577 	word *lp = runq->argv->words;
578 	word *rp = runq->argv->next->words;
579 	word *vp = runq->argv->next->next->words;
580 	int lc = count(lp), rc = count(rp);
581 	if(lc!=0 || rc!=0){
582 		if(lc==0 || rc==0){
583 			Xerror1("null list in concatenation");
584 			return;
585 		}
586 		if(lc!=1 && rc!=1 && lc!=rc){
587 			Xerror1("mismatched list lengths in concatenation");
588 			return;
589 		}
590 		vp = conclist(lp, rp, vp);
591 	}
592 	poplist();
593 	poplist();
594 	runq->argv->words = vp;
595 }
596 
597 void
Xassign(void)598 Xassign(void)
599 {
600 	var *v;
601 	if(count(runq->argv->words)!=1){
602 		Xerror1("variable name not singleton!");
603 		return;
604 	}
605 	deglob(runq->argv->words->word);
606 	v = vlook(runq->argv->words->word);
607 	poplist();
608 	globlist();
609 	freewords(v->val);
610 	v->val = runq->argv->words;
611 	v->changed = 1;
612 	runq->argv->words = 0;
613 	poplist();
614 }
615 /*
616  * copy arglist a, adding the copy to the front of tail
617  */
618 
619 word*
copywords(word * a,word * tail)620 copywords(word *a, word *tail)
621 {
622 	word *v = 0, **end;
623 	for(end=&v;a;a = a->next,end=&(*end)->next)
624 		*end = newword(a->word, 0);
625 	*end = tail;
626 	return v;
627 }
628 
629 void
Xdol(void)630 Xdol(void)
631 {
632 	word *a, *star;
633 	char *s, *t;
634 	int n;
635 	if(count(runq->argv->words)!=1){
636 		Xerror1("variable name not singleton!");
637 		return;
638 	}
639 	s = runq->argv->words->word;
640 	deglob(s);
641 	n = 0;
642 	for(t = s;'0'<=*t && *t<='9';t++) n = n*10+*t-'0';
643 	a = runq->argv->next->words;
644 	if(n==0 || *t)
645 		a = copywords(vlook(s)->val, a);
646 	else{
647 		star = vlook("*")->val;
648 		if(star && 1<=n && n<=count(star)){
649 			while(--n) star = star->next;
650 			a = newword(star->word, a);
651 		}
652 	}
653 	poplist();
654 	runq->argv->words = a;
655 }
656 
657 void
Xqdol(void)658 Xqdol(void)
659 {
660 	word *a, *p;
661 	char *s;
662 	int n;
663 	if(count(runq->argv->words)!=1){
664 		Xerror1("variable name not singleton!");
665 		return;
666 	}
667 	s = runq->argv->words->word;
668 	deglob(s);
669 	a = vlook(s)->val;
670 	poplist();
671 	n = count(a);
672 	if(n==0){
673 		pushword("");
674 		return;
675 	}
676 	for(p = a;p;p = p->next) n+=strlen(p->word);
677 	s = emalloc(n);
678 	if(a){
679 		strcpy(s, a->word);
680 		for(p = a->next;p;p = p->next){
681 			strcat(s, " ");
682 			strcat(s, p->word);
683 		}
684 	}
685 	else
686 		s[0]='\0';
687 	pushword(s);
688 	efree(s);
689 }
690 
691 word*
copynwords(word * a,word * tail,int n)692 copynwords(word *a, word *tail, int n)
693 {
694 	word *v, **end;
695 
696 	v = 0;
697 	end = &v;
698 	while(n-- > 0){
699 		*end = newword(a->word, 0);
700 		end = &(*end)->next;
701 		a = a->next;
702 	}
703 	*end = tail;
704 	return v;
705 }
706 
707 word*
subwords(word * val,int len,word * sub,word * a)708 subwords(word *val, int len, word *sub, word *a)
709 {
710 	int n, m;
711 	char *s;
712 	if(!sub)
713 		return a;
714 	a = subwords(val, len, sub->next, a);
715 	s = sub->word;
716 	deglob(s);
717 	m = 0;
718 	n = 0;
719 	while('0'<=*s && *s<='9')
720 		n = n*10+ *s++ -'0';
721 	if(*s == '-'){
722 		if(*++s == 0)
723 			m = len - n;
724 		else{
725 			while('0'<=*s && *s<='9')
726 				m = m*10+ *s++ -'0';
727 			m -= n;
728 		}
729 	}
730 	if(n<1 || n>len || m<0)
731 		return a;
732 	if(n+m>len)
733 		m = len-n;
734 	while(--n > 0)
735 		val = val->next;
736 	return copynwords(val, a, m+1);
737 }
738 
739 void
Xsub(void)740 Xsub(void)
741 {
742 	word *a, *v;
743 	char *s;
744 	if(count(runq->argv->next->words)!=1){
745 		Xerror1("variable name not singleton!");
746 		return;
747 	}
748 	s = runq->argv->next->words->word;
749 	deglob(s);
750 	a = runq->argv->next->next->words;
751 	v = vlook(s)->val;
752 	a = subwords(v, count(v), runq->argv->words, a);
753 	poplist();
754 	poplist();
755 	runq->argv->words = a;
756 }
757 
758 void
Xcount(void)759 Xcount(void)
760 {
761 	word *a;
762 	char *s, *t;
763 	int n;
764 	char num[12];
765 	if(count(runq->argv->words)!=1){
766 		Xerror1("variable name not singleton!");
767 		return;
768 	}
769 	s = runq->argv->words->word;
770 	deglob(s);
771 	n = 0;
772 	for(t = s;'0'<=*t && *t<='9';t++) n = n*10+*t-'0';
773 	if(n==0 || *t){
774 		a = vlook(s)->val;
775 		inttoascii(num, count(a));
776 	}
777 	else{
778 		a = vlook("*")->val;
779 		inttoascii(num, a && 1<=n && n<=count(a)?1:0);
780 	}
781 	poplist();
782 	pushword(num);
783 }
784 
785 void
Xlocal(void)786 Xlocal(void)
787 {
788 	if(count(runq->argv->words)!=1){
789 		Xerror1("variable name must be singleton\n");
790 		return;
791 	}
792 	deglob(runq->argv->words->word);
793 	runq->local = newvar(strdup(runq->argv->words->word), runq->local);
794 	poplist();
795 	globlist();
796 	runq->local->val = runq->argv->words;
797 	runq->local->changed = 1;
798 	runq->argv->words = 0;
799 	poplist();
800 }
801 
802 void
Xunlocal(void)803 Xunlocal(void)
804 {
805 	var *v = runq->local, *hid;
806 	if(v==0)
807 		panic("Xunlocal: no locals!", 0);
808 	runq->local = v->next;
809 	hid = vlook(v->name);
810 	hid->changed = 1;
811 	efree(v->name);
812 	freewords(v->val);
813 	efree((char *)v);
814 }
815 
816 void
freewords(word * w)817 freewords(word *w)
818 {
819 	word *nw;
820 	while(w){
821 		efree(w->word);
822 		nw = w->next;
823 		efree((char *)w);
824 		w = nw;
825 	}
826 }
827 
828 void
Xfn(void)829 Xfn(void)
830 {
831 	var *v;
832 	word *a;
833 	int end;
834 	end = runq->code[runq->pc].i;
835 	globlist();
836 	for(a = runq->argv->words;a;a = a->next){
837 		v = gvlook(a->word);
838 		if(v->fn)
839 			codefree(v->fn);
840 		v->fn = codecopy(runq->code);
841 		v->pc = runq->pc+2;
842 		v->fnchanged = 1;
843 	}
844 	runq->pc = end;
845 	poplist();
846 }
847 
848 void
Xdelfn(void)849 Xdelfn(void)
850 {
851 	var *v;
852 	word *a;
853 	for(a = runq->argv->words;a;a = a->next){
854 		v = gvlook(a->word);
855 		if(v->fn)
856 			codefree(v->fn);
857 		v->fn = 0;
858 		v->fnchanged = 1;
859 	}
860 	poplist();
861 }
862 
863 char*
concstatus(char * s,char * t)864 concstatus(char *s, char *t)
865 {
866 	static char v[NSTATUS+1];
867 	int n = strlen(s);
868 	strncpy(v, s, NSTATUS);
869 	if(n<NSTATUS){
870 		v[n]='|';
871 		strncpy(v+n+1, t, NSTATUS-n-1);
872 	}
873 	v[NSTATUS]='\0';
874 	return v;
875 }
876 
877 void
Xpipewait(void)878 Xpipewait(void)
879 {
880 	char status[NSTATUS+1];
881 	if(runq->pid==-1)
882 		setstatus(concstatus(runq->status, getstatus()));
883 	else{
884 		strncpy(status, getstatus(), NSTATUS);
885 		status[NSTATUS]='\0';
886 		Waitfor(runq->pid, 1);
887 		runq->pid=-1;
888 		setstatus(concstatus(getstatus(), status));
889 	}
890 }
891 
892 void
Xrdcmds(void)893 Xrdcmds(void)
894 {
895 	struct thread *p = runq;
896 	word *prompt;
897 	flush(err);
898 	nerror = 0;
899 	if(flag['s'] && !truestatus())
900 		pfmt(err, "status=%v\n", vlook("status")->val);
901 	if(runq->iflag){
902 		prompt = vlook("prompt")->val;
903 		if(prompt)
904 			promptstr = prompt->word;
905 		else
906 			promptstr="% ";
907 	}
908 	Noerror();
909 	if(yyparse()){
910 		if(!p->iflag || p->eof && !Eintr()){
911 			if(p->cmdfile)
912 				efree(p->cmdfile);
913 			closeio(p->cmdfd);
914 			Xreturn();	/* should this be omitted? */
915 		}
916 		else{
917 			if(Eintr()){
918 				pchr(err, '\n');
919 				p->eof = 0;
920 			}
921 			--p->pc;	/* go back for next command */
922 		}
923 	}
924 	else{
925 		ntrap = 0;	/* avoid double-interrupts during blocked writes */
926 		--p->pc;	/* re-execute Xrdcmds after codebuf runs */
927 		start(codebuf, 1, runq->local);
928 	}
929 	freenodes();
930 }
931 
932 void
Xerror(char * s)933 Xerror(char *s)
934 {
935 	if(strcmp(argv0, "rc")==0 || strcmp(argv0, "/bin/rc")==0)
936 		pfmt(err, "rc: %s: %r\n", s);
937 	else
938 		pfmt(err, "rc (%s): %s: %r\n", argv0, s);
939 	flush(err);
940 	setstatus("error");
941 	while(!runq->iflag) Xreturn();
942 }
943 
944 void
Xerror1(char * s)945 Xerror1(char *s)
946 {
947 	if(strcmp(argv0, "rc")==0 || strcmp(argv0, "/bin/rc")==0)
948 		pfmt(err, "rc: %s\n", s);
949 	else
950 		pfmt(err, "rc (%s): %s\n", argv0, s);
951 	flush(err);
952 	setstatus("error");
953 	while(!runq->iflag) Xreturn();
954 }
955 
956 void
setstatus(char * s)957 setstatus(char *s)
958 {
959 	setvar("status", newword(s, (word *)0));
960 }
961 
962 char*
getstatus(void)963 getstatus(void)
964 {
965 	var *status = vlook("status");
966 	return status->val?status->val->word:"";
967 }
968 
969 int
truestatus(void)970 truestatus(void)
971 {
972 	char *s;
973 	for(s = getstatus();*s;s++)
974 		if(*s!='|' && *s!='0')
975 			return 0;
976 	return 1;
977 }
978 
979 void
Xdelhere(void)980 Xdelhere(void)
981 {
982 	Unlink(runq->code[runq->pc++].s);
983 }
984 
985 void
Xfor(void)986 Xfor(void)
987 {
988 	if(runq->argv->words==0){
989 		poplist();
990 		runq->pc = runq->code[runq->pc].i;
991 	}
992 	else{
993 		freelist(runq->local->val);
994 		runq->local->val = runq->argv->words;
995 		runq->local->changed = 1;
996 		runq->argv->words = runq->argv->words->next;
997 		runq->local->val->next = 0;
998 		runq->pc++;
999 	}
1000 }
1001 
1002 void
Xglob(void)1003 Xglob(void)
1004 {
1005 	globlist();
1006 }
1007