rc: import 9front's improvements
This commit is contained in:
parent
26a2f0a1be
commit
085f5dfa34
|
@ -31,10 +31,7 @@ int
|
||||||
morecode(void)
|
morecode(void)
|
||||||
{
|
{
|
||||||
ncode+=100;
|
ncode+=100;
|
||||||
codebuf = (code *)realloc((char *)codebuf, ncode*sizeof codebuf[0]);
|
codebuf = (code *)erealloc((char *)codebuf, ncode*sizeof codebuf[0]);
|
||||||
if(codebuf==0)
|
|
||||||
panic("Can't realloc %d bytes in morecode!",
|
|
||||||
ncode*sizeof codebuf[0]);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -55,7 +52,7 @@ compile(tree *t)
|
||||||
emiti(0); /* reference count */
|
emiti(0); /* reference count */
|
||||||
outcode(t, flag['e']?1:0);
|
outcode(t, flag['e']?1:0);
|
||||||
if(nerror){
|
if(nerror){
|
||||||
efree((char *)codebuf);
|
free(codebuf);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
readhere();
|
readhere();
|
||||||
|
@ -68,7 +65,7 @@ void
|
||||||
cleanhere(char *f)
|
cleanhere(char *f)
|
||||||
{
|
{
|
||||||
emitf(Xdelhere);
|
emitf(Xdelhere);
|
||||||
emits(strdup(f));
|
emits(estrdup(f));
|
||||||
}
|
}
|
||||||
|
|
||||||
char*
|
char*
|
||||||
|
@ -120,13 +117,10 @@ outcode(tree *t, int eflag)
|
||||||
break;
|
break;
|
||||||
case '&':
|
case '&':
|
||||||
emitf(Xasync);
|
emitf(Xasync);
|
||||||
if(havefork){
|
p = emiti(0);
|
||||||
p = emiti(0);
|
outcode(c0, eflag);
|
||||||
outcode(c0, eflag);
|
emitf(Xexit);
|
||||||
emitf(Xexit);
|
stuffdot(p);
|
||||||
stuffdot(p);
|
|
||||||
} else
|
|
||||||
emits(fnstr(c0));
|
|
||||||
break;
|
break;
|
||||||
case ';':
|
case ';':
|
||||||
outcode(c0, eflag);
|
outcode(c0, eflag);
|
||||||
|
@ -140,14 +134,21 @@ outcode(tree *t, int eflag)
|
||||||
emitf(Xconc);
|
emitf(Xconc);
|
||||||
break;
|
break;
|
||||||
case '`':
|
case '`':
|
||||||
emitf(Xbackq);
|
emitf(Xmark);
|
||||||
if(havefork){
|
if(c0){
|
||||||
p = emiti(0);
|
|
||||||
outcode(c0, 0);
|
outcode(c0, 0);
|
||||||
emitf(Xexit);
|
emitf(Xglob);
|
||||||
stuffdot(p);
|
} else {
|
||||||
} else
|
emitf(Xmark);
|
||||||
emits(fnstr(c0));
|
emitf(Xword);
|
||||||
|
emits(estrdup("ifs"));
|
||||||
|
emitf(Xdol);
|
||||||
|
}
|
||||||
|
emitf(Xbackq);
|
||||||
|
p = emiti(0);
|
||||||
|
outcode(c1, 0);
|
||||||
|
emitf(Xexit);
|
||||||
|
stuffdot(p);
|
||||||
break;
|
break;
|
||||||
case ANDAND:
|
case ANDAND:
|
||||||
outcode(c0, 0);
|
outcode(c0, 0);
|
||||||
|
@ -223,13 +224,10 @@ outcode(tree *t, int eflag)
|
||||||
break;
|
break;
|
||||||
case SUBSHELL:
|
case SUBSHELL:
|
||||||
emitf(Xsubshell);
|
emitf(Xsubshell);
|
||||||
if(havefork){
|
p = emiti(0);
|
||||||
p = emiti(0);
|
outcode(c0, eflag);
|
||||||
outcode(c0, eflag);
|
emitf(Xexit);
|
||||||
emitf(Xexit);
|
stuffdot(p);
|
||||||
stuffdot(p);
|
|
||||||
} else
|
|
||||||
emits(fnstr(c0));
|
|
||||||
if(eflag)
|
if(eflag)
|
||||||
emitf(Xeflag);
|
emitf(Xeflag);
|
||||||
break;
|
break;
|
||||||
|
@ -270,7 +268,7 @@ outcode(tree *t, int eflag)
|
||||||
else{
|
else{
|
||||||
emitf(Xmark);
|
emitf(Xmark);
|
||||||
emitf(Xword);
|
emitf(Xword);
|
||||||
emits(strdup("*"));
|
emits(estrdup("*"));
|
||||||
emitf(Xdol);
|
emitf(Xdol);
|
||||||
}
|
}
|
||||||
emitf(Xmark); /* dummy value for Xlocal */
|
emitf(Xmark); /* dummy value for Xlocal */
|
||||||
|
@ -286,8 +284,19 @@ outcode(tree *t, int eflag)
|
||||||
emitf(Xunlocal);
|
emitf(Xunlocal);
|
||||||
break;
|
break;
|
||||||
case WORD:
|
case WORD:
|
||||||
emitf(Xword);
|
if(t->quoted){
|
||||||
emits(strdup(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){
|
||||||
|
@ -305,14 +314,10 @@ outcode(tree *t, int eflag)
|
||||||
case PIPEFD:
|
case PIPEFD:
|
||||||
emitf(Xpipefd);
|
emitf(Xpipefd);
|
||||||
emiti(t->rtype);
|
emiti(t->rtype);
|
||||||
if(havefork){
|
p = emiti(0);
|
||||||
p = emiti(0);
|
outcode(c0, eflag);
|
||||||
outcode(c0, eflag);
|
emitf(Xexit);
|
||||||
emitf(Xexit);
|
stuffdot(p);
|
||||||
stuffdot(p);
|
|
||||||
} else {
|
|
||||||
emits(fnstr(c0));
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case REDIR:
|
case REDIR:
|
||||||
emitf(Xmark);
|
emitf(Xmark);
|
||||||
|
@ -367,16 +372,11 @@ outcode(tree *t, int eflag)
|
||||||
emitf(Xpipe);
|
emitf(Xpipe);
|
||||||
emiti(t->fd0);
|
emiti(t->fd0);
|
||||||
emiti(t->fd1);
|
emiti(t->fd1);
|
||||||
if(havefork){
|
p = emiti(0);
|
||||||
p = emiti(0);
|
q = emiti(0);
|
||||||
q = emiti(0);
|
outcode(c0, eflag);
|
||||||
outcode(c0, eflag);
|
emitf(Xexit);
|
||||||
emitf(Xexit);
|
stuffdot(p);
|
||||||
stuffdot(p);
|
|
||||||
} else {
|
|
||||||
emits(fnstr(c0));
|
|
||||||
q = emiti(0);
|
|
||||||
}
|
|
||||||
outcode(c1, eflag);
|
outcode(c1, eflag);
|
||||||
emitf(Xreturn);
|
emitf(Xreturn);
|
||||||
stuffdot(q);
|
stuffdot(q);
|
||||||
|
@ -485,11 +485,12 @@ 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==Xword || p->f==Xdelhere) efree((++p)->s);
|
else if(p->f==Xglobs) free(p[1].s), p+=2;
|
||||||
|
else if(p->f==Xword || p->f==Xdelhere) free((++p)->s);
|
||||||
else if(p->f==Xfn){
|
else if(p->f==Xfn){
|
||||||
efree(p[2].s);
|
free(p[2].s);
|
||||||
p+=2;
|
p+=2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
efree((char *)cp);
|
free(cp);
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,20 +37,34 @@ start(code *c, int pc, var *local)
|
||||||
}
|
}
|
||||||
|
|
||||||
word*
|
word*
|
||||||
newword(char *wd, word *next)
|
Newword(char *wd, word *next)
|
||||||
{
|
{
|
||||||
word *p = new(word);
|
word *p = new(word);
|
||||||
p->word = strdup(wd);
|
p->word = wd;
|
||||||
p->next = next;
|
p->next = next;
|
||||||
|
p->glob = 0;
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
word*
|
||||||
void
|
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*
|
||||||
|
newword(char *wd, word *next)
|
||||||
|
{
|
||||||
|
return Newword(estrdup(wd), next);
|
||||||
|
}
|
||||||
|
word*
|
||||||
|
pushword(char *wd)
|
||||||
|
{
|
||||||
|
return Pushword(estrdup(wd));
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -63,8 +77,8 @@ popword(void)
|
||||||
if(p==0)
|
if(p==0)
|
||||||
panic("popword but no word!", 0);
|
panic("popword but no word!", 0);
|
||||||
runq->argv->words = p->next;
|
runq->argv->words = p->next;
|
||||||
efree(p->word);
|
free(p->word);
|
||||||
efree((char *)p);
|
free(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -73,8 +87,8 @@ freelist(word *w)
|
||||||
word *nw;
|
word *nw;
|
||||||
while(w){
|
while(w){
|
||||||
nw = w->next;
|
nw = w->next;
|
||||||
efree(w->word);
|
free(w->word);
|
||||||
efree((char *)w);
|
free(w);
|
||||||
w = nw;
|
w = nw;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -96,7 +110,7 @@ poplist(void)
|
||||||
panic("poplist but no argv", 0);
|
panic("poplist but no argv", 0);
|
||||||
freelist(p->words);
|
freelist(p->words);
|
||||||
runq->argv = p->next;
|
runq->argv = p->next;
|
||||||
efree((char *)p);
|
free(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
|
@ -122,7 +136,7 @@ var*
|
||||||
newvar(char *name, var *next)
|
newvar(char *name, var *next)
|
||||||
{
|
{
|
||||||
var *v = new(var);
|
var *v = new(var);
|
||||||
v->name = name;
|
v->name = estrdup(name);
|
||||||
v->val = 0;
|
v->val = 0;
|
||||||
v->fn = 0;
|
v->fn = 0;
|
||||||
v->changed = 0;
|
v->changed = 0;
|
||||||
|
@ -166,7 +180,6 @@ main(int argc, char *argv[])
|
||||||
:(word *)0);
|
:(word *)0);
|
||||||
setvar("rcname", newword(argv[0], (word *)0));
|
setvar("rcname", newword(argv[0], (word *)0));
|
||||||
i = 0;
|
i = 0;
|
||||||
memset(bootstrap, 0, sizeof bootstrap);
|
|
||||||
bootstrap[i++].i = 1;
|
bootstrap[i++].i = 1;
|
||||||
bootstrap[i++].f = Xmark;
|
bootstrap[i++].f = Xmark;
|
||||||
bootstrap[i++].f = Xword;
|
bootstrap[i++].f = Xword;
|
||||||
|
@ -187,8 +200,9 @@ main(int argc, char *argv[])
|
||||||
start(bootstrap, 1, (var *)0);
|
start(bootstrap, 1, (var *)0);
|
||||||
/* prime bootstrap argv */
|
/* prime bootstrap argv */
|
||||||
pushlist();
|
pushlist();
|
||||||
argv0 = strdup(argv[0]);
|
argv0 = estrdup(argvcopy[0]);
|
||||||
for(i = argc-1;i!=0;--i) pushword(argv[i]);
|
for(i = argc-1; i != 0; --i)
|
||||||
|
pushword(argv[i]);
|
||||||
for(;;){
|
for(;;){
|
||||||
if(flag['r'])
|
if(flag['r'])
|
||||||
pfnc(err, runq);
|
pfnc(err, runq);
|
||||||
|
@ -207,7 +221,7 @@ main(int argc, char *argv[])
|
||||||
* Xappend(file)[fd] open file to append
|
* Xappend(file)[fd] open file to append
|
||||||
* Xassign(name, val) assign val to name
|
* Xassign(name, val) assign val to name
|
||||||
* Xasync{... Xexit} make thread for {}, no wait
|
* Xasync{... Xexit} make thread for {}, no wait
|
||||||
* Xbackq{... Xreturn} make thread for {}, push stdout
|
* Xbackq(split){... Xreturn} make thread for {}, push stdout
|
||||||
* Xbang complement condition
|
* Xbang complement condition
|
||||||
* Xcase(pat, value){...} exec code on match, leave (value) on
|
* Xcase(pat, value){...} exec code on match, leave (value) on
|
||||||
* stack
|
* stack
|
||||||
|
@ -215,18 +229,15 @@ main(int argc, char *argv[])
|
||||||
* Xconc(left, right) concatenate, push results
|
* Xconc(left, right) concatenate, push results
|
||||||
* Xcount(name) push var count
|
* Xcount(name) push var count
|
||||||
* Xdelfn(name) delete function definition
|
* Xdelfn(name) delete function definition
|
||||||
* Xdelhere
|
* Xdeltraps(names) delete named traps
|
||||||
* Xdol(name) get variable value
|
* Xdol(name) get variable value
|
||||||
|
* Xqdol(name) concatenate variable components
|
||||||
* Xdup[i j] dup file descriptor
|
* Xdup[i j] dup file descriptor
|
||||||
* Xeflag
|
|
||||||
* Xerror
|
|
||||||
* Xexit rc exits with status
|
* Xexit rc exits with status
|
||||||
* 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
|
||||||
* Xglob
|
* Xglobs[string globsize] push globbing string
|
||||||
* Xif
|
|
||||||
* Xifnot
|
|
||||||
* 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
|
||||||
|
@ -235,21 +246,16 @@ main(int argc, char *argv[])
|
||||||
* wait for both
|
* wait for both
|
||||||
* Xpipefd[type]{... Xreturn} connect {} to pipe (input or output,
|
* Xpipefd[type]{... Xreturn} connect {} to pipe (input or output,
|
||||||
* depending on type), push /dev/fd/??
|
* depending on type), push /dev/fd/??
|
||||||
* Xpipewait
|
|
||||||
* Xpopm(value) pop value from stack
|
* Xpopm(value) pop value from stack
|
||||||
* Xpopredir
|
|
||||||
* Xrdcmds
|
|
||||||
* Xrdfn
|
|
||||||
* Xrdwr(file)[fd] open file for reading and writing
|
* Xrdwr(file)[fd] open file for reading and writing
|
||||||
* Xread(file)[fd] open file to read
|
* Xread(file)[fd] open file to read
|
||||||
* Xqdol(name) concatenate variable components
|
* Xsettraps(names){... Xreturn} define trap functions
|
||||||
* Xreturn kill thread
|
* Xshowtraps print trap list
|
||||||
* Xsimple(args) run command and wait
|
* Xsimple(args) run command and wait
|
||||||
* Xsub
|
* Xreturn kill thread
|
||||||
* Xsubshell{... Xexit} execute {} in a subshell and wait
|
* Xsubshell{... Xexit} execute {} in a subshell and wait
|
||||||
* Xtrue{...} execute {} if true
|
* Xtrue{...} execute {} if true
|
||||||
* Xunlocal delete local variable
|
* Xunlocal delete local variable
|
||||||
* Xwastrue
|
|
||||||
* Xword[string] push string
|
* Xword[string] push string
|
||||||
* Xwrite(file)[fd] open file to write
|
* Xwrite(file)[fd] open file to write
|
||||||
*/
|
*/
|
||||||
|
@ -326,7 +332,7 @@ Xexit(void)
|
||||||
--runq->pc;
|
--runq->pc;
|
||||||
starval = vlook("*")->val;
|
starval = vlook("*")->val;
|
||||||
start(trapreq->fn, trapreq->pc, (struct var *)0);
|
start(trapreq->fn, trapreq->pc, (struct var *)0);
|
||||||
runq->local = newvar(strdup("*"), runq->local);
|
runq->local = newvar("*", runq->local);
|
||||||
runq->local->val = copywords(starval, (struct word *)0);
|
runq->local->val = copywords(starval, (struct word *)0);
|
||||||
runq->local->changed = 1;
|
runq->local->changed = 1;
|
||||||
runq->redir = runq->startredir = 0;
|
runq->redir = runq->startredir = 0;
|
||||||
|
@ -440,7 +446,7 @@ Xpopredir(void)
|
||||||
runq->redir = rp->next;
|
runq->redir = rp->next;
|
||||||
if(rp->type==ROPEN)
|
if(rp->type==ROPEN)
|
||||||
close(rp->from);
|
close(rp->from);
|
||||||
efree((char *)rp);
|
free(rp);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -451,7 +457,7 @@ Xreturn(void)
|
||||||
while(p->argv) poplist();
|
while(p->argv) poplist();
|
||||||
codefree(p->code);
|
codefree(p->code);
|
||||||
runq = p->ret;
|
runq = p->ret;
|
||||||
efree((char *)p);
|
free(p);
|
||||||
if(runq==0)
|
if(runq==0)
|
||||||
Exit(getstatus());
|
Exit(getstatus());
|
||||||
}
|
}
|
||||||
|
@ -483,6 +489,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)
|
||||||
{
|
{
|
||||||
|
@ -541,7 +554,7 @@ Xmatch(void)
|
||||||
setstatus("");
|
setstatus("");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
efree(subject);
|
free(subject);
|
||||||
poplist();
|
poplist();
|
||||||
poplist();
|
poplist();
|
||||||
}
|
}
|
||||||
|
@ -559,7 +572,7 @@ Xcase(void)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
efree(s);
|
free(s);
|
||||||
if(ok)
|
if(ok)
|
||||||
runq->pc++;
|
runq->pc++;
|
||||||
else
|
else
|
||||||
|
@ -570,16 +583,25 @@ Xcase(void)
|
||||||
word*
|
word*
|
||||||
conclist(word *lp, word *rp, word *tail)
|
conclist(word *lp, word *rp, word *tail)
|
||||||
{
|
{
|
||||||
char *buf;
|
word *v, *p, **end;
|
||||||
word *v;
|
int ln, rn;
|
||||||
if(lp->next || rp->next)
|
|
||||||
tail = conclist(lp->next==0? lp: lp->next,
|
for(end = &v;;){
|
||||||
rp->next==0? rp: rp->next, tail);
|
ln = strlen(lp->word), rn = strlen(rp->word);
|
||||||
buf = emalloc(strlen(lp->word)+strlen((char *)rp->word)+1);
|
p = Newword(emalloc(ln+rn+1), (word *)0);
|
||||||
strcpy(buf, lp->word);
|
memmove(p->word, lp->word, ln);
|
||||||
strcat(buf, rp->word);
|
memmove(p->word+ln, rp->word, rn+1);
|
||||||
v = newword(buf, tail);
|
if(lp->glob || rp->glob)
|
||||||
efree(buf);
|
p->glob = Globsize(p->word);
|
||||||
|
*end = p, end = &p->next;
|
||||||
|
if(lp->next == 0 && rp->next == 0)
|
||||||
|
break;
|
||||||
|
if(lp->next)
|
||||||
|
lp = lp->next;
|
||||||
|
if(rp->next)
|
||||||
|
rp = rp->next;
|
||||||
|
}
|
||||||
|
*end = tail;
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -606,6 +628,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)
|
||||||
{
|
{
|
||||||
|
@ -614,12 +647,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();
|
||||||
|
@ -648,8 +679,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;
|
||||||
|
@ -669,35 +699,17 @@ Xdol(void)
|
||||||
void
|
void
|
||||||
Xqdol(void)
|
Xqdol(void)
|
||||||
{
|
{
|
||||||
word *a, *p;
|
word *a;
|
||||||
char *s;
|
char *s;
|
||||||
int n;
|
|
||||||
if(count(runq->argv->words)!=1){
|
if(count(runq->argv->words)!=1){
|
||||||
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();
|
||||||
n = count(a);
|
Pushword(list2str(a));
|
||||||
if(n==0){
|
|
||||||
pushword("");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
for(p = a;p;p = p->next) n+=strlen(p->word);
|
|
||||||
s = emalloc(n);
|
|
||||||
if(a){
|
|
||||||
strcpy(s, a->word);
|
|
||||||
for(p = a->next;p;p = p->next){
|
|
||||||
strcat(s, " ");
|
|
||||||
strcat(s, p->word);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
s[0]='\0';
|
|
||||||
pushword(s);
|
|
||||||
efree(s);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
word*
|
word*
|
||||||
|
@ -724,8 +736,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')
|
||||||
|
@ -757,8 +768,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);
|
||||||
|
@ -801,11 +811,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(strdup(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();
|
||||||
|
@ -820,9 +828,9 @@ Xunlocal(void)
|
||||||
runq->local = v->next;
|
runq->local = v->next;
|
||||||
hid = vlook(v->name);
|
hid = vlook(v->name);
|
||||||
hid->changed = 1;
|
hid->changed = 1;
|
||||||
efree(v->name);
|
free(v->name);
|
||||||
freewords(v->val);
|
freewords(v->val);
|
||||||
efree((char *)v);
|
free(v);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -830,9 +838,9 @@ freewords(word *w)
|
||||||
{
|
{
|
||||||
word *nw;
|
word *nw;
|
||||||
while(w){
|
while(w){
|
||||||
efree(w->word);
|
free(w->word);
|
||||||
nw = w->next;
|
nw = w->next;
|
||||||
efree((char *)w);
|
free(w);
|
||||||
w = nw;
|
w = nw;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -844,8 +852,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);
|
||||||
|
@ -921,7 +928,7 @@ Xrdcmds(void)
|
||||||
if(yyparse()){
|
if(yyparse()){
|
||||||
if(!p->iflag || p->eof && !Eintr()){
|
if(!p->iflag || p->eof && !Eintr()){
|
||||||
if(p->cmdfile)
|
if(p->cmdfile)
|
||||||
efree(p->cmdfile);
|
free(p->cmdfile);
|
||||||
closeio(p->cmdfd);
|
closeio(p->cmdfd);
|
||||||
Xreturn(); /* should this be omitted? */
|
Xreturn(); /* should this be omitted? */
|
||||||
}
|
}
|
||||||
|
@ -1014,5 +1021,5 @@ Xfor(void)
|
||||||
void
|
void
|
||||||
Xglob(void)
|
Xglob(void)
|
||||||
{
|
{
|
||||||
globlist();
|
globlist(runq->argv->words);
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,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);
|
||||||
|
@ -29,6 +29,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;
|
||||||
|
@ -76,7 +77,6 @@ struct builtin{
|
||||||
};
|
};
|
||||||
extern struct builtin Builtin[];
|
extern struct builtin Builtin[];
|
||||||
int eflagok; /* kludge flag so that -e doesn't exit in startup */
|
int eflagok; /* kludge flag so that -e doesn't exit in startup */
|
||||||
int havefork;
|
|
||||||
|
|
||||||
void execcd(void), execwhatis(void), execeval(void), execexec(void);
|
void execcd(void), execwhatis(void), execeval(void), execexec(void);
|
||||||
int execforkexec(void);
|
int execforkexec(void);
|
||||||
|
|
|
@ -19,18 +19,17 @@ void Exit(char*);
|
||||||
int ForkExecute(char*, char**, int, int, int);
|
int ForkExecute(char*, char**, int, int, int);
|
||||||
int Globsize(char*);
|
int Globsize(char*);
|
||||||
int Isatty(int);
|
int Isatty(int);
|
||||||
void Memcpy(void*, void*, int32_t);
|
|
||||||
void Noerror(void);
|
void Noerror(void);
|
||||||
int Opendir(char*);
|
int Opendir(char*);
|
||||||
int32_t Read(int, void*, int32_t);
|
int Read(int, void*, int);
|
||||||
int Readdir(int, void*, int);
|
int Readdir(int, void*, int);
|
||||||
int32_t Seek(int, int32_t, int32_t);
|
int Seek(int, int, int);
|
||||||
void Trapinit(void);
|
void Trapinit(void);
|
||||||
void Unlink(char*);
|
void Unlink(char*);
|
||||||
void Updenv(void);
|
void Updenv(void);
|
||||||
void Vinit(void);
|
void Vinit(void);
|
||||||
int Waitfor(int, int);
|
int Waitfor(int, int);
|
||||||
int32_t Write(int, void*, int32_t);
|
int Write(int, void*, int);
|
||||||
void addwaitpid(int);
|
void addwaitpid(int);
|
||||||
int advance(void);
|
int advance(void);
|
||||||
int back(int);
|
int back(int);
|
||||||
|
@ -39,19 +38,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*, int32_t);
|
void inttoascii(char*, int);
|
||||||
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);
|
||||||
|
@ -61,7 +59,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*);
|
||||||
|
|
|
@ -10,22 +10,22 @@
|
||||||
#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
|
int
|
||||||
|
@ -45,23 +45,33 @@ globsort(word *left, word *right)
|
||||||
for(a = left,n = 0;a!=right;a = a->next,n++) list[n] = a->word;
|
for(a = left,n = 0;a!=right;a = a->next,n++) list[n] = a->word;
|
||||||
qsort((void *)list, n, sizeof(void *), globcmp);
|
qsort((void *)list, n, sizeof(void *), globcmp);
|
||||||
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);
|
free(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(uint8_t *p, uint8_t *namep)
|
matchfn(char *s, char *p)
|
||||||
{
|
{
|
||||||
uint8_t *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){
|
||||||
|
@ -76,64 +86,63 @@ globdir(uint8_t *p, uint8_t *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, AEXIST)==0)
|
if(access(name, AEXIST)==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)
|
||||||
{
|
{
|
||||||
uint8_t *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);
|
||||||
|
free(name);
|
||||||
|
if(left == right) {
|
||||||
|
deglob(w->word);
|
||||||
|
w->glob = 0;
|
||||||
|
} else {
|
||||||
|
free(w->word);
|
||||||
|
globsort(left, right);
|
||||||
|
*w = *left;
|
||||||
|
free(left);
|
||||||
}
|
}
|
||||||
globname = emalloc(globlen);
|
|
||||||
globname[0]='\0';
|
|
||||||
globdir(p, (uint8_t *)globname);
|
|
||||||
efree(globname);
|
|
||||||
if(svglobv==globv){
|
|
||||||
deglob(p);
|
|
||||||
globv = newword((char *)p, globv);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
globsort(globv, svglobv);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
word*
|
||||||
* Do p and q point at equal utf codes
|
globlist(word *l)
|
||||||
*/
|
|
||||||
int
|
|
||||||
equtf(uint8_t *p, uint8_t *q)
|
|
||||||
{
|
{
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -141,49 +150,43 @@ equtf(uint8_t *p, uint8_t *q)
|
||||||
* not jumping past nuls in broken utf codes!
|
* not jumping past nuls in broken utf codes!
|
||||||
*/
|
*/
|
||||||
|
|
||||||
uint8_t*
|
static char*
|
||||||
nextutf(uint8_t *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(uint8_t *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)
|
||||||
{
|
{
|
||||||
uint8_t *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;
|
||||||
uint8_t *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){
|
||||||
|
@ -242,27 +245,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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -12,9 +12,6 @@
|
||||||
#include "exec.h"
|
#include "exec.h"
|
||||||
#include "io.h"
|
#include "io.h"
|
||||||
#include "fns.h"
|
#include "fns.h"
|
||||||
#include <String.h>
|
|
||||||
|
|
||||||
int havefork = 1;
|
|
||||||
|
|
||||||
void
|
void
|
||||||
Xasync(void)
|
Xasync(void)
|
||||||
|
@ -22,10 +19,12 @@ Xasync(void)
|
||||||
int null = open("/dev/null", OREAD);
|
int null = open("/dev/null", OREAD);
|
||||||
int pid;
|
int pid;
|
||||||
char npid[10];
|
char npid[10];
|
||||||
|
|
||||||
if(null<0){
|
if(null<0){
|
||||||
Xerror("Can't open /dev/null\n");
|
Xerror("Can't open /dev/null\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
Updenv();
|
||||||
switch(pid = rfork(RFFDG|RFPROC|RFNOTEG)){
|
switch(pid = rfork(RFFDG|RFPROC|RFNOTEG)){
|
||||||
case -1:
|
case -1:
|
||||||
close(null);
|
close(null);
|
||||||
|
@ -55,10 +54,12 @@ Xpipe(void)
|
||||||
int lfd = p->code[pc++].i;
|
int lfd = p->code[pc++].i;
|
||||||
int rfd = p->code[pc++].i;
|
int rfd = p->code[pc++].i;
|
||||||
int pfd[2];
|
int pfd[2];
|
||||||
|
|
||||||
if(pipe(pfd)<0){
|
if(pipe(pfd)<0){
|
||||||
Xerror("can't get pipe");
|
Xerror("can't get pipe");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
Updenv();
|
||||||
switch(forkid = fork()){
|
switch(forkid = fork()){
|
||||||
case -1:
|
case -1:
|
||||||
Xerror("try again");
|
Xerror("try again");
|
||||||
|
@ -84,25 +85,25 @@ Xpipe(void)
|
||||||
/*
|
/*
|
||||||
* Who should wait for the exit from the fork?
|
* Who should wait for the exit from the fork?
|
||||||
*/
|
*/
|
||||||
|
enum { Stralloc = 100, };
|
||||||
|
|
||||||
void
|
void
|
||||||
Xbackq(void)
|
Xbackq(void)
|
||||||
{
|
{
|
||||||
int n, pid;
|
int c, l, pid;
|
||||||
int pfd[2];
|
int pfd[2];
|
||||||
char *stop;
|
char *s, *wd, *ewd, *stop;
|
||||||
char utf[UTFmax+1];
|
|
||||||
struct io *f;
|
struct io *f;
|
||||||
var *ifs = vlook("ifs");
|
|
||||||
word *v, *nextv;
|
word *v, *nextv;
|
||||||
Rune r;
|
|
||||||
String *word;
|
|
||||||
|
|
||||||
stop = ifs->val? ifs->val->word: "";
|
stop = "";
|
||||||
|
if(runq->argv && runq->argv->words)
|
||||||
|
stop = runq->argv->words->word;
|
||||||
if(pipe(pfd)<0){
|
if(pipe(pfd)<0){
|
||||||
Xerror("can't make pipe");
|
Xerror("can't make pipe");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
Updenv();
|
||||||
switch(pid = fork()){
|
switch(pid = fork()){
|
||||||
case -1:
|
case -1:
|
||||||
Xerror("try again");
|
Xerror("try again");
|
||||||
|
@ -119,28 +120,32 @@ Xbackq(void)
|
||||||
addwaitpid(pid);
|
addwaitpid(pid);
|
||||||
close(pfd[PWR]);
|
close(pfd[PWR]);
|
||||||
f = openfd(pfd[PRD]);
|
f = openfd(pfd[PRD]);
|
||||||
word = s_new();
|
s = wd = ewd = 0;
|
||||||
v = nil;
|
v = 0;
|
||||||
/* rutf requires at least UTFmax+1 bytes in utf */
|
while((c = rchr(f))!=EOF){
|
||||||
while((n = rutf(f, utf, &r)) != EOF){
|
if(s==ewd){
|
||||||
utf[n] = '\0';
|
l = s-wd;
|
||||||
if(utfutf(stop, utf) == nil)
|
wd = erealloc(wd, l+Stralloc);
|
||||||
s_nappend(word, utf, n);
|
ewd = wd+l+Stralloc-1;
|
||||||
else
|
s = wd+l;
|
||||||
/*
|
}
|
||||||
* utf/r is an ifs rune (e.g., \t, \n), thus
|
if(strchr(stop, c)){
|
||||||
* ends the current word, if any.
|
if(s!=wd){
|
||||||
*/
|
*s='\0';
|
||||||
if(s_len(word) > 0){
|
v = newword(wd, v);
|
||||||
v = newword(s_to_c(word), v);
|
s = wd;
|
||||||
s_reset(word);
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
else *s++=c;
|
||||||
}
|
}
|
||||||
if(s_len(word) > 0)
|
if(s!=wd){
|
||||||
v = newword(s_to_c(word), v);
|
*s='\0';
|
||||||
s_free(word);
|
v = newword(wd, v);
|
||||||
|
}
|
||||||
|
free(wd);
|
||||||
closeio(f);
|
closeio(f);
|
||||||
Waitfor(pid, 0);
|
Waitfor(pid, 0);
|
||||||
|
poplist(); /* ditch split in "stop" */
|
||||||
/* v points to reversed arglist -- reverse it onto argv */
|
/* v points to reversed arglist -- reverse it onto argv */
|
||||||
while(v){
|
while(v){
|
||||||
nextv = v->next;
|
nextv = v->next;
|
||||||
|
@ -161,6 +166,7 @@ Xpipefd(void)
|
||||||
char name[40];
|
char name[40];
|
||||||
int pfd[2];
|
int pfd[2];
|
||||||
int sidefd, mainfd;
|
int sidefd, mainfd;
|
||||||
|
|
||||||
if(pipe(pfd)<0){
|
if(pipe(pfd)<0){
|
||||||
Xerror("can't get pipe");
|
Xerror("can't get pipe");
|
||||||
return;
|
return;
|
||||||
|
@ -173,6 +179,7 @@ Xpipefd(void)
|
||||||
sidefd = pfd[PRD];
|
sidefd = pfd[PRD];
|
||||||
mainfd = pfd[PWR];
|
mainfd = pfd[PWR];
|
||||||
}
|
}
|
||||||
|
Updenv();
|
||||||
switch(pid = fork()){
|
switch(pid = fork()){
|
||||||
case -1:
|
case -1:
|
||||||
Xerror("try again");
|
Xerror("try again");
|
||||||
|
@ -200,6 +207,8 @@ void
|
||||||
Xsubshell(void)
|
Xsubshell(void)
|
||||||
{
|
{
|
||||||
int pid;
|
int pid;
|
||||||
|
|
||||||
|
Updenv();
|
||||||
switch(pid = fork()){
|
switch(pid = fork()){
|
||||||
case -1:
|
case -1:
|
||||||
Xerror("try again");
|
Xerror("try again");
|
||||||
|
|
|
@ -1,220 +0,0 @@
|
||||||
/*
|
|
||||||
* This file is part of the UCB release of Plan 9. It is subject to the license
|
|
||||||
* terms in the LICENSE file found in the top-level directory of this
|
|
||||||
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
|
|
||||||
* part of the UCB release of Plan 9, including this file, may be copied,
|
|
||||||
* modified, propagated, or distributed except according to the terms contained
|
|
||||||
* in the LICENSE file.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "rc.h"
|
|
||||||
#include "getflags.h"
|
|
||||||
#include "exec.h"
|
|
||||||
#include "io.h"
|
|
||||||
#include "fns.h"
|
|
||||||
|
|
||||||
int havefork = 0;
|
|
||||||
|
|
||||||
static char **
|
|
||||||
rcargv(char *s)
|
|
||||||
{
|
|
||||||
int argc;
|
|
||||||
char **argv;
|
|
||||||
word *p;
|
|
||||||
|
|
||||||
p = vlook("*")->val;
|
|
||||||
argv = emalloc((count(p)+6)*sizeof(char*));
|
|
||||||
argc = 0;
|
|
||||||
argv[argc++] = argv0;
|
|
||||||
if(flag['e'])
|
|
||||||
argv[argc++] = "-Se";
|
|
||||||
else
|
|
||||||
argv[argc++] = "-S";
|
|
||||||
argv[argc++] = "-c";
|
|
||||||
argv[argc++] = s;
|
|
||||||
for(p = vlook("*")->val; p; p = p->next)
|
|
||||||
argv[argc++] = p->word;
|
|
||||||
argv[argc] = 0;
|
|
||||||
return argv;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
Xasync(void)
|
|
||||||
{
|
|
||||||
uint32_t pid;
|
|
||||||
char buf[20], **argv;
|
|
||||||
|
|
||||||
Updenv();
|
|
||||||
|
|
||||||
argv = rcargv(runq->code[runq->pc].s);
|
|
||||||
pid = ForkExecute(argv0, argv, -1, 1, 2);
|
|
||||||
free(argv);
|
|
||||||
|
|
||||||
if(pid == 0) {
|
|
||||||
Xerror("proc failed");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
runq->pc++;
|
|
||||||
sprint(buf, "%d", pid);
|
|
||||||
setvar("apid", newword(buf, (word *)0));
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
Xbackq(void)
|
|
||||||
{
|
|
||||||
char wd[8193], **argv;
|
|
||||||
int c;
|
|
||||||
char *s, *ewd=&wd[8192], *stop;
|
|
||||||
struct io *f;
|
|
||||||
var *ifs = vlook("ifs");
|
|
||||||
word *v, *nextv;
|
|
||||||
int pfd[2];
|
|
||||||
int pid;
|
|
||||||
|
|
||||||
stop = ifs->val?ifs->val->word:"";
|
|
||||||
if(pipe(pfd)<0){
|
|
||||||
Xerror("can't make pipe");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Updenv();
|
|
||||||
|
|
||||||
argv = rcargv(runq->code[runq->pc].s);
|
|
||||||
pid = ForkExecute(argv0, argv, -1, pfd[1], 2);
|
|
||||||
free(argv);
|
|
||||||
|
|
||||||
close(pfd[1]);
|
|
||||||
|
|
||||||
if(pid == 0) {
|
|
||||||
Xerror("proc failed");
|
|
||||||
close(pfd[0]);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
f = openfd(pfd[0]);
|
|
||||||
s = wd;
|
|
||||||
v = 0;
|
|
||||||
while((c=rchr(f))!=EOF){
|
|
||||||
if(strchr(stop, c) || s==ewd){
|
|
||||||
if(s!=wd){
|
|
||||||
*s='\0';
|
|
||||||
v=newword(wd, v);
|
|
||||||
s=wd;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else *s++=c;
|
|
||||||
}
|
|
||||||
if(s!=wd){
|
|
||||||
*s='\0';
|
|
||||||
v=newword(wd, v);
|
|
||||||
}
|
|
||||||
closeio(f);
|
|
||||||
Waitfor(pid, 1);
|
|
||||||
/* 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++;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
Xpipe(void)
|
|
||||||
{
|
|
||||||
thread *p=runq;
|
|
||||||
int pc=p->pc, pid;
|
|
||||||
int rfd=p->code[pc+1].i;
|
|
||||||
int pfd[2];
|
|
||||||
char **argv;
|
|
||||||
|
|
||||||
if(pipe(pfd)<0){
|
|
||||||
Xerror1("can't get pipe");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Updenv();
|
|
||||||
|
|
||||||
argv = rcargv(runq->code[pc+2].s);
|
|
||||||
pid = ForkExecute(argv0, argv, 0, pfd[1], 2);
|
|
||||||
free(argv);
|
|
||||||
close(pfd[1]);
|
|
||||||
|
|
||||||
if(pid == 0) {
|
|
||||||
Xerror("proc failed");
|
|
||||||
close(pfd[0]);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
start(p->code, pc+4, runq->local);
|
|
||||||
pushredir(ROPEN, pfd[0], rfd);
|
|
||||||
p->pc=p->code[pc+3].i;
|
|
||||||
p->pid=pid;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
Xpipefd(void)
|
|
||||||
{
|
|
||||||
Abort();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
Xsubshell(void)
|
|
||||||
{
|
|
||||||
char **argv;
|
|
||||||
int pid;
|
|
||||||
|
|
||||||
Updenv();
|
|
||||||
|
|
||||||
argv = rcargv(runq->code[runq->pc].s);
|
|
||||||
pid = ForkExecute(argv0, argv, -1, 1, 2);
|
|
||||||
free(argv);
|
|
||||||
|
|
||||||
if(pid < 0) {
|
|
||||||
Xerror("proc failed");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Waitfor(pid, 1);
|
|
||||||
runq->pc++;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* start a process running the cmd on the stack and return its pid.
|
|
||||||
*/
|
|
||||||
int
|
|
||||||
execforkexec(void)
|
|
||||||
{
|
|
||||||
char **argv;
|
|
||||||
char file[1024];
|
|
||||||
int nc;
|
|
||||||
word *path;
|
|
||||||
int pid;
|
|
||||||
|
|
||||||
if(runq->argv->words==0)
|
|
||||||
return -1;
|
|
||||||
argv = mkargv(runq->argv->words);
|
|
||||||
|
|
||||||
for(path = searchpath(runq->argv->words->word);path;path = path->next){
|
|
||||||
nc = strlen(path->word);
|
|
||||||
if(nc < sizeof file - 1){ /* 1 for / */
|
|
||||||
strcpy(file, path->word);
|
|
||||||
if(file[0]){
|
|
||||||
strcat(file, "/");
|
|
||||||
nc++;
|
|
||||||
}
|
|
||||||
if(nc+strlen(argv[1])<sizeof(file)){
|
|
||||||
strcat(file, argv[1]);
|
|
||||||
pid = ForkExecute(file, argv+1, mapfd(0), mapfd(1), mapfd(2));
|
|
||||||
if(pid >= 0){
|
|
||||||
free(argv);
|
|
||||||
return pid;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
free(argv);
|
|
||||||
return -1;
|
|
||||||
}
|
|
|
@ -14,8 +14,8 @@
|
||||||
|
|
||||||
struct here *here, **ehere;
|
struct here *here, **ehere;
|
||||||
int ser = 0;
|
int ser = 0;
|
||||||
char tmp[] = "/tmp/here0000.0000";
|
char tmp[]="/tmp/here0000.0000";
|
||||||
char hex[] = "0123456789abcdef";
|
char hex[]="0123456789abcdef";
|
||||||
|
|
||||||
void psubst(io*, uint8_t*);
|
void psubst(io*, uint8_t*);
|
||||||
void pstrs(io*, word*);
|
void pstrs(io*, word*);
|
||||||
|
@ -45,7 +45,7 @@ heredoc(tree *tag)
|
||||||
h->tag = tag;
|
h->tag = tag;
|
||||||
hexnum(&tmp[9], getpid());
|
hexnum(&tmp[9], getpid());
|
||||||
hexnum(&tmp[14], ser++);
|
hexnum(&tmp[14], ser++);
|
||||||
h->name = strdup(tmp);
|
h->name = estrdup(tmp);
|
||||||
return token(tmp, WORD);
|
return token(tmp, WORD);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,25 +58,24 @@ heredoc(tree *tag)
|
||||||
void
|
void
|
||||||
readhere(void)
|
readhere(void)
|
||||||
{
|
{
|
||||||
int c, subst;
|
|
||||||
char *s, *tag;
|
|
||||||
char line[NLINE+1];
|
|
||||||
io *f;
|
|
||||||
struct here *h, *nexth;
|
struct here *h, *nexth;
|
||||||
|
io *f;
|
||||||
for(h = here; h; h = nexth){
|
char *s, *tag;
|
||||||
subst = !h->tag->quoted;
|
int c, subst;
|
||||||
|
char line[NLINE+1];
|
||||||
|
for(h = here;h;h = nexth){
|
||||||
|
subst=!h->tag->quoted;
|
||||||
tag = h->tag->str;
|
tag = h->tag->str;
|
||||||
c = Creat(h->name);
|
c = Creat(h->name);
|
||||||
if(c < 0)
|
if(c<0)
|
||||||
yyerror("can't create here document");
|
yyerror("can't create here document");
|
||||||
f = openfd(c);
|
f = openfd(c);
|
||||||
s = line;
|
s = line;
|
||||||
pprompt();
|
pprompt();
|
||||||
while((c = rchr(runq->cmdfd)) != EOF){
|
while((c = rchr(runq->cmdfd)) != EOF){
|
||||||
if(c == '\n' || s == &line[NLINE]){
|
if(c == '\n' || s == &line[NLINE]){
|
||||||
*s = '\0';
|
*s='\0';
|
||||||
if(tag && strcmp(line, tag) == 0)
|
if(tag && strcmp(line, tag)==0)
|
||||||
break;
|
break;
|
||||||
if(subst)
|
if(subst)
|
||||||
psubst(f, (uint8_t *)line);
|
psubst(f, (uint8_t *)line);
|
||||||
|
@ -95,7 +94,7 @@ readhere(void)
|
||||||
closeio(f);
|
closeio(f);
|
||||||
cleanhere(h->name);
|
cleanhere(h->name);
|
||||||
nexth = h->next;
|
nexth = h->next;
|
||||||
efree((char *)h);
|
free(h);
|
||||||
}
|
}
|
||||||
here = 0;
|
here = 0;
|
||||||
doprompt = 1;
|
doprompt = 1;
|
||||||
|
@ -106,19 +105,26 @@ psubst(io *f, uint8_t *s)
|
||||||
{
|
{
|
||||||
int savec, n;
|
int savec, n;
|
||||||
uint8_t *t, *u;
|
uint8_t *t, *u;
|
||||||
Rune r;
|
|
||||||
word *star;
|
word *star;
|
||||||
|
|
||||||
while(*s){
|
while(*s){
|
||||||
if(*s != '$'){ /* copy plain text rune */
|
if(*s != '$'){
|
||||||
if(*s < Runeself)
|
if(0xa0 <= *s && *s <= 0xf5){
|
||||||
pchr(f, *s++);
|
pchr(f, *s++);
|
||||||
else{
|
if(*s == '\0')
|
||||||
n = chartorune(&r, (char *)s);
|
break;
|
||||||
while(n-- > 0)
|
|
||||||
pchr(f, *s++);
|
|
||||||
}
|
}
|
||||||
}else{ /* $something -- perform substitution */
|
else if(0xf6 <= *s && *s <= 0xf7){
|
||||||
|
pchr(f, *s++);
|
||||||
|
if(*s == '\0')
|
||||||
|
break;
|
||||||
|
pchr(f, *s++);
|
||||||
|
if(*s == '\0')
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
pchr(f, *s++);
|
||||||
|
}
|
||||||
|
else{
|
||||||
t = ++s;
|
t = ++s;
|
||||||
if(*t == '$')
|
if(*t == '$')
|
||||||
pchr(f, *t++);
|
pchr(f, *t++);
|
||||||
|
@ -130,14 +136,15 @@ psubst(io *f, uint8_t *s)
|
||||||
n = 0;
|
n = 0;
|
||||||
for(u = s; *u && '0' <= *u && *u <= '9'; u++)
|
for(u = s; *u && '0' <= *u && *u <= '9'; u++)
|
||||||
n = n*10 + *u - '0';
|
n = n*10 + *u - '0';
|
||||||
if(n && *u == '\0'){
|
if(n && *u=='\0'){
|
||||||
star = vlook("*")->val;
|
star = vlook("*")->val;
|
||||||
if(star && 1 <= n && n <= count(star)){
|
if(star && 1 <= n && n <= count(star)){
|
||||||
while(--n)
|
while(--n)
|
||||||
star = star->next;
|
star = star->next;
|
||||||
pstr(f, star->word);
|
pstr(f, star->word);
|
||||||
}
|
}
|
||||||
}else
|
}
|
||||||
|
else
|
||||||
pstrs(f, vlook((char *)s)->val);
|
pstrs(f, vlook((char *)s)->val);
|
||||||
*t = savec;
|
*t = savec;
|
||||||
if(savec == '^')
|
if(savec == '^')
|
||||||
|
|
|
@ -88,35 +88,6 @@ rchr(io *b)
|
||||||
return *b->bufp++;
|
return *b->bufp++;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
|
||||||
rutf(io *b, char *buf, Rune *r)
|
|
||||||
{
|
|
||||||
int n, i, c;
|
|
||||||
|
|
||||||
c = rchr(b);
|
|
||||||
if(c == EOF)
|
|
||||||
return EOF;
|
|
||||||
*buf = c;
|
|
||||||
if(c < Runesync){
|
|
||||||
*r = c;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
for(i = 1; (c = rchr(b)) != EOF; ){
|
|
||||||
buf[i++] = c;
|
|
||||||
buf[i] = 0;
|
|
||||||
if(fullrune(buf, i)){
|
|
||||||
n = chartorune(r, buf);
|
|
||||||
b->bufp -= i - n; /* push back unconsumed bytes */
|
|
||||||
assert(b->fd == -1 || b->bufp > b->buf);
|
|
||||||
return n;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* at eof */
|
|
||||||
b->bufp -= i - 1; /* consume 1 byte */
|
|
||||||
*r = Runeerror;
|
|
||||||
return runetochar(buf, r);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
pquo(io *f, char *s)
|
pquo(io *f, char *s)
|
||||||
{
|
{
|
||||||
|
@ -216,9 +187,7 @@ flush(io *f)
|
||||||
|
|
||||||
if(f->strp){
|
if(f->strp){
|
||||||
n = f->ebuf - f->strp;
|
n = f->ebuf - f->strp;
|
||||||
f->strp = realloc(f->strp, n+Stralloc+1);
|
f->strp = erealloc(f->strp, n+Stralloc+1);
|
||||||
if(f->strp==0)
|
|
||||||
panic("Can't realloc %d bytes in flush!", n+Stralloc+1);
|
|
||||||
f->bufp = f->strp + n;
|
f->bufp = f->strp + n;
|
||||||
f->ebuf = f->bufp + Stralloc;
|
f->ebuf = f->bufp + Stralloc;
|
||||||
memset(f->bufp, '\0', Stralloc+1);
|
memset(f->bufp, '\0', Stralloc+1);
|
||||||
|
@ -270,7 +239,7 @@ opencore(char *s, int len)
|
||||||
f->fd = -1 /*open("/dev/null", OREAD)*/;
|
f->fd = -1 /*open("/dev/null", OREAD)*/;
|
||||||
f->bufp = f->strp = buf;
|
f->bufp = f->strp = buf;
|
||||||
f->ebuf = buf+len;
|
f->ebuf = buf+len;
|
||||||
Memcpy(buf, s, len);
|
memmove(buf, s, len);
|
||||||
return f;
|
return f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -288,11 +257,11 @@ rewind(io *io)
|
||||||
void
|
void
|
||||||
closeio(io *io)
|
closeio(io *io)
|
||||||
{
|
{
|
||||||
if(io->fd>=0)
|
if(io->fd >= 0)
|
||||||
close(io->fd);
|
close(io->fd);
|
||||||
if(io->strp)
|
if(io->strp)
|
||||||
efree(io->strp);
|
free(io->strp);
|
||||||
efree(io);
|
free(io);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
|
|
|
@ -21,7 +21,6 @@ io *openfd(int), *openstr(void), *opencore(char *, int);
|
||||||
int emptybuf(io*);
|
int emptybuf(io*);
|
||||||
void pchr(io*, int);
|
void pchr(io*, int);
|
||||||
int rchr(io*);
|
int rchr(io*);
|
||||||
int rutf(io*, char*, Rune*);
|
|
||||||
void closeio(io*);
|
void closeio(io*);
|
||||||
void flush(io*);
|
void flush(io*);
|
||||||
int fullbuf(io*, int);
|
int fullbuf(io*, int);
|
||||||
|
|
|
@ -101,6 +101,16 @@ pprompt(void)
|
||||||
if(runq->iflag){
|
if(runq->iflag){
|
||||||
pstr(err, promptstr);
|
pstr(err, promptstr);
|
||||||
flush(err);
|
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");
|
prompt = vlook("prompt");
|
||||||
if(prompt->val && prompt->val->next)
|
if(prompt->val && prompt->val->next)
|
||||||
promptstr = prompt->val->next->word;
|
promptstr = prompt->val->next->word;
|
||||||
|
@ -163,7 +173,7 @@ addtok(char *p, int val)
|
||||||
{
|
{
|
||||||
if(p==0)
|
if(p==0)
|
||||||
return 0;
|
return 0;
|
||||||
if(p >= &tok[NTOK]){
|
if(p == &tok[NTOK-1]){
|
||||||
*p = 0;
|
*p = 0;
|
||||||
yyerror("token buffer too short");
|
yyerror("token buffer too short");
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -179,7 +189,7 @@ addutf(char *p, int c)
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
p = addtok(p, c); /* 1-byte UTF runes are special */
|
p = addtok(p, c); /* 1-byte UTF runes are special */
|
||||||
if(c < Runeself)
|
if(onebyte(c))
|
||||||
return p;
|
return p;
|
||||||
|
|
||||||
m = 0xc0;
|
m = 0xc0;
|
||||||
|
|
|
@ -30,7 +30,6 @@ pcmd(io *f, tree *t)
|
||||||
{
|
{
|
||||||
if(t==0)
|
if(t==0)
|
||||||
return;
|
return;
|
||||||
assert(f != nil);
|
|
||||||
switch(t->type){
|
switch(t->type){
|
||||||
default: pfmt(f, "bad cmd %d %p %p %p", t->type, c0, c1, c2);
|
default: pfmt(f, "bad cmd %d %p %p %p", t->type, c0, c1, c2);
|
||||||
break;
|
break;
|
||||||
|
@ -42,7 +41,7 @@ pcmd(io *f, tree *t)
|
||||||
break;
|
break;
|
||||||
case '^': pfmt(f, "%t^%t", c0, c1);
|
case '^': pfmt(f, "%t^%t", c0, c1);
|
||||||
break;
|
break;
|
||||||
case '`': pfmt(f, "`%t", c0);
|
case '`': pfmt(f, "`%t%t", c0, c1);
|
||||||
break;
|
break;
|
||||||
case ANDAND: pfmt(f, "%t && %t", c0, c1);
|
case ANDAND: pfmt(f, "%t && %t", c0, c1);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -17,52 +17,51 @@ struct{
|
||||||
char *name;
|
char *name;
|
||||||
} fname[] = {
|
} fname[] = {
|
||||||
Xappend, "Xappend",
|
Xappend, "Xappend",
|
||||||
Xassign, "Xassign",
|
|
||||||
Xasync, "Xasync",
|
Xasync, "Xasync",
|
||||||
Xbackq, "Xbackq",
|
|
||||||
Xbang, "Xbang",
|
Xbang, "Xbang",
|
||||||
Xcase, "Xcase",
|
|
||||||
Xclose, "Xclose",
|
Xclose, "Xclose",
|
||||||
Xconc, "Xconc",
|
|
||||||
Xcount, "Xcount",
|
|
||||||
Xdelfn, "Xdelfn",
|
|
||||||
Xdelhere, "Xdelhere",
|
|
||||||
Xdol, "Xdol",
|
|
||||||
Xdup, "Xdup",
|
Xdup, "Xdup",
|
||||||
Xeflag, "Xeflag",
|
Xeflag, "Xeflag",
|
||||||
(void (*)(void))Xerror, "Xerror",
|
|
||||||
Xexit, "Xexit",
|
Xexit, "Xexit",
|
||||||
Xfalse, "Xfalse",
|
Xfalse, "Xfalse",
|
||||||
Xfn, "Xfn",
|
|
||||||
Xfor, "Xfor",
|
|
||||||
Xglob, "Xglob",
|
|
||||||
Xif, "Xif",
|
|
||||||
Xifnot, "Xifnot",
|
Xifnot, "Xifnot",
|
||||||
Xjump, "Xjump",
|
Xjump, "Xjump",
|
||||||
Xlocal, "Xlocal",
|
|
||||||
Xmark, "Xmark",
|
Xmark, "Xmark",
|
||||||
Xmatch, "Xmatch",
|
|
||||||
Xpipe, "Xpipe",
|
|
||||||
Xpipefd, "Xpipefd",
|
|
||||||
Xpipewait, "Xpipewait",
|
|
||||||
Xpopm, "Xpopm",
|
Xpopm, "Xpopm",
|
||||||
Xpopredir, "Xpopredir",
|
|
||||||
Xqdol, "Xqdol",
|
|
||||||
Xrdcmds, "Xrdcmds",
|
|
||||||
Xrdfn, "Xrdfn",
|
|
||||||
Xrdwr, "Xrdwr",
|
Xrdwr, "Xrdwr",
|
||||||
Xread, "Xread",
|
Xread, "Xread",
|
||||||
Xreturn, "Xreturn",
|
Xreturn, "Xreturn",
|
||||||
Xsimple, "Xsimple",
|
|
||||||
Xsub, "Xsub",
|
|
||||||
Xsubshell, "Xsubshell",
|
|
||||||
Xtrue, "Xtrue",
|
Xtrue, "Xtrue",
|
||||||
Xunlocal, "Xunlocal",
|
Xif, "Xif",
|
||||||
Xwastrue, "Xwastrue",
|
Xwastrue, "Xwastrue",
|
||||||
Xword, "Xword",
|
Xword, "Xword",
|
||||||
Xwrite, "Xwrite",
|
Xwrite, "Xwrite",
|
||||||
0
|
Xmatch, "Xmatch",
|
||||||
};
|
Xcase, "Xcase",
|
||||||
|
Xconc, "Xconc",
|
||||||
|
Xassign, "Xassign",
|
||||||
|
Xdol, "Xdol",
|
||||||
|
Xcount, "Xcount",
|
||||||
|
Xlocal, "Xlocal",
|
||||||
|
Xunlocal, "Xunlocal",
|
||||||
|
Xfn, "Xfn",
|
||||||
|
Xdelfn, "Xdelfn",
|
||||||
|
Xpipe, "Xpipe",
|
||||||
|
Xpipewait, "Xpipewait",
|
||||||
|
Xpopredir, "Xpopredir",
|
||||||
|
Xrdcmds, "Xrdcmds",
|
||||||
|
(void (*)(void))Xerror, "Xerror",
|
||||||
|
Xbackq, "Xbackq",
|
||||||
|
Xpipefd, "Xpipefd",
|
||||||
|
Xsubshell, "Xsubshell",
|
||||||
|
Xdelhere, "Xdelhere",
|
||||||
|
Xfor, "Xfor",
|
||||||
|
Xglob, "Xglob",
|
||||||
|
Xglobs, "Xglobs",
|
||||||
|
Xrdfn, "Xrdfn",
|
||||||
|
Xsimple, "Xsimple",
|
||||||
|
Xqdol, "Xqdol",
|
||||||
|
0};
|
||||||
|
|
||||||
void
|
void
|
||||||
pfnc(io *fd, thread *t)
|
pfnc(io *fd, thread *t)
|
||||||
|
@ -72,14 +71,14 @@ pfnc(io *fd, thread *t)
|
||||||
list *a;
|
list *a;
|
||||||
|
|
||||||
pfmt(fd, "pid %d cycle %p %d ", getpid(), t->code, t->pc);
|
pfmt(fd, "pid %d cycle %p %d ", getpid(), t->code, t->pc);
|
||||||
for (i = 0; fname[i].f; i++)
|
for(i = 0; fname[i].f; i++)
|
||||||
if (fname[i].f == fn) {
|
if(fname[i].f == fn){
|
||||||
pstr(fd, fname[i].name);
|
pstr(fd, fname[i].name);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (!fname[i].f)
|
if(!fname[i].f)
|
||||||
pfmt(fd, "%p", fn);
|
pfmt(fd, "%p", fn);
|
||||||
for (a = t->argv; a; a = a->next)
|
for(a = t->argv; a; a = a->next)
|
||||||
pfmt(fd, " (%v)", a->words);
|
pfmt(fd, " (%v)", a->words);
|
||||||
pchr(fd, '\n');
|
pchr(fd, '\n');
|
||||||
flush(fd);
|
flush(fd);
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
#include "getflags.h"
|
#include "getflags.h"
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
Maxenvname = 256, /* undocumented limit */
|
Maxenvname = 128, /* undocumented limit */
|
||||||
};
|
};
|
||||||
|
|
||||||
char *Signame[] = {
|
char *Signame[] = {
|
||||||
|
@ -155,7 +155,7 @@ Vinit(void)
|
||||||
setvar(ent[i].name, val);
|
setvar(ent[i].name, val);
|
||||||
vlook(ent[i].name)->changed = 0;
|
vlook(ent[i].name)->changed = 0;
|
||||||
close(f);
|
close(f);
|
||||||
efree(buf);
|
free(buf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -163,42 +163,21 @@ Vinit(void)
|
||||||
}
|
}
|
||||||
close(dir);
|
close(dir);
|
||||||
}
|
}
|
||||||
int envdir;
|
|
||||||
|
|
||||||
void
|
void
|
||||||
Xrdfn(void)
|
Xrdfn(void)
|
||||||
{
|
{
|
||||||
int f, len;
|
if(runq->argv->words == 0)
|
||||||
Dir *e;
|
poplist();
|
||||||
char envname[Maxenvname];
|
else {
|
||||||
static Dir *ent, *allocent;
|
int f = open(runq->argv->words->word, OREAD);
|
||||||
static int nent;
|
popword();
|
||||||
|
runq->pc--;
|
||||||
for(;;){
|
if(f >= 0)
|
||||||
if(nent == 0){
|
execcmds(openfd(f));
|
||||||
free(allocent);
|
|
||||||
nent = dirread(envdir, &allocent);
|
|
||||||
ent = allocent;
|
|
||||||
}
|
|
||||||
if(nent <= 0)
|
|
||||||
break;
|
|
||||||
while(nent){
|
|
||||||
e = ent++;
|
|
||||||
nent--;
|
|
||||||
len = e->length;
|
|
||||||
if(len && strncmp(e->name, "fn#", 3)==0){
|
|
||||||
snprint(envname, sizeof envname, "/env/%s", e->name);
|
|
||||||
if((f = open(envname, OREAD))>=0){
|
|
||||||
execcmds(openfd(f));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
close(envdir);
|
|
||||||
Xreturn();
|
|
||||||
}
|
}
|
||||||
union code rdfns[4];
|
union code rdfns[8];
|
||||||
|
|
||||||
void
|
void
|
||||||
execfinit(void)
|
execfinit(void)
|
||||||
|
@ -206,17 +185,15 @@ execfinit(void)
|
||||||
static int first = 1;
|
static int first = 1;
|
||||||
if(first){
|
if(first){
|
||||||
rdfns[0].i = 1;
|
rdfns[0].i = 1;
|
||||||
rdfns[1].f = Xrdfn;
|
rdfns[1].f = Xmark;
|
||||||
rdfns[2].f = Xjump;
|
rdfns[2].f = Xglobs;
|
||||||
rdfns[3].i = 1;
|
rdfns[4].i = Globsize(rdfns[3].s = "/env/fn#\001*");
|
||||||
|
rdfns[5].f = Xglob;
|
||||||
|
rdfns[6].f = Xrdfn;
|
||||||
|
rdfns[7].f = Xreturn;
|
||||||
first = 0;
|
first = 0;
|
||||||
}
|
}
|
||||||
Xpopm();
|
poplist();
|
||||||
envdir = open("/env", OREAD);
|
|
||||||
if(envdir<0){
|
|
||||||
pfmt(err, "rc: can't open /env: %r\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
start(rdfns, 1, runq->local);
|
start(rdfns, 1, runq->local);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -284,12 +261,10 @@ addenv(var *v)
|
||||||
if((f = Creat(envname))<0)
|
if((f = Creat(envname))<0)
|
||||||
pfmt(err, "rc: can't open %s: %r\n", envname);
|
pfmt(err, "rc: can't open %s: %r\n", envname);
|
||||||
else{
|
else{
|
||||||
if(v->fn){
|
fd = openfd(f);
|
||||||
fd = openfd(f);
|
if(v->fn)
|
||||||
pfmt(fd, "fn %q %s\n", v->name, v->fn[v->pc-1].s);
|
pfmt(fd, "fn %q %s\n", v->name, v->fn[v->pc-1].s);
|
||||||
closeio(fd);
|
closeio(fd);
|
||||||
}
|
|
||||||
close(f);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -318,71 +293,35 @@ Updenv(void)
|
||||||
int
|
int
|
||||||
ForkExecute(char *file, char **argv, int sin, int sout, int serr)
|
ForkExecute(char *file, char **argv, int sin, int sout, int serr)
|
||||||
{
|
{
|
||||||
int pid;
|
return -1;
|
||||||
|
|
||||||
if(access(file, AEXEC) != 0)
|
|
||||||
return -1;
|
|
||||||
switch(pid = fork()){
|
|
||||||
case -1:
|
|
||||||
return -1;
|
|
||||||
case 0:
|
|
||||||
if(sin >= 0)
|
|
||||||
dup(sin, 0);
|
|
||||||
else
|
|
||||||
close(0);
|
|
||||||
if(sout >= 0)
|
|
||||||
dup(sout, 1);
|
|
||||||
else
|
|
||||||
close(1);
|
|
||||||
if(serr >= 0)
|
|
||||||
dup(serr, 2);
|
|
||||||
else
|
|
||||||
close(2);
|
|
||||||
exec(file, argv);
|
|
||||||
exits(file);
|
|
||||||
}
|
|
||||||
return pid;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Execute(word *args, word *path)
|
Execute(word *args, word *path)
|
||||||
{
|
{
|
||||||
char **argv = mkargv(args);
|
char **argv = mkargv(args);
|
||||||
char file[1024], errstr[1024];
|
char file[1024];
|
||||||
int nc;
|
int nc, mc;
|
||||||
|
|
||||||
Updenv();
|
Updenv();
|
||||||
errstr[0] = '\0';
|
mc = strlen(argv[1])+1;
|
||||||
for(;path;path = path->next){
|
for(;path;path = path->next){
|
||||||
nc = strlen(path->word);
|
nc = strlen(path->word);
|
||||||
if(nc < sizeof file - 1){ /* 1 for / */
|
if(nc + mc >= sizeof file - 1){ /* 1 for / */
|
||||||
strcpy(file, path->word);
|
werrstr("command path name too long");
|
||||||
if(file[0]){
|
continue;
|
||||||
strcat(file, "/");
|
|
||||||
nc++;
|
|
||||||
}
|
|
||||||
if(nc + strlen(argv[1]) < sizeof file){
|
|
||||||
strcat(file, argv[1]);
|
|
||||||
exec(file, argv+1);
|
|
||||||
rerrstr(errstr, sizeof errstr);
|
|
||||||
/*
|
|
||||||
* if file exists and is executable, exec should
|
|
||||||
* have worked, unless it's a directory or an
|
|
||||||
* executable for another architecture. in
|
|
||||||
* particular, if it failed due to lack of
|
|
||||||
* swap/vm (e.g., arg. list too long) or other
|
|
||||||
* allocation failure, stop searching and print
|
|
||||||
* the reason for failure.
|
|
||||||
*/
|
|
||||||
if (strstr(errstr, " allocat") != nil ||
|
|
||||||
strstr(errstr, " full") != nil)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else werrstr("command name too long");
|
|
||||||
}
|
}
|
||||||
|
if(nc > 0){
|
||||||
|
memmove(file, path->word, nc);
|
||||||
|
file[nc++] = '/';
|
||||||
|
}
|
||||||
|
memmove(file+nc, argv[1], mc);
|
||||||
|
exec(file, argv+1);
|
||||||
}
|
}
|
||||||
pfmt(err, "%s: %s\n", argv[1], errstr);
|
rerrstr(file, sizeof file);
|
||||||
efree((char *)argv);
|
setstatus(file);
|
||||||
|
pfmt(err, "%s: %s\n", argv[1], file);
|
||||||
|
free(argv);
|
||||||
}
|
}
|
||||||
#define NDIR 256 /* shoud be a better way */
|
#define NDIR 256 /* shoud be a better way */
|
||||||
|
|
||||||
|
@ -475,7 +414,7 @@ Again:
|
||||||
}
|
}
|
||||||
if(dir[f].i == dir[f].n)
|
if(dir[f].i == dir[f].n)
|
||||||
return 0;
|
return 0;
|
||||||
strcpy(p, dir[f].dbuf[dir[f].i].name);
|
strncpy((char*)p, dir[f].dbuf[dir[f].i].name, NDIR);
|
||||||
dir[f].i++;
|
dir[f].i++;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -527,20 +466,20 @@ Unlink(char *name)
|
||||||
remove(name);
|
remove(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t
|
int
|
||||||
Write(int fd, void *buf, int32_t cnt)
|
Write(int fd, void *buf, int cnt)
|
||||||
{
|
{
|
||||||
return write(fd, buf, cnt);
|
return write(fd, buf, cnt);
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t
|
int
|
||||||
Read(int fd, void *buf, int32_t cnt)
|
Read(int fd, void *buf, int cnt)
|
||||||
{
|
{
|
||||||
return read(fd, buf, cnt);
|
return read(fd, buf, cnt);
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t
|
int
|
||||||
Seek(int fd, int32_t cnt, int32_t whence)
|
Seek(int fd, int cnt, int whence)
|
||||||
{
|
{
|
||||||
return seek(fd, cnt, whence);
|
return seek(fd, cnt, whence);
|
||||||
}
|
}
|
||||||
|
@ -621,27 +560,13 @@ Abort(void)
|
||||||
Exit("aborting");
|
Exit("aborting");
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
Memcpy(void *a, void *b, int32_t n)
|
|
||||||
{
|
|
||||||
memmove(a, b, n);
|
|
||||||
}
|
|
||||||
|
|
||||||
void*
|
|
||||||
Malloc(uint32_t n)
|
|
||||||
{
|
|
||||||
return mallocz(n, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
int *waitpids;
|
int *waitpids;
|
||||||
int nwaitpids;
|
int nwaitpids;
|
||||||
|
|
||||||
void
|
void
|
||||||
addwaitpid(int pid)
|
addwaitpid(int pid)
|
||||||
{
|
{
|
||||||
waitpids = realloc(waitpids, (nwaitpids+1)*sizeof waitpids[0]);
|
waitpids = erealloc(waitpids, (nwaitpids+1)*sizeof waitpids[0]);
|
||||||
if(waitpids == 0)
|
|
||||||
panic("Can't realloc %d waitpids", nwaitpids+1);
|
|
||||||
waitpids[nwaitpids++] = pid;
|
waitpids[nwaitpids++] = pid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,14 +6,6 @@
|
||||||
* modified, propagated, or distributed except according to the terms contained
|
* modified, propagated, or distributed except according to the terms contained
|
||||||
* in the LICENSE file.
|
* in the LICENSE file.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
|
||||||
* Assume plan 9 by default; if Unix is defined, assume unix.
|
|
||||||
* Please don't litter the code with ifdefs. The five below should be enough.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef Unix
|
|
||||||
/* plan 9 */
|
|
||||||
#include <u.h>
|
#include <u.h>
|
||||||
#include <lib9.h>
|
#include <lib9.h>
|
||||||
|
|
||||||
|
@ -21,18 +13,6 @@
|
||||||
#define SIGINT 2
|
#define SIGINT 2
|
||||||
#define SIGQUIT 3
|
#define SIGQUIT 3
|
||||||
|
|
||||||
#define fcntl(fd, op, arg) /* unix compatibility */
|
|
||||||
#define F_SETFD
|
|
||||||
#define FD_CLOEXEC
|
|
||||||
#define YYSIZE_T size_t /* GNU Bison/yacc has hundred of types :( */
|
|
||||||
#else
|
|
||||||
#include "unix.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef ERRMAX
|
|
||||||
#define ERRMAX 128
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define YYMAXDEPTH 500
|
#define YYMAXDEPTH 500
|
||||||
#ifndef YYPREFIX
|
#ifndef YYPREFIX
|
||||||
#ifndef PAREN
|
#ifndef PAREN
|
||||||
|
@ -50,11 +30,6 @@ typedef struct redir redir;
|
||||||
typedef struct thread thread;
|
typedef struct thread thread;
|
||||||
typedef struct builtin builtin;
|
typedef struct builtin builtin;
|
||||||
|
|
||||||
#ifndef Unix
|
|
||||||
#pragma incomplete word
|
|
||||||
#pragma incomplete io
|
|
||||||
#endif
|
|
||||||
|
|
||||||
struct tree{
|
struct tree{
|
||||||
int type;
|
int type;
|
||||||
int rtype, fd0, fd1; /* details of REDIR PIPE DUP tokens */
|
int rtype, fd0, fd1; /* details of REDIR PIPE DUP tokens */
|
||||||
|
@ -84,12 +59,13 @@ union code{
|
||||||
char *s;
|
char *s;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
int newwdir;
|
||||||
char *promptstr;
|
char *promptstr;
|
||||||
int doprompt;
|
int doprompt;
|
||||||
|
|
||||||
#define NTOK 8192 /* maximum bytes in a word (token) */
|
#define NTOK 8192 /* maximum bytes in a word (token) */
|
||||||
|
|
||||||
char tok[NTOK + UTFmax];
|
char tok[NTOK];
|
||||||
|
|
||||||
#define APPEND 1
|
#define APPEND 1
|
||||||
#define WRITE 2
|
#define WRITE 2
|
||||||
|
@ -116,9 +92,11 @@ var *gvar[NVAR]; /* hash for globals */
|
||||||
|
|
||||||
#define new(type) ((type *)emalloc(sizeof(type)))
|
#define new(type) ((type *)emalloc(sizeof(type)))
|
||||||
|
|
||||||
void *emalloc(int32_t);
|
void *emalloc(int);
|
||||||
void *Malloc(uint32_t);
|
void *erealloc(void *, int);
|
||||||
void efree(void *);
|
char *estrdup(char*);
|
||||||
|
|
||||||
|
#define NOFILE 128 /* should come from <param.h> */
|
||||||
|
|
||||||
struct here{
|
struct here{
|
||||||
tree *tag;
|
tree *tag;
|
||||||
|
@ -135,7 +113,12 @@ int mypid;
|
||||||
* GLOB[...] matches anything in the brackets
|
* GLOB[...] matches anything in the brackets
|
||||||
* GLOBGLOB matches GLOB
|
* GLOBGLOB matches GLOB
|
||||||
*/
|
*/
|
||||||
#define GLOB '\001'
|
#define GLOB ((char)0x01)
|
||||||
|
/*
|
||||||
|
* onebyte(c)
|
||||||
|
* Is c the first character of a one-byte utf sequence?
|
||||||
|
*/
|
||||||
|
#define onebyte(c) ((c&0x80)==0x00)
|
||||||
|
|
||||||
char **argp;
|
char **argp;
|
||||||
char **args;
|
char **args;
|
||||||
|
|
|
@ -1,34 +0,0 @@
|
||||||
# rcmain: unix version
|
|
||||||
if(~ $#home 0) home=$HOME
|
|
||||||
if(~ $#ifs 0) ifs='
|
|
||||||
'
|
|
||||||
switch($#prompt){
|
|
||||||
case 0
|
|
||||||
prompt=('% ' ' ')
|
|
||||||
case 1
|
|
||||||
prompt=($prompt ' ')
|
|
||||||
}
|
|
||||||
if(~ $rcname ?.out) prompt=('broken! ' ' ')
|
|
||||||
if(flag p) path=/cmd
|
|
||||||
if not {
|
|
||||||
finit
|
|
||||||
if(~ $#path 0) path=(. /cmd /usr/cmd /usr/local/bin)
|
|
||||||
}
|
|
||||||
fn sigexit
|
|
||||||
if(! ~ $#cflag 0){
|
|
||||||
if(flag l && test -r $home/lib/profile) . $home/lib/profile
|
|
||||||
status=''
|
|
||||||
eval $cflag
|
|
||||||
}
|
|
||||||
if not if(flag i){
|
|
||||||
if(flag l && test -r $home/lib/profile) . $home/lib/profile
|
|
||||||
status=''
|
|
||||||
if(! ~ $#* 0) . $*
|
|
||||||
. -i /dev/fd/0
|
|
||||||
}
|
|
||||||
if not if(~ $#* 0) . /dev/fd/0
|
|
||||||
if not{
|
|
||||||
status=''
|
|
||||||
. $*
|
|
||||||
}
|
|
||||||
exit $status
|
|
|
@ -1,20 +0,0 @@
|
||||||
yacc -d syn.y
|
|
||||||
cmp -s x.tab.h y.tab.h || cp y.tab.h x.tab.h
|
|
||||||
cc -DUnix -c -I. code.c
|
|
||||||
cc -DUnix -c -I. exec.c
|
|
||||||
cc -DUnix -c -I. getflags.c
|
|
||||||
cc -DUnix -c -I. glob.c
|
|
||||||
cc -DUnix -c -I. here.c
|
|
||||||
cc -DUnix -c -I. io.c
|
|
||||||
cc -DUnix -c -I. lex.c
|
|
||||||
cc -DUnix -c -I. pcmd.c
|
|
||||||
cc -DUnix -c -I. pfnc.c
|
|
||||||
cc -DUnix -c -I. simple.c
|
|
||||||
cc -DUnix -c -I. subr.c
|
|
||||||
cc -DUnix -c -I. trap.c
|
|
||||||
cc -DUnix -c -I. tree.c
|
|
||||||
cc -DUnix -c -I. var.c
|
|
||||||
cc -DUnix -c -I. havefork.c
|
|
||||||
cc -DUnix -c -I. unix.c
|
|
||||||
cc -DUnix -c -I. y.tab.c
|
|
||||||
cc -o rc code.o exec.o getflags.o glob.o here.o io.o lex.o pcmd.o pfnc.o simple.o subr.o trap.o tree.o var.o havefork.o unix.o y.tab.o
|
|
|
@ -29,18 +29,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);
|
||||||
|
@ -64,7 +63,6 @@ Xsimple(void)
|
||||||
/* fork and wait is redundant */
|
/* fork and wait is redundant */
|
||||||
pushword("exec");
|
pushword("exec");
|
||||||
execexec();
|
execexec();
|
||||||
Xexit();
|
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
flush(err);
|
flush(err);
|
||||||
|
@ -129,6 +127,7 @@ execexec(void)
|
||||||
doredir(runq->redir);
|
doredir(runq->redir);
|
||||||
Execute(runq->argv->words, searchpath(runq->argv->words->word));
|
Execute(runq->argv->words, searchpath(runq->argv->words->word));
|
||||||
poplist();
|
poplist();
|
||||||
|
Xexit();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -140,7 +139,7 @@ execfunc(var *func)
|
||||||
runq->argv->words = 0;
|
runq->argv->words = 0;
|
||||||
poplist();
|
poplist();
|
||||||
start(func->fn, func->pc, runq->local);
|
start(func->fn, func->pc, runq->local);
|
||||||
runq->local = newvar(strdup("*"), runq->local);
|
runq->local = newvar("*", runq->local);
|
||||||
runq->local->val = starval;
|
runq->local->val = starval;
|
||||||
runq->local->changed = 1;
|
runq->local->changed = 1;
|
||||||
}
|
}
|
||||||
|
@ -149,36 +148,12 @@ 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)
|
||||||
if(chdir(word)<0) return -1;
|
return -1;
|
||||||
if(flag['i']!=0){
|
newwdir = 1;
|
||||||
if(wdirfd==-2) /* try only once */
|
|
||||||
wdirfd = open("/dev/wdir", OWRITE|OCEXEC);
|
|
||||||
if(wdirfd>=0) {
|
|
||||||
fcntl(wdirfd, F_SETFD, FD_CLOEXEC);
|
|
||||||
write(wdirfd, word, strlen(word));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *
|
|
||||||
appfile(char *dir, char *comp)
|
|
||||||
{
|
|
||||||
int dirlen, complen;
|
|
||||||
char *s, *p;
|
|
||||||
|
|
||||||
dirlen = strlen(dir);
|
|
||||||
complen = strlen(comp);
|
|
||||||
s = emalloc(dirlen + 1 + complen + 1);
|
|
||||||
memmove(s, dir, dirlen);
|
|
||||||
p = s + dirlen;
|
|
||||||
*p++ = '/';
|
|
||||||
memmove(p, comp, complen);
|
|
||||||
p[complen] = '\0';
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
execcd(void)
|
execcd(void)
|
||||||
{
|
{
|
||||||
|
@ -197,9 +172,10 @@ execcd(void)
|
||||||
cdpath = &nullpath;
|
cdpath = &nullpath;
|
||||||
for(; cdpath; cdpath = cdpath->next){
|
for(; cdpath; cdpath = cdpath->next){
|
||||||
if(cdpath->word[0] != '\0')
|
if(cdpath->word[0] != '\0')
|
||||||
dir = appfile(cdpath->word, a->next->word);
|
dir = smprint("%s/%s", cdpath->word,
|
||||||
|
a->next->word);
|
||||||
else
|
else
|
||||||
dir = strdup(a->next->word);
|
dir = estrdup(a->next->word);
|
||||||
|
|
||||||
if(dochdir(dir) >= 0){
|
if(dochdir(dir) >= 0){
|
||||||
if(cdpath->word[0] != '\0' &&
|
if(cdpath->word[0] != '\0' &&
|
||||||
|
@ -261,10 +237,10 @@ execshift(void)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
star = vlook("*");
|
star = vlook("*");
|
||||||
for(;n && star->val;--n){
|
for(;n>0 && star->val;--n){
|
||||||
a = star->val->next;
|
a = star->val->next;
|
||||||
efree(star->val->word);
|
free(star->val->word);
|
||||||
efree((char *)star->val);
|
free(star->val);
|
||||||
star->val = a;
|
star->val = a;
|
||||||
star->changed = 1;
|
star->changed = 1;
|
||||||
}
|
}
|
||||||
|
@ -272,15 +248,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)
|
||||||
{
|
{
|
||||||
|
@ -320,26 +287,19 @@ 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);
|
free(cmdline);
|
||||||
}
|
}
|
||||||
union code dotcmds[14];
|
union code dotcmds[14];
|
||||||
|
|
||||||
|
@ -382,14 +342,14 @@ execdot(void)
|
||||||
Xerror1("Usage: . [-i] file [arg ...]");
|
Xerror1("Usage: . [-i] file [arg ...]");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
zero = strdup(p->argv->words->word);
|
zero = estrdup(p->argv->words->word);
|
||||||
popword();
|
popword();
|
||||||
fd = -1;
|
fd = -1;
|
||||||
for(path = searchpath(zero); path; path = path->next){
|
for(path = searchpath(zero); path; path = path->next){
|
||||||
if(path->word[0] != '\0')
|
if(path->word[0] != '\0')
|
||||||
file = appfile(path->word, zero);
|
file = smprint("%s/%s", path->word, zero);
|
||||||
else
|
else
|
||||||
file = strdup(zero);
|
file = estrdup(zero);
|
||||||
|
|
||||||
fd = open(file, OREAD);
|
fd = open(file, OREAD);
|
||||||
free(file);
|
free(file);
|
||||||
|
@ -420,7 +380,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);
|
free(av);
|
||||||
/* push $0 value */
|
/* push $0 value */
|
||||||
pushlist();
|
pushlist();
|
||||||
pushword(zero);
|
pushword(zero);
|
||||||
|
@ -469,7 +429,6 @@ execwhatis(void){ /* mildly wrong -- should fork before writing */
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
setstatus("");
|
setstatus("");
|
||||||
memset(out, 0, sizeof out);
|
|
||||||
out->fd = mapfd(1);
|
out->fd = mapfd(1);
|
||||||
out->bufp = out->buf;
|
out->bufp = out->buf;
|
||||||
out->ebuf = &out->buf[NBUF];
|
out->ebuf = &out->buf[NBUF];
|
||||||
|
@ -505,10 +464,10 @@ execwhatis(void){ /* mildly wrong -- should fork before writing */
|
||||||
for(path = searchpath(a->word); path;
|
for(path = searchpath(a->word); path;
|
||||||
path = path->next){
|
path = path->next){
|
||||||
if(path->word[0] != '\0')
|
if(path->word[0] != '\0')
|
||||||
file = appfile(path->word,
|
file = smprint("%s/%s",
|
||||||
a->word);
|
path->word, a->word);
|
||||||
else
|
else
|
||||||
file = strdup(a->word);
|
file = estrdup(a->word);
|
||||||
if(Executable(file)){
|
if(Executable(file)){
|
||||||
pfmt(out, "%s\n", file);
|
pfmt(out, "%s\n", file);
|
||||||
free(file);
|
free(file);
|
||||||
|
|
|
@ -13,24 +13,35 @@
|
||||||
#include "fns.h"
|
#include "fns.h"
|
||||||
|
|
||||||
void *
|
void *
|
||||||
emalloc(int32_t n)
|
emalloc(int n)
|
||||||
{
|
{
|
||||||
void *p = Malloc(n);
|
void *p = malloc(n);
|
||||||
|
|
||||||
if(p==0)
|
if(p==0)
|
||||||
panic("Can't malloc %d bytes", n);
|
panic("Can't malloc %d bytes", n);
|
||||||
/* if(err){ pfmt(err, "malloc %d->%p\n", n, p); flush(err); } */
|
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void*
|
||||||
efree(void *p)
|
erealloc(void *p, int n)
|
||||||
{
|
{
|
||||||
/* pfmt(err, "free %p\n", p); flush(err); */
|
p = realloc(p, n);
|
||||||
if(p)
|
if(p==0 && n!=0)
|
||||||
free(p);
|
panic("Can't realloc %d bytes\n", n);
|
||||||
else pfmt(err, "free 0\n");
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char*
|
||||||
|
estrdup(char *s)
|
||||||
|
{
|
||||||
|
char *d;
|
||||||
|
int n;
|
||||||
|
|
||||||
|
n = strlen(s)+1;
|
||||||
|
d = emalloc(n);
|
||||||
|
memmove(d, s, n);
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
|
||||||
extern int lastword, lastdol;
|
extern int lastword, lastdol;
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -68,7 +79,7 @@ iacvt(int n)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
inttoascii(char *s, int32_t n)
|
inttoascii(char *s, int n)
|
||||||
{
|
{
|
||||||
bp = s;
|
bp = s;
|
||||||
iacvt(n);
|
iacvt(n);
|
||||||
|
|
|
@ -83,7 +83,8 @@ comword: '$' word {$$=tree1('$', $2);}
|
||||||
| '"' word {$$=tree1('"', $2);}
|
| '"' word {$$=tree1('"', $2);}
|
||||||
| COUNT word {$$=tree1(COUNT, $2);}
|
| COUNT word {$$=tree1(COUNT, $2);}
|
||||||
| WORD
|
| WORD
|
||||||
| '`' brace {$$=tree1('`', $2);}
|
| '`' brace {$$=tree2('`', (struct tree*)0, $2);}
|
||||||
|
| '`' word brace {$$=tree2('`', $2, $3);}
|
||||||
| '(' words ')' {$$=tree1(PAREN, $2);}
|
| '(' words ')' {$$=tree1(PAREN, $2);}
|
||||||
| REDIR brace {$$=mung1($1, $2); $$->type=PIPEFD;}
|
| REDIR brace {$$=mung1($1, $2); $$->type=PIPEFD;}
|
||||||
keyword: FOR|IN|WHILE|IF|NOT|TWIDDLE|BANG|SUBSHELL|SWITCH|FN
|
keyword: FOR|IN|WHILE|IF|NOT|TWIDDLE|BANG|SUBSHELL|SWITCH|FN
|
||||||
|
|
|
@ -27,7 +27,7 @@ dotrap(void)
|
||||||
trapreq = vlook(Signame[i]);
|
trapreq = vlook(Signame[i]);
|
||||||
if(trapreq->fn){
|
if(trapreq->fn){
|
||||||
start(trapreq->fn, trapreq->pc, (struct var *)0);
|
start(trapreq->fn, trapreq->pc, (struct var *)0);
|
||||||
runq->local = newvar(strdup("*"), runq->local);
|
runq->local = newvar("*", runq->local);
|
||||||
runq->local->val = copywords(starval, (struct word *)0);
|
runq->local->val = copywords(starval, (struct word *)0);
|
||||||
runq->local->changed = 1;
|
runq->local->changed = 1;
|
||||||
runq->redir = runq->startredir = 0;
|
runq->redir = runq->startredir = 0;
|
||||||
|
|
|
@ -36,8 +36,8 @@ freenodes(void)
|
||||||
for(t = treenodes;t;t = u){
|
for(t = treenodes;t;t = u){
|
||||||
u = t->next;
|
u = t->next;
|
||||||
if(t->str)
|
if(t->str)
|
||||||
efree(t->str);
|
free(t->str);
|
||||||
efree((char *)t);
|
free(t);
|
||||||
}
|
}
|
||||||
treenodes = 0;
|
treenodes = 0;
|
||||||
}
|
}
|
||||||
|
@ -120,7 +120,7 @@ simplemung(tree *t)
|
||||||
t = tree1(SIMPLE, t);
|
t = tree1(SIMPLE, t);
|
||||||
s = openstr();
|
s = openstr();
|
||||||
pfmt(s, "%t", t);
|
pfmt(s, "%t", t);
|
||||||
t->str = strdup((char *)s->strp);
|
t->str = estrdup((char *)s->strp);
|
||||||
closeio(s);
|
closeio(s);
|
||||||
for(u = t->child[0];u->type==ARGLIST;u = u->child[0]){
|
for(u = t->child[0];u->type==ARGLIST;u = u->child[0]){
|
||||||
if(u->child[1]->type==DUP
|
if(u->child[1]->type==DUP
|
||||||
|
@ -152,6 +152,6 @@ freetree(tree *p)
|
||||||
freetree(p->child[1]);
|
freetree(p->child[1]);
|
||||||
freetree(p->child[2]);
|
freetree(p->child[2]);
|
||||||
if(p->str)
|
if(p->str)
|
||||||
efree(p->str);
|
free(p->str);
|
||||||
efree((char *)p);
|
free(p);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,601 +0,0 @@
|
||||||
/*
|
|
||||||
* This file is part of the UCB release of Plan 9. It is subject to the license
|
|
||||||
* terms in the LICENSE file found in the top-level directory of this
|
|
||||||
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
|
|
||||||
* part of the UCB release of Plan 9, including this file, may be copied,
|
|
||||||
* modified, propagated, or distributed except according to the terms contained
|
|
||||||
* in the LICENSE file.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Unix versions of system-specific functions
|
|
||||||
* By convention, exported routines herein have names beginning with an
|
|
||||||
* upper case letter.
|
|
||||||
*/
|
|
||||||
#include "rc.h"
|
|
||||||
#include "io.h"
|
|
||||||
#include "exec.h"
|
|
||||||
#include "getflags.h"
|
|
||||||
#include <errno.h>
|
|
||||||
|
|
||||||
char *Rcmain = "/usr/lib/rcmain";
|
|
||||||
char *Fdprefix = "/dev/fd/";
|
|
||||||
|
|
||||||
void execfinit(void);
|
|
||||||
|
|
||||||
struct builtin Builtin[] = {
|
|
||||||
"cd", execcd,
|
|
||||||
"whatis", execwhatis,
|
|
||||||
"eval", execeval,
|
|
||||||
"exec", execexec, /* but with popword first */
|
|
||||||
"exit", execexit,
|
|
||||||
"shift", execshift,
|
|
||||||
"wait", execwait,
|
|
||||||
"umask", execumask,
|
|
||||||
".", execdot,
|
|
||||||
"finit", execfinit,
|
|
||||||
"flag", execflag,
|
|
||||||
0
|
|
||||||
};
|
|
||||||
#define SEP '\1'
|
|
||||||
char **environp;
|
|
||||||
|
|
||||||
struct word*
|
|
||||||
enval(s)
|
|
||||||
register char *s;
|
|
||||||
{
|
|
||||||
char *t, c;
|
|
||||||
struct word *v;
|
|
||||||
for(t = s;*t && *t!=SEP;t++);
|
|
||||||
c=*t;
|
|
||||||
*t='\0';
|
|
||||||
v = newword(s, c=='\0'?(struct word *)0:enval(t+1));
|
|
||||||
*t = c;
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
Vinit(void)
|
|
||||||
{
|
|
||||||
extern char **environ;
|
|
||||||
char *s;
|
|
||||||
char **env = environ;
|
|
||||||
environp = env;
|
|
||||||
for(;*env;env++){
|
|
||||||
for(s=*env;*s && *s!='(' && *s!='=';s++);
|
|
||||||
switch(*s){
|
|
||||||
case '\0':
|
|
||||||
pfmt(err, "environment %q?\n", *env);
|
|
||||||
break;
|
|
||||||
case '=':
|
|
||||||
*s='\0';
|
|
||||||
setvar(*env, enval(s+1));
|
|
||||||
*s='=';
|
|
||||||
break;
|
|
||||||
case '(': /* ignore functions for now */
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
char **envp;
|
|
||||||
|
|
||||||
void
|
|
||||||
Xrdfn(void)
|
|
||||||
{
|
|
||||||
char *s;
|
|
||||||
int len;
|
|
||||||
for(;*envp;envp++){
|
|
||||||
for(s=*envp;*s && *s!='(' && *s!='=';s++);
|
|
||||||
switch(*s){
|
|
||||||
case '\0':
|
|
||||||
pfmt(err, "environment %q?\n", *envp);
|
|
||||||
break;
|
|
||||||
case '=': /* ignore variables */
|
|
||||||
break;
|
|
||||||
case '(': /* Bourne again */
|
|
||||||
s=*envp+3;
|
|
||||||
envp++;
|
|
||||||
len = strlen(s);
|
|
||||||
s[len]='\n';
|
|
||||||
execcmds(opencore(s, len+1));
|
|
||||||
s[len]='\0';
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Xreturn();
|
|
||||||
}
|
|
||||||
|
|
||||||
union code rdfns[4];
|
|
||||||
|
|
||||||
void
|
|
||||||
execfinit(void)
|
|
||||||
{
|
|
||||||
static int first = 1;
|
|
||||||
if(first){
|
|
||||||
rdfns[0].i = 1;
|
|
||||||
rdfns[1].f = Xrdfn;
|
|
||||||
rdfns[2].f = Xjump;
|
|
||||||
rdfns[3].i = 1;
|
|
||||||
first = 0;
|
|
||||||
}
|
|
||||||
Xpopm();
|
|
||||||
envp = environp;
|
|
||||||
start(rdfns, 1, runq->local);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
cmpenv(const void *aa, const void *ab)
|
|
||||||
{
|
|
||||||
char **a = aa, **b = ab;
|
|
||||||
|
|
||||||
return strcmp(*a, *b);
|
|
||||||
}
|
|
||||||
|
|
||||||
char **
|
|
||||||
mkenv(void)
|
|
||||||
{
|
|
||||||
char **env, **ep, *p, *q;
|
|
||||||
struct var **h, *v;
|
|
||||||
struct word *a;
|
|
||||||
int nvar = 0, nchr = 0, sep;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Slightly kludgy loops look at locals then globals.
|
|
||||||
* locals no longer exist - geoff
|
|
||||||
*/
|
|
||||||
for(h = gvar-1; h != &gvar[NVAR]; h++)
|
|
||||||
for(v = h >= gvar? *h: runq->local; v ;v = v->next){
|
|
||||||
if((v==vlook(v->name)) && v->val){
|
|
||||||
nvar++;
|
|
||||||
nchr+=strlen(v->name)+1;
|
|
||||||
for(a = v->val;a;a = a->next)
|
|
||||||
nchr+=strlen(a->word)+1;
|
|
||||||
}
|
|
||||||
if(v->fn){
|
|
||||||
nvar++;
|
|
||||||
nchr+=strlen(v->name)+strlen(v->fn[v->pc-1].s)+8;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
env = (char **)emalloc((nvar+1)*sizeof(char *)+nchr);
|
|
||||||
ep = env;
|
|
||||||
p = (char *)&env[nvar+1];
|
|
||||||
for(h = gvar-1; h != &gvar[NVAR]; h++)
|
|
||||||
for(v = h >= gvar? *h: runq->local;v;v = v->next){
|
|
||||||
if((v==vlook(v->name)) && v->val){
|
|
||||||
*ep++=p;
|
|
||||||
q = v->name;
|
|
||||||
while(*q) *p++=*q++;
|
|
||||||
sep='=';
|
|
||||||
for(a = v->val;a;a = a->next){
|
|
||||||
*p++=sep;
|
|
||||||
sep = SEP;
|
|
||||||
q = a->word;
|
|
||||||
while(*q) *p++=*q++;
|
|
||||||
}
|
|
||||||
*p++='\0';
|
|
||||||
}
|
|
||||||
if(v->fn){
|
|
||||||
*ep++=p;
|
|
||||||
*p++='#'; *p++='('; *p++=')'; /* to fool Bourne */
|
|
||||||
*p++='f'; *p++='n'; *p++=' ';
|
|
||||||
q = v->name;
|
|
||||||
while(*q) *p++=*q++;
|
|
||||||
*p++=' ';
|
|
||||||
q = v->fn[v->pc-1].s;
|
|
||||||
while(*q) *p++=*q++;
|
|
||||||
*p++='\0';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*ep = 0;
|
|
||||||
qsort((void *)env, nvar, sizeof ep[0], cmpenv);
|
|
||||||
return env;
|
|
||||||
}
|
|
||||||
char *sigmsg[] = {
|
|
||||||
/* 0 normal */ 0,
|
|
||||||
/* 1 SIGHUP */ "Hangup",
|
|
||||||
/* 2 SIGINT */ 0,
|
|
||||||
/* 3 SIGQUIT */ "Quit",
|
|
||||||
/* 4 SIGILL */ "Illegal instruction",
|
|
||||||
/* 5 SIGTRAP */ "Trace/BPT trap",
|
|
||||||
/* 6 SIGIOT */ "abort",
|
|
||||||
/* 7 SIGEMT */ "EMT trap",
|
|
||||||
/* 8 SIGFPE */ "Floating exception",
|
|
||||||
/* 9 SIGKILL */ "Killed",
|
|
||||||
/* 10 SIGBUS */ "Bus error",
|
|
||||||
/* 11 SIGSEGV */ "Memory fault",
|
|
||||||
/* 12 SIGSYS */ "Bad system call",
|
|
||||||
/* 13 SIGPIPE */ 0,
|
|
||||||
/* 14 SIGALRM */ "Alarm call",
|
|
||||||
/* 15 SIGTERM */ "Terminated",
|
|
||||||
/* 16 unused */ "signal 16",
|
|
||||||
/* 17 SIGSTOP */ "Process stopped",
|
|
||||||
/* 18 unused */ "signal 18",
|
|
||||||
/* 19 SIGCONT */ "Process continued",
|
|
||||||
/* 20 SIGCHLD */ "Child death",
|
|
||||||
};
|
|
||||||
|
|
||||||
void
|
|
||||||
Waitfor(int pid, int persist)
|
|
||||||
{
|
|
||||||
int wpid, sig;
|
|
||||||
struct thread *p;
|
|
||||||
int wstat;
|
|
||||||
char wstatstr[12];
|
|
||||||
|
|
||||||
for(;;){
|
|
||||||
errno = 0;
|
|
||||||
wpid = wait(&wstat);
|
|
||||||
if(errno==EINTR && persist)
|
|
||||||
continue;
|
|
||||||
if(wpid==-1)
|
|
||||||
break;
|
|
||||||
sig = wstat&0177;
|
|
||||||
if(sig==0177){
|
|
||||||
pfmt(err, "trace: ");
|
|
||||||
sig = (wstat>>8)&0177;
|
|
||||||
}
|
|
||||||
if(sig>(sizeof sigmsg/sizeof sigmsg[0]) || sigmsg[sig]){
|
|
||||||
if(pid!=wpid)
|
|
||||||
pfmt(err, "%d: ", wpid);
|
|
||||||
if(sig<=(sizeof sigmsg/sizeof sigmsg[0]))
|
|
||||||
pfmt(err, "%s", sigmsg[sig]);
|
|
||||||
else if(sig==0177) pfmt(err, "stopped by ptrace");
|
|
||||||
else pfmt(err, "signal %d", sig);
|
|
||||||
if(wstat&0200)pfmt(err, " -- core dumped");
|
|
||||||
pfmt(err, "\n");
|
|
||||||
}
|
|
||||||
wstat = sig?sig+1000:(wstat>>8)&0xFF;
|
|
||||||
if(wpid==pid){
|
|
||||||
inttoascii(wstatstr, wstat);
|
|
||||||
setstatus(wstatstr);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
for(p = runq->ret;p;p = p->ret)
|
|
||||||
if(p->pid==wpid){
|
|
||||||
p->pid=-1;
|
|
||||||
inttoascii(p->status, wstat);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
char **
|
|
||||||
mkargv(a)
|
|
||||||
register struct 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
|
|
||||||
Updenv(void)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
Execute(struct word *args, struct word *path)
|
|
||||||
{
|
|
||||||
char *msg="not found";
|
|
||||||
int txtbusy = 0;
|
|
||||||
char **env = mkenv();
|
|
||||||
char **argv = mkargv(args);
|
|
||||||
char file[512];
|
|
||||||
|
|
||||||
for(;path;path = path->next){
|
|
||||||
strcpy(file, path->word);
|
|
||||||
if(file[0])
|
|
||||||
strcat(file, "/");
|
|
||||||
strcat(file, argv[1]);
|
|
||||||
ReExec:
|
|
||||||
execve(file, argv+1, env);
|
|
||||||
switch(errno){
|
|
||||||
case ENOEXEC:
|
|
||||||
pfmt(err, "%s: Bourne again\n", argv[1]);
|
|
||||||
argv[0]="sh";
|
|
||||||
argv[1] = strdup(file);
|
|
||||||
execve("/cmd/sh", argv, env);
|
|
||||||
goto Bad;
|
|
||||||
case ETXTBSY:
|
|
||||||
if(++txtbusy!=5){
|
|
||||||
sleep(txtbusy);
|
|
||||||
goto ReExec;
|
|
||||||
}
|
|
||||||
msg="text busy"; goto Bad;
|
|
||||||
case EACCES:
|
|
||||||
msg="no access";
|
|
||||||
break;
|
|
||||||
case ENOMEM:
|
|
||||||
msg="not enough memory"; goto Bad;
|
|
||||||
case E2BIG:
|
|
||||||
msg="too big"; goto Bad;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Bad:
|
|
||||||
pfmt(err, "%s: %s\n", argv[1], msg);
|
|
||||||
efree((char *)env);
|
|
||||||
efree((char *)argv);
|
|
||||||
}
|
|
||||||
|
|
||||||
#define NDIR 14 /* should get this from param.h */
|
|
||||||
|
|
||||||
Globsize(p)
|
|
||||||
register 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <dirent.h>
|
|
||||||
|
|
||||||
#define NDIRLIST 50
|
|
||||||
|
|
||||||
DIR *dirlist[NDIRLIST];
|
|
||||||
|
|
||||||
Opendir(name)
|
|
||||||
char *name;
|
|
||||||
{
|
|
||||||
DIR **dp;
|
|
||||||
for(dp = dirlist;dp!=&dirlist[NDIRLIST];dp++)
|
|
||||||
if(*dp==0){
|
|
||||||
*dp = opendir(name);
|
|
||||||
return *dp?dp-dirlist:-1;
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
Readdir(int f, char *p, int onlydirs)
|
|
||||||
{
|
|
||||||
struct dirent *dp = readdir(dirlist[f]);
|
|
||||||
|
|
||||||
if(dp==0)
|
|
||||||
return 0;
|
|
||||||
strcpy(p, dp->d_name);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
Closedir(int f)
|
|
||||||
{
|
|
||||||
closedir(dirlist[f]);
|
|
||||||
dirlist[f] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
char *Signame[] = {
|
|
||||||
"sigexit", "sighup", "sigint", "sigquit",
|
|
||||||
"sigill", "sigtrap", "sigiot", "sigemt",
|
|
||||||
"sigfpe", "sigkill", "sigbus", "sigsegv",
|
|
||||||
"sigsys", "sigpipe", "sigalrm", "sigterm",
|
|
||||||
"sig16", "sigstop", "sigtstp", "sigcont",
|
|
||||||
"sigchld", "sigttin", "sigttou", "sigtint",
|
|
||||||
"sigxcpu", "sigxfsz", "sig26", "sig27",
|
|
||||||
"sig28", "sig29", "sig30", "sig31",
|
|
||||||
0,
|
|
||||||
};
|
|
||||||
|
|
||||||
void
|
|
||||||
gettrap(int sig)
|
|
||||||
{
|
|
||||||
signal(sig, gettrap);
|
|
||||||
trap[sig]++;
|
|
||||||
ntrap++;
|
|
||||||
if(ntrap>=NSIG){
|
|
||||||
pfmt(err, "rc: Too many traps (trap %d), dumping core\n", sig);
|
|
||||||
signal(SIGABRT, (void (*)())0);
|
|
||||||
kill(getpid(), SIGABRT);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
Trapinit(void)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
void (*sig)();
|
|
||||||
|
|
||||||
if(1 || flag['d']){ /* wrong!!! */
|
|
||||||
sig = signal(SIGINT, gettrap);
|
|
||||||
if(sig==SIG_IGN)
|
|
||||||
signal(SIGINT, SIG_IGN);
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
for(i = 1;i<=NSIG;i++) if(i!=SIGCHLD){
|
|
||||||
sig = signal(i, gettrap);
|
|
||||||
if(sig==SIG_IGN)
|
|
||||||
signal(i, SIG_IGN);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Unlink(name)
|
|
||||||
char *name;
|
|
||||||
{
|
|
||||||
return unlink(name);
|
|
||||||
}
|
|
||||||
Write(fd, buf, cnt)
|
|
||||||
char *buf;
|
|
||||||
{
|
|
||||||
return write(fd, buf, cnt);
|
|
||||||
}
|
|
||||||
Read(fd, buf, cnt)
|
|
||||||
char *buf;
|
|
||||||
{
|
|
||||||
return read(fd, buf, cnt);
|
|
||||||
}
|
|
||||||
Seek(fd, cnt, whence)
|
|
||||||
int32_t cnt;
|
|
||||||
{
|
|
||||||
return lseek(fd, cnt, whence);
|
|
||||||
}
|
|
||||||
Executable(file)
|
|
||||||
char *file;
|
|
||||||
{
|
|
||||||
return(access(file, AEXEC)==0);
|
|
||||||
}
|
|
||||||
Creat(file)
|
|
||||||
char *file;
|
|
||||||
{
|
|
||||||
return creat(file, 0666);
|
|
||||||
}
|
|
||||||
Dup(a, b){
|
|
||||||
return dup2(a, b);
|
|
||||||
}
|
|
||||||
Dup1(a){
|
|
||||||
return dup(a);
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* Wrong: should go through components of a|b|c and return the maximum.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
Exit(char *stat)
|
|
||||||
{
|
|
||||||
int n = 0;
|
|
||||||
|
|
||||||
while(*stat){
|
|
||||||
if(*stat!='|'){
|
|
||||||
if(*stat<'0' || '9'<*stat)
|
|
||||||
exit(1);
|
|
||||||
else n = n*10+*stat-'0';
|
|
||||||
}
|
|
||||||
stat++;
|
|
||||||
}
|
|
||||||
exit(n);
|
|
||||||
}
|
|
||||||
Eintr(){
|
|
||||||
return errno==EINTR;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
Noerror()
|
|
||||||
{
|
|
||||||
errno = 0;
|
|
||||||
}
|
|
||||||
Isatty(fd){
|
|
||||||
return isatty(fd);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
Abort()
|
|
||||||
{
|
|
||||||
abort();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
execumask(void) /* wrong -- should fork before writing */
|
|
||||||
{
|
|
||||||
int m;
|
|
||||||
struct io out[1];
|
|
||||||
switch(count(runq->argv->words)){
|
|
||||||
default:
|
|
||||||
pfmt(err, "Usage: umask [umask]\n");
|
|
||||||
setstatus("umask usage");
|
|
||||||
poplist();
|
|
||||||
return;
|
|
||||||
case 2:
|
|
||||||
umask(octal(runq->argv->words->next->word));
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
umask(m = umask(0));
|
|
||||||
out->fd = mapfd(1);
|
|
||||||
out->bufp = out->buf;
|
|
||||||
out->ebuf=&out->buf[NBUF];
|
|
||||||
out->strp = 0;
|
|
||||||
pfmt(out, "%o\n", m);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
setstatus("");
|
|
||||||
poplist();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
Memcpy(a, b, n)
|
|
||||||
int8_t *a, *b;
|
|
||||||
{
|
|
||||||
memmove(a, b, n);
|
|
||||||
}
|
|
||||||
|
|
||||||
void*
|
|
||||||
Malloc(unsigned long n)
|
|
||||||
{
|
|
||||||
return (void *)malloc(n);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
errstr(char *buf, int len)
|
|
||||||
{
|
|
||||||
strncpy(buf, strerror(errno), len);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
needsrcquote(int c)
|
|
||||||
{
|
|
||||||
if(c <= ' ')
|
|
||||||
return 1;
|
|
||||||
if(strchr("`^#*[]=|\\?${}()'<>&;", c))
|
|
||||||
return 1;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
rfork(int bits)
|
|
||||||
{
|
|
||||||
return fork();
|
|
||||||
}
|
|
||||||
|
|
||||||
int *waitpids;
|
|
||||||
int nwaitpids;
|
|
||||||
|
|
||||||
void
|
|
||||||
addwaitpid(int pid)
|
|
||||||
{
|
|
||||||
waitpids = realloc(waitpids, (nwaitpids+1)*sizeof waitpids[0]);
|
|
||||||
if(waitpids == 0)
|
|
||||||
panic("Can't realloc %d waitpids", nwaitpids+1);
|
|
||||||
waitpids[nwaitpids++] = pid;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
delwaitpid(int pid)
|
|
||||||
{
|
|
||||||
int r, w;
|
|
||||||
|
|
||||||
for(r=w=0; r<nwaitpids; r++)
|
|
||||||
if(waitpids[r] != pid)
|
|
||||||
waitpids[w++] = waitpids[r];
|
|
||||||
nwaitpids = w;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
clearwaitpids(void)
|
|
||||||
{
|
|
||||||
nwaitpids = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
havewaitpid(int pid)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for(i=0; i<nwaitpids; i++)
|
|
||||||
if(waitpids[i] == pid)
|
|
||||||
return 1;
|
|
||||||
return 0;
|
|
||||||
}
|
|
|
@ -1,62 +0,0 @@
|
||||||
/*
|
|
||||||
* This file is part of the UCB release of Plan 9. It is subject to the license
|
|
||||||
* terms in the LICENSE file found in the top-level directory of this
|
|
||||||
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
|
|
||||||
* part of the UCB release of Plan 9, including this file, may be copied,
|
|
||||||
* modified, propagated, or distributed except according to the terms contained
|
|
||||||
* in the LICENSE file.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#undef _BSD_EXTENSION /* avoid multiple def'n if predefined */
|
|
||||||
#undef _PLAN9_SOURCE
|
|
||||||
#undef _POSIX_SOURCE
|
|
||||||
#undef _RESEARCH_SOURCE
|
|
||||||
#undef _SUSV2_SOURCE
|
|
||||||
|
|
||||||
#define _BSD_EXTENSION
|
|
||||||
#define _PLAN9_SOURCE
|
|
||||||
#define _POSIX_SOURCE
|
|
||||||
#define _RESEARCH_SOURCE
|
|
||||||
#define _SUSV2_SOURCE
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <signal.h>
|
|
||||||
#include <inttypes.h>
|
|
||||||
|
|
||||||
#ifndef NSIG
|
|
||||||
#define NSIG 32
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* plan 9 compatibility */
|
|
||||||
#define RFPROC 1
|
|
||||||
#define RFFDG 1
|
|
||||||
#define RFNOTEG 1
|
|
||||||
|
|
||||||
#define uintptr_t uintptr_t
|
|
||||||
|
|
||||||
char *strdup(const char *);
|
|
||||||
|
|
||||||
#define nil ((void*)0)
|
|
||||||
|
|
||||||
/* in case uchar, etc. are built-in types */
|
|
||||||
#define uchar _fmtuchar
|
|
||||||
#define ushort _fmtushort
|
|
||||||
#define uint32_t _fmtuint
|
|
||||||
#define ulong _fmtulong
|
|
||||||
#define vlong _fmtvlong
|
|
||||||
#define uvlong _fmtuvlong
|
|
||||||
|
|
||||||
typedef unsigned char uchar;
|
|
||||||
typedef unsigned short ushort;
|
|
||||||
typedef unsigned int uint32_t;
|
|
||||||
typedef unsigned long ulong;
|
|
||||||
typedef unsigned long long uvlong;
|
|
||||||
|
|
||||||
#define OREAD O_RDONLY
|
|
||||||
#define OWRITE O_WRONLY
|
|
||||||
#define ORDWR O_RDWR
|
|
||||||
#define OCEXEC 0
|
|
|
@ -11,17 +11,14 @@
|
||||||
#include "exec.h"
|
#include "exec.h"
|
||||||
#include "fns.h"
|
#include "fns.h"
|
||||||
|
|
||||||
unsigned
|
int
|
||||||
hash(char *as, int n)
|
hash(char *s, int n)
|
||||||
{
|
{
|
||||||
int i = 1;
|
int h = 0, i = 1;
|
||||||
unsigned h = 0;
|
while(*s)
|
||||||
uint8_t *s;
|
|
||||||
|
|
||||||
s = (uint8_t *)as;
|
|
||||||
while (*s)
|
|
||||||
h += *s++ * i++;
|
h += *s++ * i++;
|
||||||
return h % n;
|
h%=n;
|
||||||
|
return h < 0 ? h+n : h;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define NKW 30
|
#define NKW 30
|
||||||
|
@ -76,8 +73,10 @@ gvlook(char *name)
|
||||||
{
|
{
|
||||||
int h = hash(name, NVAR);
|
int h = hash(name, NVAR);
|
||||||
var *v;
|
var *v;
|
||||||
for(v = gvar[h];v;v = v->next) if(strcmp(v->name, name)==0) return v;
|
for(v = gvar[h];v;v = v->next)
|
||||||
return gvar[h] = newvar(strdup(name), gvar[h]);
|
if(strcmp(v->name, name)==0)
|
||||||
|
return v;
|
||||||
|
return gvar[h] = newvar(name, gvar[h]);
|
||||||
}
|
}
|
||||||
|
|
||||||
var*
|
var*
|
||||||
|
|
|
@ -1,570 +0,0 @@
|
||||||
/*
|
|
||||||
* This file is part of the UCB release of Plan 9. It is subject to the license
|
|
||||||
* terms in the LICENSE file found in the top-level directory of this
|
|
||||||
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
|
|
||||||
* part of the UCB release of Plan 9, including this file, may be copied,
|
|
||||||
* modified, propagated, or distributed except according to the terms contained
|
|
||||||
* in the LICENSE file.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Plan 9 versions of system-specific functions
|
|
||||||
* By convention, exported routines herein have names beginning with an
|
|
||||||
* upper case letter.
|
|
||||||
*/
|
|
||||||
#include "rc.h"
|
|
||||||
#include "exec.h"
|
|
||||||
#include "io.h"
|
|
||||||
#include "fns.h"
|
|
||||||
#include "getflags.h"
|
|
||||||
char *Signame[] = {
|
|
||||||
"sigexit", "sighup", "sigint", "sigquit",
|
|
||||||
"sigalrm", "sigkill", "sigfpe", "sigterm",
|
|
||||||
0
|
|
||||||
};
|
|
||||||
char *syssigname[] = {
|
|
||||||
"exit", /* can't happen */
|
|
||||||
"hangup",
|
|
||||||
"interrupt",
|
|
||||||
"quit", /* can't happen */
|
|
||||||
"alarm",
|
|
||||||
"kill",
|
|
||||||
"sys: fp: ",
|
|
||||||
"term",
|
|
||||||
0
|
|
||||||
};
|
|
||||||
char *Rcmain = "/rc/lib/rcmain";
|
|
||||||
char *Fdprefix = "/fd/";
|
|
||||||
|
|
||||||
void execfinit(void);
|
|
||||||
void execbind(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,
|
|
||||||
0
|
|
||||||
};
|
|
||||||
|
|
||||||
void
|
|
||||||
Vinit(void)
|
|
||||||
{
|
|
||||||
int dir, f, len;
|
|
||||||
word *val;
|
|
||||||
char *buf, *s;
|
|
||||||
Dir *ent;
|
|
||||||
int i, nent;
|
|
||||||
char envname[256];
|
|
||||||
dir = open("/env", OREAD);
|
|
||||||
if(dir<0){
|
|
||||||
pfmt(err, "rc: can't open /env: %r\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
ent = nil;
|
|
||||||
for(;;){
|
|
||||||
nent = dirread(dir, &ent);
|
|
||||||
if(nent <= 0)
|
|
||||||
break;
|
|
||||||
for(i = 0; i<nent; i++){
|
|
||||||
len = ent[i].length;
|
|
||||||
if(len && strncmp(ent[i].name, "fn#", 3)!=0){
|
|
||||||
snprint(envname, sizeof envname, "/env/%s", ent[i].name);
|
|
||||||
if((f = open(envname, OREAD))>=0){
|
|
||||||
buf = emalloc((int)len+1);
|
|
||||||
read(f, buf, (int32_t)len);
|
|
||||||
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);
|
|
||||||
efree(buf);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
free(ent);
|
|
||||||
}
|
|
||||||
close(dir);
|
|
||||||
}
|
|
||||||
int envdir;
|
|
||||||
|
|
||||||
void
|
|
||||||
Xrdfn(void)
|
|
||||||
{
|
|
||||||
int f, len;
|
|
||||||
static Dir *ent, *allocent;
|
|
||||||
static int nent;
|
|
||||||
Dir *e;
|
|
||||||
char envname[256];
|
|
||||||
|
|
||||||
for(;;){
|
|
||||||
if(nent == 0){
|
|
||||||
free(allocent);
|
|
||||||
nent = dirread(envdir, &allocent);
|
|
||||||
ent = allocent;
|
|
||||||
}
|
|
||||||
if(nent <= 0)
|
|
||||||
break;
|
|
||||||
while(nent){
|
|
||||||
e = ent++;
|
|
||||||
nent--;
|
|
||||||
len = e->length;
|
|
||||||
if(len && strncmp(e->name, "fn#", 3)==0){
|
|
||||||
snprint(envname, sizeof envname, "/env/%s", e->name);
|
|
||||||
if((f = open(envname, OREAD))>=0){
|
|
||||||
execcmds(openfd(f));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
close(envdir);
|
|
||||||
Xreturn();
|
|
||||||
}
|
|
||||||
union code rdfns[4];
|
|
||||||
|
|
||||||
void
|
|
||||||
execfinit(void)
|
|
||||||
{
|
|
||||||
static int first = 1;
|
|
||||||
if(first){
|
|
||||||
rdfns[0].i = 1;
|
|
||||||
rdfns[1].f = Xrdfn;
|
|
||||||
rdfns[2].f = Xjump;
|
|
||||||
rdfns[3].i = 1;
|
|
||||||
first = 0;
|
|
||||||
}
|
|
||||||
Xpopm();
|
|
||||||
envdir = open("/env", OREAD);
|
|
||||||
if(envdir<0){
|
|
||||||
pfmt(err, "rc: can't open /env: %r\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
start(rdfns, 1, runq->local);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
Waitfor(int pid, int persist)
|
|
||||||
{
|
|
||||||
thread *p;
|
|
||||||
Waitmsg *w;
|
|
||||||
char errbuf[ERRMAX];
|
|
||||||
|
|
||||||
while((w = wait()) != nil){
|
|
||||||
if(w->pid==pid){
|
|
||||||
setstatus(w->msg);
|
|
||||||
free(w);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
for(p = runq->ret;p;p = p->ret)
|
|
||||||
if(p->pid==w->pid){
|
|
||||||
p->pid=-1;
|
|
||||||
strcpy(p->status, w->msg);
|
|
||||||
}
|
|
||||||
free(w);
|
|
||||||
}
|
|
||||||
|
|
||||||
errstr(errbuf, sizeof errbuf);
|
|
||||||
if(strcmp(errbuf, "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
|
|
||||||
addenv(var *v)
|
|
||||||
{
|
|
||||||
char envname[256];
|
|
||||||
word *w;
|
|
||||||
int f;
|
|
||||||
io *fd;
|
|
||||||
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);
|
|
||||||
else{
|
|
||||||
for(w = v->val;w;w = w->next)
|
|
||||||
write(f, w->word, strlen(w->word)+1L);
|
|
||||||
close(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);
|
|
||||||
else{
|
|
||||||
if(v->fn){
|
|
||||||
fd = openfd(f);
|
|
||||||
pfmt(fd, "fn %q %s\n", v->name, v->fn[v->pc-1].s);
|
|
||||||
closeio(fd);
|
|
||||||
}
|
|
||||||
close(f);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
updenvlocal(var *v)
|
|
||||||
{
|
|
||||||
if(v){
|
|
||||||
updenvlocal(v->next);
|
|
||||||
addenv(v);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
Updenv(void)
|
|
||||||
{
|
|
||||||
var *v, **h;
|
|
||||||
for(h = gvar;h!=&gvar[NVAR];h++)
|
|
||||||
for(v=*h;v;v = v->next)
|
|
||||||
addenv(v);
|
|
||||||
if(runq)
|
|
||||||
updenvlocal(runq->local);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
ForkExecute(char *file, char **argv, int sin, int sout, int serr)
|
|
||||||
{
|
|
||||||
int pid;
|
|
||||||
|
|
||||||
{int i;
|
|
||||||
fprint(2, "forkexec %s", file);
|
|
||||||
for(i = 0; argv[i]; i++)fprint(2, " %s", argv[i]);
|
|
||||||
fprint(2, " %d %d %d\n", sin, sout, serr);
|
|
||||||
}
|
|
||||||
if(access(file, AEXEC) != 0)
|
|
||||||
return -1;
|
|
||||||
fprint(2, "forking\n");
|
|
||||||
switch(pid = fork()){
|
|
||||||
case -1:
|
|
||||||
return -1;
|
|
||||||
case 0:
|
|
||||||
if(sin >= 0)
|
|
||||||
dup(sin, 0);
|
|
||||||
else
|
|
||||||
close(0);
|
|
||||||
if(sout >= 0)
|
|
||||||
dup(sout, 1);
|
|
||||||
else
|
|
||||||
close(1);
|
|
||||||
if(serr >= 0)
|
|
||||||
dup(serr, 2);
|
|
||||||
else
|
|
||||||
close(2);
|
|
||||||
fprint(2, "execing\n");
|
|
||||||
exec(file, argv);
|
|
||||||
fprint(2, "exec: %r\n");
|
|
||||||
exits(file);
|
|
||||||
}
|
|
||||||
return pid;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
Execute(word *args, word *path)
|
|
||||||
{
|
|
||||||
char **argv = mkargv(args);
|
|
||||||
char file[1024];
|
|
||||||
int nc;
|
|
||||||
Updenv();
|
|
||||||
for(;path;path = path->next){
|
|
||||||
nc = strlen(path->word);
|
|
||||||
if(nc<1024){
|
|
||||||
strcpy(file, path->word);
|
|
||||||
if(file[0]){
|
|
||||||
strcat(file, "/");
|
|
||||||
nc++;
|
|
||||||
}
|
|
||||||
if(nc+strlen(argv[1])<1024){
|
|
||||||
strcat(file, argv[1]);
|
|
||||||
exec(file, argv+1);
|
|
||||||
}
|
|
||||||
else werrstr("command name too long");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
rerrstr(file, sizeof file);
|
|
||||||
pfmt(err, "%s: %s\n", argv[1], file);
|
|
||||||
efree((char *)argv);
|
|
||||||
}
|
|
||||||
#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
|
|
||||||
#define NDBUF 32
|
|
||||||
struct{
|
|
||||||
Dir *dbuf;
|
|
||||||
int i;
|
|
||||||
int n;
|
|
||||||
}dir[NFD];
|
|
||||||
|
|
||||||
int
|
|
||||||
Opendir(char *name)
|
|
||||||
{
|
|
||||||
Dir *db;
|
|
||||||
int f;
|
|
||||||
f = open(name, OREAD);
|
|
||||||
if(f==-1)
|
|
||||||
return f;
|
|
||||||
db = dirfstat(f);
|
|
||||||
if(db!=nil && (db->mode&DMDIR)){
|
|
||||||
if(f<NFD){
|
|
||||||
dir[f].i = 0;
|
|
||||||
dir[f].n = 0;
|
|
||||||
}
|
|
||||||
free(db);
|
|
||||||
return f;
|
|
||||||
}
|
|
||||||
free(db);
|
|
||||||
close(f);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
trimdirs(Dir *d, int nd)
|
|
||||||
{
|
|
||||||
int r, w;
|
|
||||||
|
|
||||||
for(r=w=0; r<nd; r++)
|
|
||||||
if(d[r].mode&DMDIR)
|
|
||||||
d[w++] = d[r];
|
|
||||||
return w;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* onlydirs is advisory -- it means you only
|
|
||||||
* need to return the directories. it's okay to
|
|
||||||
* return files too (e.g., on unix where you can't
|
|
||||||
* tell during the readdir), but that just makes
|
|
||||||
* the globber work harder.
|
|
||||||
*/
|
|
||||||
int
|
|
||||||
Readdir(int f, void *p, int onlydirs)
|
|
||||||
{
|
|
||||||
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(n>0){
|
|
||||||
if(onlydirs){
|
|
||||||
n = trimdirs(dir[f].dbuf, n);
|
|
||||||
if(n == 0)
|
|
||||||
goto Again;
|
|
||||||
}
|
|
||||||
dir[f].n = n;
|
|
||||||
}else
|
|
||||||
dir[f].n = 0;
|
|
||||||
dir[f].i = 0;
|
|
||||||
}
|
|
||||||
if(dir[f].i == dir[f].n)
|
|
||||||
return 0;
|
|
||||||
strcpy(p, dir[f].dbuf[dir[f].i].name);
|
|
||||||
dir[f].i++;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
Closedir(int f)
|
|
||||||
{
|
|
||||||
if(f>=0 && f<NFD){
|
|
||||||
free(dir[f].dbuf);
|
|
||||||
dir[f].i = 0;
|
|
||||||
dir[f].n = 0;
|
|
||||||
dir[f].dbuf = 0;
|
|
||||||
}
|
|
||||||
close(f);
|
|
||||||
}
|
|
||||||
int interrupted = 0;
|
|
||||||
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:
|
|
||||||
if(strcmp(s, "interrupt")!=0 || trap[i]==0){
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
Trapinit(void)
|
|
||||||
{
|
|
||||||
notify(notifyf);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
Unlink(char *name)
|
|
||||||
{
|
|
||||||
remove(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t
|
|
||||||
Write(int fd, void *buf, int32_t cnt)
|
|
||||||
{
|
|
||||||
return write(fd, buf, (int32_t)cnt);
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t
|
|
||||||
Read(int fd, void *buf, int32_t cnt)
|
|
||||||
{
|
|
||||||
return read(fd, buf, cnt);
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t
|
|
||||||
Seek(int fd, int32_t cnt, int32_t whence)
|
|
||||||
{
|
|
||||||
return seek(fd, cnt, whence);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
Executable(char *file)
|
|
||||||
{
|
|
||||||
Dir *statbuf;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
statbuf = dirstat(file);
|
|
||||||
if(statbuf == nil)
|
|
||||||
return 0;
|
|
||||||
ret = ((statbuf->mode&0111)!=0 && (statbuf->mode&DMDIR)==0);
|
|
||||||
free(statbuf);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
Creat(char *file)
|
|
||||||
{
|
|
||||||
return create(file, 1, 0666L);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
Dup(int a, int b)
|
|
||||||
{
|
|
||||||
return dup(a, b);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
Dup1(int)
|
|
||||||
{
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
Exit(char *stat)
|
|
||||||
{
|
|
||||||
Updenv();
|
|
||||||
setstatus(stat);
|
|
||||||
exits(truestatus()?"":getstatus());
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
Eintr(void)
|
|
||||||
{
|
|
||||||
return interrupted;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
Noerror(void)
|
|
||||||
{
|
|
||||||
interrupted = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
Isatty(int fd)
|
|
||||||
{
|
|
||||||
Dir *d1, *d2;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
d1 = dirfstat(fd);
|
|
||||||
if(d1 == nil)
|
|
||||||
return 0;
|
|
||||||
if(strncmp(d1->name, "ptty", 4)==0){ /* fwd complaints to philw */
|
|
||||||
free(d1);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
d2 = dirstat("/dev/cons");
|
|
||||||
if(d2 == nil){
|
|
||||||
free(d1);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
ret = (d1->type==d2->type&&d1->dev==d2->dev&&d1->qid.path==d2->qid.path);
|
|
||||||
free(d1);
|
|
||||||
free(d2);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
Abort(void)
|
|
||||||
{
|
|
||||||
pfmt(err, "aborting\n");
|
|
||||||
flush(err);
|
|
||||||
Exit("aborting");
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
Memcpy(void *a, void *b, int32_t n)
|
|
||||||
{
|
|
||||||
memmove(a, b, n);
|
|
||||||
}
|
|
||||||
|
|
||||||
void*
|
|
||||||
Malloc(uint32_t n)
|
|
||||||
{
|
|
||||||
return malloc(n);
|
|
||||||
}
|
|
Loading…
Reference in New Issue