code: plan9front

ref: e72da62915b09d5673b0c0179ba8dfe045aeb8c3
dir: /sys/src/cmd/rc/simple.c/

View raw version
/*
 * Maybe `simple' is a misnomer.
 */
#include "rc.h"
#include "getflags.h"
#include "exec.h"
#include "io.h"
#include "fns.h"
/*
 * Search through the following code to see if we're just going to exit.
 */
int
exitnext(void){
	code *c=&runq->code[runq->pc];
	while(1){
		if(c->f==Xpopredir || c->f==Xunlocal)
			c++;
		else if(c->f==Xsrcline || c->f==Xsrcfile)
			c += 2;
		else
			break;
	}
	return c->f==Xexit;
}

void
Xsimple(void)
{
	word *a;
	var *v;
	struct builtin *bp;
	int pid;

	a = globlist(runq->argv->words);
	if(a==0){
		Xerror1("empty argument list");
		return;
	}
	if(flag['x'])
		pfmt(err, "%v\n", a); /* wrong, should do redirs */
	v = gvlook(a->word);
	if(v->fn)
		execfunc(v);
	else{
		if(strcmp(a->word, "builtin")==0){
			if(count(a)==1){
				pfmt(err, "builtin: empty argument list\n");
				setstatus("empty arg list");
				poplist();
				return;
			}
			a = a->next;
			popword();
		}
		for(bp = Builtin;bp->name;bp++)
			if(strcmp(a->word, bp->name)==0){
				(*bp->fnc)();
				return;
			}
		if(exitnext()){
			/* fork and wait is redundant */
			pushword("exec");
			execexec();
		}
		else{
			flush(err);
			Updenv();	/* necessary so changes don't go out again */
			if((pid = execforkexec()) < 0){
				Xerror("try again");
				return;
			}

			/* interrupts don't get us out */
			poplist();
			while(Waitfor(pid, 1) < 0)
				;
		}
	}
}

void
doredir(redir *rp)
{
	if(rp){
		doredir(rp->next);
		switch(rp->type){
		case ROPEN:
			if(rp->from!=rp->to){
				Dup(rp->from, rp->to);
				close(rp->from);
			}
			break;
		case RDUP:
			Dup(rp->from, rp->to);
			break;
		case RCLOSE:
			close(rp->from);
			break;
		}
	}
}

word*
searchpath(char *w, char *v)
{
	static struct word nullpath = { "", 0 };
	word *path;

	if(w[0] && w[0] != '/' && w[0] != '#' &&
	  (w[0] != '.' || (w[1] && w[1] != '/' && (w[1] != '.' || w[2] && w[2] != '/')))){
		path = vlook(v)->val;
		if(path)
			return path;
	}
	return &nullpath;
}

void
execexec(void)
{
	popword();	/* "exec" */
	if(runq->argv->words==0){
		Xerror1("empty argument list");
		return;
	}
	doredir(runq->redir);
	Execute(runq->argv->words, searchpath(runq->argv->words->word, "path"));
	poplist();
	Xexit();
}

void
execfunc(var *func)
{
	word *starval;
	popword();
	starval = runq->argv->words;
	runq->argv->words = 0;
	poplist();
	start(func->fn, func->pc, runq->local);
	runq->local = newvar("*", runq->local);
	runq->local->val = starval;
	runq->local->changed = 1;
}

int
dochdir(char *word)
{
	/* report to /dev/wdir if it exists and we're interactive */
	if(chdir(word)<0)
		return -1;
	newwdir = 1;
	return 1;
}

void
execcd(void)
{
	word *a = runq->argv->words;
	word *cdpath;
	char *dir;

	setstatus("can't cd");
	switch(count(a)){
	default:
		pfmt(err, "Usage: cd [directory]\n");
		break;
	case 2:
		a = a->next;
		for(cdpath = searchpath(a->word, "cdpath"); cdpath; cdpath = cdpath->next){
			if(cdpath->word[0] != '\0')
				dir = smprint("%s/%s", cdpath->word, a->word);
			else
				dir = estrdup(a->word);
			if(dochdir(dir) >= 0){
				if(cdpath->word[0] != '\0' && strcmp(cdpath->word, ".") != 0)
					pfmt(err, "%s\n", dir);
				free(dir);
				setstatus("");
				break;
			}
			free(dir);
		}
		if(cdpath==0)
			pfmt(err, "Can't cd %s: %r\n", a->word);
		break;
	case 1:
		a = vlook("home")->val;
		if(count(a)>=1){
			if(dochdir(a->word)>=0)
				setstatus("");
			else
				pfmt(err, "Can't cd %s: %r\n", a->word);
		}
		else
			pfmt(err, "Can't cd -- $home empty\n");
		break;
	}
	poplist();
}

void
execexit(void)
{
	switch(count(runq->argv->words)){
	default:
		pfmt(err, "Usage: exit [status]\nExiting anyway\n");
	case 2:
		setstatus(runq->argv->words->next->word);
	case 1:	Xexit();
	}
}

void
execshift(void)
{
	int n;
	word *a;
	var *star;
	switch(count(runq->argv->words)){
	default:
		pfmt(err, "Usage: shift [n]\n");
		setstatus("shift usage");
		poplist();
		return;
	case 2:
		n = atoi(runq->argv->words->next->word);
		break;
	case 1:
		n = 1;
		break;
	}
	star = vlook("*");
	for(;n>0 && star->val;--n){
		a = star->val->next;
		free(star->val->word);
		free(star->val);
		star->val = a;
		star->changed = 1;
	}
	setstatus("");
	poplist();
}

int
mapfd(int fd)
{
	redir *rp;
	for(rp = runq->redir;rp;rp = rp->next){
		switch(rp->type){
		case RCLOSE:
			if(rp->from==fd)
				fd=-1;
			break;
		case RDUP:
		case ROPEN:
			if(rp->to==fd)
				fd = rp->from;
			break;
		}
	}
	return fd;
}
union code rdcmds[4];

void
execcmds(io *f)
{
	static int first = 1;

	if(first){
		rdcmds[0].i = 1;
		rdcmds[1].f = Xrdcmds;
		rdcmds[2].f = Xreturn;
		first = 0;
	}
	start(rdcmds, 1, runq->local);
	runq->cmdfd = f;
	runq->iflast = 0;
}

void
execeval(void)
{
	char *cmdline;
	int len;
	if(count(runq->argv->words)<=1){
		Xerror1("Usage: eval cmd ...");
		return;
	}
	eflagok = 1;
	cmdline = list2str(runq->argv->words->next);
	len = strlen(cmdline);
	cmdline[len] = '\n';
	poplist();
	execcmds(opencore(cmdline, len+1));
	free(cmdline);
}
union code dotcmds[14];

void
execdot(void)
{
	int iflag = 0;
	int fd;
	list *av;
	thread *p = runq;
	char *zero, *file;
	word *path;
	static int first = 1;

	if(first){
		dotcmds[0].i = 1;
		dotcmds[1].f = Xmark;
		dotcmds[2].f = Xword;
		dotcmds[3].s="0";
		dotcmds[4].f = Xlocal;
		dotcmds[5].f = Xmark;
		dotcmds[6].f = Xword;
		dotcmds[7].s="*";
		dotcmds[8].f = Xlocal;
		dotcmds[9].f = Xrdcmds;
		dotcmds[10].f = Xunlocal;
		dotcmds[11].f = Xunlocal;
		dotcmds[12].f = Xreturn;
		first = 0;
	}
	else
		eflagok = 1;

	popword();
	if(p->argv->words && strcmp(p->argv->words->word, "-i")==0){
		iflag = 1;
		popword();
	}
	/* get input file */
	if(p->argv->words==0){
		Xerror1("Usage: . [-i] file [arg ...]");
		return;
	}
	zero = estrdup(p->argv->words->word);
	popword();
	fd = -1;
	for(path = searchpath(zero, "path"); path; path = path->next){
		if(path->word[0] != '\0')
			file = smprint("%s/%s", path->word, zero);
		else
			file = estrdup(zero);

		fd = open(file, 0);
		free(file);
		if(fd >= 0)
			break;
		if(strcmp(file, "/dev/stdin")==0){	/* for sun & ucb */
			fd = Dup1(0);
			if(fd>=0)
				break;
		}
	}
	if(fd<0){
		pfmt(err, "%s: ", zero);
		setstatus("can't open");
		Xerror(".: can't open");
		return;
	}

	lexline = 1;

	/* set up for a new command loop */
	start(dotcmds, 1, (struct var *)0);
	pushredir(RCLOSE, fd, 0);
	runq->cmdfile = zero;
	runq->cmdfd = openfd(fd);
	runq->iflag = iflag;
	runq->iflast = 0;
	/* push $* value */
	pushlist();
	runq->argv->words = p->argv->words;
	/* free caller's copy of $* */
	av = p->argv;
	p->argv = av->next;
	free(av);
	/* push $0 value */
	pushlist();
	pushword(zero);
	ndot++;
}

void
execflag(void)
{
	char *letter, *val;
	switch(count(runq->argv->words)){
	case 2:
		setstatus(flag[(uchar)runq->argv->words->next->word[0]]?"":"flag not set");
		break;
	case 3:
		letter = runq->argv->words->next->word;
		val = runq->argv->words->next->next->word;
		if(strlen(letter)==1){
			if(strcmp(val, "+")==0){
				flag[(uchar)letter[0]] = flagset;
				break;
			}
			if(strcmp(val, "-")==0){
				flag[(uchar)letter[0]] = 0;
				break;
			}
		}
	default:
		Xerror1("Usage: flag [letter] [+-]");
		return;
	}
	poplist();
}

void
execwhatis(void){	/* mildly wrong -- should fork before writing */
	word *a, *b, *path;
	var *v;
	struct builtin *bp;
	char *file;
	struct io out[1];
	int found, sep;
	a = runq->argv->words->next;
	if(a==0){
		Xerror1("Usage: whatis name ...");
		return;
	}
	setstatus("");
	out->fd = mapfd(1);
	out->bufp = out->buf;
	out->ebuf = &out->buf[NBUF];
	out->strp = 0;
	for(;a;a = a->next){
		v = vlook(a->word);
		if(v->val){
			pfmt(out, "%s=", a->word);
			if(v->val->next==0)
				pfmt(out, "%q\n", v->val->word);
			else{
				sep='(';
				for(b = v->val;b && b->word;b = b->next){
					pfmt(out, "%c%q", sep, b->word);
					sep=' ';
				}
				pfmt(out, ")\n");
			}
			found = 1;
		}
		else
			found = 0;
		v = gvlook(a->word);
		if(v->fn)
			pfmt(out, "fn %q %s\n", v->name, v->fn[v->pc-1].s);
		else{
			for(bp = Builtin;bp->name;bp++)
				if(strcmp(a->word, bp->name)==0){
					pfmt(out, "builtin %s\n", a->word);
					break;
				}
			if(!bp->name){
				for(path = searchpath(a->word, "path"); path;
				    path = path->next){
					if(path->word[0] != '\0')
						file = smprint("%s/%s",
							path->word, a->word);
					else
						file = estrdup(a->word);
					if(Executable(file)){
						pfmt(out, "%s\n", file);
						free(file);
						break;
					}
					free(file);
				}
				if(!path && !found){
					pfmt(err, "%s: not found\n", a->word);
					setstatus("not found");
				}
			}
		}
	}
	poplist();
	flush(err);
}

void
execwait(void)
{
	switch(count(runq->argv->words)){
	default:
		Xerror1("Usage: wait [pid]");
		return;
	case 2:
		Waitfor(atoi(runq->argv->words->next->word), 0);
		break;
	case 1:
		Waitfor(-1, 0);
		break;
	}
	poplist();
}