From b90036a062ca330ac5f667cd1ee503686cbe0b80 Mon Sep 17 00:00:00 2001 From: cinap_lenrek Date: Fri, 31 Dec 2021 15:27:10 +0000 Subject: [PATCH] rc: fix everything Untangle the lexer and interpreter thread state. Fix the file and line number error reporting, getting rid of Xsrcfile instruction, as the whole code block can only come from a single file, stuff the source file in slot[1] of the code block instead. Remove limitations for globber (path element limits) and be more intelligent about handling globbing by inserting Xglob instruction only when needed and not run it over every Xsimple argument list. Remove fragile ndot magic and make it explicit by adding the -q flag to . builtin command. Add -b flag for full compilation. Make exitnext() smart, so we can speculate thru rcmain and avoid the fork(). Get rid of all print(2) format functions and use io instead. Improve the io library, adding rstr() to handle tokenization, which allows us to look ahead in the already read buffer for the terminators, avoiding alot of string copies. Auto indent pcmd(), to make line number reporting more usefull. Implement here documents properly, so they can work everywhere. --- sys/man/1/rc | 22 +- sys/src/cmd/rc/code.c | 168 ++++++---- sys/src/cmd/rc/exec.c | 651 ++++++++++++++++++++------------------ sys/src/cmd/rc/exec.h | 51 +-- sys/src/cmd/rc/fns.h | 44 +-- sys/src/cmd/rc/glob.c | 126 ++++---- sys/src/cmd/rc/havefork.c | 169 +++++----- sys/src/cmd/rc/here.c | 106 ++----- sys/src/cmd/rc/io.c | 235 ++++++++------ sys/src/cmd/rc/io.h | 16 +- sys/src/cmd/rc/lex.c | 232 ++++++++------ sys/src/cmd/rc/pcmd.c | 33 +- sys/src/cmd/rc/pfnc.c | 34 +- sys/src/cmd/rc/plan9.c | 441 ++++++++++---------------- sys/src/cmd/rc/rc.h | 80 +++-- sys/src/cmd/rc/simple.c | 336 +++++++++++--------- sys/src/cmd/rc/subr.c | 41 +-- sys/src/cmd/rc/syn.y | 14 +- sys/src/cmd/rc/trap.c | 13 +- sys/src/cmd/rc/tree.c | 91 ++++-- sys/src/cmd/rc/var.c | 23 +- 21 files changed, 1527 insertions(+), 1399 deletions(-) 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); +}