diff --git a/sys/man/1/rc b/sys/man/1/rc index 252fd8a60..f994d5b32 100644 --- a/sys/man/1/rc +++ b/sys/man/1/rc @@ -615,7 +615,7 @@ usually because their execution changes or depends on internal state. .PD 0 .HP -.BI . " file ..." +.BI . " [-biq] file ..." .br Execute commands from .IR file . @@ -625,6 +625,20 @@ is set for the duration to the remainder of the argument list following .I File is searched for using .BR $path . +The flags +.B -b +and +.B -i +can be set for the new commands +(see description below). +The +.B -q +flag suppresses errors, +inhibiting the effect of +.B -e +and +.B -v +flags of the main interpreter. .HP .BI builtin " command ..." .br @@ -974,6 +988,10 @@ Print each simple command before executing it. .B -r Print debugging information (internal form of commands as they are executed). +.TP +.B -b +Compile the command file as a whole before executing. +This allows syntax checking of the whole file. .PD .SH FILES .TF $home/lib/profile @@ -1004,6 +1022,4 @@ to check the value of changes .BR $status . .PP -Functions containing here documents don't work. -.PP Free carets don't get inserted next to keywords. diff --git a/sys/src/cmd/rc/code.c b/sys/src/cmd/rc/code.c index 8e0142997..67c2eb925 100644 --- a/sys/src/cmd/rc/code.c +++ b/sys/src/cmd/rc/code.c @@ -7,13 +7,12 @@ #define c1 t->child[1] #define c2 t->child[2] code *codebuf; -int codep, ncode; +int codep, ncode, codeline; #define emitf(x) ((codep!=ncode || morecode()), codebuf[codep].f = (x), codep++) #define emiti(x) ((codep!=ncode || morecode()), codebuf[codep].i = (x), codep++) #define emits(x) ((codep!=ncode || morecode()), codebuf[codep].s = (x), codep++) void stuffdot(int); -char *fnstr(tree*); void outcode(tree*, int); void codeswitch(tree*, int); int iscase(tree*); @@ -23,7 +22,7 @@ void codefree(code*); int morecode(void) { - ncode+=100; + ncode+=ncode; codebuf = (code *)erealloc((char *)codebuf, ncode*sizeof codebuf[0]); return 0; } @@ -42,53 +41,66 @@ compile(tree *t) ncode = 100; codebuf = emalloc(ncode*sizeof codebuf[0]); codep = 0; + codeline = 0; /* force source */ emiti(0); /* reference count */ - outcode(t, flag['e']?1:0); + emits(estrdup(lex->file)); /* source file name */ + outcode(t, !lex->qflag && flag['e']!=0); if(nerror){ free(codebuf); return 0; } - readhere(); emitf(Xreturn); emitf(0); return 1; } +/* + * called on a tree where we expect eigther + * a pattern or a string instead of a glob to + * remove the GLOB chars from the strings + * or set glob to -1 for pattern so not Xglob + * is inserted when compiling the tree. + */ void -cleanhere(char *f) +noglobs(tree *t, int pattern) { - emitf(Xdelhere); - emits(estrdup(f)); -} - -char* -fnstr(tree *t) -{ - io *f = openstr(); - void *v; - - pfmt(f, "%t", t); - v = f->strp; - f->strp = 0; - closeio(f); - return v; +Again: + if(t==0) + return; + if(t->type==WORD && t->glob){ + if(pattern) + t->glob=-1; + else{ + deglob(t->str); + t->glob=0; + } + } + if(t->type==WORDS || t->type=='^'){ + t->glob=0; + noglobs(c1, pattern); + t = c0; + goto Again; + } } void outcode(tree *t, int eflag) { - static int line; + void (*f)(void); int p, q; tree *tt; - char *f; if(t==0) return; if(t->type!=NOT && t->type!=';') - runq->iflast = 0; - if(t->line != line){ - line = t->line; - emitf(Xsrcline); - emiti(line); + lex->iflast = 0; + if(t->line != codeline){ + codeline = t->line; + if(codebuf && codep >= 2 && codebuf[codep-2].f == Xsrcline) + codebuf[codep-1].i = codeline; + else { + emitf(Xsrcline); + emiti(codeline); + } } switch(t->type){ default: @@ -96,26 +108,51 @@ outcode(tree *t, int eflag) break; case '$': emitf(Xmark); + noglobs(c0, 0); outcode(c0, eflag); emitf(Xdol); break; case '"': emitf(Xmark); emitf(Xmark); + noglobs(c0, 0); outcode(c0, eflag); emitf(Xdol); emitf(Xqw); + emitf(Xpush); break; case SUB: emitf(Xmark); + noglobs(c0, 0); outcode(c0, eflag); emitf(Xmark); + noglobs(c1, 0); outcode(c1, eflag); emitf(Xsub); break; case '&': emitf(Xasync); p = emiti(0); + + /* undocumented? */ + emitf(Xmark); + emitf(Xword); + emits(estrdup("/dev/null")); + emitf(Xread); + emiti(0); + + /* insert rfork s for plan9 */ + f = builtinfunc("rfork"); + if(f){ + emitf(Xmark); + emitf(Xword); + emits(estrdup("s")); + emitf(Xword); + emits(estrdup("rfork")); + emitf(f); + } + + codeline = 0; /* force source */ outcode(c0, eflag); emitf(Xexit); stuffdot(p); @@ -134,16 +171,18 @@ outcode(tree *t, int eflag) case '`': emitf(Xmark); if(c0){ + noglobs(c0, 0); outcode(c0, 0); - emitf(Xglob); } else { emitf(Xmark); emitf(Xword); emits(estrdup("ifs")); emitf(Xdol); } + emitf(Xqw); emitf(Xbackq); p = emiti(0); + codeline = 0; /* force source */ outcode(c1, 0); emitf(Xexit); stuffdot(p); @@ -169,24 +208,20 @@ outcode(tree *t, int eflag) break; case COUNT: emitf(Xmark); + noglobs(c0, 0); outcode(c0, eflag); emitf(Xcount); break; case FN: emitf(Xmark); + noglobs(c0, 0); outcode(c0, eflag); if(c1){ emitf(Xfn); p = emiti(0); emits(fnstr(c1)); - if((f = curfile(runq)) != nil){ - emitf(Xsrcfile); - emits(estrdup(f)); - } - emitf(Xsrcline); - emiti(runq->lexline); + codeline = 0; /* force source */ outcode(c1, eflag); - emitf(Xunlocal); /* get rid of $* */ emitf(Xreturn); stuffdot(p); } @@ -202,7 +237,7 @@ outcode(tree *t, int eflag) stuffdot(p); break; case NOT: - if(!runq->iflast) + if(!lex->iflast) yyerror("`if not' does not follow `if(...)'"); emitf(Xifnot); p = emiti(0); @@ -229,6 +264,7 @@ outcode(tree *t, int eflag) case SUBSHELL: emitf(Xsubshell); p = emiti(0); + codeline = 0; /* force source */ outcode(c0, eflag); emitf(Xexit); stuffdot(p); @@ -240,9 +276,11 @@ outcode(tree *t, int eflag) break; case TWIDDLE: emitf(Xmark); + noglobs(c1, 1); outcode(c1, eflag); emitf(Xmark); outcode(c0, eflag); + emitf(Xqw); emitf(Xmatch); if(eflag) emitf(Xeflag); @@ -267,7 +305,6 @@ outcode(tree *t, int eflag) emitf(Xmark); if(c1){ outcode(c1, eflag); - emitf(Xglob); } else{ emitf(Xmark); @@ -277,6 +314,7 @@ outcode(tree *t, int eflag) } emitf(Xmark); /* dummy value for Xlocal */ emitf(Xmark); + noglobs(c0, 0); outcode(c0, eflag); emitf(Xlocal); p = emitf(Xfor); @@ -288,19 +326,9 @@ outcode(tree *t, int eflag) emitf(Xunlocal); break; case WORD: - if(t->quoted){ - emitf(Xword); - emits(estrdup(t->str)); - } else { - if((q = Globsize(t->str)) > 0){ - emitf(Xglobs); - emits(estrdup(t->str)); - emiti(q); - } else { - emitf(Xword); - emits(deglob(estrdup(t->str))); - } - } + emitf(Xword); + emits(t->str); + t->str=0; /* passed ownership */ break; case DUP: if(t->rtype==DUPFD){ @@ -319,14 +347,20 @@ outcode(tree *t, int eflag) emitf(Xpipefd); emiti(t->rtype); p = emiti(0); + codeline = 0; /* force source */ outcode(c0, eflag); emitf(Xexit); stuffdot(p); break; case REDIR: emitf(Xmark); + if(t->rtype==HERE){ + /* replace end marker with mktmep() pattern */ + free(c0->str); + c0->str=estrdup("/tmp/here.XXXXXXXXXXX"); + c0->glob=0; + } outcode(c0, eflag); - emitf(Xglob); switch(t->rtype){ case APPEND: emitf(Xappend); @@ -335,12 +369,16 @@ outcode(tree *t, int eflag) emitf(Xwrite); break; case READ: - case HERE: emitf(Xread); break; case RDWR: emitf(Xrdwr); break; + case HERE: + emitf(Xhere); + emits(t->str); + t->str=0; /* passed ownership */ + break; } emiti(t->fd0); outcode(c1, eflag); @@ -354,6 +392,7 @@ outcode(tree *t, int eflag) emitf(Xmark); outcode(c1, eflag); emitf(Xmark); + noglobs(c0, 0); outcode(c0, eflag); emitf(Xlocal); /* push var for cmd */ } @@ -366,6 +405,7 @@ outcode(tree *t, int eflag) emitf(Xmark); outcode(c1, eflag); emitf(Xmark); + noglobs(c0, 0); outcode(c0, eflag); emitf(Xassign); /* set var permanently */ } @@ -378,18 +418,23 @@ outcode(tree *t, int eflag) emiti(t->fd1); p = emiti(0); q = emiti(0); + codeline = 0; /* force source */ outcode(c0, eflag); emitf(Xexit); stuffdot(p); + codeline = 0; /* force source */ outcode(c1, eflag); emitf(Xreturn); stuffdot(q); emitf(Xpipewait); break; } + if(t->glob > 0) + emitf(Xglob); if(t->type!=NOT && t->type!=';') - runq->iflast = t->type==IF; - else if(c0) runq->iflast = c0->type==IF; + lex->iflast = t->type==IF; + else if(c0) + lex->iflast = c0->type==IF; } /* * switch code looks like this: @@ -427,6 +472,7 @@ codeswitch(tree *t, int eflag) } emitf(Xmark); outcode(c0, eflag); + emitf(Xqw); emitf(Xjump); nextcase = emiti(0); out = emitf(Xjump); @@ -436,7 +482,10 @@ codeswitch(tree *t, int eflag) while(t->type==';'){ tt = c1; emitf(Xmark); - for(t = c0->child[0];t->type==ARGLIST;t = c0) outcode(c1, eflag); + for(t = c0->child[0];t->type==ARGLIST;t = c0) { + noglobs(c1, 1); + outcode(c1, eflag); + } emitf(Xcase); nextcase = emiti(0); t = tt; @@ -481,7 +530,7 @@ codefree(code *cp) code *p; if(--cp[0].i!=0) return; - for(p = cp+1;p->f;p++){ + for(p = cp+2;p->f;p++){ if(p->f==Xappend || p->f==Xclose || p->f==Xread || p->f==Xwrite || p->f==Xrdwr || p->f==Xasync || p->f==Xbackq || p->f==Xcase || p->f==Xfalse @@ -490,12 +539,13 @@ codefree(code *cp) || p->f==Xsubshell || p->f==Xtrue) p++; else if(p->f==Xdup || p->f==Xpipefd) p+=2; else if(p->f==Xpipe) p+=4; - else if(p->f==Xglobs || p->f==Xsrcfile) free(p[1].s), p+=2; - else if(p->f==Xword || p->f==Xdelhere) free((++p)->s); + else if(p->f==Xhere) free(p[1].s), p+=2; + else if(p->f==Xword) free((++p)->s); else if(p->f==Xfn){ free(p[2].s); p+=2; } } + free(cp[1].s); free(cp); } diff --git a/sys/src/cmd/rc/exec.c b/sys/src/cmd/rc/exec.c index 7cada279d..f200f3065 100644 --- a/sys/src/cmd/rc/exec.c +++ b/sys/src/cmd/rc/exec.c @@ -3,64 +3,96 @@ #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) +start(code *c, int pc, var *local, redir *redir) { - struct thread *p = new(struct thread); - + thread *p = new(thread); p->code = codecopy(c); - p->line = runq?runq->line:0; + p->line = 0; p->pc = pc; p->argv = 0; - p->redir = p->startredir = runq?runq->redir:nil; + p->redir = p->startredir = redir; + p->lex = 0; p->local = local; - p->cmdfile = nil; - p->cmdfd = 0; - p->eof = 0; p->iflag = 0; - p->lineno = runq ? runq->lineno : 1; p->ret = runq; runq = p; } -word* -Newword(char *wd, word *next) +void +startfunc(var *func, word *starval, var *local, redir *redir) { - word *p = new(word); - p->word = wd; + 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); +} + +word* +Newword(char *s, word *next) +{ + word *p=new(word); + p->word = s; p->next = next; - p->glob = 0; return p; } word* -Pushword(char *wd) +newword(char *s, word *next) { - word *w; + 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); - w = Newword(wd, runq->argv->words); - runq->argv->words = w; - return w; -} - -word* -newword(char *wd, word *next) -{ - return Newword(estrdup(wd), next); + p = Newword(s, runq->argv->words); + runq->argv->words = p; + return p; } word* -pushword(char *wd) +pushword(char *s) { - return Pushword(estrdup(wd)); + return Pushword(estrdup(s)); +} +char* +Freeword(word *p) +{ + char *s = p->word; + free(p); + return s; } - void -popword(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) @@ -69,40 +101,38 @@ popword(void) if(p==0) panic("popword but no word!", 0); runq->argv->words = p->next; - free(p->word); - free(p); + return Freeword(p); } - void -freelist(word *w) +popword(void) { - word *nw; - while(w){ - nw = w->next; - free(w->word); - free(w); - w = nw; - } + free(Popword()); } void pushlist(void) { list *p = new(list); - p->next = runq->argv; p->words = 0; + p->next = runq->argv; runq->argv = p; } - -void -poplist(void) +word* +Poplist(void) { + word *w; list *p = runq->argv; if(p==0) panic("poplist but no argv", 0); - freelist(p->words); + w = p->words; runq->argv = p->next; free(p); + return w; +} +void +poplist(void) +{ + freewords(Poplist()); } int @@ -116,7 +146,7 @@ count(word *w) void pushredir(int type, int from, int to) { - redir * rp = new(redir); + redir *rp = new(redir); rp->type = type; rp->from = from; rp->to = to; @@ -124,6 +154,43 @@ pushredir(int type, int from, int to) 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->from == fd){ + 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) { @@ -139,33 +206,25 @@ shuffleredir(void) *rr = rp; } -var* -newvar(char *name, var *next) -{ - var *v = new(var); - v->name = estrdup(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 $*) + * fabricate bootstrap code and start it (*=(argv);. -bq /usr/lib/rcmain $*) * start interpreting code */ +char *argv0="rc"; void main(int argc, char *argv[]) { - code bootstrap[17]; - char num[12], *rcmain; + code bootstrap[20]; + char num[12]; + char *rcmain=Rcmain; + int i; - argc = getflags(argc, argv, "SsrdiIlxepvVc:1m:1[command]", 1); + argv0 = argv[0]; + argc = getflags(argc, argv, "SsrdiIlxebpvVc:1m:1[command]", 1); if(argc==-1) usage("[file [arg ...]]"); if(argv[0][0]=='-') @@ -173,8 +232,8 @@ main(int argc, char *argv[]) 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); + if(flag['m']) rcmain = flag['m'][0]; + err = openiofd(2); kinit(); Trapinit(); Vinit(); @@ -183,38 +242,36 @@ main(int argc, char *argv[]) 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); - runq->cmdfile = strdup("rc"); - runq->lexline = 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(); - argv0 = estrdup(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)(); + (*runq->code[runq->pc++].f)(); if(ntrap) dotrap(); } @@ -236,15 +293,13 @@ main(int argc, char *argv[]) * 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 - * Xqw(list) quote list, push result * Xdup[i j] dup file descriptor * Xexit rc exits with status * Xfalse{...} execute {} if false - * Xfn(name){... Xreturn} define function + * Xfn(name){... Xreturn} define function * Xfor(var, list){... Xreturn} for loop - * Xglobs[string globsize] push globbing string + * Xglob(word) glob word inplace * Xjump[addr] goto * Xlocal(name, val) create local variable, assign value * Xmark mark stack @@ -254,26 +309,26 @@ main(int argc, char *argv[]) * 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 - * Xsettraps(names){... Xreturn} define trap functions - * Xshowtraps print trap list - * Xsimple(args) run command and wait * 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 - * Xsrcline[line] set current line number - * Xsrcfile[file] set current file name */ void Xappend(void) { char *file; - int f; + int fd; + switch(count(runq->argv->words)){ default: Xerror1(">> requires singleton"); @@ -285,14 +340,12 @@ Xappend(void) break; } file = runq->argv->words->word; - if((f = open(file, 1))<0 && (f = Creat(file))<0){ - pfmt(err, "%s: ", file); + if((fd = Open(file, 1))<0 && (fd = Creat(file))<0){ Xerror("can't open"); return; } - Seek(f, 0L, 2); - pushredir(ROPEN, f, runq->code[runq->pc].i); - runq->pc++; + Seek(fd, 0L, 2); + pushredir(ROPEN, fd, runq->code[runq->pc++].i); poplist(); } @@ -311,8 +364,7 @@ Xbang(void) void Xclose(void) { - pushredir(RCLOSE, runq->code[runq->pc].i, 0); - runq->pc++; + pushredir(RCLOSE, runq->code[runq->pc++].i, 0); } void @@ -325,26 +377,21 @@ Xdup(void) void Xeflag(void) { - if(eflagok && !truestatus()) Xexit(); + if(!truestatus()) Xexit(); } void Xexit(void) { - struct var *trapreq; - struct word *starval; static int beenhere = 0; + if(getpid()==mypid && !beenhere){ - trapreq = vlook("sigexit"); + var *trapreq = vlook("sigexit"); + word *starval = vlook("*")->val; if(trapreq->fn){ beenhere = 1; --runq->pc; - starval = vlook("*")->val; - start(trapreq->fn, trapreq->pc, (struct var *)0); - runq->local = newvar("*", runq->local); - runq->local->val = copywords(starval, (struct word *)0); - runq->local->changed = 1; - runq->redir = runq->startredir = 0; + startfunc(trapreq, copywords(starval, (word*)0), (var*)0, (redir*)0); return; } } @@ -387,87 +434,115 @@ Xpopm(void) } void -Xread(void) +Xpush(void) +{ + word *t, *h = Poplist(); + for(t = h; t->next; t = t->next) + ; + t->next = runq->argv->words; + runq->argv->words = h; +} + +void +Xhere(void) { char *file; - int f; + int fd; + io *io; + switch(count(runq->argv->words)){ default: - Xerror1("< requires singleton\n"); + Xerror1("<< requires singleton"); return; case 0: - Xerror1("< requires file\n"); + Xerror1("<< requires file"); return; case 1: break; } - file = runq->argv->words->word; - if((f = open(file, 0))<0){ - pfmt(err, "%s: ", file); + file = mktemp(runq->argv->words->word); + if((fd = Creat(file))<0){ Xerror("can't open"); return; } - pushredir(ROPEN, f, runq->code[runq->pc].i); - runq->pc++; + io = openiofd(fd); + psubst(io, (uchar*)runq->code[runq->pc++].s); + flushio(io); + closeio(io); + /* open for reading and unlink */ + if((fd = Open(file, 3))<0){ + Xerror("can't open"); + return; + } + pushredir(ROPEN, fd, runq->code[runq->pc++].i); + poplist(); +} + +void +Xread(void) +{ + int fd; + + switch(count(runq->argv->words)){ + default: + Xerror1("< requires singleton"); + return; + case 0: + Xerror1("< requires file"); + return; + case 1: + break; + } + if((fd = Open(runq->argv->words->word, 0))<0){ + Xerror("can't open"); + return; + } + pushredir(ROPEN, fd, runq->code[runq->pc++].i); poplist(); } void Xrdwr(void) { - char *file; - int f; + int fd; switch(count(runq->argv->words)){ default: - Xerror1("<> requires singleton\n"); + Xerror1("<> requires singleton"); return; case 0: - Xerror1("<> requires file\n"); + Xerror1("<> requires file"); return; case 1: break; } - file = runq->argv->words->word; - if((f = open(file, ORDWR))<0){ - pfmt(err, "%s: ", file); + if((fd = Open(runq->argv->words->word, 2))<0){ Xerror("can't open"); return; } - pushredir(ROPEN, f, runq->code[runq->pc].i); - runq->pc++; + pushredir(ROPEN, fd, runq->code[runq->pc++].i); poplist(); } -void -turfredir(void) -{ - while(runq->redir!=runq->startredir) - Xpopredir(); -} - void Xpopredir(void) { - struct redir *rp = runq->redir; + redir *rp = runq->redir; + if(rp==0) - panic("turfredir null!", 0); + panic("Xpopredir null!", 0); runq->redir = rp->next; if(rp->type==ROPEN) - close(rp->from); + Close(rp->from); free(rp); } void Xreturn(void) { - struct thread *p = runq; - turfredir(); - while(p->argv) poplist(); - codefree(p->code); - free(p->cmdfile); - runq = p->ret; - free(p); + while(runq->redir!=runq->startredir) + Xpopredir(); + popthread(); if(runq==0) Exit(getstatus()); } @@ -499,72 +574,42 @@ Xword(void) pushword(runq->code[runq->pc++].s); } -void -Xglobs(void) -{ - word *w = pushword(runq->code[runq->pc++].s); - w->glob = runq->code[runq->pc++].i; -} - void Xwrite(void) { - char *file; - int f; + int fd; + switch(count(runq->argv->words)){ default: - Xerror1("> requires singleton\n"); + Xerror1("> requires singleton"); return; case 0: - Xerror1("> requires file\n"); + Xerror1("> requires file"); return; case 1: break; } - file = runq->argv->words->word; - if((f = Creat(file))<0){ - pfmt(err, "%s: ", file); + if((fd = Creat(runq->argv->words->word))<0){ Xerror("can't open"); return; } - pushredir(ROPEN, f, runq->code[runq->pc].i); - runq->pc++; + pushredir(ROPEN, fd, runq->code[runq->pc++].i); 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); + char *s; + setstatus("no match"); + s = runq->argv->words->word; for(p = runq->argv->next->words;p;p = p->next) - if(match(subject, p->word, '\0')){ + if(match(s, p->word, '\0')){ setstatus(""); break; } - free(subject); poplist(); poplist(); } @@ -575,14 +620,14 @@ Xcase(void) word *p; char *s; int ok = 0; - s = list2str(runq->argv->next->words); + + s = runq->argv->next->words->word; for(p = runq->argv->words;p;p = p->next){ if(match(s, p->word, '\0')){ ok = 1; break; } } - free(s); if(ok) runq->pc++; else @@ -590,7 +635,7 @@ Xcase(void) poplist(); } -word* +static word* conclist(word *lp, word *rp, word *tail) { word *v, *p, **end; @@ -601,8 +646,6 @@ conclist(word *lp, word *rp, word *tail) p = Newword(emalloc(ln+rn+1), (word *)0); memmove(p->word, lp->word, ln); memmove(p->word+ln, rp->word, rn+1); - if(lp->glob || rp->glob) - p->glob = Globsize(p->word); *end = p, end = &p->next; if(lp->next == 0 && rp->next == 0) break; @@ -636,41 +679,30 @@ Xconc(void) runq->argv->words = vp; } -char* -Str(word *a) -{ - char *s = a->word; - if(a->glob){ - a->glob = 0; - deglob(s); - } - return s; -} - void Xassign(void) { var *v; + if(count(runq->argv->words)!=1){ Xerror1("variable name not singleton!"); return; } - v = vlook(Str(runq->argv->words)); + v = vlook(runq->argv->words->word); poplist(); freewords(v->val); - v->val = globlist(runq->argv->words); + v->val = Poplist(); 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; @@ -683,12 +715,13 @@ Xdol(void) word *a, *star; char *s, *t; int n; + if(count(runq->argv->words)!=1){ Xerror1("variable name not singleton!"); return; } - s = Str(runq->argv->words); n = 0; + s = runq->argv->words->word; for(t = s;'0'<=*t && *t<='9';t++) n = n*10+*t-'0'; a = runq->argv->next->words; if(n==0 || *t) @@ -707,23 +740,34 @@ Xdol(void) void Xqw(void) { - char *s; - word *a; + char *s, *d; + word *a, *p; + int n; a = runq->argv->words; - if(a && a->next == 0){ - runq->argv->words = 0; - poplist(); - a->next = runq->argv->words; - runq->argv->words = a; + if(a==0){ + pushword(""); return; } - s = list2str(a); - poplist(); - Pushword(s); + if(a->next==0) + return; + n=0; + for(p=a;p;p=p->next) + n+=1+strlen(p->word); + s = emalloc(n+1); + d = s; + d += strlen(strcpy(d, a->word)); + for(p=a->next;p;p=p->next){ + *d++=' '; + d += strlen(strcpy(d, p->word)); + } + free(a->word); + freewords(a->next); + a->word = s; + a->next = 0; } -word* +static word* copynwords(word *a, word *tail, int n) { word *v, **end; @@ -739,15 +783,16 @@ copynwords(word *a, word *tail, int n) return v; } -word* +static word* subwords(word *val, int len, word *sub, word *a) { int n, m; char *s; - if(!sub) + + if(sub==0) return a; a = subwords(val, len, sub->next, a); - s = Str(sub); + s = sub->word; m = 0; n = 0; while('0'<=*s && *s<='9') @@ -775,11 +820,12 @@ Xsub(void) { word *a, *v; char *s; + if(count(runq->argv->next->words)!=1){ Xerror1("variable name not singleton!"); return; } - s = Str(runq->argv->next->words); + s = runq->argv->next->words->word; a = runq->argv->next->next->words; v = vlook(s)->val; a = subwords(v, count(v), runq->argv->words, a); @@ -792,15 +838,15 @@ void Xcount(void) { word *a; - char *s, *t; + char *s, *t, num[12]; int n; - char num[12]; + if(count(runq->argv->words)!=1){ Xerror1("variable name not singleton!"); return; } - s = Str(runq->argv->words); n = 0; + s = runq->argv->words->word; for(t = s;'0'<=*t && *t<='9';t++) n = n*10+*t-'0'; if(n==0 || *t){ a = vlook(s)->val; @@ -818,41 +864,25 @@ void Xlocal(void) { if(count(runq->argv->words)!=1){ - Xerror1("variable name must be singleton\n"); + Xerror1("variable name must be singleton"); return; } - runq->local = newvar(Str(runq->argv->words), runq->local); + runq->local = newvar(runq->argv->words->word, runq->local); poplist(); - runq->local->val = globlist(runq->argv->words); + runq->local->val = Poplist(); runq->local->changed = 1; - runq->argv->words = 0; - poplist(); } void Xunlocal(void) { - var *v = runq->local, *hid; + var *hid, *v = runq->local; if(v==0) panic("Xunlocal: no locals!", 0); runq->local = v->next; hid = vlook(v->name); hid->changed = 1; - free(v->name); - freewords(v->val); - free(v); -} - -void -freewords(word *w) -{ - word *nw; - while(w){ - free(w->word); - nw = w->next; - free(w); - w = nw; - } + freevar(v); } void @@ -860,17 +890,16 @@ Xfn(void) { var *v; word *a; - int end; - end = runq->code[runq->pc].i; - for(a = globlist(runq->argv->words);a;a = a->next){ + int pc = runq->pc; + runq->pc = runq->code[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->pc = pc+2; v->fnchanged = 1; } - runq->pc = end; poplist(); } @@ -889,7 +918,7 @@ Xdelfn(void) poplist(); } -char* +static char* concstatus(char *s, char *t) { static char v[NSTATUS+1]; @@ -918,62 +947,80 @@ Xpipewait(void) } } +static char *promptstr; + void Xrdcmds(void) { - struct thread *p = runq; - word *prompt; + thread *p = runq; - flush(err); - nerror = 0; if(flag['s'] && !truestatus()) pfmt(err, "status=%v\n", vlook("status")->val); - if(runq->iflag){ - prompt = vlook("prompt")->val; + flushio(err); + + lex = p->lex; + if(p->iflag){ + word *prompt = vlook("prompt")->val; if(prompt) promptstr = prompt->word; else promptstr="% "; } Noerror(); + nerror = 0; if(yyparse()){ - if(!p->iflag || p->eof && !Eintr()){ - closeio(p->cmdfd); - Xreturn(); - } - else{ + if(p->iflag && (!lex->eof || Eintr())){ if(Eintr()){ pchr(err, '\n'); - p->eof = 0; + lex->eof = 0; } --p->pc; /* go back for next command */ } } else{ + if(lex->eof){ + dontclose(lex->input->fd); + freelexer(lex); + p->lex = 0; + } else + --p->pc; /* re-execute Xrdcmds after codebuf runs */ ntrap = 0; /* avoid double-interrupts during blocked writes */ - --p->pc; /* re-execute Xrdcmds after codebuf runs */ - start(codebuf, 1, runq->local); + start(codebuf, 2, p->local, p->redir); } + lex = 0; freenodes(); } -char* -curfile(thread *p) +void +pprompt(void) { - for(; p != nil; p = p->ret) - if(p->cmdfile != nil) - return p->cmdfile; - return "unknown"; + word *prompt; + + if(!runq->iflag) + return; + + Prompt(promptstr); + doprompt = 0; + + prompt = vlook("prompt")->val; + if(prompt && prompt->next) + promptstr = prompt->next->word; + else + promptstr = "\t"; +} + +char* +srcfile(thread *p) +{ + return p->code[1].s; } void Xerror(char *s) { - if(strcmp(argv0, "rc")==0 || strcmp(argv0, "/bin/rc")==0) - pfmt(err, "rc:%d: %s: %r\n", runq->line, s); - else - pfmt(err, "%s:%d: %s: %r\n", curfile(runq), runq->line, s); - flush(err); + pfln(err, srcfile(runq), runq->line); + pfmt(err, ": %s: %r\n", s); + flushio(err); setstatus("error"); while(!runq->iflag) Xreturn(); } @@ -981,11 +1028,9 @@ Xerror(char *s) void Xerror1(char *s) { - if(strcmp(argv0, "rc")==0 || strcmp(argv0, "/bin/rc")==0) - pfmt(err, "rc:%d: %s\n", runq->line, s); - else - pfmt(err, "%s:%d: %s\n", curfile(runq), runq->line, s); - flush(err); + pfln(err, srcfile(runq), runq->line); + pfmt(err, ": %s\n", s); + flushio(err); setstatus("error"); while(!runq->iflag) Xreturn(); } @@ -1013,25 +1058,20 @@ truestatus(void) return 1; } -void -Xdelhere(void) -{ - Unlink(runq->code[runq->pc++].s); -} - void Xfor(void) { - if(runq->argv->words==0){ + word *a = runq->argv->words; + if(a==0){ poplist(); runq->pc = runq->code[runq->pc].i; } else{ - freelist(runq->local->val); - runq->local->val = runq->argv->words; + runq->argv->words = a->next; + a->next = 0; + freewords(runq->local->val); + runq->local->val = a; runq->local->changed = 1; - runq->argv->words = runq->argv->words->next; - runq->local->val->next = 0; runq->pc++; } } @@ -1039,7 +1079,7 @@ Xfor(void) void Xglob(void) { - globlist(runq->argv->words); + globword(runq->argv->words); } void @@ -1047,10 +1087,3 @@ Xsrcline(void) { runq->line = runq->code[runq->pc++].i; } - -void -Xsrcfile(void) -{ - free(runq->cmdfile); - runq->cmdfile = strdup(runq->code[runq->pc++].s); -} diff --git a/sys/src/cmd/rc/exec.h b/sys/src/cmd/rc/exec.h index 1d07b58d5..d75c7f1cd 100644 --- a/sys/src/cmd/rc/exec.h +++ b/sys/src/cmd/rc/exec.h @@ -4,15 +4,16 @@ extern void Xappend(void), Xasync(void), Xbackq(void), Xbang(void), Xclose(void); extern void Xconc(void), Xcount(void), Xdelfn(void), Xdol(void), Xqw(void), Xdup(void); extern void Xexit(void), Xfalse(void), Xfn(void), Xfor(void), Xglob(void); -extern void Xjump(void), Xmark(void), Xmatch(void), Xpipe(void), Xread(void); -extern void Xrdwr(void), Xsrcline(void), Xsrcfile(void); -extern void Xrdfn(void), Xunredir(void), Xstar(void), Xreturn(void), Xsubshell(void); -extern void Xtrue(void), Xword(void), Xglobs(void), Xwrite(void), Xpipefd(void), Xcase(void); -extern void Xlocal(void), Xunlocal(void), Xassign(void), Xsimple(void), Xpopm(void); +extern void Xjump(void), Xmark(void), Xmatch(void), Xpipe(void), Xread(void), Xhere(void); +extern void Xrdwr(void), Xsrcline(void); +extern void Xunredir(void), Xstar(void), Xreturn(void), Xsubshell(void); +extern void Xtrue(void), Xword(void), Xwrite(void), Xpipefd(void), Xcase(void); +extern void Xlocal(void), Xunlocal(void), Xassign(void), Xsimple(void), Xpopm(void), Xpush(void); extern void Xrdcmds(void), Xwastrue(void), Xif(void), Xifnot(void), Xpipewait(void); -extern void Xdelhere(void), Xpopredir(void), Xsub(void), Xeflag(void), Xsettrue(void); +extern void Xpopredir(void), Xsub(void), Xeflag(void), Xsettrue(void); extern void Xerror(char*); extern void Xerror1(char*); + /* * word lists are in correct order, * i.e. word0->word1->word2->word3->0 @@ -20,60 +21,64 @@ extern void Xerror1(char*); struct word{ char *word; word *next; - int glob; /* Globsize(word) */ }; struct list{ word *words; list *next; }; word *newword(char *, word *), *copywords(word *, word *); + struct redir{ - char type; /* what to do */ - short from, to; /* what to do it to */ - redir *next; /* what else to do (reverse order) */ + int type; /* what to do */ + int from, to; /* what to do it to */ + redir *next; /* what else to do (reverse order) */ }; -#define NSTATUS ERRMAX /* length of status (from plan 9) */ +#define NSTATUS 128 /* length of status */ + /* * redir types */ #define ROPEN 1 /* dup2(from, to); close(from); */ #define RDUP 2 /* dup2(from, to); */ #define RCLOSE 3 /* close(from); */ +void shuffleredir(void); + struct thread{ code *code; /* code for this thread */ int pc; /* code[pc] is the next instruction */ - int line; /* source code line */ + int line; /* source code line for Xsrcline */ list *argv; /* argument stack */ redir *redir; /* redirection stack */ redir *startredir; /* redir inheritance point */ var *local; /* list of local variables */ - char *cmdfile; /* file name in Xrdcmd */ - io *cmdfd; /* file descriptor for Xrdcmd */ - int lexline; /* file descriptor line */ - int iflast; /* static `if not' checking */ - int eof; /* is cmdfd at eof? */ + lexer *lex; /* lexer for Xrdcmds */ int iflag; /* interactive? */ - int lineno; /* linenumber */ int pid; /* process for Xpipewait to wait for */ char status[NSTATUS]; /* status for Xpipewait */ - tree *treenodes; /* tree nodes created by this process */ thread *ret; /* who continues when this finishes */ }; + thread *runq; +void turfstack(var*); + code *codecopy(code*); code *codebuf; /* compiler output */ +extern int ifnot; + int ntrap; /* number of outstanding traps */ int trap[NSIG]; /* number of outstanding traps per type */ struct builtin{ char *name; void (*fnc)(void); }; -extern struct builtin Builtin[]; -int eflagok; /* kludge flag so that -e doesn't exit in startup */ +extern void (*builtinfunc(char *name))(void); void execcd(void), execwhatis(void), execeval(void), execexec(void); int execforkexec(void); void execexit(void), execshift(void); void execwait(void), execumask(void), execdot(void), execflag(void); -void execfunc(var*), execcmds(io *); -char *curfile(thread*); \ No newline at end of file +void execfunc(var*), execcmds(io*, char*, var*, redir*); +void startfunc(var*, word*, var*, redir*); + +char *srcfile(thread*); +char *getstatus(void); diff --git a/sys/src/cmd/rc/fns.h b/sys/src/cmd/rc/fns.h index db48e6105..1d60b988a 100644 --- a/sys/src/cmd/rc/fns.h +++ b/sys/src/cmd/rc/fns.h @@ -1,63 +1,65 @@ void Abort(void); -void Closedir(int); +int Chdir(char*); +void Close(int); +void Closedir(void*); int Creat(char*); int Dup(int, int); int Dup1(int); int Eintr(void); int Executable(char*); -void Execute(word*, word*); +void Exec(char**); void Exit(char*); -int ForkExecute(char*, char**, int, int, int); -int Globsize(char*); +char* Errstr(void); +char* Freeword(word*); +int Fork(void); int Isatty(int); +word* Newword(char*,word*); void Noerror(void); -int Opendir(char*); +int Open(char*, int); +void* Opendir(char*); +word* Poplist(void); +char* Popword(void); +word* Pushword(char*); long Read(int, void*, long); -int Readdir(int, void*, int); +char* Readdir(void*, int); long Seek(int, long, long); void Trapinit(void); -void Unlink(char*); void Updenv(void); void Vinit(void); int Waitfor(int, int); long Write(int, void*, long); void addwaitpid(int); -int advance(void); -int back(int); -void cleanhere(char*); +void clearwaitpids(void); void codefree(code*); int compile(tree*); -char * list2str(word*); int count(word*); char* deglob(char*); void delwaitpid(int); void dotrap(void); void freenodes(void); void freewords(word*); -word* globlist(word*); +void globword(word*); int havewaitpid(int); int idchr(int); -void inttoascii(char*, long); +void inttoascii(char*, int); void kinit(void); int mapfd(int); int match(char*, char*, int); -char** mkargv(word*); -void clearwaitpids(void); +char* makepath(char*, char*); void panic(char*, int); -void pathinit(void); +void pfln(io*, char*, int); void poplist(void); void popword(void); void pprompt(void); +void Prompt(char*); +void psubst(io *f, uchar *s); void pushlist(void); void pushredir(int, int, int); word* pushword(char*); -void readhere(void); -word* searchpath(char*, char*); +char* readhere(tree*, io*); void setstatus(char*); -void setvar(char*, word*); -void shuffleredir(void); void skipnl(void); -void start(code*, int, var*); +void start(code*, int, var*, redir*); int truestatus(void); void usage(char*); int wordchr(int); diff --git a/sys/src/cmd/rc/glob.c b/sys/src/cmd/rc/glob.c index 00c9f7504..a82d59280 100644 --- a/sys/src/cmd/rc/glob.c +++ b/sys/src/cmd/rc/glob.c @@ -5,18 +5,19 @@ /* * delete all the GLOB marks from s, in place */ - char* deglob(char *s) { - char *b = s; - char *t = s; - do{ - if(*t==GLOB) - t++; - *s++=*t; - }while(*t++); - return b; + char *r = strchr(s, GLOB); + if(r){ + char *w = r++; + do{ + if(*r==GLOB) + r++; + *w++=*r; + }while(*r++); + } + return s; } static int @@ -55,93 +56,86 @@ matchfn(char *s, char *p) return match(s, p, '/'); } -static word* -globdir(word *list, char *p, char *name, char *namep) +static void +pappend(char **pdir, char *name) { - char *t, *newp; - int f; + char *path = makepath(*pdir, name); + free(*pdir); + *pdir = path; +} + +static word* +globdir(word *list, char *pattern, char *name) +{ + char *slash, *glob, *entry; + void *dir; /* append slashes, Readdir() already filtered directories */ - while(*p=='/'){ - *namep++=*p++; - *namep='\0'; + while(*pattern=='/'){ + pappend(&name, "/"); + pattern++; } - if(*p=='\0') - return newword(name, list); + if(*pattern=='\0') + return Newword(name, list); + /* scan the pattern looking for a component with a metacharacter in it */ - t = namep; - newp = p; - while(*newp){ - if(*newp==GLOB) - break; - *t=*newp++; - if(*t++=='/'){ - namep = t; - p = newp; - } - } + glob=strchr(pattern, GLOB); + /* If we ran out of pattern, append the name if accessible */ - if(*newp=='\0'){ - *t='\0'; + if(glob==0){ + pappend(&name, pattern); if(access(name, 0)==0) - list = newword(name, list); - return list; + return Newword(name, list); + goto out; } + + *glob='\0'; + slash=strrchr(pattern, '/'); + if(slash){ + *slash='\0'; + pappend(&name, pattern); + *slash='/'; + pattern=slash+1; + } + *glob=GLOB; + /* read the directory and recur for any entry that matches */ - *namep='\0'; - if((f = Opendir(name[0]?name:".")) >= 0){ - while(*newp!='/' && *newp!='\0') newp++; - while(Readdir(f, namep, *newp=='/')){ - if(matchfn(namep, p)){ - for(t = namep;*t;t++); - list = globdir(list, newp, name, t); - } - } - Closedir(f); + dir = Opendir(name[0]?name:"."); + if(dir==0) + goto out; + slash=strchr(glob, '/'); + while((entry=Readdir(dir, slash!=0)) != 0){ + if(matchfn(entry, pattern)) + list = globdir(list, slash?slash:"", makepath(name, entry)); } + Closedir(dir); +out: + free(name); return list; } /* * Subsitute a word with its glob in place. */ - -static void +void globword(word *w) { word *left, *right; - char *name; - if(w->glob == 0) + if(w==0 || strchr(w->word, GLOB)==0) return; - name = emalloc(w->glob); - memset(name, 0, w->glob); right = w->next; - left = globdir(right, w->word, name, name); - free(name); + left = globdir(right, w->word, estrdup("")); if(left == right) { deglob(w->word); - w->glob = 0; } else { free(w->word); globsort(left, right); - *w = *left; - free(left); + w->next = left->next; + w->word = Freeword(left); } } -word* -globlist(word *l) -{ - word *p, *q; - - for(p=l;p;p=q){ - q = p->next; - globword(p); - } - return l; -} - /* * Return a pointer to the next utf code in the string, * not jumping past nuls in broken utf codes! diff --git a/sys/src/cmd/rc/havefork.c b/sys/src/cmd/rc/havefork.c index 86d6c91f6..669540e54 100644 --- a/sys/src/cmd/rc/havefork.c +++ b/sys/src/cmd/rc/havefork.c @@ -4,32 +4,61 @@ #include "io.h" #include "fns.h" +static int *waitpids; +static int nwaitpids; + +void +addwaitpid(int pid) +{ + waitpids = erealloc(waitpids, (nwaitpids+1)*sizeof waitpids[0]); + waitpids[nwaitpids++] = pid; +} + +void +delwaitpid(int pid) +{ + int r, w; + + for(r=w=0; rcode, runq->pc+1, runq->local); + start(runq->code, runq->pc+1, runq->local, runq->redir); runq->ret = 0; break; default: addwaitpid(pid); - close(null); runq->pc = runq->code[runq->pc].i; inttoascii(npid, pid); setvar("apid", newword(npid, (word *)0)); @@ -40,8 +69,8 @@ Xasync(void) void Xpipe(void) { - struct thread *p = runq; - int pc = p->pc, forkid; + thread *p = runq; + int pid, pc = p->pc; int lfd = p->code[pc++].i; int rfd = p->code[pc++].i; int pfd[2]; @@ -50,25 +79,24 @@ Xpipe(void) Xerror("can't get pipe"); return; } - Updenv(); - switch(forkid = fork()){ + switch(pid = Fork()){ case -1: Xerror("try again"); break; case 0: clearwaitpids(); - start(p->code, pc+2, runq->local); + Close(pfd[PRD]); + start(p->code, pc+2, runq->local, runq->redir); runq->ret = 0; - close(pfd[PRD]); pushredir(ROPEN, pfd[PWR], lfd); break; default: - addwaitpid(forkid); - start(p->code, p->code[pc].i, runq->local); - close(pfd[PWR]); + addwaitpid(pid); + Close(pfd[PWR]); + start(p->code, p->code[pc].i, runq->local, runq->redir); pushredir(ROPEN, pfd[PRD], rfd); p->pc = p->code[pc+1].i; - p->pid = forkid; + p->pid = pid; break; } } @@ -76,74 +104,50 @@ Xpipe(void) /* * Who should wait for the exit from the fork? */ -enum { Stralloc = 100, }; void Xbackq(void) { - int c, l, pid; - int pfd[2]; - char *s, *wd, *ewd, *stop; - struct io *f; - word *v, *nextv; + int pid, pfd[2]; + char *s, *split; + word *end, **link; + io *f; - stop = ""; - if(runq->argv && runq->argv->words) - stop = runq->argv->words->word; if(pipe(pfd)<0){ Xerror("can't make pipe"); return; } - Updenv(); - switch(pid = fork()){ + switch(pid = Fork()){ case -1: Xerror("try again"); - close(pfd[PRD]); - close(pfd[PWR]); + Close(pfd[PRD]); + Close(pfd[PWR]); return; case 0: clearwaitpids(); - close(pfd[PRD]); - start(runq->code, runq->pc+1, runq->local); + Close(pfd[PRD]); + start(runq->code, runq->pc+1, runq->local, runq->redir); pushredir(ROPEN, pfd[PWR], 1); return; default: addwaitpid(pid); - close(pfd[PWR]); - f = openfd(pfd[PRD]); - s = wd = ewd = 0; - v = 0; - while((c = rchr(f))!=EOF){ - if(s==ewd){ - l = s-wd; - wd = erealloc(wd, l+Stralloc); - ewd = wd+l+Stralloc-1; - s = wd+l; - } - if(strchr(stop, c)){ - if(s!=wd){ - *s='\0'; - v = newword(wd, v); - s = wd; - } - } - else *s++=c; + Close(pfd[PWR]); + + split = Popword(); + poplist(); + f = openiofd(pfd[PRD]); + end = runq->argv->words; + link = &runq->argv->words; + while((s = rstr(f, split)) != 0){ + *link = Newword(s, (word*)0); + link = &(*link)->next; } - if(s!=wd){ - *s='\0'; - v = newword(wd, v); - } - free(wd); + *link = end; closeio(f); + free(split); + Waitfor(pid, 0); - poplist(); /* ditch split in "stop" */ - /* 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; } @@ -152,8 +156,8 @@ Xbackq(void) void Xpipefd(void) { - struct thread *p = runq; - int pc = p->pc, pid; + thread *p = runq; + int pid, pc = p->pc; char name[40]; int pfd[2]; int sidefd, mainfd; @@ -170,23 +174,22 @@ Xpipefd(void) sidefd = pfd[PRD]; mainfd = pfd[PWR]; } - Updenv(); - switch(pid = fork()){ + switch(pid = Fork()){ case -1: Xerror("try again"); break; case 0: clearwaitpids(); - start(p->code, pc+2, runq->local); - close(mainfd); + Close(mainfd); + start(p->code, pc+2, runq->local, runq->redir); pushredir(ROPEN, sidefd, p->code[pc].i==READ?1:0); runq->ret = 0; break; default: addwaitpid(pid); - close(sidefd); + Close(sidefd); pushredir(ROPEN, mainfd, mainfd); - shuffleredir(); /* shuffle redir to bottom of stack for turfredir() */ + shuffleredir(); /* shuffle redir to bottom of stack for Xpopredir() */ strcpy(name, Fdprefix); inttoascii(name+strlen(name), mainfd); pushword(name); @@ -200,14 +203,13 @@ Xsubshell(void) { int pid; - Updenv(); - switch(pid = fork()){ + switch(pid = Fork()){ case -1: Xerror("try again"); break; case 0: clearwaitpids(); - start(runq->code, runq->pc+1, runq->local); + start(runq->code, runq->pc+1, runq->local, runq->redir); runq->ret = 0; break; default: @@ -222,20 +224,15 @@ int execforkexec(void) { int pid; - int n; - char buf[ERRMAX]; - switch(pid = fork()){ + switch(pid = Fork()){ case -1: return -1; case 0: clearwaitpids(); pushword("exec"); execexec(); - strcpy(buf, "can't exec: "); - n = strlen(buf); - errstr(buf+n, ERRMAX-n); - Exit(buf); + /* does not return */ } addwaitpid(pid); return pid; diff --git a/sys/src/cmd/rc/here.c b/sys/src/cmd/rc/here.c index 3ee8d6395..0f9258fe6 100644 --- a/sys/src/cmd/rc/here.c +++ b/sys/src/cmd/rc/here.c @@ -2,93 +2,49 @@ #include "exec.h" #include "io.h" #include "fns.h" -struct here *here, **ehere; -int ser = 0; -char tmp[]="/tmp/here0000.0000"; -char hex[]="0123456789abcdef"; void psubst(io*, uchar*); void pstrs(io*, word*); -void -hexnum(char *p, int n) +char* +readhere(tree *tag, io *in) { - *p++=hex[(n>>12)&0xF]; - *p++=hex[(n>>8)&0xF]; - *p++=hex[(n>>4)&0xF]; - *p = hex[n&0xF]; -} - -tree* -heredoc(tree *tag) -{ - struct here *h; + io *out; + char c, *m; if(tag->type!=WORD){ yyerror("Bad here tag"); - return nil; + return 0; } - h = new(struct here); - h->next = 0; - if(here) - *ehere = h; - else - here = h; - ehere=&h->next; - h->tag = tag; - hexnum(&tmp[9], getpid()); - hexnum(&tmp[14], ser++); - h->name = estrdup(tmp); - return token(tmp, WORD); -} -/* - * bug: lines longer than NLINE get split -- this can cause spurious - * missubstitution, or a misrecognized EOF marker. - */ -#define NLINE 4096 - -void -readhere(void) -{ - struct here *h, *nexth; - io *f; - char *s, *tag; - int c, subst; - char line[NLINE+1]; - for(h = here;h;h = nexth){ - subst=!h->tag->quoted; - tag = h->tag->str; - c = Creat(h->name); - if(c<0) - yyerror("can't create here document"); - f = openfd(c); - s = line; - pprompt(); - while((c = rchr(runq->cmdfd))!=EOF){ - if(c=='\n' || s==&line[NLINE]){ - *s='\0'; - if(tag && strcmp(line, tag)==0) break; - if(subst) - psubst(f, (uchar *)line); - else - pstr(f, line); - s = line; - if(c=='\n'){ - pprompt(); - pchr(f, c); - } - else *s++=c; - } - else *s++=c; + pprompt(); + out = openiostr(); + m = tag->str; + while((c = rchr(in)) != EOF){ + if(c=='\0'){ + yyerror("NUL bytes in here doc"); + closeio(out); + return 0; } - flush(f); - closeio(f); - cleanhere(h->name); - nexth = h->next; - free(h); + if(c=='\n'){ + lex->line++; + if(m && *m=='\0'){ + out->bufp -= m - tag->str; + *out->bufp='\0'; + break; + } + pprompt(); + m = tag->str; + } else if(m){ + if(*m == c){ + m++; + } else { + m = 0; + } + } + pchr(out, c); } - here = 0; doprompt = 1; + return closeiostr(out); } void diff --git a/sys/src/cmd/rc/io.c b/sys/src/cmd/rc/io.c index 2010e80ef..6c89b048f 100644 --- a/sys/src/cmd/rc/io.c +++ b/sys/src/cmd/rc/io.c @@ -3,18 +3,13 @@ #include "io.h" #include "fns.h" -enum { Stralloc = 100, }; - -int pfmtnest = 0; +enum { + NBUF = 8192, +}; void -pfmt(io *f, char *fmt, ...) +vpfmt(io *f, char *fmt, va_list ap) { - va_list ap; - char err[ERRMAX]; - - va_start(ap, fmt); - pfmtnest++; for(;*fmt;fmt++) { if(*fmt!='%') { pchr(f, *fmt); @@ -42,51 +37,103 @@ pfmt(io *f, char *fmt, ...) pwrd(f, va_arg(ap, char *)); break; case 'r': - errstr(err, sizeof err); pstr(f, err); + pstr(f, Errstr()); break; case 's': pstr(f, va_arg(ap, char *)); break; case 't': - pcmd(f, va_arg(ap, struct tree *)); + pcmd(f, va_arg(ap, tree *)); break; case 'v': - pval(f, va_arg(ap, struct word *)); + pval(f, va_arg(ap, word *)); break; default: pchr(f, *fmt); break; } } +} + +void +pfmt(io *f, char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + vpfmt(f, fmt, ap); va_end(ap); - if(--pfmtnest==0) - flush(f); } void pchr(io *b, int c) { - if(b->bufp==b->ebuf) - fullbuf(b, c); - else *b->bufp++=c; + if(b->bufp>=b->ebuf) + flushio(b); + *b->bufp++=c; } int rchr(io *b) { - if(b->bufp==b->ebuf) - return emptybuf(b); + if(b->bufp>=b->ebuf) + return emptyiobuf(b); return *b->bufp++; } +char* +rstr(io *b, char *stop) +{ + char *s, *p; + int l, m, n; + + do { + l = rchr(b); + if(l == EOF) + return 0; + } while(strchr(stop, l)); + b->bufp--; + + s = 0; + l = 0; + for(;;){ + p = (char*)b->bufp; + n = (char*)b->ebuf - p; + if(n > 0){ + for(m = 0; m < n; m++){ + if(strchr(stop, p[m])==0) + continue; + + b->bufp += m+1; + if(m > 0 || s==0){ + s = erealloc(s, l+m+1); + memmove(s+l, p, m); + l += m; + } + s[l]='\0'; + return s; + } + s = erealloc(s, l+m+1); + memmove(s+l, p, m); + l += m; + b->bufp += m; + } + if(emptyiobuf(b) == EOF){ + if(s) s[l]='\0'; + return s; + } + b->bufp--; + } +} + void pquo(io *f, char *s) { pchr(f, '\''); - for(;*s;s++) + for(;*s;s++){ if(*s=='\'') - pfmt(f, "''"); - else pchr(f, *s); + pchr(f, *s); + pchr(f, *s); + } pchr(f, '\''); } @@ -154,37 +201,82 @@ poct(io *f, unsigned n) void pval(io *f, word *a) { - if(a){ - while(a->next && a->next->word){ - pwrd(f, (char *)a->word); - pchr(f, ' '); - a = a->next; - } + if(a==0) + return; + while(a->next && a->next->word){ pwrd(f, (char *)a->word); + pchr(f, ' '); + a = a->next; } + pwrd(f, (char *)a->word); } -int -fullbuf(io *f, int c) +io* +newio(uchar *buf, int len, int fd) { - flush(f); - return *f->bufp++=c; + io *f = new(io); + f->buf = buf; + f->bufp = buf; + f->ebuf = buf+len; + f->fd = fd; + return f; +} + +/* + * Open a string buffer for writing. + */ +io* +openiostr(void) +{ + uchar *buf = emalloc(100+1); + memset(buf, '\0', 100+1); + return newio(buf, 100, -1); +} + +/* + * Return the buf, free the io + */ +char* +closeiostr(io *f) +{ + void *buf = f->buf; + free(f); + return buf; +} + +/* + * Use a open file descriptor for reading. + */ +io* +openiofd(int fd) +{ + return newio(emalloc(NBUF), 0, fd); +} + +/* + * Open a corebuffer to read. EOF occurs after reading len + * characters from buf. + */ +io* +openiocore(uchar *buf, int len) +{ + return newio(buf, len, -1); } void -flush(io *f) +flushio(io *f) { int n; - if(f->strp){ - n = f->ebuf - f->strp; - f->strp = erealloc(f->strp, n+Stralloc+1); - f->bufp = f->strp + n; - f->ebuf = f->bufp + Stralloc; - memset(f->bufp, '\0', Stralloc+1); + if(f->fd<0){ + n = f->ebuf - f->buf; + f->buf = erealloc(f->buf, n+n+1); + f->bufp = f->buf + n; + f->ebuf = f->bufp + n; + memset(f->bufp, '\0', n+1); } else{ - n = f->bufp-f->buf; + n = f->bufp - f->buf; if(n && Write(f->fd, f->buf, n) != n){ Write(2, "Write error\n", 12); if(ntrap) @@ -195,71 +287,18 @@ flush(io *f) } } -io* -openfd(int fd) -{ - io *f = new(struct io); - f->fd = fd; - f->bufp = f->ebuf = f->buf; - f->strp = 0; - return f; -} - -io* -openstr(void) -{ - io *f = new(struct io); - - f->fd = -1; - f->bufp = f->strp = emalloc(Stralloc+1); - f->ebuf = f->bufp + Stralloc; - memset(f->bufp, '\0', Stralloc+1); - return f; -} -/* - * Open a corebuffer to read. EOF occurs after reading len - * characters from buf. - */ - -io* -opencore(char *s, int len) -{ - io *f = new(struct io); - uchar *buf = emalloc(len); - - f->fd = -1 /*open("/dev/null", 0)*/; - f->bufp = f->strp = buf; - f->ebuf = buf+len; - memmove(buf, s, len); - return f; -} - void -rewind(io *io) +closeio(io *f) { - if(io->fd==-1) - io->bufp = io->strp; - else{ - io->bufp = io->ebuf = io->buf; - Seek(io->fd, 0L, 0); - } -} - -void -closeio(io *io) -{ - if(io->fd>=0) - close(io->fd); - if(io->strp) - free(io->strp); - free(io); + if(f->fd>=0) Close(f->fd); + free(closeiostr(f)); } int -emptybuf(io *f) +emptyiobuf(io *f) { int n; - if(f->fd==-1 || (n = Read(f->fd, f->buf, NBUF))<=0) return EOF; + if(f->fd<0 || (n = Read(f->fd, f->buf, NBUF))<=0) return EOF; f->bufp = f->buf; f->ebuf = f->buf + n; return *f->bufp++; diff --git a/sys/src/cmd/rc/io.h b/sys/src/cmd/rc/io.h index 7d7cd146e..7a1600397 100644 --- a/sys/src/cmd/rc/io.h +++ b/sys/src/cmd/rc/io.h @@ -1,20 +1,20 @@ #define EOF (-1) -#define NBUF 512 struct io{ int fd; - uchar *bufp, *ebuf, *strp; - uchar buf[NBUF]; + uchar *buf, *bufp, *ebuf; + io *next; }; io *err; -io *openfd(int), *openstr(void), *opencore(char *, int); -int emptybuf(io*); +io *openiofd(int), *openiostr(void), *openiocore(uchar*, int); void pchr(io*, int); int rchr(io*); +char *rstr(io*, char*); +char *closeiostr(io*); void closeio(io*); -void flush(io*); -int fullbuf(io*, int); +int emptyiobuf(io*); +void flushio(io*); void pdec(io*, int); void poct(io*, unsigned); void pptr(io*, void*); @@ -23,5 +23,7 @@ void pwrd(io*, char*); void pstr(io*, char*); void pcmd(io*, tree*); void pval(io*, word*); +void pfun(io*, void(*)(void)); void pfnc(io*, thread*); void pfmt(io*, char*, ...); +void vpfmt(io*, char*, va_list); diff --git a/sys/src/cmd/rc/lex.c b/sys/src/cmd/rc/lex.c index 3462bed69..5e061b989 100644 --- a/sys/src/cmd/rc/lex.c +++ b/sys/src/cmd/rc/lex.c @@ -1,9 +1,12 @@ #include "rc.h" -#include "exec.h" #include "io.h" #include "getflags.h" #include "fns.h" -int getnext(void); + +lexer *lex; + +int doprompt = 1; +int nerror; int wordchr(int c) @@ -21,105 +24,109 @@ idchr(int c) */ return c>' ' && !strchr("!\"#$%&'()+,-./:;<=>?@[\\]^`{|}~", c); } -int future = EOF; -int doprompt = 1; -int inquote; -int incomm; -int lastc; -int ndot; -int nerror; -int nlexpath; -int lexpathsz; -/* - * Look ahead in the input stream - */ +lexer* +newlexer(io *input, char *file) +{ + lexer *n = new(struct lexer); + n->input = input; + n->file = file; + n->line = 1; + n->eof = 0; + n->future = EOF; + n->peekc = '{'; + n->epilog = "}\n"; + n->lastc = 0; + n->inquote = 0; + n->incomm = 0; + n->lastword = 0; + n->lastdol = 0; + n->iflast = 0; + n->qflag = 0; + n->tok[0] = 0; + return n; +} -int -nextc(void) +void +freelexer(lexer *p) { - if(future==EOF) - future = getnext(); - return future; -} -/* - * Consume the lookahead character. - */ -int -advance(void) -{ - int c = nextc(); - lastc = future; - future = EOF; - if(c == '\n') - runq->lexline++; - return c; + closeio(p->input); + free(p->file); + free(p); } + /* * read a character from the input stream */ - -int +static int getnext(void) { int c; - static int peekc = EOF; - if(peekc!=EOF){ - c = peekc; - peekc = EOF; + + if(lex->peekc!=EOF){ + c = lex->peekc; + lex->peekc = EOF; return c; } - if(runq->eof) + if(lex->eof){ +epilog: + if(*lex->epilog) + return *lex->epilog++; + doprompt = 1; return EOF; + } if(doprompt) pprompt(); - c = rchr(runq->cmdfd); - if(!inquote && c=='\\'){ - c = rchr(runq->cmdfd); - if(c=='\n' && !incomm){ /* don't continue a comment */ + c = rchr(lex->input); + if(c=='\\' && !lex->inquote){ + c = rchr(lex->input); + if(c=='\n' && !lex->incomm){ /* don't continue a comment */ doprompt = 1; c=' '; } else{ - peekc = c; + lex->peekc = c; c='\\'; } } - doprompt = doprompt || c=='\n' || c==EOF; - if(c==EOF) - runq->eof++; - else if(flag['V'] || ndot>=2 && flag['v']) pchr(err, c); + if(c==EOF){ + lex->eof = 1; + goto epilog; + } else { + if(c=='\n') + doprompt = 1; + if((!lex->qflag && flag['v']!=0) || flag['V']) + pchr(err, c); + } return c; } -void -pprompt(void) +/* + * Look ahead in the input stream + */ +static int +nextc(void) { - var *prompt; - if(runq->iflag){ - pstr(err, promptstr); - flush(err); - if(newwdir){ - char dir[4096]; - int fd; - if((fd=open("/dev/wdir", OWRITE))>=0){ - getwd(dir, sizeof(dir)); - write(fd, dir, strlen(dir)); - close(fd); - } - newwdir = 0; - } - prompt = vlook("prompt"); - if(prompt->val && prompt->val->next) - promptstr = prompt->val->next->word; - else - promptstr="\t"; - } - runq->lineno++; - doprompt = 0; + if(lex->future==EOF) + lex->future = getnext(); + return lex->future; } -void +/* + * Consume the lookahead character. + */ +static int +advance(void) +{ + int c = nextc(); + lex->lastc = lex->future; + lex->future = EOF; + if(c == '\n') + lex->line++; + return c; +} + +static void skipwhite(void) { int c; @@ -127,11 +134,11 @@ skipwhite(void) c = nextc(); /* Why did this used to be if(!inquote && c=='#') ?? */ if(c=='#'){ - incomm = 1; + lex->incomm = 1; for(;;){ c = nextc(); if(c=='\n' || c==EOF) { - incomm = 0; + lex->incomm = 0; break; } advance(); @@ -156,7 +163,7 @@ skipnl(void) } } -int +static int nextis(int c) { if(nextc()==c){ @@ -166,12 +173,12 @@ nextis(int c) return 0; } -char* +static char* addtok(char *p, int val) { if(p==0) return 0; - if(p==&tok[NTOK-1]){ + if(p==&lex->tok[NTOK-1]){ *p = 0; yyerror("token buffer too short"); return 0; @@ -180,7 +187,7 @@ addtok(char *p, int val) return p; } -char* +static char* addutf(char *p, int c) { uchar b, m; @@ -202,16 +209,16 @@ addutf(char *p, int c) return p; } -int lastdol; /* was the last token read '$' or '$#' or '"'? */ -int lastword; /* was the last token read a word or compound word terminator? */ - int yylex(void) { - int c, d = nextc(); + int glob, c, d = nextc(); + char *tok = lex->tok; char *w = tok; - struct tree *t; + tree *t; + yylval.tree = 0; + /* * Embarassing sneakiness: if the last token read was a quoted or unquoted * WORD then we alter the meaning of what follows. If the next character @@ -219,8 +226,8 @@ yylex(void) * if the next character is the first character of a simple or compound word, * we insert a `^' before it. */ - if(lastword){ - lastword = 0; + if(lex->lastword){ + lex->lastword = 0; if(d=='('){ advance(); strcpy(tok, "( [SUB]"); @@ -231,15 +238,15 @@ yylex(void) return '^'; } } - inquote = 0; + lex->inquote = 0; skipwhite(); switch(c = advance()){ case EOF: - lastdol = 0; + lex->lastdol = 0; strcpy(tok, "EOF"); return EOF; case '$': - lastdol = 1; + lex->lastdol = 1; if(nextis('#')){ strcpy(tok, "$#"); return COUNT; @@ -251,7 +258,7 @@ yylex(void) strcpy(tok, "$"); return '$'; case '&': - lastdol = 0; + lex->lastdol = 0; if(nextis('&')){ skipnl(); strcpy(tok, "&&"); @@ -260,7 +267,7 @@ yylex(void) strcpy(tok, "&"); return '&'; case '|': - lastdol = 0; + lex->lastdol = 0; if(nextis(c)){ skipnl(); strcpy(tok, "||"); @@ -268,7 +275,7 @@ yylex(void) } case '<': case '>': - lastdol = 0; + lex->lastdol = 0; /* * funny redirection tokens: * redir: arrow | arrow '[' fd ']' @@ -355,9 +362,9 @@ yylex(void) skipnl(); return t->type; case '\'': - lastdol = 0; - lastword = 1; - inquote = 1; + lex->lastdol = 0; + lex->lastword = 1; + lex->inquote = 1; for(;;){ c = advance(); if(c==EOF) @@ -377,28 +384,51 @@ yylex(void) return t->type; } if(!wordchr(c)){ - lastdol = 0; + lex->lastdol = 0; tok[0] = c; tok[1]='\0'; return c; } + glob = 0; for(;;){ - if(c=='*' || c=='[' || c=='?' || c==GLOB) + if(c=='*' || c=='[' || c=='?' || c==GLOB){ + glob = 1; w = addtok(w, GLOB); + } w = addutf(w, c); c = nextc(); - if(lastdol?!idchr(c):!wordchr(c)) break; + if(lex->lastdol?!idchr(c):!wordchr(c)) break; advance(); } - lastword = 1; - lastdol = 0; + lex->lastword = 1; + lex->lastdol = 0; if(w!=0) *w='\0'; t = klook(tok); if(t->type!=WORD) - lastword = 0; + lex->lastword = 0; + else + t->glob = glob; t->quoted = 0; yylval.tree = t; return t->type; } + +void +yyerror(char *m) +{ + pfln(err, lex->file, lex->line); + pstr(err, ": "); + if(lex->tok[0] && lex->tok[0]!='\n') + pfmt(err, "token %q: ", lex->tok); + pfmt(err, "%s\n", m); + flushio(err); + + lex->lastword = 0; + lex->lastdol = 0; + while(lex->lastc!='\n' && lex->lastc!=EOF) advance(); + nerror++; + + setstatus(m); +} diff --git a/sys/src/cmd/rc/pcmd.c b/sys/src/cmd/rc/pcmd.c index 8061669e2..67edaf856 100644 --- a/sys/src/cmd/rc/pcmd.c +++ b/sys/src/cmd/rc/pcmd.c @@ -6,7 +6,7 @@ #define c1 t->child[1] #define c2 t->child[2] -void +static void pdeglob(io *f, char *s) { while(*s){ @@ -16,6 +16,14 @@ pdeglob(io *f, char *s) } } +static int ntab = 0; + +static char* +tabs(void) +{ + return "\t\t\t\t\t\t\t\t"+8-(ntab%8); +} + void pcmd(io *f, tree *t) { @@ -38,7 +46,11 @@ pcmd(io *f, tree *t) break; case BANG: pfmt(f, "! %t", c0); break; - case BRACE: pfmt(f, "{%t}", c0); + case BRACE: + ntab++; + pfmt(f, "{\n%s%t", tabs(), c0); + ntab--; + pfmt(f, "\n%s}", tabs()); break; case COUNT: pfmt(f, "$#%t", c0); break; @@ -75,9 +87,14 @@ pcmd(io *f, tree *t) break; case ';': if(c0){ - if(c1) - pfmt(f, "%t\n%t", c0, c1); - else pfmt(f, "%t", c0); + pfmt(f, "%t", c0); + if(c1){ + if(c0->line==c1->line) + pstr(f, "; "); + else + pfmt(f, "\n%s", tabs()); + pfmt(f, "%t", c1); + } } else pfmt(f, "%t", c1); break; @@ -109,6 +126,8 @@ pcmd(io *f, tree *t) pchr(f, ' '); switch(t->rtype){ case HERE: + if(c1) + pfmt(f, "%t ", c1); pchr(f, '<'); case READ: case RDWR: @@ -127,7 +146,9 @@ pcmd(io *f, tree *t) break; } pfmt(f, "%t", c0); - if(c1) + if(t->rtype == HERE) + pfmt(f, "\n%s%t\n", t->str, c0); + else if(c1) pfmt(f, " %t", c1); break; case '=': diff --git a/sys/src/cmd/rc/pfnc.c b/sys/src/cmd/rc/pfnc.c index 83f871ff8..e975d59af 100644 --- a/sys/src/cmd/rc/pfnc.c +++ b/sys/src/cmd/rc/pfnc.c @@ -18,8 +18,10 @@ struct{ Xjump, "Xjump", Xmark, "Xmark", Xpopm, "Xpopm", + Xpush, "Xpush", Xrdwr, "Xrdwr", Xread, "Xread", + Xhere, "Xhere", Xreturn, "Xreturn", Xtrue, "Xtrue", Xif, "Xif", @@ -44,31 +46,33 @@ struct{ Xbackq, "Xbackq", Xpipefd, "Xpipefd", Xsubshell, "Xsubshell", - Xdelhere, "Xdelhere", Xfor, "Xfor", Xglob, "Xglob", - Xglobs, "Xglobs", - Xrdfn, "Xrdfn", Xsimple, "Xsimple", Xqw, "Xqw", Xsrcline, "Xsrcline", 0}; void -pfnc(io *fd, thread *t) +pfun(io *f, void (*fn)(void)) { int i; - void (*fn)(void) = t->code[t->pc].f; + for(i = 0;fname[i].f;i++) if(fname[i].f==fn){ + pstr(f, fname[i].name); + return; + } + pfmt(f, "%p", fn); +} + +void +pfnc(io *f, thread *t) +{ list *a; - pfmt(fd, "%s:%d: pid %d cycle %p %d ", t->cmdfile, t->line, getpid(), t->code, t->pc); - for(i = 0;fname[i].f;i++) if(fname[i].f==fn){ - pstr(fd, fname[i].name); - break; - } - if(!fname[i].f) - pfmt(fd, "%p", fn); - for(a = t->argv;a;a = a->next) pfmt(fd, " (%v)", a->words); - pchr(fd, '\n'); - flush(fd); + pfln(f, srcfile(t), t->line); + pfmt(f, " pid %d cycle %p %d ", getpid(), t->code, t->pc); + pfun(f, t->code[t->pc].f); + for(a = t->argv;a;a = a->next) pfmt(f, " (%v)", a->words); + pchr(f, '\n'); + flushio(f); } diff --git a/sys/src/cmd/rc/plan9.c b/sys/src/cmd/rc/plan9.c index fb375b270..555417054 100644 --- a/sys/src/cmd/rc/plan9.c +++ b/sys/src/cmd/rc/plan9.c @@ -9,16 +9,33 @@ #include "fns.h" #include "getflags.h" -enum { - Maxenvname = 128, /* undocumented limit */ +static void execrfork(void); +static void execfinit(void); + +builtin Builtin[] = { + "cd", execcd, + "whatis", execwhatis, + "eval", execeval, + "exec", execexec, /* but with popword first */ + "exit", execexit, + "shift", execshift, + "wait", execwait, + ".", execdot, + "flag", execflag, + "finit", execfinit, + "rfork", execrfork, + 0 }; +char Rcmain[]="/rc/lib/rcmain"; +char Fdprefix[]="/fd/"; + char *Signame[] = { "sigexit", "sighup", "sigint", "sigquit", "sigalrm", "sigkill", "sigfpe", "sigterm", 0 }; -char *syssigname[] = { +static char *syssigname[] = { "exit", /* can't happen */ "hangup", "interrupt", @@ -29,32 +46,24 @@ char *syssigname[] = { "term", 0 }; -char Rcmain[]="/rc/lib/rcmain"; -char Fdprefix[]="/fd/"; -void execfinit(void); -void execbind(void); -void execmount(void); -void execnewpgrp(void); -builtin Builtin[] = { - "cd", execcd, - "whatis", execwhatis, - "eval", execeval, - "exec", execexec, /* but with popword first */ - "exit", execexit, - "shift", execshift, - "wait", execwait, - ".", execdot, - "finit", execfinit, - "flag", execflag, - "rfork", execnewpgrp, - 0 -}; -void -execnewpgrp(void) +static void +execfinit(void) +{ + char *cmds = estrdup("for(i in '/env/fn#'*){. -bq $i}\n"); + int line = runq->line; + poplist(); + execcmds(openiocore((uchar*)cmds, strlen(cmds)), estrdup(srcfile(runq)), runq->local, runq->redir); + runq->lex->line = line; + runq->lex->qflag = 1; +} + +static void +execrfork(void) { int arg; char *s; + switch(count(runq->argv->words)){ case 1: arg = RFENVG|RFNAMEG|RFNOTEG; @@ -91,11 +100,11 @@ execnewpgrp(void) return; } if(rfork(arg)==-1){ - pfmt(err, "rc: %s failed\n", runq->argv->words->word); + pfmt(err, "%s: %s failed\n", argv0, runq->argv->words->word); setstatus("rfork failed"); } else { if(arg & RFCFDG){ - struct redir *rp; + redir *rp; for(rp = runq->redir; rp; rp = rp->next) rp->type = 0; } @@ -104,93 +113,59 @@ execnewpgrp(void) poplist(); } +char* +Env(char *name, int fn) +{ + static char buf[128]; + + strcpy(buf, "/env/"); + if(fn) strcat(buf, "fn#"); + return strncat(buf, name, sizeof(buf)-1); +} + void Vinit(void) { - int dir, f, len, i, n, nent; - char *buf, *s; - char envname[Maxenvname]; - word *val; + int dir, fd, i, n; Dir *ent; - dir = open("/env", OREAD); + dir = Open(Env("", 0), 0); if(dir<0){ - pfmt(err, "rc: can't open /env: %r\n"); + pfmt(err, "%s: can't open: %r\n", argv0); return; } - ent = nil; for(;;){ - nent = dirread(dir, &ent); - if(nent <= 0) + ent = 0; + n = dirread(dir, &ent); + if(n <= 0) break; - for(i = 0; i=0){ - buf = emalloc(len+1); - n = readn(f, buf, len); - if (n <= 0) - buf[0] = '\0'; - else - buf[n] = '\0'; - val = 0; - /* Charitably add a 0 at the end if need be */ - if(buf[len-1]) - buf[len++]='\0'; - s = buf+len-1; - for(;;){ - while(s!=buf && s[-1]!='\0') --s; - val = newword(s, val); - if(s==buf) - break; - --s; - } - setvar(ent[i].name, val); - vlook(ent[i].name)->changed = 0; - close(f); - free(buf); + for(i = 0; i=0){ + io *f = openiofd(fd); + word *w = 0, **wp = &w; + char *s; + while((s = rstr(f, "")) != 0){ + *wp = Newword(s, (word*)0); + wp = &(*wp)->next; } + closeio(f); + setvar(ent[i].name, w); + vlook(ent[i].name)->changed = 0; } } free(ent); } - close(dir); + Close(dir); } -void -Xrdfn(void) +char* +Errstr(void) { - if(runq->argv->words == 0) - poplist(); - else { - free(runq->cmdfile); - int f = open(runq->argv->words->word, 0); - runq->cmdfile = strdup(runq->argv->words->word); - runq->lexline = 1; - runq->pc--; - popword(); - if(f>=0) execcmds(openfd(f)); - } -} -union code rdfns[8]; - -void -execfinit(void) -{ - static int first = 1; - if(first){ - rdfns[0].i = 1; - rdfns[1].f = Xmark; - rdfns[2].f = Xglobs; - rdfns[4].i = Globsize(rdfns[3].s = "/env/fn#\001*"); - rdfns[5].f = Xglob; - rdfns[6].f = Xrdfn; - rdfns[7].f = Xreturn; - first = 0; - } - poplist(); - start(rdfns, 1, runq->local); + static char err[ERRMAX]; + rerrstr(err, sizeof err); + return err; } int @@ -198,7 +173,6 @@ Waitfor(int pid, int) { thread *p; Waitmsg *w; - char errbuf[ERRMAX]; if(pid >= 0 && !havewaitpid(pid)) return 0; @@ -218,54 +192,46 @@ Waitfor(int pid, int) free(w); } - errstr(errbuf, sizeof errbuf); - if(strcmp(errbuf, "interrupted")==0) return -1; + if(strcmp(Errstr(), "interrupted")==0) return -1; return 0; } -char ** -mkargv(word *a) -{ - char **argv = (char **)emalloc((count(a)+2)*sizeof(char *)); - char **argp = argv+1; /* leave one at front for runcoms */ - for(;a;a = a->next) *argp++=a->word; - *argp = 0; - return argv; -} - -void +static void addenv(var *v) { - char envname[Maxenvname]; word *w; - int f; - io *fd; + int fd; + io *f; + if(v->changed){ v->changed = 0; - snprint(envname, sizeof envname, "/env/%s", v->name); - if((f = Creat(envname))<0) - pfmt(err, "rc: can't open %s: %r\n", envname); + if((fd = Creat(Env(v->name, 0)))<0) + pfmt(err, "%s: can't open: %r\n", argv0); else{ - for(w = v->val;w;w = w->next) - write(f, w->word, strlen(w->word)+1L); - close(f); + f = openiofd(fd); + for(w = v->val;w;w = w->next){ + pstr(f, w->word); + pchr(f, '\0'); + } + flushio(f); + closeio(f); } } if(v->fnchanged){ v->fnchanged = 0; - snprint(envname, sizeof envname, "/env/fn#%s", v->name); - if((f = Creat(envname))<0) - pfmt(err, "rc: can't open %s: %r\n", envname); + if((fd = Creat(Env(v->name, 1)))<0) + pfmt(err, "%s: can't open: %r\n", argv0); else{ - fd = openfd(f); + f = openiofd(fd); if(v->fn) - pfmt(fd, "fn %q %s\n", v->name, v->fn[v->pc-1].s); - closeio(fd); + pfmt(f, "fn %q %s\n", v->name, v->fn[v->pc-1].s); + flushio(f); + closeio(f); } } } -void +static void updenvlocal(var *v) { if(v){ @@ -283,80 +249,43 @@ Updenv(void) addenv(v); if(runq) updenvlocal(runq->local); -} - -/* not used on plan 9 */ -int -ForkExecute(char *, char **, int, int, int) -{ - return -1; + flushio(err); } void -Execute(word *args, word *path) +Exec(char **argv) { - char **argv = mkargv(args); - char file[1024]; - int nc, mc; + exec(argv[0], argv+1); +} +int +Fork(void) +{ Updenv(); - mc = strlen(argv[1])+1; - for(;path;path = path->next){ - nc = strlen(path->word); - if(nc + mc >= sizeof file - 1){ /* 1 for / */ - werrstr("command path name too long"); - continue; - } - if(nc > 0){ - memmove(file, path->word, nc); - file[nc++] = '/'; - } - memmove(file+nc, argv[1], mc); - exec(file, argv+1); - } - rerrstr(file, sizeof file); - setstatus(file); - pfmt(err, "%s: %s\n", argv[1], file); - free(argv); + return rfork(RFPROC|RFFDG|RFREND); } -#define NDIR 256 /* shoud be a better way */ -int -Globsize(char *p) -{ - int isglob = 0, globlen = NDIR+1; - for(;*p;p++){ - if(*p==GLOB){ - p++; - if(*p!=GLOB) - isglob++; - globlen+=*p=='*'?NDIR:1; - } - else - globlen++; - } - return isglob?globlen:0; -} -#define NFD 50 -struct{ +typedef struct readdir readdir; +struct readdir { Dir *dbuf; - int i; - int n; -}dir[NFD]; + int i, n; + int fd; +}; -int +void* Opendir(char *name) { - int f; - - if((f = open(name, 0)) < 0) - return f; - if(fdbuf = 0; + rd->i = 0; + rd->n = 0; + rd->fd = fd; + return rd; } static int @@ -370,57 +299,52 @@ trimdirs(Dir *d, int nd) return w; } -int -Readdir(int f, void *p, int onlydirs) +char* +Readdir(void *arg, int onlydirs) { + readdir *rd = arg; int n; - - if(f<0 || f>=NFD) - return 0; Again: - if(dir[f].i==dir[f].n){ /* read */ - free(dir[f].dbuf); - dir[f].dbuf = 0; - n = dirread(f, &dir[f].dbuf); + if(rd->i>=rd->n){ /* read */ + free(rd->dbuf); + rd->dbuf = 0; + n = dirread(rd->fd, &rd->dbuf); if(n>0){ if(onlydirs){ - n = trimdirs(dir[f].dbuf, n); + n = trimdirs(rd->dbuf, n); if(n == 0) goto Again; } - dir[f].n = n; + rd->n = n; }else - dir[f].n = 0; - dir[f].i = 0; + rd->n = 0; + rd->i = 0; } - if(dir[f].i == dir[f].n) + if(rd->i>=rd->n) return 0; - strncpy((char*)p, dir[f].dbuf[dir[f].i].name, NDIR); - dir[f].i++; - return 1; + return rd->dbuf[rd->i++].name; } void -Closedir(int f) +Closedir(void *arg) { - if(f>=0 && ffd); + free(rd->dbuf); + free(rd); } -int interrupted = 0; -void + +static int interrupted = 0; + +static void notifyf(void*, char *s) { int i; + for(i = 0;syssigname[i];i++) if(strncmp(s, syssigname[i], strlen(syssigname[i]))==0){ if(strncmp(s, "sys: ", 5)!=0) interrupted = 1; goto Out; } - pfmt(err, "rc: note: %s\n", s); noted(NDFLT); return; Out: @@ -428,10 +352,6 @@ Out: trap[i]++; ntrap++; } - if(ntrap>=32){ /* rc is probably in a trap loop */ - pfmt(err, "rc: Too many traps (trap %s), aborting\n", s); - abort(); - } noted(NCONT); } @@ -441,12 +361,6 @@ Trapinit(void) notify(notifyf); } -void -Unlink(char *name) -{ - remove(name); -} - long Write(int fd, void *buf, long cnt) { @@ -479,10 +393,23 @@ Executable(char *file) return ret; } +int +Open(char *file, int mode) +{ + static int tab[] = {OREAD,OWRITE,ORDWR,OREAD|ORCLOSE}; + return open(file, tab[mode&3]); +} + +void +Close(int fd) +{ + close(fd); +} + int Creat(char *file) { - return create(file, 1, 0666L); + return create(file, OWRITE, 0666L); } int @@ -524,11 +451,6 @@ Isatty(int fd) if(fd2path(fd, buf, sizeof buf) != 0) return 0; - - /* might be #c/cons during boot - fixed 22 april 2005, remove this later */ - if(strcmp(buf, "#c/cons") == 0) - return 1; - /* might be /mnt/term/dev/cons */ return strlen(buf) >= 9 && strcmp(buf+strlen(buf)-9, "/dev/cons") == 0; } @@ -537,51 +459,32 @@ void Abort(void) { pfmt(err, "aborting\n"); - flush(err); Exit("aborting"); } -int *waitpids; -int nwaitpids; - -void -addwaitpid(int pid) -{ - waitpids = erealloc(waitpids, (nwaitpids+1)*sizeof waitpids[0]); - waitpids[nwaitpids++] = pid; -} - -void -delwaitpid(int pid) -{ - int r, w; - - for(r=w=0; r=0){ + getwd(dir, sizeof(dir)); + Write(fd, dir, strlen(dir)); + Close(fd); + } + newwdir = 0; + } } diff --git a/sys/src/cmd/rc/rc.h b/sys/src/cmd/rc/rc.h index 87bc5c8a9..7e0b0611c 100644 --- a/sys/src/cmd/rc/rc.h +++ b/sys/src/cmd/rc/rc.h @@ -30,6 +30,7 @@ typedef struct io io; typedef union code code; typedef struct var var; typedef struct list list; +typedef struct lexer lexer; typedef struct redir redir; typedef struct thread thread; typedef struct builtin builtin; @@ -40,10 +41,11 @@ typedef struct builtin builtin; struct tree{ int type; int rtype, fd0, fd1; /* details of REDIR PIPE DUP tokens */ - char *str; - int quoted; - int iskw; int line; + char glob; /* 0=string, 1=glob, -1=pattern see globprop() and noglobs() */ + char quoted; + char iskw; + char *str; tree *child[3]; tree *next; }; @@ -52,12 +54,15 @@ tree *token(char*, int), *klook(char*), *tree1(int, tree*); tree *tree2(int, tree*, tree*), *tree3(int, tree*, tree*, tree*); tree *mung1(tree*, tree*), *mung2(tree*, tree*, tree*); tree *mung3(tree*, tree*, tree*, tree*), *epimung(tree*, tree*); -tree *simplemung(tree*), *heredoc(tree*); -void freetree(tree*); -tree *cmdtree; +tree *simplemung(tree*); +tree *globprop(tree*); +char *fnstr(tree*); /* - * The first word of any code vector is a reference count. + * The first word of any code vector is a reference count + * and the second word is a string for srcfile(). + * Code starts at pc 2. The last code word must be a zero + * terminator for codefree(). * Always create a new reference to a code vector by calling codecopy(.). * Always call codefree(.) when deleting a reference. */ @@ -67,13 +72,34 @@ union code{ char *s; }; -int newwdir; -char *promptstr; -int doprompt; - #define NTOK 8192 -char tok[NTOK]; +struct lexer{ + io *input; + char *file; + int line; + + char *prolog; + char *epilog; + + int peekc; + int future; + int lastc; + + char eof; + char inquote; + char incomm; + char lastword; /* was the last token read a word or compound word terminator? */ + char lastdol; /* was the last token read '$' or '$#' or '"'? */ + char iflast; /* static `if not' checking */ + + char qflag; + + char tok[NTOK]; +}; +extern lexer *lex; /* current lexer */ +lexer *newlexer(io*, char*); +void freelexer(lexer*); #define APPEND 1 #define WRITE 2 @@ -84,15 +110,16 @@ char tok[NTOK]; #define RDWR 7 struct var{ - char *name; /* ascii name */ - word *val; /* value */ - int changed; - code *fn; /* pointer to function's code vector */ - int fnchanged; - int pc; /* pc of start of function */ var *next; /* next on hash or local list */ + word *val; /* value */ + code *fn; /* pointer to function's code vector */ + int pc; /* pc of start of function */ + char fnchanged; + char changed; + char name[]; }; var *vlook(char*), *gvlook(char*), *newvar(char*, var*); +void setvar(char*, word*), freevar(var*); #define NVAR 521 @@ -104,13 +131,6 @@ void *emalloc(long); void *erealloc(void *, long); char *estrdup(char*); -#define NOFILE 128 /* should come from */ - -struct here{ - tree *tag; - char *name; - struct here *next; -}; int mypid; /* @@ -141,12 +161,4 @@ extern int doprompt; /* is it time for a prompt? */ */ #define PRD 0 #define PWR 1 -char Rcmain[], Fdprefix[]; -/* - * How many dot commands have we executed? - * Used to ensure that -v flag doesn't print rcmain. - */ -extern int ndot; -extern int lastc; -extern int lastword; -char *getstatus(void); +extern char Rcmain[], Fdprefix[]; diff --git a/sys/src/cmd/rc/simple.c b/sys/src/cmd/rc/simple.c index 661533b97..812914573 100644 --- a/sys/src/cmd/rc/simple.c +++ b/sys/src/cmd/rc/simple.c @@ -6,32 +6,63 @@ #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){ - code *c=&runq->code[runq->pc]; + int i=ifnot; + thread *p=runq; + code *c; +loop: + c=&p->code[p->pc]; while(1){ if(c->f==Xpopredir || c->f==Xunlocal) c++; - else if(c->f==Xsrcline || c->f==Xsrcfile) + else if(c->f==Xsrcline) c += 2; - else + else if(c->f==Xwastrue){ + c++; + i=0; + } + else if(c->f==Xifnot){ + if(i) + c += 2; + else + c = &p->code[c[1].i]; + } + else if(c->f==Xreturn){ + p = p->ret; + if(p==0) + return 1; + goto loop; + }else break; } return c->f==Xexit; } +void (*builtinfunc(char *name))(void) +{ + extern builtin Builtin[]; + builtin *bp; + + for(bp = Builtin;bp->name;bp++) + if(strcmp(name, bp->name)==0) + return bp->fnc; + return 0; +} + void Xsimple(void) { + void (*f)(void); word *a; var *v; - struct builtin *bp; int pid; - a = globlist(runq->argv->words); + a = runq->argv->words; if(a==0){ Xerror1("empty argument list"); return; @@ -43,28 +74,25 @@ Xsimple(void) 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)(); + if(a==0){ + Xerror1("builtin: empty argument list"); return; } + popword(); /* "builtin" */ + } + f = builtinfunc(a->word); + if(f){ + (*f)(); + return; + } if(exitnext()){ /* fork and wait is redundant */ pushword("exec"); execexec(); + /* does not return */ } else{ - flush(err); - Updenv(); /* necessary so changes don't go out again */ if((pid = execforkexec()) < 0){ Xerror("try again"); return; @@ -78,7 +106,7 @@ Xsimple(void) } } -void +static void doredir(redir *rp) { if(rp){ @@ -87,14 +115,14 @@ doredir(redir *rp) case ROPEN: if(rp->from!=rp->to){ Dup(rp->from, rp->to); - close(rp->from); + Close(rp->from); } break; case RDUP: Dup(rp->from, rp->to); break; case RCLOSE: - close(rp->from); + Close(rp->from); break; } } @@ -115,42 +143,61 @@ searchpath(char *w, char *v) return &nullpath; } +char* +makepath(char *dir, char *file) +{ + char *path; + int m, n = strlen(dir); + if(n==0) return estrdup(file); + while (n > 0 && dir[n-1]=='/') n--; + while (file[0]=='/') file++; + m = strlen(file); + path = emalloc(n + m + 2); + if(n>0) memmove(path, dir, n); + path[n++]='/'; + memmove(path+n, file, m+1); + return path; +} + +static char** +mkargv(word *a) +{ + char **argv = (char **)emalloc((count(a)+2)*sizeof(char *)); + char **argp = argv+1; + for(;a;a = a->next) *argp++=a->word; + *argp = 0; + return argv; +} + void execexec(void) { + char **argv; + word *path; + popword(); /* "exec" */ if(runq->argv->words==0){ Xerror1("empty argument list"); return; } + argv = mkargv(runq->argv->words); + Updenv(); doredir(runq->redir); - Execute(runq->argv->words, searchpath(runq->argv->words->word, "path")); - poplist(); + for(path = searchpath(argv[1], "path"); path; path = path->next){ + argv[0] = makepath(path->word, argv[1]); + Exec(argv); + } + setstatus(Errstr()); + pfln(err, srcfile(runq), runq->line); + pfmt(err, ": %s: %r\n", argv[1]); Xexit(); } void execfunc(var *func) { - word *starval; - popword(); - starval = runq->argv->words; - runq->argv->words = 0; - poplist(); - start(func->fn, func->pc, runq->local); - runq->local = newvar("*", 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 */ - if(chdir(word)<0) - return -1; - newwdir = 1; - return 1; + popword(); /* name */ + startfunc(func, Poplist(), runq->local, runq->redir); } void @@ -168,11 +215,8 @@ execcd(void) case 2: a = a->next; for(cdpath = searchpath(a->word, "cdpath"); cdpath; cdpath = cdpath->next){ - if(cdpath->word[0] != '\0') - dir = smprint("%s/%s", cdpath->word, a->word); - else - dir = estrdup(a->word); - if(dochdir(dir) >= 0){ + dir = makepath(cdpath->word, a->word); + if(Chdir(dir)>=0){ if(cdpath->word[0] != '\0' && strcmp(cdpath->word, ".") != 0) pfmt(err, "%s\n", dir); free(dir); @@ -186,8 +230,8 @@ execcd(void) break; case 1: a = vlook("home")->val; - if(count(a)>=1){ - if(dochdir(a->word)>=0) + if(a){ + if(Chdir(a->word)>=0) setstatus(""); else pfmt(err, "Can't cd %s: %r\n", a->word); @@ -233,8 +277,7 @@ execshift(void) star = vlook("*"); for(;n>0 && star->val;--n){ a = star->val->next; - free(star->val->word); - free(star->val); + free(Freeword(star->val)); star->val = a; star->changed = 1; } @@ -261,94 +304,98 @@ mapfd(int fd) } return fd; } -union code rdcmds[4]; void -execcmds(io *f) +execcmds(io *input, char *file, var *local, redir *redir) { - static int first = 1; + static union code rdcmds[5]; - if(first){ + if(rdcmds[0].i==0){ rdcmds[0].i = 1; - rdcmds[1].f = Xrdcmds; - rdcmds[2].f = Xreturn; - first = 0; + rdcmds[1].s="*rdcmds*"; + rdcmds[2].f = Xrdcmds; + rdcmds[3].f = Xreturn; + rdcmds[4].f = 0; } - start(rdcmds, 1, runq->local); - runq->cmdfd = f; - runq->iflast = 0; + + if(exitnext()) turfstack(local); + + start(rdcmds, 2, local, redir); + runq->lex = newlexer(input, file); } void execeval(void) { - char *cmdline; + char *cmds; int len; - if(count(runq->argv->words)<=1){ + io *f; + + popword(); /* "eval" */ + + if(runq->argv->words==0){ Xerror1("Usage: eval cmd ..."); return; } - eflagok = 1; - cmdline = list2str(runq->argv->words->next); - len = strlen(cmdline); - cmdline[len] = '\n'; + Xqw(); /* make into single word */ + cmds = Popword(); + len = strlen(cmds); + cmds[len++] = '\n'; poplist(); - execcmds(opencore(cmdline, len+1)); - free(cmdline); + + f = openiostr(); + pfln(f, srcfile(runq), runq->line); + pstr(f, " *eval*"); + + execcmds(openiocore((uchar*)cmds, len), closeiostr(f), runq->local, runq->redir); } -union code dotcmds[14]; void execdot(void) { - int iflag = 0; - int fd; - list *av; - thread *p = runq; - char *zero, *file; - word *path; - static int first = 1; + int fd, bflag, iflag, qflag; + word *path, *argv; + char *file; - 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(); /* "." */ - popword(); - if(p->argv->words && strcmp(p->argv->words->word, "-i")==0){ - iflag = 1; + bflag = iflag = qflag = 0; + while(runq->argv->words && runq->argv->words->word[0]=='-'){ + char *f = runq->argv->words->word+1; + if(*f == '-'){ + popword(); + break; + } + for(; *f; f++){ + switch(*f){ + case 'b': + bflag = 1; + continue; + case 'i': + iflag = 1; + continue; + case 'q': + qflag = 1; + continue; + } + goto Usage; + } popword(); } + /* get input file */ - if(p->argv->words==0){ - Xerror1("Usage: . [-i] file [arg ...]"); + if(runq->argv->words==0){ +Usage: + Xerror1("Usage: . [-biq] file [arg ...]"); return; } - zero = estrdup(p->argv->words->word); - popword(); + argv = Poplist(); + + file = 0; fd = -1; - for(path = searchpath(zero, "path"); path; path = path->next){ - if(path->word[0] != '\0') - file = smprint("%s/%s", path->word, zero); - else - file = estrdup(zero); - - fd = open(file, 0); - free(file); + for(path = searchpath(argv->word, "path"); path; path = path->next){ + file = makepath(path->word, argv->word); + fd = Open(file, 0); if(fd >= 0) break; if(strcmp(file, "/dev/stdin")==0){ /* for sun & ucb */ @@ -356,33 +403,31 @@ execdot(void) if(fd>=0) break; } + free(file); } if(fd<0){ - pfmt(err, "%s: ", zero); - setstatus("can't open"); - Xerror(".: can't open"); + if(!qflag) Xerror(".: can't open"); + freewords(argv); return; } - /* set up for a new command loop */ - start(dotcmds, 1, (struct var *)0); + execcmds(openiofd(fd), file, (var*)0, runq->redir); pushredir(RCLOSE, fd, 0); - runq->cmdfile = zero; - runq->cmdfd = openfd(fd); - runq->lexline = 1; + runq->lex->qflag = qflag; 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; - free(av); - /* push $0 value */ - pushlist(); - pushword(zero); - ndot++; + if(iflag || !bflag && flag['b']==0){ + runq->lex->peekc=EOF; + runq->lex->epilog=""; + } + + runq->local = newvar("*", runq->local); + runq->local->val = argv->next; + argv->next=0; + runq->local->changed = 1; + + runq->local = newvar("0", runq->local); + runq->local->val = argv; + runq->local->changed = 1; } void @@ -417,9 +462,8 @@ void execwhatis(void){ /* mildly wrong -- should fork before writing */ word *a, *b, *path; var *v; - struct builtin *bp; char *file; - struct io out[1]; + io *out; int found, sep; a = runq->argv->words->next; if(a==0){ @@ -427,10 +471,7 @@ execwhatis(void){ /* mildly wrong -- should fork before writing */ return; } setstatus(""); - out->fd = mapfd(1); - out->bufp = out->buf; - out->ebuf = &out->buf[NBUF]; - out->strp = 0; + out = openiofd(mapfd(1)); for(;a;a = a->next){ v = vlook(a->word); if(v->val){ @@ -443,7 +484,7 @@ execwhatis(void){ /* mildly wrong -- should fork before writing */ pfmt(out, "%c%q", sep, b->word); sep=' '; } - pfmt(out, ")\n"); + pstr(out, ")\n"); } found = 1; } @@ -453,19 +494,11 @@ execwhatis(void){ /* mildly wrong -- should fork before writing */ if(v->fn) pfmt(out, "fn %q %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 = path->next){ - if(path->word[0] != '\0') - file = smprint("%s/%s", - path->word, a->word); - else - file = estrdup(a->word); + if(builtinfunc(a->word)) + pfmt(out, "builtin %s\n", a->word); + else { + for(path = searchpath(a->word, "path"); path; path = path->next){ + file = makepath(path->word, a->word); if(Executable(file)){ pfmt(out, "%s\n", file); free(file); @@ -479,9 +512,10 @@ execwhatis(void){ /* mildly wrong -- should fork before writing */ } } } + flushio(out); } poplist(); - flush(err); + free(closeiostr(out)); /* don't close fd */ } void diff --git a/sys/src/cmd/rc/subr.c b/sys/src/cmd/rc/subr.c index 8ac58e7c9..723fa429d 100644 --- a/sys/src/cmd/rc/subr.c +++ b/sys/src/cmd/rc/subr.c @@ -9,7 +9,6 @@ emalloc(long n) void *p = malloc(n); if(p==0) panic("Can't malloc %d bytes", n); - setmalloctag(p, getcallerpc(&n)); return p; } @@ -19,44 +18,29 @@ erealloc(void *p, long n) p = realloc(p, n); if(p==0 && n!=0) panic("Can't realloc %d bytes\n", n); - setrealloctag(p, getcallerpc(&p)); return p; } char* estrdup(char *s) { - char *d; - int n; - - n = strlen(s)+1; - d = emalloc(n); + int n = strlen(s)+1; + char *d = emalloc(n); memmove(d, s, n); return d; } -extern int lastword, lastdol; - void -yyerror(char *m) +pfln(io *fd, char *file, int line) { - pfmt(err, "rc: "); - if(runq->cmdfile && !runq->iflag) - pfmt(err, "%s:%d: ", runq->cmdfile, runq->lineno); - else if(runq->cmdfile) - pfmt(err, "%s: ", runq->cmdfile); - else if(!runq->iflag) - pfmt(err, "line %d: ", runq->lineno); - if(tok[0] && tok[0]!='\n') - pfmt(err, "token %q: ", tok); - pfmt(err, "%s\n", m); - flush(err); - lastword = 0; - lastdol = 0; - while(lastc!='\n' && lastc!=EOF) advance(); - nerror++; - setvar("status", newword(m, (word *)0)); + if(file && line) + pfmt(fd, "%s:%d", file, line); + else if(file) + pstr(fd, file); + else + pstr(fd, argv0); } + char *bp; static void @@ -72,7 +56,7 @@ iacvt(int n) } void -inttoascii(char *s, long n) +inttoascii(char *s, int n) { bp = s; iacvt(n); @@ -82,9 +66,8 @@ inttoascii(char *s, long n) void panic(char *s, int n) { - pfmt(err, "rc: "); + pfmt(err, "%s: ", argv0); pfmt(err, s, n); pchr(err, '\n'); - flush(err); Abort(); } diff --git a/sys/src/cmd/rc/syn.y b/sys/src/cmd/rc/syn.y index 051c9e88e..7aeb7f571 100644 --- a/sys/src/cmd/rc/syn.y +++ b/sys/src/cmd/rc/syn.y @@ -36,7 +36,7 @@ paren: '(' body ')' {$$=tree1(PCMD, $2);} assign: first '=' word {$$=tree2('=', $1, $3);} epilog: {$$=0;} | redir epilog {$$=mung2($1, $1->child[0], $2);} -redir: REDIR word {$$=mung1($1, $1->rtype==HERE?heredoc($2):$2);} +redir: REDIR word {($$=mung1($1, $2))->str=$1->rtype==HERE?readhere($2,lex->input):0;} | DUP cmd: {$$=0;} | brace epilog {$$=epimung($1, $2);} @@ -54,7 +54,7 @@ cmd: {$$=0;} */ {$$=mung3($1, $3, $5 ? $5 : tree1(PAREN, $5), $8);} | FOR '(' word ')' {skipnl();} cmd - {$$=mung3($1, $3, (struct tree *)0, $6);} + {$$=mung3($1, $3, (tree*)0, $6);} | WHILE paren {skipnl();} cmd {$$=mung2($1, $2, $4);} | SWITCH word {skipnl();} brace @@ -74,19 +74,19 @@ simple: first | simple word {$$=tree2(ARGLIST, $1, $2);} | simple redir {$$=tree2(ARGLIST, $1, $2);} first: comword -| first '^' word {$$=tree2('^', $1, $3);} -word: keyword {lastword=1; $1->type=WORD;} +| first '^' word {$$=globprop(tree2('^', $1, $3));} +word: keyword {lex->lastword=1; $1->type=WORD;} | comword -| word '^' word {$$=tree2('^', $1, $3);} +| word '^' word {$$=globprop(tree2('^', $1, $3));} comword: '$' word {$$=tree1('$', $2);} | '$' word SUB words ')' {$$=tree2(SUB, $2, $4);} | '"' word {$$=tree1('"', $2);} | COUNT word {$$=tree1(COUNT, $2);} | WORD -| '`' brace {$$=tree2('`', (struct tree*)0, $2);} +| '`' brace {$$=tree2('`', (tree*)0, $2);} | '`' word brace {$$=tree2('`', $2, $3);} | '(' words ')' {$$=tree1(PAREN, $2);} | REDIR brace {$$=mung1($1, $2); $$->type=PIPEFD;} keyword: FOR|IN|WHILE|IF|NOT|TWIDDLE|BANG|SUBSHELL|SWITCH|FN -words: {$$=(struct tree*)0;} +words: {$$=(tree*)0;} | words word {$$=tree2(WORDS, $1, $2);} diff --git a/sys/src/cmd/rc/trap.c b/sys/src/cmd/rc/trap.c index fa7e35832..59f06d25b 100644 --- a/sys/src/cmd/rc/trap.c +++ b/sys/src/cmd/rc/trap.c @@ -8,21 +8,16 @@ void dotrap(void) { int i; - struct var *trapreq; - struct word *starval; + var *trapreq; + word *starval; starval = vlook("*")->val; while(ntrap) for(i = 0;i!=NSIG;i++) while(trap[i]){ --trap[i]; --ntrap; if(getpid()!=mypid) Exit(getstatus()); trapreq = vlook(Signame[i]); - if(trapreq->fn){ - start(trapreq->fn, trapreq->pc, (struct var *)0); - runq->local = newvar("*", runq->local); - runq->local->val = copywords(starval, (struct word *)0); - runq->local->changed = 1; - runq->redir = runq->startredir = 0; - } + if(trapreq->fn) + startfunc(trapreq, copywords(starval, (word*)0), (var*)0, (redir*)0); else if(i==SIGINT || i==SIGQUIT){ /* * run the stack down until we uncover the diff --git a/sys/src/cmd/rc/tree.c b/sys/src/cmd/rc/tree.c index ce9fd152a..da7157312 100644 --- a/sys/src/cmd/rc/tree.c +++ b/sys/src/cmd/rc/tree.c @@ -1,22 +1,30 @@ #include "rc.h" -#include "exec.h" #include "io.h" #include "fns.h" -tree *treenodes; + /* * create and clear a new tree node, and add it * to the node list. */ +static tree *treefree, *treenodes; tree* newtree(void) { - tree *t = new(tree); + tree *t; + + t = treefree; + if(t==0) + t = new(tree); + else + treefree = t->next; + t->quoted = 0; + t->glob = 0; t->iskw = 0; t->str = 0; t->child[0] = t->child[1] = t->child[2] = 0; + t->line = lex->line; t->next = treenodes; - t->line = runq->lexline; treenodes = t; return t; } @@ -24,12 +32,21 @@ newtree(void) void freenodes(void) { - tree *t, *u; - for(t = treenodes;t;t = u){ - u = t->next; - if(t->str) + tree *t; + + t = treenodes; + while(t){ + if(t->str){ free(t->str); - free(t); + t->str = 0; + } + t->child[0] = t->child[1] = t->child[2] = 0; + if(t->next==0){ + t->next = treefree; + treefree = treenodes; + break; + } + t = t->next; } treenodes = 0; } @@ -61,6 +78,13 @@ tree3(int type, tree *c0, tree *c1, tree *c2) t->child[0] = c0; t->child[1] = c1; t->child[2] = c2; + + if(c0) + t->line = c0->line; + else if(c1) + t->line = c1->line; + else if(c2) + t->line = c2->line; return t; } @@ -98,22 +122,18 @@ epimung(tree *comp, tree *epi) p->child[1] = comp; return epi; } + /* * Add a SIMPLE node at the root of t and percolate all the redirections * up to the root. */ - tree* simplemung(tree *t) { tree *u; - struct io *s; t = tree1(SIMPLE, t); - s = openstr(); - pfmt(s, "%t", t); - t->str = estrdup((char *)s->strp); - closeio(s); + t->str = fnstr(t); for(u = t->child[0];u->type==ARGLIST;u = u->child[0]){ if(u->child[1]->type==DUP || u->child[1]->type==REDIR){ @@ -125,25 +145,36 @@ simplemung(tree *t) return t; } +char* +fnstr(tree *t) +{ + io *f = openiostr(); + pfmt(f, "%t", t); + return closeiostr(f); +} + +tree* +globprop(tree *t) +{ + tree *c0 = t->child[0]; + tree *c1 = t->child[1]; + if(t->glob==0){ + if(c0->glob || c1->glob){ + if(c0->glob) + c0->glob=-1; + if(c1->glob) + c1->glob=-1; + t->glob=1; + } + } + return t; +} + tree* token(char *str, int type) { tree *t = newtree(); - + t->str = estrdup(str); t->type = type; - t->str = strdup(str); return t; } - -void -freetree(tree *p) -{ - if(p==0) - return; - freetree(p->child[0]); - freetree(p->child[1]); - freetree(p->child[2]); - if(p->str) - free(p->str); - free(p); -} diff --git a/sys/src/cmd/rc/var.c b/sys/src/cmd/rc/var.c index f6b8dbb09..586ebe75b 100644 --- a/sys/src/cmd/rc/var.c +++ b/sys/src/cmd/rc/var.c @@ -57,6 +57,20 @@ klook(char *name) return t; } +var* +newvar(char *name, var *next) +{ + int n = strlen(name)+1; + var *v = emalloc(sizeof(var)+n); + memmove(v->name, name, n); + v->next = next; + v->val = 0; + v->fn = 0; + v->changed = 0; + v->fnchanged = 0; + return v; +} + var* gvlook(char *name) { @@ -79,8 +93,15 @@ vlook(char *name) void setvar(char *name, word *val) { - struct var *v = vlook(name); + var *v = vlook(name); freewords(v->val); v->val = val; v->changed = 1; } + +void +freevar(var *v) +{ + freewords(v->val); + free(v); +}