diff options
author | rsc <devnull@localhost> | 2003-11-23 18:04:08 +0000 |
---|---|---|
committer | rsc <devnull@localhost> | 2003-11-23 18:04:08 +0000 |
commit | f08fdedcee12c06e3ce9ac9bec363915978e8289 (patch) | |
tree | d67a27473be1e8f98d3694028104d9ddf915345b /src/cmd/rc/simple.c | |
parent | 5993a8f2756bc455101a8c9ce95347d5050e7883 (diff) | |
download | plan9port-f08fdedcee12c06e3ce9ac9bec363915978e8289.tar.gz plan9port-f08fdedcee12c06e3ce9ac9bec363915978e8289.tar.bz2 plan9port-f08fdedcee12c06e3ce9ac9bec363915978e8289.zip |
Plan 9's rc.
not a clear win over byron's,
but at least it has the right syntax.
Diffstat (limited to 'src/cmd/rc/simple.c')
-rw-r--r-- | src/cmd/rc/simple.c | 443 |
1 files changed, 443 insertions, 0 deletions
diff --git a/src/cmd/rc/simple.c b/src/cmd/rc/simple.c new file mode 100644 index 00000000..c85c9098 --- /dev/null +++ b/src/cmd/rc/simple.c @@ -0,0 +1,443 @@ +/* + * Maybe `simple' is a misnomer. + */ +#include "rc.h" +#include "getflags.h" +#include "exec.h" +#include "io.h" +#include "fns.h" +/* + * Search through the following code to see if we're just going to exit. + */ +int +exitnext(void){ + union code *c=&runq->code[runq->pc]; + while(c->f==Xpopredir) c++; + return c->f==Xexit; +} +void Xsimple(void){ + word *a; + thread *p=runq; + var *v; + struct builtin *bp; + int pid, n; + char buf[ERRMAX]; + globlist(); + a=runq->argv->words; + if(a==0){ + Xerror1("empty argument list"); + return; + } + if(flag['x']) + pfmt(err, "%v\n", p->argv->words); /* wrong, should do redirs */ + v=gvlook(a->word); + if(v->fn) + execfunc(v); + else{ + if(strcmp(a->word, "builtin")==0){ + if(count(a)==1){ + pfmt(err, "builtin: empty argument list\n"); + setstatus("empty arg list"); + poplist(); + return; + } + a=a->next; + popword(); + } + for(bp=Builtin;bp->name;bp++) + if(strcmp(a->word, bp->name)==0){ + (*bp->fnc)(); + return; + } + if(exitnext()){ + /* fork and wait is redundant */ + pushword("exec"); + execexec(); + Xexit(); + } + else{ + flush(err); + Updenv(); /* necessary so changes don't go out again */ + switch(pid=fork()){ + case -1: + Xerror("try again"); + return; + case 0: + pushword("exec"); + execexec(); + strcpy(buf, "can't exec: "); + n = strlen(buf); + errstr(buf+n, ERRMAX-n); + Exit(buf); + default: + poplist(); + /* interrupts don't get us out */ + while(Waitfor(pid, 1) < 0) + ; + } + } + } +} +struct word nullpath={ "", 0}; +void doredir(redir *rp) +{ + if(rp){ + doredir(rp->next); + switch(rp->type){ + case ROPEN: + if(rp->from!=rp->to){ + Dup(rp->from, rp->to); + close(rp->from); + } + break; + case RDUP: Dup(rp->from, rp->to); break; + case RCLOSE: close(rp->from); break; + } + } +} +word *searchpath(char *w){ + word *path; + if(strncmp(w, "/", 1)==0 + || strncmp(w, "#", 1)==0 + || strncmp(w, "./", 2)==0 + || strncmp(w, "../", 3)==0 + || (path=vlook("path")->val)==0) + path=&nullpath; + return path; +} +void execexec(void){ + popword(); /* "exec" */ + if(runq->argv->words==0){ + Xerror1("empty argument list"); + return; + } + doredir(runq->redir); + Execute(runq->argv->words, searchpath(runq->argv->words->word)); + poplist(); +} +void execfunc(var *func) +{ + word *starval; + popword(); + starval=runq->argv->words; + runq->argv->words=0; + poplist(); + start(func->fn, func->pc, (struct var *)0); + runq->local=newvar(strdup("*"), runq->local); + runq->local->val=starval; + runq->local->changed=1; +} +int dochdir(char *word){ + /* report to /dev/wdir if it exists and we're interactive */ + static int wdirfd = -2; + if(chdir(word)<0) return -1; + if(flag['i']!=0){ + if(wdirfd==-2) /* try only once */ + wdirfd = open("/dev/wdir", OWRITE|OCEXEC); + if(wdirfd>=0) + write(wdirfd, word, strlen(word)); + } + return 1; +} +void execcd(void){ + word *a=runq->argv->words; + word *cdpath; + char dir[512]; + setstatus("can't cd"); + cdpath=vlook("cdpath")->val; + switch(count(a)){ + default: + pfmt(err, "Usage: cd [directory]\n"); + break; + case 2: + if(a->next->word[0]=='/' || cdpath==0) cdpath=&nullpath; + for(;cdpath;cdpath=cdpath->next){ + strcpy(dir, cdpath->word); + if(dir[0]) strcat(dir, "/"); + strcat(dir, a->next->word); + if(dochdir(dir)>=0){ + if(strlen(cdpath->word) + && strcmp(cdpath->word, ".")!=0) + pfmt(err, "%s\n", dir); + setstatus(""); + break; + } + } + if(cdpath==0) pfmt(err, "Can't cd %s: %r\n", a->next->word); + break; + case 1: + a=vlook("home")->val; + if(count(a)>=1){ + if(dochdir(a->word)>=0) + setstatus(""); + else + pfmt(err, "Can't cd %s: %r\n", a->word); + } + else + pfmt(err, "Can't cd -- $home empty\n"); + break; + } + poplist(); +} +void execexit(void){ + switch(count(runq->argv->words)){ + default: pfmt(err, "Usage: exit [status]\nExiting anyway\n"); + case 2: setstatus(runq->argv->words->next->word); + case 1: Xexit(); + } +} +void execshift(void){ + int n; + word *a; + var *star; + switch(count(runq->argv->words)){ + default: + pfmt(err, "Usage: shift [n]\n"); + setstatus("shift usage"); + poplist(); + return; + case 2: n=atoi(runq->argv->words->next->word); break; + case 1: n=1; break; + } + star=vlook("*"); + for(;n && star->val;--n){ + a=star->val->next; + efree(star->val->word); + efree((char *)star->val); + star->val=a; + star->changed=1; + } + setstatus(""); + poplist(); +} +int octal(char *s) +{ + int n=0; + while(*s==' ' || *s=='\t' || *s=='\n') s++; + while('0'<=*s && *s<='7') n=n*8+*s++-'0'; + return n; +} +int mapfd(int fd) +{ + redir *rp; + for(rp=runq->redir;rp;rp=rp->next){ + switch(rp->type){ + case RCLOSE: + if(rp->from==fd) fd=-1; + break; + case RDUP: + case ROPEN: + if(rp->to==fd) fd=rp->from; + break; + } + } + return fd; +} +union code rdcmds[4]; +void execcmds(io *f) +{ + static int first=1; + if(first){ + rdcmds[0].i=1; + rdcmds[1].f=Xrdcmds; + rdcmds[2].f=Xreturn; + first=0; + } + start(rdcmds, 1, runq->local); + runq->cmdfd=f; + runq->iflast=0; +} +void execeval(void){ + char *cmdline, *s, *t; + int len=0; + word *ap; + if(count(runq->argv->words)<=1){ + Xerror1("Usage: eval cmd ..."); + return; + } + eflagok=1; + for(ap=runq->argv->words->next;ap;ap=ap->next) + len+=1+strlen(ap->word); + cmdline=emalloc(len); + s=cmdline; + for(ap=runq->argv->words->next;ap;ap=ap->next){ + for(t=ap->word;*t;) *s++=*t++; + *s++=' '; + } + s[-1]='\n'; + poplist(); + execcmds(opencore(cmdline, len)); + efree(cmdline); +} +union code dotcmds[14]; +void execdot(void){ + int iflag=0; + int fd; + list *av; + thread *p=runq; + char *zero; + static int first=1; + char file[512]; + word *path; + if(first){ + dotcmds[0].i=1; + dotcmds[1].f=Xmark; + dotcmds[2].f=Xword; + dotcmds[3].s="0"; + dotcmds[4].f=Xlocal; + dotcmds[5].f=Xmark; + dotcmds[6].f=Xword; + dotcmds[7].s="*"; + dotcmds[8].f=Xlocal; + dotcmds[9].f=Xrdcmds; + dotcmds[10].f=Xunlocal; + dotcmds[11].f=Xunlocal; + dotcmds[12].f=Xreturn; + first=0; + } + else + eflagok=1; + popword(); + if(p->argv->words && strcmp(p->argv->words->word, "-i")==0){ + iflag=1; + popword(); + } + /* get input file */ + if(p->argv->words==0){ + Xerror1("Usage: . [-i] file [arg ...]"); + return; + } + zero=strdup(p->argv->words->word); + popword(); + fd=-1; + for(path=searchpath(zero);path;path=path->next){ + strcpy(file, path->word); + if(file[0]) strcat(file, "/"); + strcat(file, zero); + if((fd=open(file, 0))>=0) break; + if(strcmp(file, "/dev/stdin")==0){ /* for sun & ucb */ + fd=Dup1(0); + if(fd>=0) break; + } + } + if(fd<0){ + pfmt(err, "%s: ", zero); + setstatus("can't open"); + Xerror(".: can't open"); + return; + } + /* set up for a new command loop */ + start(dotcmds, 1, (struct var *)0); + pushredir(RCLOSE, fd, 0); + runq->cmdfile=zero; + runq->cmdfd=openfd(fd); + runq->iflag=iflag; + runq->iflast=0; + /* push $* value */ + pushlist(); + runq->argv->words=p->argv->words; + /* free caller's copy of $* */ + av=p->argv; + p->argv=av->next; + efree((char *)av); + /* push $0 value */ + pushlist(); + pushword(zero); + ndot++; +} +void execflag(void){ + char *letter, *val; + switch(count(runq->argv->words)){ + case 2: + setstatus(flag[(uchar)runq->argv->words->next->word[0]]?"":"flag not set"); + break; + case 3: + letter=runq->argv->words->next->word; + val=runq->argv->words->next->next->word; + if(strlen(letter)==1){ + if(strcmp(val, "+")==0){ + flag[(uchar)letter[0]]=flagset; + break; + } + if(strcmp(val, "-")==0){ + flag[(uchar)letter[0]]=0; + break; + } + } + default: + Xerror1("Usage: flag [letter] [+-]"); + return; + } + poplist(); +} +void execwhatis(void){ /* mildly wrong -- should fork before writing */ + word *a, *b, *path; + var *v; + struct builtin *bp; + char file[512]; + struct io out[1]; + int found, sep; + a=runq->argv->words->next; + if(a==0){ + Xerror1("Usage: whatis name ..."); + return; + } + setstatus(""); + out->fd=mapfd(1); + out->bufp=out->buf; + out->ebuf=&out->buf[NBUF]; + out->strp=0; + for(;a;a=a->next){ + v=vlook(a->word); + if(v->val){ + pfmt(out, "%s=", a->word); + if(v->val->next==0) + pfmt(out, "%q\n", v->val->word); + else{ + sep='('; + for(b=v->val;b && b->word;b=b->next){ + pfmt(out, "%c%q", sep, b->word); + sep=' '; + } + pfmt(out, ")\n"); + } + found=1; + } + else + found=0; + v=gvlook(a->word); + if(v->fn) pfmt(out, "fn %s %s\n", v->name, v->fn[v->pc-1].s); + else{ + for(bp=Builtin;bp->name;bp++) + if(strcmp(a->word, bp->name)==0){ + pfmt(out, "builtin %s\n", a->word); + break; + } + if(!bp->name){ + for(path=searchpath(a->word);path;path=path->next){ + strcpy(file, path->word); + if(file[0]) strcat(file, "/"); + strcat(file, a->word); + if(Executable(file)){ + pfmt(out, "%s\n", file); + break; + } + } + if(!path && !found){ + pfmt(err, "%s: not found\n", a->word); + setstatus("not found"); + } + } + } + } + poplist(); + flush(err); +} +void execwait(void){ + switch(count(runq->argv->words)){ + default: Xerror1("Usage: wait [pid]"); return; + case 2: Waitfor(atoi(runq->argv->words->next->word), 0); break; + case 1: Waitfor(-1, 0); break; + } + poplist(); +} |