henesyinit from p9fce6d0435 years agoHistory
887 lines · 17.5 KB · C
RawDownload
#include "rc.h"#include "getflags.h"#include "exec.h"#include "io.h"#include "fns.h"/* * Start executing the given code at the given pc with the given redirection */void start(code *c, int pc, var *local){	struct thread *p=new(struct thread);	p->code=codecopy(c);	p->pc=pc;	p->argv=0;	p->redir=p->startredir=runq?runq->redir:0;	p->local=local;	p->cmdfile=0;	p->cmdfd=0;	p->eof=0;	p->iflag=0;	p->lineno=1;	p->ret=runq;	runq=p;}word *newword(char *wd, word *next){	word *p=new(word);	p->word=strdup(wd);	p->next=next;	return p;}void pushword(char *wd){	if(runq->argv==0) panic("pushword but no argv!", 0);	runq->argv->words=newword(wd, runq->argv->words);}void popword(void){	word *p;	if(runq->argv==0) panic("popword but no argv!", 0);	p=runq->argv->words;	if(p==0) panic("popword but no word!", 0);	runq->argv->words=p->next;	efree(p->word);	efree((char *)p);}void freelist(word *w){	word *nw;	while(w){		nw=w->next;		efree(w->word);		efree((char *)w);		w=nw;	}}void pushlist(void){	list *p=new(list);	p->next=runq->argv;	p->words=0;	runq->argv=p;}void poplist(void){	list *p=runq->argv;	if(p==0) panic("poplist but no argv", 0);	freelist(p->words);	runq->argv=p->next;	efree((char *)p);}int count(word *w){	int n;	for(n=0;w;n++) w=w->next;	return n;}void pushredir(int type, int from, int to){	redir * rp=new(redir);	rp->type=type;	rp->from=from;	rp->to=to;	rp->next=runq->redir;	runq->redir=rp;}var *newvar(char *name, var *next){	var *v=new(var);	v->name=name;	v->val=0;	v->fn=0;	v->changed=0;	v->fnchanged=0;	v->next=next;	return v;}/* * get command line flags, initialize keywords & traps. * get values from environment. * set $pid, $cflag, $* * fabricate bootstrap code and start it (*=(argv);. /usr/lib/rcmain $*) * start interpreting code */main(int argc, char *argv[]){	code bootstrap[17];	char num[12];	int i;	argc=getflags(argc, argv, "srdiIlxepvVc:1[command]", 1);	if(argc==-1) usage("[file [arg ...]]");	if(argc==1 && Isatty(0)) flag['i']=flagset;	if(argv[0][0]=='-') flag['l']=flagset;	if(flag['I']) flag['i']=0;	err=openfd(2);	kinit();	Trapinit();	Vinit();	itoa(num, mypid=getpid());	setvar("pid", newword(num, (word *)0));	setvar("cflag", flag['c']?newword(flag['c'][0], (word *)0)				:(word *)0);	setvar("rcname", newword(argv[0], (word *)0));	i=0;	bootstrap[i++].i=1;	bootstrap[i++].f=Xmark;	bootstrap[i++].f=Xword;	bootstrap[i++].s="*";	bootstrap[i++].f=Xassign;	bootstrap[i++].f=Xmark;	bootstrap[i++].f=Xmark;	bootstrap[i++].f=Xword;	bootstrap[i++].s="*";	bootstrap[i++].f=Xdol;	bootstrap[i++].f=Xword;	bootstrap[i++].s=Rcmain;	bootstrap[i++].f=Xword;	bootstrap[i++].s=".";	bootstrap[i++].f=Xsimple;	bootstrap[i++].f=Xexit;	bootstrap[i].i=0;	start(bootstrap, 1, (var *)0);	/* prime bootstrap argv */	pushlist();	for(i=argc-1;i!=0;--i) pushword(argv[i]);	for(;;){		if(flag['r']) pfnc(err, runq);		runq->pc++;		(*runq->code[runq->pc-1].f)();		if(ntrap) dotrap();	}}/* * Opcode routines * Arguments on stack (...) * Arguments in line [...] * Code in line with jump around {...} * * Xappend(file)[fd]			open file to append * Xassign(name, val)			assign val to name * Xasync{... Xexit}			make thread for {}, no wait * Xbackq{... Xreturn}			make thread for {}, push stdout * Xbang				complement condition * Xcase(pat, value){...}		exec code on match, leave (value) on * 					stack * Xclose[i]				close file descriptor * Xconc(left, right)			concatenate, push results * Xcount(name)				push var count * Xdelfn(name)				delete function definition * Xdeltraps(names)			delete named traps * Xdol(name)				get variable value * Xqdol(name)				concatenate variable components * Xdup[i j]				dup file descriptor * Xexit				rc exits with status * Xfalse{...}				execute {} if false * Xfn(name){... Xreturn}			define function * Xfor(var, list){... Xreturn}		for loop * Xjump[addr]				goto * Xlocal(name, val)			create local variable, assign value * Xmark				mark stack * Xmatch(pat, str)			match pattern, set status * Xpipe[i j]{... Xreturn}{... Xreturn}	construct a pipe between 2 new threads, * 					wait for both * Xpipefd[type]{... Xreturn}		connect {} to pipe (input or output, * 					depending on type), push /dev/fd/?? * Xpopm(value)				pop value from stack * Xread(file)[fd]			open file to read * Xsettraps(names){... Xreturn}		define trap functions * Xshowtraps				print trap list * Xsimple(args)			run command and wait * Xreturn				kill thread * Xsubshell{... Xexit}			execute {} in a subshell and wait * Xtrue{...}				execute {} if true * Xunlocal				delete local variable * Xword[string]			push string * Xwrite(file)[fd]			open file to write */void Xappend(void){	char *file;	int f;	switch(count(runq->argv->words)){	default: Xerror(">> requires singleton"); return;	case 0: Xerror(">> requires file"); return;	case 1: break;	}	file=runq->argv->words->word;	if((f=open(file, 1))<0 && (f=Creat(file))<0){		Xperror(file);		return;	}	Seek(f, 0L, 2);	pushredir(ROPEN, f, runq->code[runq->pc].i);	runq->pc++;	poplist();}void Xasync(void){	int null=open("/dev/null", 0);	int pid;	char npid[10];	if(null<0){		Xperror("/dev/null");		return;	}	switch(pid=rfork(RFFDG|RFPROC|RFNOTEG)){	case -1:		close(null);		Xperror("rfork");		break;	case 0:		pushredir(ROPEN, null, 0);		start(runq->code, runq->pc+1, runq->local);		runq->ret=0;		break;	default:		close(null);		runq->pc=runq->code[runq->pc].i;		itoa(npid, pid);		setvar("apid", newword(npid, (word *)0));		break;	}}void Xsettrue(void){	setstatus("");}void Xbang(void){	setstatus(truestatus()?"false":"");}void Xclose(void){	pushredir(RCLOSE, runq->code[runq->pc].i, 0);	runq->pc++;}void Xdup(void){	pushredir(RDUP, runq->code[runq->pc].i, runq->code[runq->pc+1].i);	runq->pc+=2;}void Xeflag(void){	if(eflagok && !truestatus()) Xexit();}void Xexit(void){	struct var *trapreq;	struct word *starval;	static int beenhere=0;	if(getpid()==mypid && !beenhere){		trapreq=vlook("sigexit");		if(trapreq->fn){			beenhere=1;			--runq->pc;			starval=vlook("*")->val;			start(trapreq->fn, trapreq->pc, (struct var *)0);			runq->local=newvar(strdup("*"), runq->local);			runq->local->val=copywords(starval, (struct word *)0);			runq->local->changed=1;			runq->redir=runq->startredir=0;			return;		}	}	Exit(getstatus());}void Xfalse(void){	if(truestatus()) runq->pc=runq->code[runq->pc].i;	else runq->pc++;}int ifnot;		/* dynamic if not flag */void Xifnot(void){	if(ifnot)		runq->pc++;	else		runq->pc=runq->code[runq->pc].i;}void Xjump(void){	runq->pc=runq->code[runq->pc].i;}void Xmark(void){	pushlist();}void Xpopm(void){	poplist();}void Xread(void){	char *file;	int f;	switch(count(runq->argv->words)){	default: Xerror("< requires singleton\n"); return;	case 0: Xerror("< requires file\n"); return;	case 1: break;	}	file=runq->argv->words->word;	if((f=open(file, 0))<0){		Xperror(file);		return;	}	pushredir(ROPEN, f, runq->code[runq->pc].i);	runq->pc++;	poplist();}void turfredir(void){	while(runq->redir!=runq->startredir)		Xpopredir();}void Xpopredir(void){	struct redir *rp=runq->redir;	if(rp==0) panic("turfredir null!", 0);	runq->redir=rp->next;	if(rp->type==ROPEN) close(rp->from);	efree((char *)rp);}void Xreturn(void){	struct thread *p=runq;	turfredir();	while(p->argv) poplist();	codefree(p->code);	runq=p->ret;	efree((char *)p);	if(runq==0) Exit(getstatus());}void Xtrue(void){	if(truestatus()) runq->pc++;	else runq->pc=runq->code[runq->pc].i;}void Xif(void){	ifnot=1;	if(truestatus()) runq->pc++;	else runq->pc=runq->code[runq->pc].i;}void Xwastrue(void){	ifnot=0;}void Xword(void){	pushword(runq->code[runq->pc++].s);}void Xwrite(void){	char *file;	int f;	switch(count(runq->argv->words)){	default: Xerror("> requires singleton\n"); return;	case 0: Xerror("> requires file\n"); return;	case 1: break;	}	file=runq->argv->words->word;	if((f=Creat(file))<0){		Xperror(file);		return;	}	pushredir(ROPEN, f, runq->code[runq->pc].i);	runq->pc++;	poplist();}char *list2str(word *words){	char *value, *s, *t;	int len=0;	word *ap;	for(ap=words;ap;ap=ap->next)		len+=1+strlen(ap->word);	value=emalloc(len+1);	s=value;	for(ap=words;ap;ap=ap->next){		for(t=ap->word;*t;) *s++=*t++;		*s++=' ';	}	if(s==value) *s='\0';	else s[-1]='\0';	return value;}void Xmatch(void){	word *p;	char *subject;	subject=list2str(runq->argv->words);	setstatus("no match");	for(p=runq->argv->next->words;p;p=p->next)		if(match(subject, p->word, '\0')){			setstatus("");			break;		}	efree(subject);	poplist();	poplist();}void Xcase(void){	word *p;	char *s;	int ok=0;	s=list2str(runq->argv->next->words);	for(p=runq->argv->words;p;p=p->next){		if(match(s, p->word, '\0')){			ok=1;			break;		}	}	efree(s);	if(ok)		runq->pc++;	else		runq->pc=runq->code[runq->pc].i;	poplist();}word *conclist(word *lp, word *rp, word *tail){	char *buf;	word *v;	if(lp->next || rp->next)		tail=conclist(lp->next==0?lp:lp->next, rp->next==0?rp:rp->next,			tail);	buf=emalloc(strlen(lp->word)+strlen(rp->word)+1);	strcpy(buf, lp->word);	strcat(buf, rp->word);	v=newword(buf, tail);	efree(buf);	return v;}void Xconc(void){	word *lp=runq->argv->words;	word *rp=runq->argv->next->words;	word *vp=runq->argv->next->next->words;	int lc=count(lp), rc=count(rp);	if(lc!=0 || rc!=0){		if(lc==0 || rc==0){			Xerror("null list in concatenation");			return;		}		if(lc!=1 && rc!=1 && lc!=rc){			Xerror("mismatched list lengths in concatenation");			return;		}		vp=conclist(lp, rp, vp);	}	poplist();	poplist();	runq->argv->words=vp;}void Xassign(void){	var *v;	if(count(runq->argv->words)!=1){		Xerror("variable name not singleton!");		return;	}	deglob(runq->argv->words->word);	v=vlook(runq->argv->words->word);	poplist();	globlist();	freewords(v->val);	v->val=runq->argv->words;	v->changed=1;	runq->argv->words=0;	poplist();}/* * copy arglist a, adding the copy to the front of tail */word *copywords(word *a, word *tail){	word *v=0, **end;	for(end=&v;a;a=a->next,end=&(*end)->next)		*end=newword(a->word, 0);	*end=tail;	return v;}void Xdol(void){	word *a, *star;	char *s, *t;	int n;	if(count(runq->argv->words)!=1){		Xerror("variable name not singleton!");		return;	}	s=runq->argv->words->word;	deglob(s);	n=0;	for(t=s;'0'<=*t && *t<='9';t++) n=n*10+*t-'0';	a=runq->argv->next->words;	if(n==0 || *t)		a=copywords(vlook(s)->val, a);	else{		star=vlook("*")->val;		if(star && 1<=n && n<=count(star)){			while(--n) star=star->next;			a=newword(star->word, a);		}	}	poplist();	runq->argv->words=a;}void Xqdol(void){	word *a, *p;	char *s;

Lines 1–500 of 887.