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