xref: /plan9-contrib/sys/src/cmd/rc/simple.c (revision 219b2ee8daee37f4aad58d63f21287faa8e4ffdc)
13e12c5d1SDavid du Colombier /*
23e12c5d1SDavid du Colombier  * Maybe `simple' is a misnomer.
33e12c5d1SDavid du Colombier  */
43e12c5d1SDavid du Colombier #include "rc.h"
53e12c5d1SDavid du Colombier #include "getflags.h"
63e12c5d1SDavid du Colombier #include "exec.h"
73e12c5d1SDavid du Colombier #include "io.h"
83e12c5d1SDavid du Colombier #include "fns.h"
93e12c5d1SDavid du Colombier /*
103e12c5d1SDavid du Colombier  * Search through the following code to see if we're just going to exit.
113e12c5d1SDavid du Colombier  */
123e12c5d1SDavid du Colombier exitnext(void){
133e12c5d1SDavid du Colombier 	union code *c=&runq->code[runq->pc];
143e12c5d1SDavid du Colombier 	while(c->f==Xpopredir) c++;
153e12c5d1SDavid du Colombier 	return c->f==Xexit;
163e12c5d1SDavid du Colombier }
173e12c5d1SDavid du Colombier void Xsimple(void){
183e12c5d1SDavid du Colombier 	word *a;
193e12c5d1SDavid du Colombier 	thread *p=runq;
203e12c5d1SDavid du Colombier 	var *v;
213e12c5d1SDavid du Colombier 	struct builtin *bp;
223e12c5d1SDavid du Colombier 	int pid;
233e12c5d1SDavid du Colombier 	globlist();
243e12c5d1SDavid du Colombier 	a=runq->argv->words;
253e12c5d1SDavid du Colombier 	if(a==0){
263e12c5d1SDavid du Colombier 		Xerror("empty argument list");
273e12c5d1SDavid du Colombier 		return;
283e12c5d1SDavid du Colombier 	}
293e12c5d1SDavid du Colombier 	if(flag['x'])
303e12c5d1SDavid du Colombier 		pfmt(err, "%v\n", p->argv->words); /* wrong, should do redirs */
313e12c5d1SDavid du Colombier 	v=gvlook(a->word);
323e12c5d1SDavid du Colombier 	if(v->fn)
333e12c5d1SDavid du Colombier 		execfunc(v);
343e12c5d1SDavid du Colombier 	else{
353e12c5d1SDavid du Colombier 		if(strcmp(a->word, "builtin")==0){
363e12c5d1SDavid du Colombier 			if(count(a)==1){
373e12c5d1SDavid du Colombier 				pfmt(err, "builtin: empty argument list\n");
383e12c5d1SDavid du Colombier 				setstatus("empty arg list");
393e12c5d1SDavid du Colombier 				poplist();
403e12c5d1SDavid du Colombier 				return;
413e12c5d1SDavid du Colombier 			}
423e12c5d1SDavid du Colombier 			a=a->next;
433e12c5d1SDavid du Colombier 			popword();
443e12c5d1SDavid du Colombier 		}
453e12c5d1SDavid du Colombier 		for(bp=Builtin;bp->name;bp++)
463e12c5d1SDavid du Colombier 			if(strcmp(a->word, bp->name)==0){
473e12c5d1SDavid du Colombier 				(*bp->fnc)();
483e12c5d1SDavid du Colombier 				return;
493e12c5d1SDavid du Colombier 			}
503e12c5d1SDavid du Colombier 		if(exitnext()){
513e12c5d1SDavid du Colombier 			/* fork and wait is redundant */
523e12c5d1SDavid du Colombier 			pushword("exec");
533e12c5d1SDavid du Colombier 			execexec();
543e12c5d1SDavid du Colombier 			Xexit();
553e12c5d1SDavid du Colombier 		}
563e12c5d1SDavid du Colombier 		else{
573e12c5d1SDavid du Colombier 			flush(err);
583e12c5d1SDavid du Colombier 			Updenv();
593e12c5d1SDavid du Colombier 			switch(pid=fork()){
603e12c5d1SDavid du Colombier 			case -1:
61*219b2ee8SDavid du Colombier 				Xperror("try again");
623e12c5d1SDavid du Colombier 				return;
633e12c5d1SDavid du Colombier 			case 0:
643e12c5d1SDavid du Colombier 				pushword("exec");
653e12c5d1SDavid du Colombier 				execexec();
663e12c5d1SDavid du Colombier 				Exit("can't exec");
673e12c5d1SDavid du Colombier 			default:
683e12c5d1SDavid du Colombier 				poplist();
693e12c5d1SDavid du Colombier 				/* interrupts don't get us out */
703e12c5d1SDavid du Colombier 				while(Waitfor(pid, 1) < 0)
713e12c5d1SDavid du Colombier 					;
723e12c5d1SDavid du Colombier 			}
733e12c5d1SDavid du Colombier 		}
743e12c5d1SDavid du Colombier 	}
753e12c5d1SDavid du Colombier }
763e12c5d1SDavid du Colombier struct word nullpath={ "", 0};
773e12c5d1SDavid du Colombier void doredir(redir *rp)
783e12c5d1SDavid du Colombier {
793e12c5d1SDavid du Colombier 	if(rp){
803e12c5d1SDavid du Colombier 		doredir(rp->next);
813e12c5d1SDavid du Colombier 		switch(rp->type){
823e12c5d1SDavid du Colombier 		case ROPEN:
833e12c5d1SDavid du Colombier 			if(rp->from!=rp->to){
843e12c5d1SDavid du Colombier 				Dup(rp->from, rp->to);
853e12c5d1SDavid du Colombier 				close(rp->from);
863e12c5d1SDavid du Colombier 			}
873e12c5d1SDavid du Colombier 			break;
883e12c5d1SDavid du Colombier 		case RDUP: Dup(rp->from, rp->to); break;
893e12c5d1SDavid du Colombier 		case RCLOSE: close(rp->from); break;
903e12c5d1SDavid du Colombier 		}
913e12c5d1SDavid du Colombier 	}
923e12c5d1SDavid du Colombier }
933e12c5d1SDavid du Colombier word *searchpath(char *w){
943e12c5d1SDavid du Colombier 	word *path;
953e12c5d1SDavid du Colombier 	if(strncmp(w, "/", 1)==0
963e12c5d1SDavid du Colombier 	|| strncmp(w, "#", 1)==0
973e12c5d1SDavid du Colombier 	|| strncmp(w, "./", 2)==0
983e12c5d1SDavid du Colombier 	|| strncmp(w, "../", 3)==0
993e12c5d1SDavid du Colombier 	|| (path=vlook("path")->val)==0)
1003e12c5d1SDavid du Colombier 		path=&nullpath;
1013e12c5d1SDavid du Colombier 	return path;
1023e12c5d1SDavid du Colombier }
1033e12c5d1SDavid du Colombier void execexec(void){
1043e12c5d1SDavid du Colombier 	word *path;
1053e12c5d1SDavid du Colombier 	popword();	/* "exec" */
1063e12c5d1SDavid du Colombier 	if(runq->argv->words==0){
1073e12c5d1SDavid du Colombier 		Xerror("empty argument list");
1083e12c5d1SDavid du Colombier 		return;
1093e12c5d1SDavid du Colombier 	}
1103e12c5d1SDavid du Colombier 	doredir(runq->redir);
1113e12c5d1SDavid du Colombier 	Execute(runq->argv->words, searchpath(runq->argv->words->word));
1123e12c5d1SDavid du Colombier 	poplist();
1133e12c5d1SDavid du Colombier }
1143e12c5d1SDavid du Colombier void execfunc(var *func)
1153e12c5d1SDavid du Colombier {
1163e12c5d1SDavid du Colombier 	word *starval;
1173e12c5d1SDavid du Colombier 	popword();
1183e12c5d1SDavid du Colombier 	starval=runq->argv->words;
1193e12c5d1SDavid du Colombier 	runq->argv->words=0;
1203e12c5d1SDavid du Colombier 	poplist();
1213e12c5d1SDavid du Colombier 	start(func->fn, func->pc, (struct var *)0);
1223e12c5d1SDavid du Colombier 	runq->local=newvar(strdup("*"), runq->local);
1233e12c5d1SDavid du Colombier 	runq->local->val=starval;
1243e12c5d1SDavid du Colombier 	runq->local->changed=1;
1253e12c5d1SDavid du Colombier }
1263e12c5d1SDavid du Colombier void execcd(void){
1273e12c5d1SDavid du Colombier 	word *a=runq->argv->words;
1283e12c5d1SDavid du Colombier 	word *cdpath;
1293e12c5d1SDavid du Colombier 	char dir[512];
1303e12c5d1SDavid du Colombier 	setstatus("can't cd");
1313e12c5d1SDavid du Colombier 	cdpath=vlook("cdpath")->val;
1323e12c5d1SDavid du Colombier 	switch(count(a)){
1333e12c5d1SDavid du Colombier 	default:
1343e12c5d1SDavid du Colombier 		pfmt(err, "Usage: cd [directory]\n");
1353e12c5d1SDavid du Colombier 		break;
1363e12c5d1SDavid du Colombier 	case 2:
1373e12c5d1SDavid du Colombier 		if(a->next->word[0]=='/' || cdpath==0) cdpath=&nullpath;
1383e12c5d1SDavid du Colombier 		for(;cdpath;cdpath=cdpath->next){
1393e12c5d1SDavid du Colombier 			strcpy(dir, cdpath->word);
1403e12c5d1SDavid du Colombier 			if(dir[0]) strcat(dir, "/");
1413e12c5d1SDavid du Colombier 			strcat(dir, a->next->word);
1423e12c5d1SDavid du Colombier 			if(chdir(dir)>=0){
1433e12c5d1SDavid du Colombier 				if(strlen(cdpath->word)
1443e12c5d1SDavid du Colombier 				&& strcmp(cdpath->word, ".")!=0)
1453e12c5d1SDavid du Colombier 					pfmt(err, "%s\n", dir);
1463e12c5d1SDavid du Colombier 				setstatus("");
1473e12c5d1SDavid du Colombier 				break;
1483e12c5d1SDavid du Colombier 			}
1493e12c5d1SDavid du Colombier 		}
1503e12c5d1SDavid du Colombier 		if(cdpath==0) pfmt(err, "Can't cd %s\n", a->next->word);
1513e12c5d1SDavid du Colombier 		break;
1523e12c5d1SDavid du Colombier 	case 1:
1533e12c5d1SDavid du Colombier 		a=vlook("home")->val;
1543e12c5d1SDavid du Colombier 		if(count(a)>=1){
1553e12c5d1SDavid du Colombier 			if(chdir(a->word)>=0)
1563e12c5d1SDavid du Colombier 				setstatus("");
1573e12c5d1SDavid du Colombier 			else
1583e12c5d1SDavid du Colombier 				pfmt(err, "Can't cd %s\n", a->word);
1593e12c5d1SDavid du Colombier 		}
1603e12c5d1SDavid du Colombier 		else
1613e12c5d1SDavid du Colombier 			pfmt(err, "Can't cd -- $home empty\n");
1623e12c5d1SDavid du Colombier 		break;
1633e12c5d1SDavid du Colombier 	}
1643e12c5d1SDavid du Colombier 	poplist();
1653e12c5d1SDavid du Colombier }
1663e12c5d1SDavid du Colombier void execexit(void){
1673e12c5d1SDavid du Colombier 	switch(count(runq->argv->words)){
1683e12c5d1SDavid du Colombier 	default: pfmt(err, "Usage: exit [status]\nExiting anyway\n");
1693e12c5d1SDavid du Colombier 	case 2: setstatus(runq->argv->words->next->word);
1703e12c5d1SDavid du Colombier 	case 1:	Xexit();
1713e12c5d1SDavid du Colombier 	}
1723e12c5d1SDavid du Colombier }
1733e12c5d1SDavid du Colombier void execshift(void){
1743e12c5d1SDavid du Colombier 	int n;
1753e12c5d1SDavid du Colombier 	word *a;
1763e12c5d1SDavid du Colombier 	var *star;
1773e12c5d1SDavid du Colombier 	switch(count(runq->argv->words)){
1783e12c5d1SDavid du Colombier 	default:
1793e12c5d1SDavid du Colombier 		pfmt(err, "Usage: shift [n]\n");
1803e12c5d1SDavid du Colombier 		setstatus("shift usage");
1813e12c5d1SDavid du Colombier 		poplist();
1823e12c5d1SDavid du Colombier 		return;
1833e12c5d1SDavid du Colombier 	case 2: n=atoi(runq->argv->words->next->word); break;
1843e12c5d1SDavid du Colombier 	case 1: n=1; break;
1853e12c5d1SDavid du Colombier 	}
1863e12c5d1SDavid du Colombier 	star=vlook("*");
1873e12c5d1SDavid du Colombier 	for(;n && star->val;--n){
1883e12c5d1SDavid du Colombier 		a=star->val->next;
1893e12c5d1SDavid du Colombier 		efree(star->val->word);
1903e12c5d1SDavid du Colombier 		efree((char *)star->val);
1913e12c5d1SDavid du Colombier 		star->val=a;
1923e12c5d1SDavid du Colombier 		star->changed=1;
1933e12c5d1SDavid du Colombier 	}
1943e12c5d1SDavid du Colombier 	setstatus("");
1953e12c5d1SDavid du Colombier 	poplist();
1963e12c5d1SDavid du Colombier }
1973e12c5d1SDavid du Colombier int octal(char *s)
1983e12c5d1SDavid du Colombier {
1993e12c5d1SDavid du Colombier 	int n=0;
2003e12c5d1SDavid du Colombier 	while(*s==' ' || *s=='\t' || *s=='\n') s++;
2013e12c5d1SDavid du Colombier 	while('0'<=*s && *s<='7') n=n*8+*s++-'0';
2023e12c5d1SDavid du Colombier 	return n;
2033e12c5d1SDavid du Colombier }
2043e12c5d1SDavid du Colombier int mapfd(int fd)
2053e12c5d1SDavid du Colombier {
2063e12c5d1SDavid du Colombier 	redir *rp;
2073e12c5d1SDavid du Colombier 	for(rp=runq->redir;rp;rp=rp->next){
2083e12c5d1SDavid du Colombier 		switch(rp->type){
2093e12c5d1SDavid du Colombier 		case RCLOSE:
2103e12c5d1SDavid du Colombier 			if(rp->from==fd) fd=-1;
2113e12c5d1SDavid du Colombier 			break;
2123e12c5d1SDavid du Colombier 		case RDUP:
2133e12c5d1SDavid du Colombier 		case ROPEN:
2143e12c5d1SDavid du Colombier 			if(rp->to==fd) fd=rp->from;
2153e12c5d1SDavid du Colombier 			break;
2163e12c5d1SDavid du Colombier 		}
2173e12c5d1SDavid du Colombier 	}
2183e12c5d1SDavid du Colombier 	return fd;
2193e12c5d1SDavid du Colombier }
2203e12c5d1SDavid du Colombier union code rdcmds[4];
2213e12c5d1SDavid du Colombier void execcmds(io *f)
2223e12c5d1SDavid du Colombier {
2233e12c5d1SDavid du Colombier 	static int first=1;
2243e12c5d1SDavid du Colombier 	if(first){
2253e12c5d1SDavid du Colombier 		rdcmds[0].i=1;
2263e12c5d1SDavid du Colombier 		rdcmds[1].f=Xrdcmds;
2273e12c5d1SDavid du Colombier 		rdcmds[2].f=Xreturn;
2283e12c5d1SDavid du Colombier 		first=0;
2293e12c5d1SDavid du Colombier 	}
2303e12c5d1SDavid du Colombier 	start(rdcmds, 1, runq->local);
2313e12c5d1SDavid du Colombier 	runq->cmdfd=f;
2323e12c5d1SDavid du Colombier 	runq->iflast=0;
2333e12c5d1SDavid du Colombier }
2343e12c5d1SDavid du Colombier void execeval(void){
2353e12c5d1SDavid du Colombier 	char *cmdline, *s, *t;
2363e12c5d1SDavid du Colombier 	int len=0;
2373e12c5d1SDavid du Colombier 	word *ap;
2383e12c5d1SDavid du Colombier 	if(count(runq->argv->words)<=1){
2393e12c5d1SDavid du Colombier 		Xerror("Usage: eval cmd ...");
2403e12c5d1SDavid du Colombier 		return;
2413e12c5d1SDavid du Colombier 	}
242*219b2ee8SDavid du Colombier 	eflagok=1;
2433e12c5d1SDavid du Colombier 	for(ap=runq->argv->words->next;ap;ap=ap->next)
2443e12c5d1SDavid du Colombier 		len+=1+strlen(ap->word);
2453e12c5d1SDavid du Colombier 	cmdline=emalloc(len);
2463e12c5d1SDavid du Colombier 	s=cmdline;
2473e12c5d1SDavid du Colombier 	for(ap=runq->argv->words->next;ap;ap=ap->next){
2483e12c5d1SDavid du Colombier 		for(t=ap->word;*t;) *s++=*t++;
2493e12c5d1SDavid du Colombier 		*s++=' ';
2503e12c5d1SDavid du Colombier 	}
2513e12c5d1SDavid du Colombier 	s[-1]='\n';
2523e12c5d1SDavid du Colombier 	poplist();
2533e12c5d1SDavid du Colombier 	execcmds(opencore(cmdline, len));
2543e12c5d1SDavid du Colombier 	efree(cmdline);
2553e12c5d1SDavid du Colombier }
2563e12c5d1SDavid du Colombier union code dotcmds[14];
2573e12c5d1SDavid du Colombier void execdot(void){
2583e12c5d1SDavid du Colombier 	int iflag=0;
2593e12c5d1SDavid du Colombier 	int fd;
2603e12c5d1SDavid du Colombier 	list *av;
2613e12c5d1SDavid du Colombier 	thread *p=runq;
2623e12c5d1SDavid du Colombier 	char *zero;
2633e12c5d1SDavid du Colombier 	static int first=1;
2643e12c5d1SDavid du Colombier 	char file[512];
2653e12c5d1SDavid du Colombier 	word *path;
2663e12c5d1SDavid du Colombier 	if(first){
2673e12c5d1SDavid du Colombier 		dotcmds[0].i=1;
2683e12c5d1SDavid du Colombier 		dotcmds[1].f=Xmark;
2693e12c5d1SDavid du Colombier 		dotcmds[2].f=Xword;
2703e12c5d1SDavid du Colombier 		dotcmds[3].s="0";
2713e12c5d1SDavid du Colombier 		dotcmds[4].f=Xlocal;
2723e12c5d1SDavid du Colombier 		dotcmds[5].f=Xmark;
2733e12c5d1SDavid du Colombier 		dotcmds[6].f=Xword;
2743e12c5d1SDavid du Colombier 		dotcmds[7].s="*";
2753e12c5d1SDavid du Colombier 		dotcmds[8].f=Xlocal;
2763e12c5d1SDavid du Colombier 		dotcmds[9].f=Xrdcmds;
2773e12c5d1SDavid du Colombier 		dotcmds[10].f=Xunlocal;
2783e12c5d1SDavid du Colombier 		dotcmds[11].f=Xunlocal;
2793e12c5d1SDavid du Colombier 		dotcmds[12].f=Xreturn;
2803e12c5d1SDavid du Colombier 		first=0;
2813e12c5d1SDavid du Colombier 	}
282*219b2ee8SDavid du Colombier 	else
283*219b2ee8SDavid du Colombier 		eflagok=1;
2843e12c5d1SDavid du Colombier 	popword();
2853e12c5d1SDavid du Colombier 	if(p->argv->words && strcmp(p->argv->words->word, "-i")==0){
2863e12c5d1SDavid du Colombier 		iflag=1;
2873e12c5d1SDavid du Colombier 		popword();
2883e12c5d1SDavid du Colombier 	}
2893e12c5d1SDavid du Colombier 	/* get input file */
2903e12c5d1SDavid du Colombier 	if(p->argv->words==0){
2913e12c5d1SDavid du Colombier 		Xerror("Usage: . [-i] file [arg ...]");
2923e12c5d1SDavid du Colombier 		return;
2933e12c5d1SDavid du Colombier 	}
2943e12c5d1SDavid du Colombier 	zero=strdup(p->argv->words->word);
2953e12c5d1SDavid du Colombier 	popword();
296*219b2ee8SDavid du Colombier 	strcpy(file, "**No file name**");
2973e12c5d1SDavid du Colombier 	for(path=searchpath(zero);path;path=path->next){
2983e12c5d1SDavid du Colombier 		strcpy(file, path->word);
2993e12c5d1SDavid du Colombier 		if(file[0]) strcat(file, "/");
3003e12c5d1SDavid du Colombier 		strcat(file, zero);
3013e12c5d1SDavid du Colombier 		if((fd=open(file, 0))>=0) break;
3023e12c5d1SDavid du Colombier 		if(strcmp(file, "/dev/stdin")==0){	/* for sun & ucb */
3033e12c5d1SDavid du Colombier 			fd=Dup1(0);
3043e12c5d1SDavid du Colombier 			if(fd>=0) break;
3053e12c5d1SDavid du Colombier 		}
3063e12c5d1SDavid du Colombier 	}
3073e12c5d1SDavid du Colombier 	if(fd<0){
308*219b2ee8SDavid du Colombier 		Xperror(file);
3093e12c5d1SDavid du Colombier 		return;
3103e12c5d1SDavid du Colombier 	}
3113e12c5d1SDavid du Colombier 	/* set up for a new command loop */
3123e12c5d1SDavid du Colombier 	start(dotcmds, 1, (struct var *)0);
3133e12c5d1SDavid du Colombier 	pushredir(RCLOSE, fd, 0);
3143e12c5d1SDavid du Colombier 	runq->cmdfile=zero;
3153e12c5d1SDavid du Colombier 	runq->cmdfd=openfd(fd);
3163e12c5d1SDavid du Colombier 	runq->iflag=iflag;
3173e12c5d1SDavid du Colombier 	runq->iflast=0;
3183e12c5d1SDavid du Colombier 	/* push $* value */
3193e12c5d1SDavid du Colombier 	pushlist();
3203e12c5d1SDavid du Colombier 	runq->argv->words=p->argv->words;
3213e12c5d1SDavid du Colombier 	/* free caller's copy of $* */
3223e12c5d1SDavid du Colombier 	av=p->argv;
3233e12c5d1SDavid du Colombier 	p->argv=av->next;
3243e12c5d1SDavid du Colombier 	efree((char *)av);
3253e12c5d1SDavid du Colombier 	/* push $0 value */
3263e12c5d1SDavid du Colombier 	pushlist();
3273e12c5d1SDavid du Colombier 	pushword(zero);
3283e12c5d1SDavid du Colombier 	ndot++;
3293e12c5d1SDavid du Colombier }
3303e12c5d1SDavid du Colombier void execflag(void){
3313e12c5d1SDavid du Colombier 	char *letter, *val;
3323e12c5d1SDavid du Colombier 	switch(count(runq->argv->words)){
3333e12c5d1SDavid du Colombier 	case 2:
3343e12c5d1SDavid du Colombier 		setstatus(flag[runq->argv->words->next->word[0]]?"":"flag not set");
3353e12c5d1SDavid du Colombier 		break;
3363e12c5d1SDavid du Colombier 	case 3:
3373e12c5d1SDavid du Colombier 		letter=runq->argv->words->next->word;
3383e12c5d1SDavid du Colombier 		val=runq->argv->words->next->next->word;
3393e12c5d1SDavid du Colombier 		if(strlen(letter)==1){
3403e12c5d1SDavid du Colombier 			if(strcmp(val, "+")==0){
3413e12c5d1SDavid du Colombier 				flag[letter[0]]=flagset;
3423e12c5d1SDavid du Colombier 				break;
3433e12c5d1SDavid du Colombier 			}
3443e12c5d1SDavid du Colombier 			if(strcmp(val, "-")==0){
3453e12c5d1SDavid du Colombier 				flag[letter[0]]=0;
3463e12c5d1SDavid du Colombier 				break;
3473e12c5d1SDavid du Colombier 			}
3483e12c5d1SDavid du Colombier 		}
3493e12c5d1SDavid du Colombier 	default:
3503e12c5d1SDavid du Colombier 		Xerror("Usage: flag [letter] [+-]");
3513e12c5d1SDavid du Colombier 		return;
3523e12c5d1SDavid du Colombier 	}
3533e12c5d1SDavid du Colombier 	poplist();
3543e12c5d1SDavid du Colombier }
3553e12c5d1SDavid du Colombier void execwhatis(void){	/* mildly wrong -- should fork before writing */
3563e12c5d1SDavid du Colombier 	word *a, *b, *path;
3573e12c5d1SDavid du Colombier 	var *v;
3583e12c5d1SDavid du Colombier 	struct builtin *bp;
3593e12c5d1SDavid du Colombier 	char file[512];
3603e12c5d1SDavid du Colombier 	struct io out[1];
3613e12c5d1SDavid du Colombier 	int found, sep;
3623e12c5d1SDavid du Colombier 	a=runq->argv->words->next;
3633e12c5d1SDavid du Colombier 	if(a==0){
3643e12c5d1SDavid du Colombier 		Xerror("Usage: whatis name ...");
3653e12c5d1SDavid du Colombier 		return;
3663e12c5d1SDavid du Colombier 	}
3673e12c5d1SDavid du Colombier 	setstatus("");
3683e12c5d1SDavid du Colombier 	out->fd=mapfd(1);
3693e12c5d1SDavid du Colombier 	out->bufp=out->buf;
3703e12c5d1SDavid du Colombier 	out->ebuf=&out->buf[NBUF];
3713e12c5d1SDavid du Colombier 	out->strp=0;
3723e12c5d1SDavid du Colombier 	for(;a;a=a->next){
3733e12c5d1SDavid du Colombier 		v=vlook(a->word);
3743e12c5d1SDavid du Colombier 		if(v->val){
3753e12c5d1SDavid du Colombier 			pfmt(out, "%s=", a->word);
3763e12c5d1SDavid du Colombier 			if(v->val->next==0)
3773e12c5d1SDavid du Colombier 				pfmt(out, "%q\n", v->val->word);
3783e12c5d1SDavid du Colombier 			else{
3793e12c5d1SDavid du Colombier 				sep='(';
3803e12c5d1SDavid du Colombier 				for(b=v->val;b && b->word;b=b->next){
3813e12c5d1SDavid du Colombier 					pfmt(out, "%c%q", sep, b->word);
3823e12c5d1SDavid du Colombier 					sep=' ';
3833e12c5d1SDavid du Colombier 				}
3843e12c5d1SDavid du Colombier 				pfmt(out, ")\n");
3853e12c5d1SDavid du Colombier 			}
3863e12c5d1SDavid du Colombier 			found=1;
3873e12c5d1SDavid du Colombier 		}
3883e12c5d1SDavid du Colombier 		else
3893e12c5d1SDavid du Colombier 			found=0;
3903e12c5d1SDavid du Colombier 		v=gvlook(a->word);
3913e12c5d1SDavid du Colombier 		if(v->fn) pfmt(out, "fn %s %s\n", v->name, v->fn[v->pc-1].s);
3923e12c5d1SDavid du Colombier 		else{
3933e12c5d1SDavid du Colombier 			for(bp=Builtin;bp->name;bp++)
3943e12c5d1SDavid du Colombier 				if(strcmp(a->word, bp->name)==0){
3953e12c5d1SDavid du Colombier 					pfmt(out, "builtin %s\n", a->word);
3963e12c5d1SDavid du Colombier 					break;
3973e12c5d1SDavid du Colombier 				}
3983e12c5d1SDavid du Colombier 			if(!bp->name){
3993e12c5d1SDavid du Colombier 				for(path=searchpath(a->word);path;path=path->next){
4003e12c5d1SDavid du Colombier 					strcpy(file, path->word);
4013e12c5d1SDavid du Colombier 					if(file[0]) strcat(file, "/");
4023e12c5d1SDavid du Colombier 					strcat(file, a->word);
4033e12c5d1SDavid du Colombier 					if(Executable(file)){
4043e12c5d1SDavid du Colombier 						pfmt(out, "%s\n", file);
4053e12c5d1SDavid du Colombier 						break;
4063e12c5d1SDavid du Colombier 					}
4073e12c5d1SDavid du Colombier 				}
4083e12c5d1SDavid du Colombier 				if(!path && !found){
4093e12c5d1SDavid du Colombier 					pfmt(err, "%s: not found\n", a->word);
4103e12c5d1SDavid du Colombier 					setstatus("not found");
4113e12c5d1SDavid du Colombier 				}
4123e12c5d1SDavid du Colombier 			}
4133e12c5d1SDavid du Colombier 		}
4143e12c5d1SDavid du Colombier 	}
4153e12c5d1SDavid du Colombier 	poplist();
4163e12c5d1SDavid du Colombier 	flush(err);
4173e12c5d1SDavid du Colombier }
4183e12c5d1SDavid du Colombier void execwait(void){
4193e12c5d1SDavid du Colombier 	switch(count(runq->argv->words)){
4203e12c5d1SDavid du Colombier 	default: Xerror("Usage: wait [pid]"); return;
4213e12c5d1SDavid du Colombier 	case 2: Waitfor(atoi(runq->argv->words->next->word), 0); break;
4223e12c5d1SDavid du Colombier 	case 1: Waitfor(-1, 0); break;
4233e12c5d1SDavid du Colombier 	}
424*219b2ee8SDavid du Colombier 	poplist();
4253e12c5d1SDavid du Colombier }
426