shithub: riscv

Download patch

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 */