| #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 |
| */ |
| char *argv0="rc"; |
| 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; |
| v->changefn = 0; |
| 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 |
| */ |
| int |
| main(int argc, char *argv[]) |
| { |
| code bootstrap[32]; |
| char num[12], *rcmain; |
| int i; |
| |
| argc=getflags(argc, argv, "srdiIlxepvVc: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; |
| rcmain=flag['m']?flag['m'][0]:Rcmain(); |
| err=openfd(2); |
| kinit(); |
| Trapinit(); |
| Vinit(); |
| itoa(num, mypid=getpid()); |
| pathinit(); |
| 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(); |
| argv0 = strdup(argv[0]); |
| 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: Xerror1(">> requires singleton"); return; |
| case 0: Xerror1(">> 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: Xerror1("< requires singleton\n"); return; |
| case 0: Xerror1("< 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: Xerror1("> requires singleton\n"); return; |
| case 0: Xerror1("> 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, int c){ |
| 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++=c; |
| } |
| if(s==value) *s='\0'; |
| else s[-1]='\0'; |
| return value; |
| } |
| char *list2str(word *words){ |
| return _list2str(words, ' '); |
| } |
| 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){ |
| Xerror1("null list in concatenation"); |
| return; |
| } |
| if(lc!=1 && rc!=1 && lc!=rc){ |
| Xerror1("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){ |
| Xerror1("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; |
| if(v->changefn) |
| v->changefn(v); |
| 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){ |
| Xerror1("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; |
| int n; |
| if(count(runq->argv->words)!=1){ |
| Xerror1("variable name not singleton!"); |
| return; |
| } |
| s=runq->argv->words->word; |
| deglob(s); |
| a=vlook(s)->val; |
| poplist(); |
| n=count(a); |
| if(n==0){ |
| pushword(""); |
| return; |
| } |
| for(p=a;p;p=p->next) n+=strlen(p->word); |
| s=emalloc(n); |
| if(a){ |
| strcpy(s, a->word); |
| for(p=a->next;p;p=p->next){ |
| strcat(s, " "); |
| strcat(s, p->word); |
| } |
| } |
| else |
| s[0]='\0'; |
| pushword(s); |
| efree(s); |
| } |
| word *subwords(word *val, int len, word *sub, word *a) |
| { |
| int n; |
| char *s; |
| if(!sub) return a; |
| a=subwords(val, len, sub->next, a); |
| s=sub->word; |
| deglob(s); |
| n=0; |
| while('0'<=*s && *s<='9') n=n*10+ *s++ -'0'; |
| if(n<1 || len<n) return a; |
| for(;n!=1;--n) val=val->next; |
| return newword(val->word, a); |
| } |
| void Xsub(void){ |
| word *a, *v; |
| char *s; |
| if(count(runq->argv->next->words)!=1){ |
| Xerror1("variable name not singleton!"); |
| return; |
| } |
| s=runq->argv->next->words->word; |
| deglob(s); |
| a=runq->argv->next->next->words; |
| v=vlook(s)->val; |
| a=subwords(v, count(v), runq->argv->words, a); |
| poplist(); |
| poplist(); |
| runq->argv->words=a; |
| } |
| void Xcount(void){ |
| word *a; |
| char *s, *t; |
| int n; |
| char num[12]; |
| if(count(runq->argv->words)!=1){ |
| Xerror1("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'; |
| if(n==0 || *t){ |
| a=vlook(s)->val; |
| itoa(num, count(a)); |
| } |
| else{ |
| a=vlook("*")->val; |
| itoa(num, a && 1<=n && n<=count(a)?1:0); |
| } |
| poplist(); |
| pushword(num); |
| } |
| void Xlocal(void){ |
| if(count(runq->argv->words)!=1){ |
| Xerror1("variable name must be singleton\n"); |
| return; |
| } |
| deglob(runq->argv->words->word); |
| runq->local=newvar(strdup(runq->argv->words->word), runq->local); |
| runq->local->val=copywords(runq->argv->next->words, (word *)0); |
| runq->local->changed=1; |
| poplist(); |
| poplist(); |
| } |
| void Xunlocal(void){ |
| var *v=runq->local, *hid; |
| if(v==0) panic("Xunlocal: no locals!", 0); |
| runq->local=v->next; |
| hid=vlook(v->name); |
| hid->changed=1; |
| efree(v->name); |
| freewords(v->val); |
| efree((char *)v); |
| } |
| void freewords(word *w) |
| { |
| word *nw; |
| while(w){ |
| efree(w->word); |
| nw=w->next; |
| efree((char *)w); |
| w=nw; |
| } |
| } |
| void Xfn(void){ |
| var *v; |
| word *a; |
| int end; |
| end=runq->code[runq->pc].i; |
| for(a=runq->argv->words;a;a=a->next){ |
| v=gvlook(a->word); |
| if(v->fn) codefree(v->fn); |
| v->fn=codecopy(runq->code); |
| v->pc=runq->pc+2; |
| v->fnchanged=1; |
| } |
| runq->pc=end; |
| poplist(); |
| } |
| void Xdelfn(void){ |
| var *v; |
| word *a; |
| for(a=runq->argv->words;a;a=a->next){ |
| v=gvlook(a->word); |
| if(v->fn) codefree(v->fn); |
| v->fn=0; |
| v->fnchanged=1; |
| } |
| poplist(); |
| } |
| void Xpipe(void){ |
| struct thread *p=runq; |
| int pc=p->pc, forkid; |
| int lfd=p->code[pc++].i; |
| int rfd=p->code[pc++].i; |
| int pfd[2]; |
| if(pipe(pfd)<0){ |
| Xerror("can't get pipe"); |
| return; |
| } |
| switch(forkid=fork()){ |
| case -1: |
| Xerror("try again"); |
| break; |
| case 0: |
| start(p->code, pc+2, runq->local); |
| runq->ret=0; |
| close(pfd[PRD]); |
| pushredir(ROPEN, pfd[PWR], lfd); |
| break; |
| default: |
| start(p->code, p->code[pc].i, runq->local); |
| close(pfd[PWR]); |
| pushredir(ROPEN, pfd[PRD], rfd); |
| p->pc=p->code[pc+1].i; |
| p->pid=forkid; |
| break; |
| } |
| } |
| char *concstatus(char *s, char *t) |
| { |
| static char v[NSTATUS+1]; |
| int n=strlen(s); |
| strncpy(v, s, NSTATUS); |
| if(n<NSTATUS){ |
| v[n]='|'; |
| strncpy(v+n+1, t, NSTATUS-n-1); |
| } |
| v[NSTATUS]='\0'; |
| return v; |
| } |
| void Xpipewait(void){ |
| char status[NSTATUS+1]; |
| if(runq->pid==-1) |
| setstatus(concstatus(runq->status, getstatus())); |
| else{ |
| strncpy(status, getstatus(), NSTATUS); |
| status[NSTATUS]='\0'; |
| Waitfor(runq->pid, 1); |
| runq->pid=-1; |
| setstatus(concstatus(getstatus(), status)); |
| } |
| } |
| void Xrdcmds(void){ |
| struct thread *p=runq; |
| word *prompt; |
| flush(err); |
| nerror=0; |
| if(flag['s'] && !truestatus()) |
| pfmt(err, "status=%v\n", vlook("status")->val); |
| if(runq->iflag){ |
| prompt=vlook("prompt")->val; |
| if(prompt) |
| promptstr=prompt->word; |
| else |
| promptstr="% "; |
| } |
| Noerror(); |
| if(yyparse()){ |
| if(!p->iflag || p->eof && !Eintr()){ |
| if(p->cmdfile) efree(p->cmdfile); |
| closeio(p->cmdfd); |
| Xreturn(); /* should this be omitted? */ |
| } |
| else{ |
| if(Eintr()){ |
| pchr(err, '\n'); |
| p->eof=0; |
| } |
| --p->pc; /* go back for next command */ |
| } |
| } |
| else{ |
| ntrap = 0; /* avoid double-interrupts during blocked writes */ |
| --p->pc; /* re-execute Xrdcmds after codebuf runs */ |
| start(codebuf, 1, runq->local); |
| } |
| freenodes(); |
| } |
| void Xerror(char *s) |
| { |
| if(strcmp(argv0, "rc")==0 || strcmp(argv0, "/bin/rc")==0) |
| pfmt(err, "rc: %s: %r\n", s); |
| else |
| pfmt(err, "rc (%s): %s: %r\n", argv0, s); |
| flush(err); |
| while(!runq->iflag) Xreturn(); |
| } |
| void Xerror1(char *s) |
| { |
| if(strcmp(argv0, "rc")==0 || strcmp(argv0, "/bin/rc")==0) |
| pfmt(err, "rc: %s\n", s); |
| else |
| pfmt(err, "rc (%s): %s\n", argv0, s); |
| flush(err); |
| while(!runq->iflag) Xreturn(); |
| } |
| void Xbackq(void){ |
| char wd[8193]; |
| int c; |
| char *s, *ewd=&wd[8192], *stop; |
| struct io *f; |
| var *ifs=vlook("ifs"); |
| word *v, *nextv; |
| int pfd[2]; |
| int pid; |
| stop=ifs->val?ifs->val->word:""; |
| if(pipe(pfd)<0){ |
| Xerror("can't make pipe"); |
| return; |
| } |
| switch(pid=fork()){ |
| case -1: Xerror("try again"); |
| close(pfd[PRD]); |
| close(pfd[PWR]); |
| return; |
| case 0: |
| close(pfd[PRD]); |
| start(runq->code, runq->pc+1, runq->local); |
| pushredir(ROPEN, pfd[PWR], 1); |
| return; |
| default: |
| close(pfd[PWR]); |
| f=openfd(pfd[PRD]); |
| s=wd; |
| v=0; |
| while((c=rchr(f))!=EOF){ |
| if(strchr(stop, c) || s==ewd){ |
| if(s!=wd){ |
| *s='\0'; |
| v=newword(wd, v); |
| s=wd; |
| } |
| } |
| else *s++=c; |
| } |
| if(s!=wd){ |
| *s='\0'; |
| v=newword(wd, v); |
| } |
| closeio(f); |
| Waitfor(pid, 0); |
| /* v points to reversed arglist -- reverse it onto argv */ |
| while(v){ |
| nextv=v->next; |
| v->next=runq->argv->words; |
| runq->argv->words=v; |
| v=nextv; |
| } |
| runq->pc=runq->code[runq->pc].i; |
| return; |
| } |
| } |
| /* |
| * Who should wait for the exit from the fork? |
| */ |
| void Xpipefd(void){ |
| struct thread *p=runq; |
| int pc=p->pc; |
| char name[40]; |
| int pfd[2]; |
| int sidefd, mainfd; |
| if(pipe(pfd)<0){ |
| Xerror("can't get pipe"); |
| return; |
| } |
| if(p->code[pc].i==READ){ |
| sidefd=pfd[PWR]; |
| mainfd=pfd[PRD]; |
| } |
| else{ |
| sidefd=pfd[PRD]; |
| mainfd=pfd[PWR]; |
| } |
| switch(fork()){ |
| case -1: |
| Xerror("try again"); |
| break; |
| case 0: |
| start(p->code, pc+2, runq->local); |
| close(mainfd); |
| pushredir(ROPEN, sidefd, p->code[pc].i==READ?1:0); |
| runq->ret=0; |
| break; |
| default: |
| close(sidefd); |
| pushredir(ROPEN, mainfd, mainfd); /* isn't this a noop? */ |
| strcpy(name, Fdprefix); |
| itoa(name+strlen(name), mainfd); |
| pushword(name); |
| p->pc=p->code[pc+1].i; |
| break; |
| } |
| } |
| void Xsubshell(void){ |
| int pid; |
| switch(pid=fork()){ |
| case -1: |
| Xerror("try again"); |
| break; |
| case 0: |
| start(runq->code, runq->pc+1, runq->local); |
| runq->ret=0; |
| break; |
| default: |
| Waitfor(pid, 1); |
| runq->pc=runq->code[runq->pc].i; |
| break; |
| } |
| } |
| void setstatus(char *s) |
| { |
| setvar("status", newword(s, (word *)0)); |
| } |
| char *getstatus(void){ |
| var *status=vlook("status"); |
| return status->val?status->val->word:""; |
| } |
| int truestatus(void){ |
| char *s; |
| for(s=getstatus();*s;s++) |
| if(*s!='|' && *s!='0') return 0; |
| return 1; |
| } |
| void Xdelhere(void){ |
| Unlink(runq->code[runq->pc++].s); |
| } |
| void Xfor(void){ |
| if(runq->argv->words==0){ |
| poplist(); |
| runq->pc=runq->code[runq->pc].i; |
| } |
| else{ |
| freelist(runq->local->val); |
| runq->local->val=runq->argv->words; |
| runq->local->changed=1; |
| runq->argv->words=runq->argv->words->next; |
| runq->local->val->next=0; |
| runq->pc++; |
| } |
| } |
| void Xglob(void){ |
| globlist(); |
| } |