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