#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 */void 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(argv[0][0]=='-') flag['l']=flagset; if(flag['I']) flag['i'] = 0; else if(flag['i']==0 && argc==1 && Isatty(0)) flag['i'] = flagset; 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){ pfmt(err, "%s: ", file); Xerror("can't open"); 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){ Xerror("Can't open /dev/null\n"); return; } switch(pid=rfork(RFFDG|RFPROC|RFNOTEG)){ case -1: close(null); Xerror("try again"); 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){ pfmt(err, "%s: ", file); Xerror("can't open"); 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){ pfmt(err, "%s: ", file); Xerror("can't open"); 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;}Lines 1–500 of 885. Load more
#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 */ void 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(argv[0][0]=='-') flag['l']=flagset; if(flag['I']) flag['i'] = 0; else if(flag['i']==0 && argc==1 && Isatty(0)) flag['i'] = flagset; 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){ pfmt(err, "%s: ", file); Xerror("can't open"); 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){ Xerror("Can't open /dev/null\n"); return; } switch(pid=rfork(RFFDG|RFPROC|RFNOTEG)){ case -1: close(null); Xerror("try again"); 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){ pfmt(err, "%s: ", file); Xerror("can't open"); 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){ pfmt(err, "%s: ", file); Xerror("can't open"); 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; }