plan9port

fork of plan9port with libvec, libstr and libsdb
Log | Files | Refs | README | LICENSE

exec.c (17157B)


      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 	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
    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
    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
    269 Xsettrue(void)
    270 {
    271 	setstatus("");
    272 }
    273 
    274 void
    275 Xbang(void)
    276 {
    277 	setstatus(truestatus()?"false":"");
    278 }
    279 
    280 void
    281 Xclose(void)
    282 {
    283 	pushredir(RCLOSE, runq->code[runq->pc].i, 0);
    284 	runq->pc++;
    285 }
    286 
    287 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
    295 Xeflag(void)
    296 {
    297 	if(eflagok && !truestatus()) Xexit();
    298 }
    299 
    300 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
    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
    332 Xifnot(void)
    333 {
    334 	if(ifnot)
    335 		runq->pc++;
    336 	else
    337 		runq->pc = runq->code[runq->pc].i;
    338 }
    339 
    340 void
    341 Xjump(void)
    342 {
    343 	runq->pc = runq->code[runq->pc].i;
    344 }
    345 
    346 void
    347 Xmark(void)
    348 {
    349 	pushlist();
    350 }
    351 
    352 void
    353 Xpopm(void)
    354 {
    355 	poplist();
    356 }
    357 
    358 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
    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
    412 turfredir(void)
    413 {
    414 	while(runq->redir!=runq->startredir)
    415 		Xpopredir();
    416 }
    417 
    418 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
    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
    444 Xtrue(void)
    445 {
    446 	if(truestatus()) runq->pc++;
    447 	else runq->pc = runq->code[runq->pc].i;
    448 }
    449 
    450 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
    459 Xwastrue(void)
    460 {
    461 	ifnot = 0;
    462 }
    463 
    464 void
    465 Xword(void)
    466 {
    467 	pushword(runq->code[runq->pc++].s);
    468 }
    469 
    470 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*
    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
    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
    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*
    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
    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
    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*
    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
    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
    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*
    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*
    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
    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
    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
    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
    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
    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
    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
    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*
    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
    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
    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
    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
    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
    952 setstatus(char *s)
    953 {
    954 	setvar("status", newword(s, (word *)0));
    955 }
    956 
    957 char*
    958 getstatus(void)
    959 {
    960 	var *status = vlook("status");
    961 	return status->val?status->val->word:"";
    962 }
    963 
    964 int
    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
    975 Xdelhere(void)
    976 {
    977 	Unlink(runq->code[runq->pc++].s);
    978 }
    979 
    980 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
    998 Xglob(void)
    999 {
   1000 	globlist();
   1001 }