1194 lines · 19.2 KB · C
RawDownload
#include "rc.h"#include "getflags.h"#include "exec.h"#include "io.h"#include "fns.h" char *argv0="rc";io *err;int mypid;thread *runq; /* * Start executing the given code at the given pc with the given redirection */voidstart(code *c, int pc, var *local, redir *redir){	thread *p = new(thread);	p->code = codecopy(c);	p->line = 0;	p->pc = pc;	p->argv = 0;	p->redir = p->startredir = redir;	p->lex = 0;	p->local = local;	p->iflag = 0;	p->pid = 0;	p->status = 0;	p->ret = runq;	runq = p;} voidstartfunc(var *func, word *starval, var *local, redir *redir){	start(func->fn, func->pc, local, redir);	runq->local = newvar("*", runq->local);	runq->local->val = starval;	runq->local->changed = 1;} static voidpopthread(void){	thread *p = runq;	while(p->argv) poplist();	while(p->local && (p->ret==0 || p->local!=p->ret->local))		Xunlocal();	runq = p->ret;	if(p->lex) freelexer(p->lex);	codefree(p->code);	free(p->status);	free(p);} word*Newword(char *s, word *next){	word *p=new(word);	p->word = s;	p->next = next;	return p;}word*newword(char *s, word *next){	return Newword(estrdup(s), next);}word*Pushword(char *s){	word *p;	if(s==0)		panic("null pushword", 0);	if(runq->argv==0)		panic("pushword but no argv!", 0);	p = Newword(s, runq->argv->words);	runq->argv->words = p;	return p;}word*pushword(char *s){	return Pushword(estrdup(s));}char*Freeword(word *p){	char *s = p->word;	free(p);	return s;}voidfreewords(word *w){	word *p;	while((p = w)!=0){		w = w->next;		free(Freeword(p));	}}char*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;	return Freeword(p);}voidpopword(void){	free(Popword());} voidpushlist(void){	list *p = new(list);	p->words = 0;	p->next = runq->argv;	runq->argv = p;}word*Poplist(void){	word *w;	list *p = runq->argv;	if(p==0)		panic("poplist but no argv", 0);	w = p->words;	runq->argv = p->next;	free(p);	return w;}voidpoplist(void){	freewords(Poplist());} intcount(word *w){	int n;	for(n = 0;w;n++) w = w->next;	return n;} static intclobbersfd(redir *rp, int fd){	while(rp){		if(rp->to==fd)			return 1;		rp = rp->next;	}	return 0;} voidpushredir(int type, int from, int to){	redir *rp; 	/* don't let dups clobber the from fd for file redirects */	if(type==ROPEN && clobbersfd(runq->redir, from)){		pushredir(type, Dup1(from), to);		Close(from);		return;	} 	rp = new(redir);	rp->type = type;	rp->from = from;	rp->to = to;	rp->next = runq->redir;	runq->redir = rp;} static voiddontclose(int fd){	redir *rp; 	if(fd<0)		return;	for(rp = runq->redir; rp != runq->startredir; rp = rp->next){		if(rp->type == RCLOSE && rp->to == fd){			rp->to = -1;			rp->type = 0;			break;		}	}} /* * we are about to start a new thread that should exit on * return, so the current stack is not needed anymore. * free all the threads and lexers, but preserve the * redirections and anything referenced by local. */voidturfstack(var *local){	while(local){		thread *p; 		for(p = runq; p && p->local == local; p = p->ret)			p->local = local->next;		local = local->next;	}	while(runq) {		if(runq->lex) dontclose(runq->lex->input->fd);		popthread();	}} voidshuffleredir(void){	redir **rr, *rp; 	rp = runq->redir;	if(rp==0)		return;	runq->redir = rp->next;	rp->next = runq->startredir;	for(rr = &runq->redir; *rr != rp->next; rr = &((*rr)->next))		;	*rr = rp;} /* * get command line flags, initialize keywords & traps. * get values from environment. * set $pid, $cflag, $* * fabricate bootstrap code and start it (*=(argv);. -bq /usr/lib/rcmain $*) * start interpreting code */voidmain(int argc, char *argv[]){	code bootstrap[20];	char num[12];	char *rcmain=Rcmain; 	int i;	argv0 = argv[0];	argc = getflags(argc, argv, "srdiIlxebpvVc:1m:1[command]", 1);	if(argc==-1)		usage("[file [arg ...]]");	if(argv[0][0]=='-')		flag['l'] = flagset;	if(flag['I'])		flag['i'] = 0;	else if(flag['i']==0 && argc==1 && Isatty(0)) flag['i'] = flagset;	if(flag['m']) rcmain = flag['m'][0];	err = openiofd(2);	kinit();	Trapinit();	Vinit();	inttoascii(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));	bootstrap[0].i = 1;	bootstrap[1].s="*bootstrap*";	bootstrap[2].f = Xmark;	bootstrap[3].f = Xword;	bootstrap[4].s="*";	bootstrap[5].f = Xassign;	bootstrap[6].f = Xmark;	bootstrap[7].f = Xmark;	bootstrap[8].f = Xword;	bootstrap[9].s="*";	bootstrap[10].f = Xdol;	bootstrap[11].f = Xword;	bootstrap[12].s = rcmain;	bootstrap[13].f = Xword;	bootstrap[14].s="-bq";	bootstrap[15].f = Xword;	bootstrap[16].s=".";	bootstrap[17].f = Xsimple;	bootstrap[18].f = Xexit;	bootstrap[19].f = 0;	start(bootstrap, 2, (var*)0, (redir*)0); 	/* prime bootstrap argv */	pushlist();	for(i = argc-1;i!=0;--i) pushword(argv[i]); 	for(;;){		if(flag['r'])			pfnc(err, runq);		(*runq->code[runq->pc++].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(split){... 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 * Xdol(name)				get variable value * 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 * Xglob(list)				glob a list of words inplace * 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 * Xpush(words)				push words down a list * Xqw(words)				quote words inplace * Xrdwr(file)[fd]			open file for reading and writing * Xread(file)[fd]			open file to read * Xreturn				kill thread * Xsimple(args)			run command and wait * Xsrcline[line]			set current source line number * 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 */ voidXappend(void){	char *file;	int fd; 	switch(count(runq->argv->words)){	default:		Xerror1(">> requires singleton");		return;	case 0:		Xerror1(">> requires file");		return;	case 1:		break;	}	file = runq->argv->words->word;	if((fd = Open(file, 1))<0 && (fd = Creat(file))<0){		Xerror3(">> can't open", file, Errstr());		return;	}	Seek(fd, 0L, 2);	pushredir(ROPEN, fd, runq->code[runq->pc++].i);	poplist();} voidXsettrue(void){	setstatus("");} voidXbang(void){	setstatus(truestatus()?"false":"");} voidXclose(void){	pushredir(RCLOSE, -1, runq->code[runq->pc++].i);} voidXdup(void){	pushredir(RDUP, runq->code[runq->pc].i, runq->code[runq->pc+1].i);	runq->pc+=2;} voidXeflag(void){	if(!truestatus()) Xexit();} static int trapped; var*trapexit(void){	if(getpid()==mypid && !trapped){		var *trap = vlook("sigexit");		if(trap->fn)			return trap;	}	return (var*)0;} voidXexit(void){	var *trap = trapexit();	if(trap==0) Exit();	if(runq) --runq->pc;	startfunc(trap, copywords(vlook("*")->val, (word*)0), (var*)0, (redir*)0);	trapped = 1;} voidXfalse(void){	if(truestatus()) runq->pc = runq->code[runq->pc].i;	else runq->pc++;}int ifnot;		/* dynamic if not flag */ voidXifnot(void){	if(ifnot)		runq->pc++;	else		runq->pc = runq->code[runq->pc].i;} voidXjump(void){	runq->pc = runq->code[runq->pc].i;} voidXmark(void){	pushlist();} voidXpopm(void){	poplist();} voidXpush(void){	word *t, *h = Poplist();	for(t = h; t->next; t = t->next)		;	t->next = runq->argv->words;	runq->argv->words = h;} static intherefile(char *tmp){	char *s = tmp+strlen(tmp)-1;	static int ser;	int fd, i; 	i = ser++;	while(*s == 'Y'){		*s-- = (i%26) + 'A';		i = i/26;	}	i = getpid();	while(*s == 'X'){		*s-- = (i%10) + '0';		i = i/10;	}	s++;	for(i='a'; i<'z'; i++){		if(access(tmp, 0)!=0 && (fd = Creat(tmp))>=0)			return fd;		*s = i;	}

Lines 1–500 of 1194.