ref: 7717051e3ce062fbdb8415e4befa5205d25e80bb
parent: 81f867f4fb3d7fd495be3282a01d2e4a9b1a56fd
author: cinap_lenrek <[email protected]>
date: Sun May 15 15:10:37 EDT 2016
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().
--- a/sys/src/cmd/rc/code.c
+++ b/sys/src/cmd/rc/code.c
@@ -274,8 +274,19 @@
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 @@
|| 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);
--- a/sys/src/cmd/rc/exec.c
+++ b/sys/src/cmd/rc/exec.c
@@ -33,14 +33,18 @@
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 @@
{
return Newword(estrdup(wd), next);
}
-void
+word*
pushword(char *wd)
{
- Pushword(estrdup(wd));
+ return Pushword(estrdup(wd));
}
void
@@ -220,6 +224,7 @@
* 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 @@
}
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
void
Xglob(void)
{
- globlist();
+ globlist(runq->argv->words);
}
--- a/sys/src/cmd/rc/exec.h
+++ b/sys/src/cmd/rc/exec.h
@@ -7,7 +7,7 @@
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 @@
struct word{
char *word;
word *next;
+ int glob; /* Globsize(word) */
};
struct list{
word *words;
--- a/sys/src/cmd/rc/fns.h
+++ b/sys/src/cmd/rc/fns.h
@@ -30,19 +30,18 @@
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 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*);
--- a/sys/src/cmd/rc/glob.c
+++ b/sys/src/cmd/rc/glob.c
@@ -1,16 +1,15 @@
#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)
@@ -17,15 +16,16 @@
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 @@
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 @@
/* 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,12 +141,12 @@
* 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);
}
/*
@@ -145,38 +153,31 @@
* 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){
@@ -234,28 +235,4 @@
}
}
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;
- }
}
--- a/sys/src/cmd/rc/lex.c
+++ b/sys/src/cmd/rc/lex.c
@@ -366,8 +366,7 @@
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();
--- a/sys/src/cmd/rc/pfnc.c
+++ b/sys/src/cmd/rc/pfnc.c
@@ -38,6 +38,7 @@
Xdelfn, "Xdelfn",
Xpipe, "Xpipe",
Xpipewait, "Xpipewait",
+ Xpopredir, "Xpopredir",
Xrdcmds, "Xrdcmds",
(void (*)(void))Xerror, "Xerror",
Xbackq, "Xbackq",
@@ -46,6 +47,7 @@
Xdelhere, "Xdelhere",
Xfor, "Xfor",
Xglob, "Xglob",
+ Xglobs, "Xglobs",
Xrdfn, "Xrdfn",
Xsimple, "Xsimple",
Xrdfn, "Xrdfn",
--- a/sys/src/cmd/rc/simple.c
+++ b/sys/src/cmd/rc/simple.c
@@ -20,18 +20,17 @@
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 @@
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 @@
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 @@
}
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 @@
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 @@
/* free caller's copy of $* */
av = p->argv;
p->argv = av->next;
- efree((char *)av);
+ efree(av);
/* push $0 value */
pushlist();
pushword(zero);
--- a/sys/src/cmd/rc/tree.c
+++ b/sys/src/cmd/rc/tree.c
@@ -28,7 +28,7 @@
u = t->next;
if(t->str)
efree(t->str);
- efree((char *)t);
+ efree(t);
}
treenodes = 0;
}
@@ -144,5 +144,5 @@
freetree(p->child[2]);
if(p->str)
efree(p->str);
- efree((char *)p);
+ efree(p);
}
--- a/sys/src/cmd/rc/unix.c
+++ b/sys/src/cmd/rc/unix.c
@@ -277,8 +277,8 @@
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)
@@ -431,6 +431,14 @@
}
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;
--- a/sys/src/cmd/rc/win32.c
+++ b/sys/src/cmd/rc/win32.c
@@ -301,7 +301,7 @@
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 */