#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. Load more
#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 */ void start(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; } void startfunc(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 void popthread(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; } void freewords(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); } void popword(void) { free(Popword()); } void pushlist(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; } void poplist(void) { freewords(Poplist()); } int count(word *w) { int n; for(n = 0;w;n++) w = w->next; return n; } static int clobbersfd(redir *rp, int fd) { while(rp){ if(rp->to==fd) return 1; rp = rp->next; } return 0; } void pushredir(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 void dontclose(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. */ void turfstack(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(); } } void shuffleredir(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 */ void main(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 */ void Xappend(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(); } void Xsettrue(void) { setstatus(""); } void Xbang(void) { setstatus(truestatus()?"false":""); } void Xclose(void) { pushredir(RCLOSE, -1, runq->code[runq->pc++].i); } void Xdup(void) { pushredir(RDUP, runq->code[runq->pc].i, runq->code[runq->pc+1].i); runq->pc+=2; } void Xeflag(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; } void Xexit(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; } 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 Xpush(void) { word *t, *h = Poplist(); for(t = h; t->next; t = t->next) ; t->next = runq->argv->words; runq->argv->words = h; } static int herefile(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; }