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().
This commit is contained in:
cinap_lenrek 2016-05-15 19:10:37 +02:00
parent 81f867f4fb
commit 7717051e3c
11 changed files with 169 additions and 173 deletions

View file

@ -274,8 +274,19 @@ outcode(tree *t, int eflag)
emitf(Xunlocal); emitf(Xunlocal);
break; break;
case WORD: case WORD:
emitf(Xword); if(t->quoted){
emits(estrdup(t->str)); 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; break;
case DUP: case DUP:
if(t->rtype==DUPFD){ if(t->rtype==DUPFD){
@ -473,6 +484,7 @@ codefree(code *cp)
|| p->f==Xsubshell || p->f==Xtrue) p++; || p->f==Xsubshell || p->f==Xtrue) p++;
else if(p->f==Xdup || p->f==Xpipefd) p+=2; else if(p->f==Xdup || p->f==Xpipefd) p+=2;
else if(p->f==Xpipe) p+=4; 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==Xword || p->f==Xdelhere) efree((++p)->s);
else if(p->f==Xfn){ else if(p->f==Xfn){
efree(p[2].s); efree(p[2].s);

View file

@ -33,14 +33,18 @@ Newword(char *wd, word *next)
word *p = new(word); word *p = new(word);
p->word = wd; p->word = wd;
p->next = next; p->next = next;
p->glob = 0;
return p; return p;
} }
void word*
Pushword(char *wd) Pushword(char *wd)
{ {
word *w;
if(runq->argv==0) if(runq->argv==0)
panic("pushword but no 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* word*
@ -48,10 +52,10 @@ newword(char *wd, word *next)
{ {
return Newword(estrdup(wd), next); return Newword(estrdup(wd), next);
} }
void word*
pushword(char *wd) pushword(char *wd)
{ {
Pushword(estrdup(wd)); return Pushword(estrdup(wd));
} }
void void
@ -220,6 +224,7 @@ main(int argc, char *argv[])
* Xfalse{...} execute {} if false * Xfalse{...} execute {} if false
* Xfn(name){... Xreturn} define function * Xfn(name){... Xreturn} define function
* Xfor(var, list){... Xreturn} for loop * Xfor(var, list){... Xreturn} for loop
* Xglobs[string globsize] push globbing string
* Xjump[addr] goto * Xjump[addr] goto
* Xlocal(name, val) create local variable, assign value * Xlocal(name, val) create local variable, assign value
* Xmark mark stack * Xmark mark stack
@ -471,6 +476,13 @@ Xword(void)
pushword(runq->code[runq->pc++].s); 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 void
Xwrite(void) Xwrite(void)
{ {
@ -566,6 +578,8 @@ conclist(word *lp, word *rp, word *tail)
p = Newword(emalloc(ln+rn+1), (word *)0); p = Newword(emalloc(ln+rn+1), (word *)0);
Memcpy(p->word, lp->word, ln); Memcpy(p->word, lp->word, ln);
Memcpy(p->word+ln, rp->word, rn+1); Memcpy(p->word+ln, rp->word, rn+1);
if(lp->glob || rp->glob)
p->glob = Globsize(p->word);
*end = p, end = &p->next; *end = p, end = &p->next;
if(lp->next == 0 && rp->next == 0) if(lp->next == 0 && rp->next == 0)
break; break;
@ -599,6 +613,17 @@ Xconc(void)
runq->argv->words = vp; runq->argv->words = vp;
} }
char*
Str(word *a)
{
char *s = a->word;
if(a->glob){
a->glob = 0;
deglob(s);
}
return s;
}
void void
Xassign(void) Xassign(void)
{ {
@ -607,12 +632,10 @@ Xassign(void)
Xerror1("variable name not singleton!"); Xerror1("variable name not singleton!");
return; return;
} }
deglob(runq->argv->words->word); v = vlook(Str(runq->argv->words));
v = vlook(runq->argv->words->word);
poplist(); poplist();
globlist();
freewords(v->val); freewords(v->val);
v->val = runq->argv->words; v->val = globlist(runq->argv->words);
v->changed = 1; v->changed = 1;
runq->argv->words = 0; runq->argv->words = 0;
poplist(); poplist();
@ -641,8 +664,7 @@ Xdol(void)
Xerror1("variable name not singleton!"); Xerror1("variable name not singleton!");
return; return;
} }
s = runq->argv->words->word; s = Str(runq->argv->words);
deglob(s);
n = 0; n = 0;
for(t = s;'0'<=*t && *t<='9';t++) n = n*10+*t-'0'; for(t = s;'0'<=*t && *t<='9';t++) n = n*10+*t-'0';
a = runq->argv->next->words; a = runq->argv->next->words;
@ -668,8 +690,7 @@ Xqdol(void)
Xerror1("variable name not singleton!"); Xerror1("variable name not singleton!");
return; return;
} }
s = runq->argv->words->word; s = Str(runq->argv->words);
deglob(s);
a = vlook(s)->val; a = vlook(s)->val;
poplist(); poplist();
Pushword(list2str(a)); Pushword(list2str(a));
@ -699,8 +720,7 @@ subwords(word *val, int len, word *sub, word *a)
if(!sub) if(!sub)
return a; return a;
a = subwords(val, len, sub->next, a); a = subwords(val, len, sub->next, a);
s = sub->word; s = Str(sub);
deglob(s);
m = 0; m = 0;
n = 0; n = 0;
while('0'<=*s && *s<='9') while('0'<=*s && *s<='9')
@ -732,8 +752,7 @@ Xsub(void)
Xerror1("variable name not singleton!"); Xerror1("variable name not singleton!");
return; return;
} }
s = runq->argv->next->words->word; s = Str(runq->argv->next->words);
deglob(s);
a = runq->argv->next->next->words; a = runq->argv->next->next->words;
v = vlook(s)->val; v = vlook(s)->val;
a = subwords(v, count(v), runq->argv->words, a); a = subwords(v, count(v), runq->argv->words, a);
@ -753,8 +772,7 @@ Xcount(void)
Xerror1("variable name not singleton!"); Xerror1("variable name not singleton!");
return; return;
} }
s = runq->argv->words->word; s = Str(runq->argv->words);
deglob(s);
n = 0; n = 0;
for(t = s;'0'<=*t && *t<='9';t++) n = n*10+*t-'0'; for(t = s;'0'<=*t && *t<='9';t++) n = n*10+*t-'0';
if(n==0 || *t){ if(n==0 || *t){
@ -776,11 +794,9 @@ Xlocal(void)
Xerror1("variable name must be singleton\n"); Xerror1("variable name must be singleton\n");
return; return;
} }
deglob(runq->argv->words->word); runq->local = newvar(Str(runq->argv->words), runq->local);
runq->local = newvar(runq->argv->words->word, runq->local);
poplist(); poplist();
globlist(); runq->local->val = globlist(runq->argv->words);
runq->local->val = runq->argv->words;
runq->local->changed = 1; runq->local->changed = 1;
runq->argv->words = 0; runq->argv->words = 0;
poplist(); poplist();
@ -819,8 +835,7 @@ Xfn(void)
word *a; word *a;
int end; int end;
end = runq->code[runq->pc].i; end = runq->code[runq->pc].i;
globlist(); for(a = globlist(runq->argv->words);a;a = a->next){
for(a = runq->argv->words;a;a = a->next){
v = gvlook(a->word); v = gvlook(a->word);
if(v->fn) if(v->fn)
codefree(v->fn); codefree(v->fn);
@ -989,5 +1004,5 @@ Xfor(void)
void void
Xglob(void) Xglob(void)
{ {
globlist(); globlist(runq->argv->words);
} }

View file

@ -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 Xjump(void), Xmark(void), Xmatch(void), Xpipe(void), Xread(void);
extern void Xrdwr(void); extern void Xrdwr(void);
extern void Xrdfn(void), Xunredir(void), Xstar(void), Xreturn(void), Xsubshell(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 Xlocal(void), Xunlocal(void), Xassign(void), Xsimple(void), Xpopm(void);
extern void Xrdcmds(void), Xwastrue(void), Xif(void), Xifnot(void), Xpipewait(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 Xdelhere(void), Xpopredir(void), Xsub(void), Xeflag(void), Xsettrue(void);
@ -20,6 +20,7 @@ extern void Xerror1(char*);
struct word{ struct word{
char *word; char *word;
word *next; word *next;
int glob; /* Globsize(word) */
}; };
struct list{ struct list{
word *words; word *words;

View file

@ -30,19 +30,18 @@ void codefree(code*);
int compile(tree*); int compile(tree*);
char * list2str(word*); char * list2str(word*);
int count(word*); int count(word*);
void deglob(void*); char* deglob(char*);
void delwaitpid(int); void delwaitpid(int);
void dotrap(void); void dotrap(void);
void freenodes(void); void freenodes(void);
void freewords(word*); void freewords(word*);
void globlist(void); word* globlist(word*);
int havewaitpid(int); int havewaitpid(int);
int idchr(int); int idchr(int);
void inttoascii(char*, long); void inttoascii(char*, long);
void kinit(void); void kinit(void);
int mapfd(int); int mapfd(int);
int match(void*, void*, int); int match(char*, char*, int);
int matchfn(void*, void*);
char** mkargv(word*); char** mkargv(word*);
void clearwaitpids(void); void clearwaitpids(void);
void panic(char*, int); void panic(char*, int);
@ -52,7 +51,7 @@ void popword(void);
void pprompt(void); void pprompt(void);
void pushlist(void); void pushlist(void);
void pushredir(int, int, int); void pushredir(int, int, int);
void pushword(char*); word* pushword(char*);
void readhere(void); void readhere(void);
word* searchpath(char*); word* searchpath(char*);
void setstatus(char*); void setstatus(char*);

View file

@ -1,31 +1,31 @@
#include "rc.h" #include "rc.h"
#include "exec.h" #include "exec.h"
#include "fns.h" #include "fns.h"
char *globname;
struct word *globv;
/* /*
* delete all the GLOB marks from s, in place * delete all the GLOB marks from s, in place
*/ */
void char*
deglob(void *as) deglob(char *s)
{ {
char *s = as; char *b = s;
char *t = s; char *t = s;
do{ do{
if(*t==GLOB) if(*t==GLOB)
t++; t++;
*s++=*t; *s++=*t;
}while(*t++); }while(*t++);
return b;
} }
int static int
globcmp(const void *s, const void *t) globcmp(void *s, void *t)
{ {
return strcmp(*(char**)s, *(char**)t); return strcmp(*(char**)s, *(char**)t);
} }
void static void
globsort(word *left, word *right) globsort(word *left, word *right)
{ {
char **list; 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]; for(a = left,n = 0;a!=right;a = a->next,n++) a->word = list[n];
efree((char *)list); efree((char *)list);
} }
/* /*
* Push names prefixed by globname and suffixed by a match of p onto the astack. * Does the string s match the pattern p
* namep points to the end of the prefix in globname. * . and .. are only matched by patterns starting with .
* * matches any sequence of characters
* ? matches any single character
* [...] matches the enclosed list of characters
*/ */
void static int
globdir(uchar *p, uchar *namep) 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; int f;
/* scan the pattern looking for a component with a metacharacter in it */ /* scan the pattern looking for a component with a metacharacter in it */
if(*p=='\0'){ if(*p=='\0')
globv = newword(globname, globv); return newword(name, list);
return;
}
t = namep; t = namep;
newp = p; newp = p;
while(*newp){ while(*newp){
@ -67,65 +77,63 @@ globdir(uchar *p, uchar *namep)
/* If we ran out of pattern, append the name if accessible */ /* If we ran out of pattern, append the name if accessible */
if(*newp=='\0'){ if(*newp=='\0'){
*t='\0'; *t='\0';
if(access(globname, 0)==0) if(access(name, 0)==0)
globv = newword(globname, globv); list = newword(name, list);
return; return list;
} }
/* read the directory and recur for any entry that matches */ /* read the directory and recur for any entry that matches */
*namep='\0'; *namep='\0';
if((f = Opendir(globname[0]?globname:"."))<0) return; if((f = Opendir(name[0]?name:".")) >= 0){
while(*newp!='/' && *newp!='\0') newp++; while(*newp!='/' && *newp!='\0') newp++;
while(Readdir(f, namep, *newp=='/')){ while(Readdir(f, namep, *newp=='/')){
if(matchfn(namep, p)){ if(matchfn(namep, p)){
for(t = namep;*t;t++); for(t = namep;*t;t++);
globdir(newp, 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. * Subsitute a word with its glob in place.
* If there are no matches, the list consists of p.
*/ */
void static void
glob(void *ap) globword(word *w)
{ {
uchar *p = ap; word *left, *right;
word *svglobv = globv; char *name;
int globlen = Globsize(ap);
if(!globlen){ if(w->glob == 0)
deglob(p);
globv = newword((char *)p, globv);
return; 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 word*
equtf(uchar *p, uchar *q) globlist(word *l)
{ {
Rune pr, qr; word *p, *q;
if(*p!=*q)
return 0;
chartorune(&pr, (char*)p); for(p=l;p;p=q){
chartorune(&qr, (char*)q); q = p->next;
return pr == qr; globword(p);
}
return l;
} }
/* /*
@ -133,50 +141,43 @@ equtf(uchar *p, uchar *q)
* not jumping past nuls in broken utf codes! * not jumping past nuls in broken utf codes!
*/ */
uchar* static char*
nextutf(uchar *p) nextutf(char *p)
{ {
Rune dummy; Rune dummy;
return p + chartorune(&dummy, (char*)p); return p + chartorune(&dummy, p);
} }
/* /*
* Convert the utf code at *p to a unicode value * Convert the utf code at *p to a unicode value
*/ */
int static int
unicode(uchar *p) unicode(char *p)
{ {
Rune r; Rune r;
chartorune(&r, (char*)p); chartorune(&r, p);
return r; return r;
} }
/* /*
* Does the string s match the pattern p * Do p and q point at equal utf codes
* . and .. are only matched by patterns starting with .
* * matches any sequence of characters
* ? matches any single character
* [...] matches the enclosed list of characters
*/ */
int static int
matchfn(void *as, void *ap) equtf(char *p, char *q)
{ {
uchar *s = as, *p = ap; if(*p!=*q)
return 0;
if(s[0]=='.' && (s[1]=='\0' || s[1]=='.' && s[2]=='\0') && p[0]!='.') return unicode(p) == unicode(q);
return 0;
return match(s, p, '/');
} }
int int
match(void *as, void *ap, int stop) match(char *s, char *p, int stop)
{ {
int compl, hit, lo, hi, t, c; int compl, hit, lo, hi, t, c;
uchar *s = as, *p = ap;
for(; *p!=stop && *p!='\0'; s = nextutf(s), p = nextutf(p)){ for(; *p!=stop && *p!='\0'; s = nextutf(s), p = nextutf(p)){
if(*p!=GLOB){ if(*p!=GLOB){
@ -235,27 +236,3 @@ match(void *as, void *ap, int stop)
} }
return *s=='\0'; 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;
}
}

View file

@ -366,8 +366,7 @@ yylex(void)
return c; return c;
} }
for(;;){ for(;;){
/* next line should have (char)c==GLOB, but ken's compiler is broken */ if(c=='*' || c=='[' || c=='?' || c==GLOB)
if(c=='*' || c=='[' || c=='?' || c==(unsigned char)GLOB)
w = addtok(w, GLOB); w = addtok(w, GLOB);
w = addutf(w, c); w = addutf(w, c);
c = nextc(); c = nextc();

View file

@ -38,6 +38,7 @@ struct{
Xdelfn, "Xdelfn", Xdelfn, "Xdelfn",
Xpipe, "Xpipe", Xpipe, "Xpipe",
Xpipewait, "Xpipewait", Xpipewait, "Xpipewait",
Xpopredir, "Xpopredir",
Xrdcmds, "Xrdcmds", Xrdcmds, "Xrdcmds",
(void (*)(void))Xerror, "Xerror", (void (*)(void))Xerror, "Xerror",
Xbackq, "Xbackq", Xbackq, "Xbackq",
@ -46,6 +47,7 @@ struct{
Xdelhere, "Xdelhere", Xdelhere, "Xdelhere",
Xfor, "Xfor", Xfor, "Xfor",
Xglob, "Xglob", Xglob, "Xglob",
Xglobs, "Xglobs",
Xrdfn, "Xrdfn", Xrdfn, "Xrdfn",
Xsimple, "Xsimple", Xsimple, "Xsimple",
Xrdfn, "Xrdfn", Xrdfn, "Xrdfn",

View file

@ -20,18 +20,17 @@ void
Xsimple(void) Xsimple(void)
{ {
word *a; word *a;
thread *p = runq;
var *v; var *v;
struct builtin *bp; struct builtin *bp;
int pid; int pid;
globlist();
a = runq->argv->words; a = globlist(runq->argv->words);
if(a==0){ if(a==0){
Xerror1("empty argument list"); Xerror1("empty argument list");
return; return;
} }
if(flag['x']) 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); v = gvlook(a->word);
if(v->fn) if(v->fn)
execfunc(v); execfunc(v);
@ -140,9 +139,9 @@ int
dochdir(char *word) dochdir(char *word)
{ {
/* report to /dev/wdir if it exists and we're interactive */ /* report to /dev/wdir if it exists and we're interactive */
static int wdirfd = -2;
if(chdir(word)<0) return -1; if(chdir(word)<0) return -1;
if(flag['i']!=0){ if(flag['i']!=0){
static int wdirfd = -2;
if(wdirfd==-2) /* try only once */ if(wdirfd==-2) /* try only once */
wdirfd = open("/dev/wdir", OWRITE|OCEXEC); wdirfd = open("/dev/wdir", OWRITE|OCEXEC);
if(wdirfd>=0) if(wdirfd>=0)
@ -234,10 +233,10 @@ execshift(void)
break; break;
} }
star = vlook("*"); star = vlook("*");
for(;n && star->val;--n){ for(;star->val;--n){
a = star->val->next; a = star->val->next;
efree(star->val->word); efree(star->val->word);
efree((char *)star->val); efree(star->val);
star->val = a; star->val = a;
star->changed = 1; star->changed = 1;
} }
@ -245,15 +244,6 @@ execshift(void)
poplist(); poplist();
} }
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 int
mapfd(int fd) mapfd(int fd)
{ {
@ -293,25 +283,18 @@ execcmds(io *f)
void void
execeval(void) execeval(void)
{ {
char *cmdline, *s, *t; char *cmdline;
int len = 0; int len;
word *ap;
if(count(runq->argv->words)<=1){ if(count(runq->argv->words)<=1){
Xerror1("Usage: eval cmd ..."); Xerror1("Usage: eval cmd ...");
return; return;
} }
eflagok = 1; eflagok = 1;
for(ap = runq->argv->words->next;ap;ap = ap->next) cmdline = list2str(runq->argv->words->next);
len+=1+strlen(ap->word); len = strlen(cmdline);
cmdline = emalloc(len); cmdline[len] = '\n';
s = cmdline;
for(ap = runq->argv->words->next;ap;ap = ap->next){
for(t = ap->word;*t;) *s++=*t++;
*s++=' ';
}
s[-1]='\n';
poplist(); poplist();
execcmds(opencore(cmdline, len)); execcmds(opencore(cmdline, len+1));
efree(cmdline); efree(cmdline);
} }
union code dotcmds[14]; union code dotcmds[14];
@ -393,7 +376,7 @@ execdot(void)
/* free caller's copy of $* */ /* free caller's copy of $* */
av = p->argv; av = p->argv;
p->argv = av->next; p->argv = av->next;
efree((char *)av); efree(av);
/* push $0 value */ /* push $0 value */
pushlist(); pushlist();
pushword(zero); pushword(zero);

View file

@ -28,7 +28,7 @@ freenodes(void)
u = t->next; u = t->next;
if(t->str) if(t->str)
efree(t->str); efree(t->str);
efree((char *)t); efree(t);
} }
treenodes = 0; treenodes = 0;
} }
@ -144,5 +144,5 @@ freetree(tree *p)
freetree(p->child[2]); freetree(p->child[2]);
if(p->str) if(p->str)
efree(p->str); efree(p->str);
efree((char *)p); efree(p);
} }

View file

@ -277,8 +277,8 @@ register struct word *args, *path;
Bad: Bad:
setstatus(msg); setstatus(msg);
pfmt(err, "%s: %s\n", argv[1], msg); pfmt(err, "%s: %s\n", argv[1], msg);
efree((char *)env); efree(env);
efree((char *)argv); efree(argv);
} }
#define NDIR 14 /* should get this from param.h */ #define NDIR 14 /* should get this from param.h */
Globsize(p) Globsize(p)
@ -432,6 +432,14 @@ Isatty(fd){
Abort(){ Abort(){
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 */ execumask(){ /* wrong -- should fork before writing */
int m; int m;
struct io out[1]; struct io out[1];

View file

@ -301,7 +301,7 @@ Execute(word *args, word *path)
rerrstr(file, sizeof file); rerrstr(file, sizeof file);
setstatus(file); setstatus(file);
pfmt(err, "%s: %s\n", argv[1], file); pfmt(err, "%s: %s\n", argv[1], file);
efree((char *)argv); efree(argv);
} }
#define NDIR 256 /* shoud be a better way */ #define NDIR 256 /* shoud be a better way */