9base

revived minimalist port of Plan 9 userland to Unix
git clone git://git.suckless.org/9base
Log | Files | Refs | README | LICENSE

exec.c (17082B)


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