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