diff options
author | cinap_lenrek <cinap_lenrek@felloff.net> | 2016-05-15 19:10:37 +0200 |
---|---|---|
committer | cinap_lenrek <cinap_lenrek@felloff.net> | 2016-05-15 19:10:37 +0200 |
commit | 7717051e3ce062fbdb8415e4befa5205d25e80bb (patch) | |
tree | 029df0be93da100936c772c5f6a83f0874930cef /sys/src/cmd | |
parent | 81f867f4fb3d7fd495be3282a01d2e4a9b1a56fd (diff) |
rc: fix inband globbing bugs, cleanup
add glob information to the word structure so we wont accidently
deglob quoted strings containing the GLOB. we store Globsize(word)
in in word->glob which avoids recalculating that values and the
check if a word should be globbed quick.
globlist() now substitutes the word inplace avoiding the copying
when all words are literals and avoids recursion.
minor cleanups: use list2str() in execeval(), move octal() to
unix.c, remove the (char*) casts to efree().
Diffstat (limited to 'sys/src/cmd')
-rw-r--r-- | sys/src/cmd/rc/code.c | 16 | ||||
-rw-r--r-- | sys/src/cmd/rc/exec.c | 65 | ||||
-rw-r--r-- | sys/src/cmd/rc/exec.h | 3 | ||||
-rw-r--r-- | sys/src/cmd/rc/fns.h | 9 | ||||
-rw-r--r-- | sys/src/cmd/rc/glob.c | 183 | ||||
-rw-r--r-- | sys/src/cmd/rc/lex.c | 3 | ||||
-rw-r--r-- | sys/src/cmd/rc/pfnc.c | 2 | ||||
-rw-r--r-- | sys/src/cmd/rc/simple.c | 43 | ||||
-rw-r--r-- | sys/src/cmd/rc/tree.c | 4 | ||||
-rw-r--r-- | sys/src/cmd/rc/unix.c | 12 | ||||
-rw-r--r-- | sys/src/cmd/rc/win32.c | 2 |
11 files changed, 169 insertions, 173 deletions
diff --git a/sys/src/cmd/rc/code.c b/sys/src/cmd/rc/code.c index 7d1abbb3a..8d64500ae 100644 --- a/sys/src/cmd/rc/code.c +++ b/sys/src/cmd/rc/code.c @@ -274,8 +274,19 @@ outcode(tree *t, int eflag) emitf(Xunlocal); break; case WORD: - emitf(Xword); - emits(estrdup(t->str)); + 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))); + } + } break; case DUP: if(t->rtype==DUPFD){ @@ -473,6 +484,7 @@ 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) efree(p[1].s), p+=2; else if(p->f==Xword || p->f==Xdelhere) efree((++p)->s); else if(p->f==Xfn){ efree(p[2].s); diff --git a/sys/src/cmd/rc/exec.c b/sys/src/cmd/rc/exec.c index a037d1df4..bf40aa7f2 100644 --- a/sys/src/cmd/rc/exec.c +++ b/sys/src/cmd/rc/exec.c @@ -33,14 +33,18 @@ Newword(char *wd, word *next) word *p = new(word); p->word = wd; p->next = next; + p->glob = 0; return p; } -void +word* Pushword(char *wd) { + word *w; if(runq->argv==0) panic("pushword but no argv!", 0); - runq->argv->words = Newword(wd, runq->argv->words); + w = Newword(wd, runq->argv->words); + runq->argv->words = w; + return w; } word* @@ -48,10 +52,10 @@ newword(char *wd, word *next) { return Newword(estrdup(wd), next); } -void +word* pushword(char *wd) { - Pushword(estrdup(wd)); + return Pushword(estrdup(wd)); } void @@ -220,6 +224,7 @@ main(int argc, char *argv[]) * Xfalse{...} execute {} if false * Xfn(name){... Xreturn} define function * Xfor(var, list){... Xreturn} for loop + * Xglobs[string globsize] push globbing string * Xjump[addr] goto * Xlocal(name, val) create local variable, assign value * Xmark mark stack @@ -472,6 +477,13 @@ Xword(void) } void +Xglobs(void) +{ + word *w = pushword(runq->code[runq->pc++].s); + w->glob = runq->code[runq->pc++].i; +} + +void Xwrite(void) { char *file; @@ -566,6 +578,8 @@ conclist(word *lp, word *rp, word *tail) p = Newword(emalloc(ln+rn+1), (word *)0); Memcpy(p->word, lp->word, ln); Memcpy(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; @@ -599,6 +613,17 @@ 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) { @@ -607,12 +632,10 @@ Xassign(void) Xerror1("variable name not singleton!"); return; } - deglob(runq->argv->words->word); - v = vlook(runq->argv->words->word); + v = vlook(Str(runq->argv->words)); poplist(); - globlist(); freewords(v->val); - v->val = runq->argv->words; + v->val = globlist(runq->argv->words); v->changed = 1; runq->argv->words = 0; poplist(); @@ -641,8 +664,7 @@ Xdol(void) Xerror1("variable name not singleton!"); return; } - s = runq->argv->words->word; - deglob(s); + s = Str(runq->argv->words); n = 0; for(t = s;'0'<=*t && *t<='9';t++) n = n*10+*t-'0'; a = runq->argv->next->words; @@ -668,8 +690,7 @@ Xqdol(void) Xerror1("variable name not singleton!"); return; } - s = runq->argv->words->word; - deglob(s); + s = Str(runq->argv->words); a = vlook(s)->val; poplist(); Pushword(list2str(a)); @@ -699,8 +720,7 @@ subwords(word *val, int len, word *sub, word *a) if(!sub) return a; a = subwords(val, len, sub->next, a); - s = sub->word; - deglob(s); + s = Str(sub); m = 0; n = 0; while('0'<=*s && *s<='9') @@ -732,8 +752,7 @@ Xsub(void) Xerror1("variable name not singleton!"); return; } - s = runq->argv->next->words->word; - deglob(s); + s = Str(runq->argv->next->words); a = runq->argv->next->next->words; v = vlook(s)->val; a = subwords(v, count(v), runq->argv->words, a); @@ -753,8 +772,7 @@ Xcount(void) Xerror1("variable name not singleton!"); return; } - s = runq->argv->words->word; - deglob(s); + s = Str(runq->argv->words); n = 0; for(t = s;'0'<=*t && *t<='9';t++) n = n*10+*t-'0'; if(n==0 || *t){ @@ -776,11 +794,9 @@ Xlocal(void) Xerror1("variable name must be singleton\n"); return; } - deglob(runq->argv->words->word); - runq->local = newvar(runq->argv->words->word, runq->local); + runq->local = newvar(Str(runq->argv->words), runq->local); poplist(); - globlist(); - runq->local->val = runq->argv->words; + runq->local->val = globlist(runq->argv->words); runq->local->changed = 1; runq->argv->words = 0; poplist(); @@ -819,8 +835,7 @@ Xfn(void) word *a; int end; end = runq->code[runq->pc].i; - globlist(); - for(a = runq->argv->words;a;a = a->next){ + for(a = globlist(runq->argv->words);a;a = a->next){ v = gvlook(a->word); if(v->fn) codefree(v->fn); @@ -989,5 +1004,5 @@ Xfor(void) void Xglob(void) { - globlist(); + globlist(runq->argv->words); } diff --git a/sys/src/cmd/rc/exec.h b/sys/src/cmd/rc/exec.h index 06d2991f5..f7fefed17 100644 --- a/sys/src/cmd/rc/exec.h +++ b/sys/src/cmd/rc/exec.h @@ -7,7 +7,7 @@ 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); extern void Xrdfn(void), Xunredir(void), Xstar(void), Xreturn(void), Xsubshell(void); -extern void Xtrue(void), Xword(void), Xwrite(void), Xpipefd(void), Xcase(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 Xrdcmds(void), Xwastrue(void), Xif(void), Xifnot(void), Xpipewait(void); extern void Xdelhere(void), Xpopredir(void), Xsub(void), Xeflag(void), Xsettrue(void); @@ -20,6 +20,7 @@ extern void Xerror1(char*); struct word{ char *word; word *next; + int glob; /* Globsize(word) */ }; struct list{ word *words; diff --git a/sys/src/cmd/rc/fns.h b/sys/src/cmd/rc/fns.h index 1559d9176..5d5be42e8 100644 --- a/sys/src/cmd/rc/fns.h +++ b/sys/src/cmd/rc/fns.h @@ -30,19 +30,18 @@ void codefree(code*); int compile(tree*); char * list2str(word*); int count(word*); -void deglob(void*); +char* deglob(char*); void delwaitpid(int); void dotrap(void); void freenodes(void); void freewords(word*); -void globlist(void); +word* globlist(word*); int havewaitpid(int); int idchr(int); void inttoascii(char*, long); void kinit(void); int mapfd(int); -int match(void*, void*, int); -int matchfn(void*, void*); +int match(char*, char*, int); char** mkargv(word*); void clearwaitpids(void); void panic(char*, int); @@ -52,7 +51,7 @@ void popword(void); void pprompt(void); void pushlist(void); void pushredir(int, int, int); -void pushword(char*); +word* pushword(char*); void readhere(void); word* searchpath(char*); void setstatus(char*); diff --git a/sys/src/cmd/rc/glob.c b/sys/src/cmd/rc/glob.c index 90513243d..10dff0421 100644 --- a/sys/src/cmd/rc/glob.c +++ b/sys/src/cmd/rc/glob.c @@ -1,31 +1,31 @@ #include "rc.h" #include "exec.h" #include "fns.h" -char *globname; -struct word *globv; + /* * delete all the GLOB marks from s, in place */ -void -deglob(void *as) +char* +deglob(char *s) { - char *s = as; + char *b = s; char *t = s; do{ if(*t==GLOB) t++; *s++=*t; }while(*t++); + return b; } -int -globcmp(const void *s, const void *t) +static int +globcmp(void *s, void *t) { return strcmp(*(char**)s, *(char**)t); } -void +static void globsort(word *left, word *right) { char **list; @@ -38,21 +38,31 @@ globsort(word *left, word *right) for(a = left,n = 0;a!=right;a = a->next,n++) a->word = list[n]; efree((char *)list); } + /* - * Push names prefixed by globname and suffixed by a match of p onto the astack. - * namep points to the end of the prefix in globname. + * Does the string s match the pattern p + * . and .. are only matched by patterns starting with . + * * matches any sequence of characters + * ? matches any single character + * [...] matches the enclosed list of characters */ -void -globdir(uchar *p, uchar *namep) +static int +matchfn(char *s, char *p) { - uchar *t, *newp; + if(s[0]=='.' && (s[1]=='\0' || s[1]=='.' && s[2]=='\0') && p[0]!='.') + return 0; + return match(s, p, '/'); +} + +static word* +globdir(word *list, char *p, char *name, char *namep) +{ + char *t, *newp; int f; /* scan the pattern looking for a component with a metacharacter in it */ - if(*p=='\0'){ - globv = newword(globname, globv); - return; - } + if(*p=='\0') + return newword(name, list); t = namep; newp = p; while(*newp){ @@ -67,65 +77,63 @@ globdir(uchar *p, uchar *namep) /* If we ran out of pattern, append the name if accessible */ if(*newp=='\0'){ *t='\0'; - if(access(globname, 0)==0) - globv = newword(globname, globv); - return; + if(access(name, 0)==0) + list = newword(name, list); + return list; } /* read the directory and recur for any entry that matches */ *namep='\0'; - if((f = Opendir(globname[0]?globname:"."))<0) return; - while(*newp!='/' && *newp!='\0') newp++; - while(Readdir(f, namep, *newp=='/')){ - if(matchfn(namep, p)){ - for(t = namep;*t;t++); - globdir(newp, t); + 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); } - Closedir(f); + return list; } + /* - * Push all file names matched by p on the current thread's stack. - * If there are no matches, the list consists of p. + * Subsitute a word with its glob in place. */ -void -glob(void *ap) +static void +globword(word *w) { - uchar *p = ap; - word *svglobv = globv; - int globlen = Globsize(ap); + word *left, *right; + char *name; - if(!globlen){ - deglob(p); - globv = newword((char *)p, globv); + if(w->glob == 0) return; + name = emalloc(w->glob); + memset(name, 0, w->glob); + right = w->next; + left = globdir(right, w->word, name, name); + efree(name); + if(left == right) { + deglob(w->word); + w->glob = 0; + } else { + efree(w->word); + globsort(left, right); + *w = *left; + efree(left); } - globname = emalloc(globlen); - memset(globname, 0, globlen); - globdir(p, (uchar *)globname); - efree(globname); - if(svglobv==globv){ - deglob(p); - globv = newword((char *)p, globv); - } - else - globsort(globv, svglobv); } -/* - * Do p and q point at equal utf codes - */ -int -equtf(uchar *p, uchar *q) +word* +globlist(word *l) { - Rune pr, qr; - - if(*p!=*q) - return 0; + word *p, *q; - chartorune(&pr, (char*)p); - chartorune(&qr, (char*)q); - return pr == qr; + for(p=l;p;p=q){ + q = p->next; + globword(p); + } + return l; } /* @@ -133,50 +141,43 @@ equtf(uchar *p, uchar *q) * not jumping past nuls in broken utf codes! */ -uchar* -nextutf(uchar *p) +static char* +nextutf(char *p) { Rune dummy; - return p + chartorune(&dummy, (char*)p); + return p + chartorune(&dummy, p); } /* * Convert the utf code at *p to a unicode value */ -int -unicode(uchar *p) +static int +unicode(char *p) { Rune r; - chartorune(&r, (char*)p); + chartorune(&r, p); return r; } /* - * Does the string s match the pattern p - * . and .. are only matched by patterns starting with . - * * matches any sequence of characters - * ? matches any single character - * [...] matches the enclosed list of characters + * Do p and q point at equal utf codes */ -int -matchfn(void *as, void *ap) +static int +equtf(char *p, char *q) { - uchar *s = as, *p = ap; - - if(s[0]=='.' && (s[1]=='\0' || s[1]=='.' && s[2]=='\0') && p[0]!='.') - return 0; - return match(s, p, '/'); + if(*p!=*q) + return 0; + return unicode(p) == unicode(q); } int -match(void *as, void *ap, int stop) +match(char *s, char *p, int stop) { int compl, hit, lo, hi, t, c; - uchar *s = as, *p = ap; for(; *p!=stop && *p!='\0'; s = nextutf(s), p = nextutf(p)){ if(*p!=GLOB){ @@ -235,27 +236,3 @@ match(void *as, void *ap, int stop) } return *s=='\0'; } - -void -globlist1(word *gl) -{ - if(gl){ - globlist1(gl->next); - glob(gl->word); - } -} - -void -globlist(void) -{ - word *a; - globv = 0; - globlist1(runq->argv->words); - poplist(); - pushlist(); - if(globv){ - for(a = globv;a->next;a = a->next); - a->next = runq->argv->words; - runq->argv->words = globv; - } -} diff --git a/sys/src/cmd/rc/lex.c b/sys/src/cmd/rc/lex.c index fecd0ec64..fa364f18d 100644 --- a/sys/src/cmd/rc/lex.c +++ b/sys/src/cmd/rc/lex.c @@ -366,8 +366,7 @@ yylex(void) return c; } for(;;){ - /* next line should have (char)c==GLOB, but ken's compiler is broken */ - if(c=='*' || c=='[' || c=='?' || c==(unsigned char)GLOB) + if(c=='*' || c=='[' || c=='?' || c==GLOB) w = addtok(w, GLOB); w = addutf(w, c); c = nextc(); diff --git a/sys/src/cmd/rc/pfnc.c b/sys/src/cmd/rc/pfnc.c index 3f2b4c98a..f1b21ca99 100644 --- a/sys/src/cmd/rc/pfnc.c +++ b/sys/src/cmd/rc/pfnc.c @@ -38,6 +38,7 @@ struct{ Xdelfn, "Xdelfn", Xpipe, "Xpipe", Xpipewait, "Xpipewait", + Xpopredir, "Xpopredir", Xrdcmds, "Xrdcmds", (void (*)(void))Xerror, "Xerror", Xbackq, "Xbackq", @@ -46,6 +47,7 @@ struct{ Xdelhere, "Xdelhere", Xfor, "Xfor", Xglob, "Xglob", + Xglobs, "Xglobs", Xrdfn, "Xrdfn", Xsimple, "Xsimple", Xrdfn, "Xrdfn", diff --git a/sys/src/cmd/rc/simple.c b/sys/src/cmd/rc/simple.c index 59e8483e6..89c8699c1 100644 --- a/sys/src/cmd/rc/simple.c +++ b/sys/src/cmd/rc/simple.c @@ -20,18 +20,17 @@ void Xsimple(void) { word *a; - thread *p = runq; var *v; struct builtin *bp; int pid; - globlist(); - a = runq->argv->words; + + a = globlist(runq->argv->words); if(a==0){ Xerror1("empty argument list"); return; } if(flag['x']) - pfmt(err, "%v\n", p->argv->words); /* wrong, should do redirs */ + pfmt(err, "%v\n", a); /* wrong, should do redirs */ v = gvlook(a->word); if(v->fn) execfunc(v); @@ -140,9 +139,9 @@ int dochdir(char *word) { /* report to /dev/wdir if it exists and we're interactive */ - static int wdirfd = -2; if(chdir(word)<0) return -1; if(flag['i']!=0){ + static int wdirfd = -2; if(wdirfd==-2) /* try only once */ wdirfd = open("/dev/wdir", OWRITE|OCEXEC); if(wdirfd>=0) @@ -234,10 +233,10 @@ execshift(void) break; } star = vlook("*"); - for(;n && star->val;--n){ + for(;star->val;--n){ a = star->val->next; efree(star->val->word); - efree((char *)star->val); + efree(star->val); star->val = a; star->changed = 1; } @@ -246,15 +245,6 @@ execshift(void) } int -octal(char *s) -{ - int n = 0; - while(*s==' ' || *s=='\t' || *s=='\n') s++; - while('0'<=*s && *s<='7') n = n*8+*s++-'0'; - return n; -} - -int mapfd(int fd) { redir *rp; @@ -293,25 +283,18 @@ execcmds(io *f) void execeval(void) { - char *cmdline, *s, *t; - int len = 0; - word *ap; + char *cmdline; + int len; if(count(runq->argv->words)<=1){ Xerror1("Usage: eval cmd ..."); return; } eflagok = 1; - for(ap = runq->argv->words->next;ap;ap = ap->next) - len+=1+strlen(ap->word); - cmdline = emalloc(len); - s = cmdline; - for(ap = runq->argv->words->next;ap;ap = ap->next){ - for(t = ap->word;*t;) *s++=*t++; - *s++=' '; - } - s[-1]='\n'; + cmdline = list2str(runq->argv->words->next); + len = strlen(cmdline); + cmdline[len] = '\n'; poplist(); - execcmds(opencore(cmdline, len)); + execcmds(opencore(cmdline, len+1)); efree(cmdline); } union code dotcmds[14]; @@ -393,7 +376,7 @@ execdot(void) /* free caller's copy of $* */ av = p->argv; p->argv = av->next; - efree((char *)av); + efree(av); /* push $0 value */ pushlist(); pushword(zero); diff --git a/sys/src/cmd/rc/tree.c b/sys/src/cmd/rc/tree.c index f7d0b4cf4..9481f0f7b 100644 --- a/sys/src/cmd/rc/tree.c +++ b/sys/src/cmd/rc/tree.c @@ -28,7 +28,7 @@ freenodes(void) u = t->next; if(t->str) efree(t->str); - efree((char *)t); + efree(t); } treenodes = 0; } @@ -144,5 +144,5 @@ freetree(tree *p) freetree(p->child[2]); if(p->str) efree(p->str); - efree((char *)p); + efree(p); } diff --git a/sys/src/cmd/rc/unix.c b/sys/src/cmd/rc/unix.c index 8eaaa09f8..e844bc5cc 100644 --- a/sys/src/cmd/rc/unix.c +++ b/sys/src/cmd/rc/unix.c @@ -277,8 +277,8 @@ register struct word *args, *path; Bad: setstatus(msg); pfmt(err, "%s: %s\n", argv[1], msg); - efree((char *)env); - efree((char *)argv); + efree(env); + efree(argv); } #define NDIR 14 /* should get this from param.h */ Globsize(p) @@ -432,6 +432,14 @@ Isatty(fd){ Abort(){ abort(); } +static int +octal(char *s) +{ + int n = 0; + while(*s==' ' || *s=='\t' || *s=='\n') s++; + while('0'<=*s && *s<='7') n = n*8+*s++-'0'; + return n; +} execumask(){ /* wrong -- should fork before writing */ int m; struct io out[1]; diff --git a/sys/src/cmd/rc/win32.c b/sys/src/cmd/rc/win32.c index 9b3cc5749..2166f7ac8 100644 --- a/sys/src/cmd/rc/win32.c +++ b/sys/src/cmd/rc/win32.c @@ -301,7 +301,7 @@ Execute(word *args, word *path) rerrstr(file, sizeof file); setstatus(file); pfmt(err, "%s: %s\n", argv[1], file); - efree((char *)argv); + efree(argv); } #define NDIR 256 /* shoud be a better way */ |