rc: fix everything
Untangle the lexer and interpreter thread state. Fix the file and line number error reporting, getting rid of Xsrcfile instruction, as the whole code block can only come from a single file, stuff the source file in slot[1] of the code block instead. Remove limitations for globber (path element limits) and be more intelligent about handling globbing by inserting Xglob instruction only when needed and not run it over every Xsimple argument list. Remove fragile ndot magic and make it explicit by adding the -q flag to . builtin command. Add -b flag for full compilation. Make exitnext() smart, so we can speculate thru rcmain and avoid the fork(). Get rid of all print(2) format functions and use io instead. Improve the io library, adding rstr() to handle tokenization, which allows us to look ahead in the already read buffer for the terminators, avoiding alot of string copies. Auto indent pcmd(), to make line number reporting more usefull. Implement here documents properly, so they can work everywhere.
This commit is contained in:
parent
855cf4326f
commit
b90036a062
21 changed files with 1527 additions and 1399 deletions
22
sys/man/1/rc
22
sys/man/1/rc
|
@ -615,7 +615,7 @@ usually because their execution changes or depends on
|
||||||
internal state.
|
internal state.
|
||||||
.PD 0
|
.PD 0
|
||||||
.HP
|
.HP
|
||||||
.BI . " file ..."
|
.BI . " [-biq] file ..."
|
||||||
.br
|
.br
|
||||||
Execute commands from
|
Execute commands from
|
||||||
.IR file .
|
.IR file .
|
||||||
|
@ -625,6 +625,20 @@ is set for the duration to the remainder of the argument list following
|
||||||
.I File
|
.I File
|
||||||
is searched for using
|
is searched for using
|
||||||
.BR $path .
|
.BR $path .
|
||||||
|
The flags
|
||||||
|
.B -b
|
||||||
|
and
|
||||||
|
.B -i
|
||||||
|
can be set for the new commands
|
||||||
|
(see description below).
|
||||||
|
The
|
||||||
|
.B -q
|
||||||
|
flag suppresses errors,
|
||||||
|
inhibiting the effect of
|
||||||
|
.B -e
|
||||||
|
and
|
||||||
|
.B -v
|
||||||
|
flags of the main interpreter.
|
||||||
.HP
|
.HP
|
||||||
.BI builtin " command ..."
|
.BI builtin " command ..."
|
||||||
.br
|
.br
|
||||||
|
@ -974,6 +988,10 @@ Print each simple command before executing it.
|
||||||
.B -r
|
.B -r
|
||||||
Print debugging information (internal form of commands
|
Print debugging information (internal form of commands
|
||||||
as they are executed).
|
as they are executed).
|
||||||
|
.TP
|
||||||
|
.B -b
|
||||||
|
Compile the command file as a whole before executing.
|
||||||
|
This allows syntax checking of the whole file.
|
||||||
.PD
|
.PD
|
||||||
.SH FILES
|
.SH FILES
|
||||||
.TF $home/lib/profile
|
.TF $home/lib/profile
|
||||||
|
@ -1004,6 +1022,4 @@ to check the value of
|
||||||
changes
|
changes
|
||||||
.BR $status .
|
.BR $status .
|
||||||
.PP
|
.PP
|
||||||
Functions containing here documents don't work.
|
|
||||||
.PP
|
|
||||||
Free carets don't get inserted next to keywords.
|
Free carets don't get inserted next to keywords.
|
||||||
|
|
|
@ -7,13 +7,12 @@
|
||||||
#define c1 t->child[1]
|
#define c1 t->child[1]
|
||||||
#define c2 t->child[2]
|
#define c2 t->child[2]
|
||||||
code *codebuf;
|
code *codebuf;
|
||||||
int codep, ncode;
|
int codep, ncode, codeline;
|
||||||
#define emitf(x) ((codep!=ncode || morecode()), codebuf[codep].f = (x), codep++)
|
#define emitf(x) ((codep!=ncode || morecode()), codebuf[codep].f = (x), codep++)
|
||||||
#define emiti(x) ((codep!=ncode || morecode()), codebuf[codep].i = (x), codep++)
|
#define emiti(x) ((codep!=ncode || morecode()), codebuf[codep].i = (x), codep++)
|
||||||
#define emits(x) ((codep!=ncode || morecode()), codebuf[codep].s = (x), codep++)
|
#define emits(x) ((codep!=ncode || morecode()), codebuf[codep].s = (x), codep++)
|
||||||
|
|
||||||
void stuffdot(int);
|
void stuffdot(int);
|
||||||
char *fnstr(tree*);
|
|
||||||
void outcode(tree*, int);
|
void outcode(tree*, int);
|
||||||
void codeswitch(tree*, int);
|
void codeswitch(tree*, int);
|
||||||
int iscase(tree*);
|
int iscase(tree*);
|
||||||
|
@ -23,7 +22,7 @@ void codefree(code*);
|
||||||
int
|
int
|
||||||
morecode(void)
|
morecode(void)
|
||||||
{
|
{
|
||||||
ncode+=100;
|
ncode+=ncode;
|
||||||
codebuf = (code *)erealloc((char *)codebuf, ncode*sizeof codebuf[0]);
|
codebuf = (code *)erealloc((char *)codebuf, ncode*sizeof codebuf[0]);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -42,53 +41,66 @@ compile(tree *t)
|
||||||
ncode = 100;
|
ncode = 100;
|
||||||
codebuf = emalloc(ncode*sizeof codebuf[0]);
|
codebuf = emalloc(ncode*sizeof codebuf[0]);
|
||||||
codep = 0;
|
codep = 0;
|
||||||
|
codeline = 0; /* force source */
|
||||||
emiti(0); /* reference count */
|
emiti(0); /* reference count */
|
||||||
outcode(t, flag['e']?1:0);
|
emits(estrdup(lex->file)); /* source file name */
|
||||||
|
outcode(t, !lex->qflag && flag['e']!=0);
|
||||||
if(nerror){
|
if(nerror){
|
||||||
free(codebuf);
|
free(codebuf);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
readhere();
|
|
||||||
emitf(Xreturn);
|
emitf(Xreturn);
|
||||||
emitf(0);
|
emitf(0);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* called on a tree where we expect eigther
|
||||||
|
* a pattern or a string instead of a glob to
|
||||||
|
* remove the GLOB chars from the strings
|
||||||
|
* or set glob to -1 for pattern so not Xglob
|
||||||
|
* is inserted when compiling the tree.
|
||||||
|
*/
|
||||||
void
|
void
|
||||||
cleanhere(char *f)
|
noglobs(tree *t, int pattern)
|
||||||
{
|
{
|
||||||
emitf(Xdelhere);
|
Again:
|
||||||
emits(estrdup(f));
|
if(t==0)
|
||||||
}
|
return;
|
||||||
|
if(t->type==WORD && t->glob){
|
||||||
char*
|
if(pattern)
|
||||||
fnstr(tree *t)
|
t->glob=-1;
|
||||||
{
|
else{
|
||||||
io *f = openstr();
|
deglob(t->str);
|
||||||
void *v;
|
t->glob=0;
|
||||||
|
}
|
||||||
pfmt(f, "%t", t);
|
}
|
||||||
v = f->strp;
|
if(t->type==WORDS || t->type=='^'){
|
||||||
f->strp = 0;
|
t->glob=0;
|
||||||
closeio(f);
|
noglobs(c1, pattern);
|
||||||
return v;
|
t = c0;
|
||||||
|
goto Again;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
outcode(tree *t, int eflag)
|
outcode(tree *t, int eflag)
|
||||||
{
|
{
|
||||||
static int line;
|
void (*f)(void);
|
||||||
int p, q;
|
int p, q;
|
||||||
tree *tt;
|
tree *tt;
|
||||||
char *f;
|
|
||||||
if(t==0)
|
if(t==0)
|
||||||
return;
|
return;
|
||||||
if(t->type!=NOT && t->type!=';')
|
if(t->type!=NOT && t->type!=';')
|
||||||
runq->iflast = 0;
|
lex->iflast = 0;
|
||||||
if(t->line != line){
|
if(t->line != codeline){
|
||||||
line = t->line;
|
codeline = t->line;
|
||||||
emitf(Xsrcline);
|
if(codebuf && codep >= 2 && codebuf[codep-2].f == Xsrcline)
|
||||||
emiti(line);
|
codebuf[codep-1].i = codeline;
|
||||||
|
else {
|
||||||
|
emitf(Xsrcline);
|
||||||
|
emiti(codeline);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
switch(t->type){
|
switch(t->type){
|
||||||
default:
|
default:
|
||||||
|
@ -96,26 +108,51 @@ outcode(tree *t, int eflag)
|
||||||
break;
|
break;
|
||||||
case '$':
|
case '$':
|
||||||
emitf(Xmark);
|
emitf(Xmark);
|
||||||
|
noglobs(c0, 0);
|
||||||
outcode(c0, eflag);
|
outcode(c0, eflag);
|
||||||
emitf(Xdol);
|
emitf(Xdol);
|
||||||
break;
|
break;
|
||||||
case '"':
|
case '"':
|
||||||
emitf(Xmark);
|
emitf(Xmark);
|
||||||
emitf(Xmark);
|
emitf(Xmark);
|
||||||
|
noglobs(c0, 0);
|
||||||
outcode(c0, eflag);
|
outcode(c0, eflag);
|
||||||
emitf(Xdol);
|
emitf(Xdol);
|
||||||
emitf(Xqw);
|
emitf(Xqw);
|
||||||
|
emitf(Xpush);
|
||||||
break;
|
break;
|
||||||
case SUB:
|
case SUB:
|
||||||
emitf(Xmark);
|
emitf(Xmark);
|
||||||
|
noglobs(c0, 0);
|
||||||
outcode(c0, eflag);
|
outcode(c0, eflag);
|
||||||
emitf(Xmark);
|
emitf(Xmark);
|
||||||
|
noglobs(c1, 0);
|
||||||
outcode(c1, eflag);
|
outcode(c1, eflag);
|
||||||
emitf(Xsub);
|
emitf(Xsub);
|
||||||
break;
|
break;
|
||||||
case '&':
|
case '&':
|
||||||
emitf(Xasync);
|
emitf(Xasync);
|
||||||
p = emiti(0);
|
p = emiti(0);
|
||||||
|
|
||||||
|
/* undocumented? */
|
||||||
|
emitf(Xmark);
|
||||||
|
emitf(Xword);
|
||||||
|
emits(estrdup("/dev/null"));
|
||||||
|
emitf(Xread);
|
||||||
|
emiti(0);
|
||||||
|
|
||||||
|
/* insert rfork s for plan9 */
|
||||||
|
f = builtinfunc("rfork");
|
||||||
|
if(f){
|
||||||
|
emitf(Xmark);
|
||||||
|
emitf(Xword);
|
||||||
|
emits(estrdup("s"));
|
||||||
|
emitf(Xword);
|
||||||
|
emits(estrdup("rfork"));
|
||||||
|
emitf(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
codeline = 0; /* force source */
|
||||||
outcode(c0, eflag);
|
outcode(c0, eflag);
|
||||||
emitf(Xexit);
|
emitf(Xexit);
|
||||||
stuffdot(p);
|
stuffdot(p);
|
||||||
|
@ -134,16 +171,18 @@ outcode(tree *t, int eflag)
|
||||||
case '`':
|
case '`':
|
||||||
emitf(Xmark);
|
emitf(Xmark);
|
||||||
if(c0){
|
if(c0){
|
||||||
|
noglobs(c0, 0);
|
||||||
outcode(c0, 0);
|
outcode(c0, 0);
|
||||||
emitf(Xglob);
|
|
||||||
} else {
|
} else {
|
||||||
emitf(Xmark);
|
emitf(Xmark);
|
||||||
emitf(Xword);
|
emitf(Xword);
|
||||||
emits(estrdup("ifs"));
|
emits(estrdup("ifs"));
|
||||||
emitf(Xdol);
|
emitf(Xdol);
|
||||||
}
|
}
|
||||||
|
emitf(Xqw);
|
||||||
emitf(Xbackq);
|
emitf(Xbackq);
|
||||||
p = emiti(0);
|
p = emiti(0);
|
||||||
|
codeline = 0; /* force source */
|
||||||
outcode(c1, 0);
|
outcode(c1, 0);
|
||||||
emitf(Xexit);
|
emitf(Xexit);
|
||||||
stuffdot(p);
|
stuffdot(p);
|
||||||
|
@ -169,24 +208,20 @@ outcode(tree *t, int eflag)
|
||||||
break;
|
break;
|
||||||
case COUNT:
|
case COUNT:
|
||||||
emitf(Xmark);
|
emitf(Xmark);
|
||||||
|
noglobs(c0, 0);
|
||||||
outcode(c0, eflag);
|
outcode(c0, eflag);
|
||||||
emitf(Xcount);
|
emitf(Xcount);
|
||||||
break;
|
break;
|
||||||
case FN:
|
case FN:
|
||||||
emitf(Xmark);
|
emitf(Xmark);
|
||||||
|
noglobs(c0, 0);
|
||||||
outcode(c0, eflag);
|
outcode(c0, eflag);
|
||||||
if(c1){
|
if(c1){
|
||||||
emitf(Xfn);
|
emitf(Xfn);
|
||||||
p = emiti(0);
|
p = emiti(0);
|
||||||
emits(fnstr(c1));
|
emits(fnstr(c1));
|
||||||
if((f = curfile(runq)) != nil){
|
codeline = 0; /* force source */
|
||||||
emitf(Xsrcfile);
|
|
||||||
emits(estrdup(f));
|
|
||||||
}
|
|
||||||
emitf(Xsrcline);
|
|
||||||
emiti(runq->lexline);
|
|
||||||
outcode(c1, eflag);
|
outcode(c1, eflag);
|
||||||
emitf(Xunlocal); /* get rid of $* */
|
|
||||||
emitf(Xreturn);
|
emitf(Xreturn);
|
||||||
stuffdot(p);
|
stuffdot(p);
|
||||||
}
|
}
|
||||||
|
@ -202,7 +237,7 @@ outcode(tree *t, int eflag)
|
||||||
stuffdot(p);
|
stuffdot(p);
|
||||||
break;
|
break;
|
||||||
case NOT:
|
case NOT:
|
||||||
if(!runq->iflast)
|
if(!lex->iflast)
|
||||||
yyerror("`if not' does not follow `if(...)'");
|
yyerror("`if not' does not follow `if(...)'");
|
||||||
emitf(Xifnot);
|
emitf(Xifnot);
|
||||||
p = emiti(0);
|
p = emiti(0);
|
||||||
|
@ -229,6 +264,7 @@ outcode(tree *t, int eflag)
|
||||||
case SUBSHELL:
|
case SUBSHELL:
|
||||||
emitf(Xsubshell);
|
emitf(Xsubshell);
|
||||||
p = emiti(0);
|
p = emiti(0);
|
||||||
|
codeline = 0; /* force source */
|
||||||
outcode(c0, eflag);
|
outcode(c0, eflag);
|
||||||
emitf(Xexit);
|
emitf(Xexit);
|
||||||
stuffdot(p);
|
stuffdot(p);
|
||||||
|
@ -240,9 +276,11 @@ outcode(tree *t, int eflag)
|
||||||
break;
|
break;
|
||||||
case TWIDDLE:
|
case TWIDDLE:
|
||||||
emitf(Xmark);
|
emitf(Xmark);
|
||||||
|
noglobs(c1, 1);
|
||||||
outcode(c1, eflag);
|
outcode(c1, eflag);
|
||||||
emitf(Xmark);
|
emitf(Xmark);
|
||||||
outcode(c0, eflag);
|
outcode(c0, eflag);
|
||||||
|
emitf(Xqw);
|
||||||
emitf(Xmatch);
|
emitf(Xmatch);
|
||||||
if(eflag)
|
if(eflag)
|
||||||
emitf(Xeflag);
|
emitf(Xeflag);
|
||||||
|
@ -267,7 +305,6 @@ outcode(tree *t, int eflag)
|
||||||
emitf(Xmark);
|
emitf(Xmark);
|
||||||
if(c1){
|
if(c1){
|
||||||
outcode(c1, eflag);
|
outcode(c1, eflag);
|
||||||
emitf(Xglob);
|
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
emitf(Xmark);
|
emitf(Xmark);
|
||||||
|
@ -277,6 +314,7 @@ outcode(tree *t, int eflag)
|
||||||
}
|
}
|
||||||
emitf(Xmark); /* dummy value for Xlocal */
|
emitf(Xmark); /* dummy value for Xlocal */
|
||||||
emitf(Xmark);
|
emitf(Xmark);
|
||||||
|
noglobs(c0, 0);
|
||||||
outcode(c0, eflag);
|
outcode(c0, eflag);
|
||||||
emitf(Xlocal);
|
emitf(Xlocal);
|
||||||
p = emitf(Xfor);
|
p = emitf(Xfor);
|
||||||
|
@ -288,19 +326,9 @@ outcode(tree *t, int eflag)
|
||||||
emitf(Xunlocal);
|
emitf(Xunlocal);
|
||||||
break;
|
break;
|
||||||
case WORD:
|
case WORD:
|
||||||
if(t->quoted){
|
emitf(Xword);
|
||||||
emitf(Xword);
|
emits(t->str);
|
||||||
emits(estrdup(t->str));
|
t->str=0; /* passed ownership */
|
||||||
} 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){
|
||||||
|
@ -319,14 +347,20 @@ outcode(tree *t, int eflag)
|
||||||
emitf(Xpipefd);
|
emitf(Xpipefd);
|
||||||
emiti(t->rtype);
|
emiti(t->rtype);
|
||||||
p = emiti(0);
|
p = emiti(0);
|
||||||
|
codeline = 0; /* force source */
|
||||||
outcode(c0, eflag);
|
outcode(c0, eflag);
|
||||||
emitf(Xexit);
|
emitf(Xexit);
|
||||||
stuffdot(p);
|
stuffdot(p);
|
||||||
break;
|
break;
|
||||||
case REDIR:
|
case REDIR:
|
||||||
emitf(Xmark);
|
emitf(Xmark);
|
||||||
|
if(t->rtype==HERE){
|
||||||
|
/* replace end marker with mktmep() pattern */
|
||||||
|
free(c0->str);
|
||||||
|
c0->str=estrdup("/tmp/here.XXXXXXXXXXX");
|
||||||
|
c0->glob=0;
|
||||||
|
}
|
||||||
outcode(c0, eflag);
|
outcode(c0, eflag);
|
||||||
emitf(Xglob);
|
|
||||||
switch(t->rtype){
|
switch(t->rtype){
|
||||||
case APPEND:
|
case APPEND:
|
||||||
emitf(Xappend);
|
emitf(Xappend);
|
||||||
|
@ -335,12 +369,16 @@ outcode(tree *t, int eflag)
|
||||||
emitf(Xwrite);
|
emitf(Xwrite);
|
||||||
break;
|
break;
|
||||||
case READ:
|
case READ:
|
||||||
case HERE:
|
|
||||||
emitf(Xread);
|
emitf(Xread);
|
||||||
break;
|
break;
|
||||||
case RDWR:
|
case RDWR:
|
||||||
emitf(Xrdwr);
|
emitf(Xrdwr);
|
||||||
break;
|
break;
|
||||||
|
case HERE:
|
||||||
|
emitf(Xhere);
|
||||||
|
emits(t->str);
|
||||||
|
t->str=0; /* passed ownership */
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
emiti(t->fd0);
|
emiti(t->fd0);
|
||||||
outcode(c1, eflag);
|
outcode(c1, eflag);
|
||||||
|
@ -354,6 +392,7 @@ outcode(tree *t, int eflag)
|
||||||
emitf(Xmark);
|
emitf(Xmark);
|
||||||
outcode(c1, eflag);
|
outcode(c1, eflag);
|
||||||
emitf(Xmark);
|
emitf(Xmark);
|
||||||
|
noglobs(c0, 0);
|
||||||
outcode(c0, eflag);
|
outcode(c0, eflag);
|
||||||
emitf(Xlocal); /* push var for cmd */
|
emitf(Xlocal); /* push var for cmd */
|
||||||
}
|
}
|
||||||
|
@ -366,6 +405,7 @@ outcode(tree *t, int eflag)
|
||||||
emitf(Xmark);
|
emitf(Xmark);
|
||||||
outcode(c1, eflag);
|
outcode(c1, eflag);
|
||||||
emitf(Xmark);
|
emitf(Xmark);
|
||||||
|
noglobs(c0, 0);
|
||||||
outcode(c0, eflag);
|
outcode(c0, eflag);
|
||||||
emitf(Xassign); /* set var permanently */
|
emitf(Xassign); /* set var permanently */
|
||||||
}
|
}
|
||||||
|
@ -378,18 +418,23 @@ outcode(tree *t, int eflag)
|
||||||
emiti(t->fd1);
|
emiti(t->fd1);
|
||||||
p = emiti(0);
|
p = emiti(0);
|
||||||
q = emiti(0);
|
q = emiti(0);
|
||||||
|
codeline = 0; /* force source */
|
||||||
outcode(c0, eflag);
|
outcode(c0, eflag);
|
||||||
emitf(Xexit);
|
emitf(Xexit);
|
||||||
stuffdot(p);
|
stuffdot(p);
|
||||||
|
codeline = 0; /* force source */
|
||||||
outcode(c1, eflag);
|
outcode(c1, eflag);
|
||||||
emitf(Xreturn);
|
emitf(Xreturn);
|
||||||
stuffdot(q);
|
stuffdot(q);
|
||||||
emitf(Xpipewait);
|
emitf(Xpipewait);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
if(t->glob > 0)
|
||||||
|
emitf(Xglob);
|
||||||
if(t->type!=NOT && t->type!=';')
|
if(t->type!=NOT && t->type!=';')
|
||||||
runq->iflast = t->type==IF;
|
lex->iflast = t->type==IF;
|
||||||
else if(c0) runq->iflast = c0->type==IF;
|
else if(c0)
|
||||||
|
lex->iflast = c0->type==IF;
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
* switch code looks like this:
|
* switch code looks like this:
|
||||||
|
@ -427,6 +472,7 @@ codeswitch(tree *t, int eflag)
|
||||||
}
|
}
|
||||||
emitf(Xmark);
|
emitf(Xmark);
|
||||||
outcode(c0, eflag);
|
outcode(c0, eflag);
|
||||||
|
emitf(Xqw);
|
||||||
emitf(Xjump);
|
emitf(Xjump);
|
||||||
nextcase = emiti(0);
|
nextcase = emiti(0);
|
||||||
out = emitf(Xjump);
|
out = emitf(Xjump);
|
||||||
|
@ -436,7 +482,10 @@ codeswitch(tree *t, int eflag)
|
||||||
while(t->type==';'){
|
while(t->type==';'){
|
||||||
tt = c1;
|
tt = c1;
|
||||||
emitf(Xmark);
|
emitf(Xmark);
|
||||||
for(t = c0->child[0];t->type==ARGLIST;t = c0) outcode(c1, eflag);
|
for(t = c0->child[0];t->type==ARGLIST;t = c0) {
|
||||||
|
noglobs(c1, 1);
|
||||||
|
outcode(c1, eflag);
|
||||||
|
}
|
||||||
emitf(Xcase);
|
emitf(Xcase);
|
||||||
nextcase = emiti(0);
|
nextcase = emiti(0);
|
||||||
t = tt;
|
t = tt;
|
||||||
|
@ -481,7 +530,7 @@ codefree(code *cp)
|
||||||
code *p;
|
code *p;
|
||||||
if(--cp[0].i!=0)
|
if(--cp[0].i!=0)
|
||||||
return;
|
return;
|
||||||
for(p = cp+1;p->f;p++){
|
for(p = cp+2;p->f;p++){
|
||||||
if(p->f==Xappend || p->f==Xclose || p->f==Xread || p->f==Xwrite
|
if(p->f==Xappend || p->f==Xclose || p->f==Xread || p->f==Xwrite
|
||||||
|| p->f==Xrdwr
|
|| p->f==Xrdwr
|
||||||
|| p->f==Xasync || p->f==Xbackq || p->f==Xcase || p->f==Xfalse
|
|| p->f==Xasync || p->f==Xbackq || p->f==Xcase || p->f==Xfalse
|
||||||
|
@ -490,12 +539,13 @@ codefree(code *cp)
|
||||||
|| p->f==Xsubshell || p->f==Xtrue) p++;
|
|| p->f==Xsubshell || p->f==Xtrue) p++;
|
||||||
else if(p->f==Xdup || p->f==Xpipefd) p+=2;
|
else if(p->f==Xdup || p->f==Xpipefd) p+=2;
|
||||||
else if(p->f==Xpipe) p+=4;
|
else if(p->f==Xpipe) p+=4;
|
||||||
else if(p->f==Xglobs || p->f==Xsrcfile) free(p[1].s), p+=2;
|
else if(p->f==Xhere) free(p[1].s), p+=2;
|
||||||
else if(p->f==Xword || p->f==Xdelhere) free((++p)->s);
|
else if(p->f==Xword) free((++p)->s);
|
||||||
else if(p->f==Xfn){
|
else if(p->f==Xfn){
|
||||||
free(p[2].s);
|
free(p[2].s);
|
||||||
p+=2;
|
p+=2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
free(cp[1].s);
|
||||||
free(cp);
|
free(cp);
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -4,15 +4,16 @@
|
||||||
extern void Xappend(void), Xasync(void), Xbackq(void), Xbang(void), Xclose(void);
|
extern void Xappend(void), Xasync(void), Xbackq(void), Xbang(void), Xclose(void);
|
||||||
extern void Xconc(void), Xcount(void), Xdelfn(void), Xdol(void), Xqw(void), Xdup(void);
|
extern void Xconc(void), Xcount(void), Xdelfn(void), Xdol(void), Xqw(void), Xdup(void);
|
||||||
extern void Xexit(void), Xfalse(void), Xfn(void), Xfor(void), Xglob(void);
|
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), Xhere(void);
|
||||||
extern void Xrdwr(void), Xsrcline(void), Xsrcfile(void);
|
extern void Xrdwr(void), Xsrcline(void);
|
||||||
extern void Xrdfn(void), Xunredir(void), Xstar(void), Xreturn(void), Xsubshell(void);
|
extern void Xunredir(void), Xstar(void), Xreturn(void), Xsubshell(void);
|
||||||
extern void Xtrue(void), Xword(void), Xglobs(void), Xwrite(void), Xpipefd(void), Xcase(void);
|
extern void Xtrue(void), Xword(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), Xpush(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 Xpopredir(void), Xsub(void), Xeflag(void), Xsettrue(void);
|
||||||
extern void Xerror(char*);
|
extern void Xerror(char*);
|
||||||
extern void Xerror1(char*);
|
extern void Xerror1(char*);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* word lists are in correct order,
|
* word lists are in correct order,
|
||||||
* i.e. word0->word1->word2->word3->0
|
* i.e. word0->word1->word2->word3->0
|
||||||
|
@ -20,60 +21,64 @@ 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;
|
||||||
list *next;
|
list *next;
|
||||||
};
|
};
|
||||||
word *newword(char *, word *), *copywords(word *, word *);
|
word *newword(char *, word *), *copywords(word *, word *);
|
||||||
|
|
||||||
struct redir{
|
struct redir{
|
||||||
char type; /* what to do */
|
int type; /* what to do */
|
||||||
short from, to; /* what to do it to */
|
int from, to; /* what to do it to */
|
||||||
redir *next; /* what else to do (reverse order) */
|
redir *next; /* what else to do (reverse order) */
|
||||||
};
|
};
|
||||||
#define NSTATUS ERRMAX /* length of status (from plan 9) */
|
#define NSTATUS 128 /* length of status */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* redir types
|
* redir types
|
||||||
*/
|
*/
|
||||||
#define ROPEN 1 /* dup2(from, to); close(from); */
|
#define ROPEN 1 /* dup2(from, to); close(from); */
|
||||||
#define RDUP 2 /* dup2(from, to); */
|
#define RDUP 2 /* dup2(from, to); */
|
||||||
#define RCLOSE 3 /* close(from); */
|
#define RCLOSE 3 /* close(from); */
|
||||||
|
void shuffleredir(void);
|
||||||
|
|
||||||
struct thread{
|
struct thread{
|
||||||
code *code; /* code for this thread */
|
code *code; /* code for this thread */
|
||||||
int pc; /* code[pc] is the next instruction */
|
int pc; /* code[pc] is the next instruction */
|
||||||
int line; /* source code line */
|
int line; /* source code line for Xsrcline */
|
||||||
list *argv; /* argument stack */
|
list *argv; /* argument stack */
|
||||||
redir *redir; /* redirection stack */
|
redir *redir; /* redirection stack */
|
||||||
redir *startredir; /* redir inheritance point */
|
redir *startredir; /* redir inheritance point */
|
||||||
var *local; /* list of local variables */
|
var *local; /* list of local variables */
|
||||||
char *cmdfile; /* file name in Xrdcmd */
|
lexer *lex; /* lexer for Xrdcmds */
|
||||||
io *cmdfd; /* file descriptor for Xrdcmd */
|
|
||||||
int lexline; /* file descriptor line */
|
|
||||||
int iflast; /* static `if not' checking */
|
|
||||||
int eof; /* is cmdfd at eof? */
|
|
||||||
int iflag; /* interactive? */
|
int iflag; /* interactive? */
|
||||||
int lineno; /* linenumber */
|
|
||||||
int pid; /* process for Xpipewait to wait for */
|
int pid; /* process for Xpipewait to wait for */
|
||||||
char status[NSTATUS]; /* status for Xpipewait */
|
char status[NSTATUS]; /* status for Xpipewait */
|
||||||
tree *treenodes; /* tree nodes created by this process */
|
|
||||||
thread *ret; /* who continues when this finishes */
|
thread *ret; /* who continues when this finishes */
|
||||||
};
|
};
|
||||||
|
|
||||||
thread *runq;
|
thread *runq;
|
||||||
|
void turfstack(var*);
|
||||||
|
|
||||||
code *codecopy(code*);
|
code *codecopy(code*);
|
||||||
code *codebuf; /* compiler output */
|
code *codebuf; /* compiler output */
|
||||||
|
extern int ifnot;
|
||||||
|
|
||||||
int ntrap; /* number of outstanding traps */
|
int ntrap; /* number of outstanding traps */
|
||||||
int trap[NSIG]; /* number of outstanding traps per type */
|
int trap[NSIG]; /* number of outstanding traps per type */
|
||||||
struct builtin{
|
struct builtin{
|
||||||
char *name;
|
char *name;
|
||||||
void (*fnc)(void);
|
void (*fnc)(void);
|
||||||
};
|
};
|
||||||
extern struct builtin Builtin[];
|
extern void (*builtinfunc(char *name))(void);
|
||||||
int eflagok; /* kludge flag so that -e doesn't exit in startup */
|
|
||||||
|
|
||||||
void execcd(void), execwhatis(void), execeval(void), execexec(void);
|
void execcd(void), execwhatis(void), execeval(void), execexec(void);
|
||||||
int execforkexec(void);
|
int execforkexec(void);
|
||||||
void execexit(void), execshift(void);
|
void execexit(void), execshift(void);
|
||||||
void execwait(void), execumask(void), execdot(void), execflag(void);
|
void execwait(void), execumask(void), execdot(void), execflag(void);
|
||||||
void execfunc(var*), execcmds(io *);
|
void execfunc(var*), execcmds(io*, char*, var*, redir*);
|
||||||
char *curfile(thread*);
|
void startfunc(var*, word*, var*, redir*);
|
||||||
|
|
||||||
|
char *srcfile(thread*);
|
||||||
|
char *getstatus(void);
|
||||||
|
|
|
@ -1,63 +1,65 @@
|
||||||
void Abort(void);
|
void Abort(void);
|
||||||
void Closedir(int);
|
int Chdir(char*);
|
||||||
|
void Close(int);
|
||||||
|
void Closedir(void*);
|
||||||
int Creat(char*);
|
int Creat(char*);
|
||||||
int Dup(int, int);
|
int Dup(int, int);
|
||||||
int Dup1(int);
|
int Dup1(int);
|
||||||
int Eintr(void);
|
int Eintr(void);
|
||||||
int Executable(char*);
|
int Executable(char*);
|
||||||
void Execute(word*, word*);
|
void Exec(char**);
|
||||||
void Exit(char*);
|
void Exit(char*);
|
||||||
int ForkExecute(char*, char**, int, int, int);
|
char* Errstr(void);
|
||||||
int Globsize(char*);
|
char* Freeword(word*);
|
||||||
|
int Fork(void);
|
||||||
int Isatty(int);
|
int Isatty(int);
|
||||||
|
word* Newword(char*,word*);
|
||||||
void Noerror(void);
|
void Noerror(void);
|
||||||
int Opendir(char*);
|
int Open(char*, int);
|
||||||
|
void* Opendir(char*);
|
||||||
|
word* Poplist(void);
|
||||||
|
char* Popword(void);
|
||||||
|
word* Pushword(char*);
|
||||||
long Read(int, void*, long);
|
long Read(int, void*, long);
|
||||||
int Readdir(int, void*, int);
|
char* Readdir(void*, int);
|
||||||
long Seek(int, long, long);
|
long Seek(int, long, long);
|
||||||
void Trapinit(void);
|
void Trapinit(void);
|
||||||
void Unlink(char*);
|
|
||||||
void Updenv(void);
|
void Updenv(void);
|
||||||
void Vinit(void);
|
void Vinit(void);
|
||||||
int Waitfor(int, int);
|
int Waitfor(int, int);
|
||||||
long Write(int, void*, long);
|
long Write(int, void*, long);
|
||||||
void addwaitpid(int);
|
void addwaitpid(int);
|
||||||
int advance(void);
|
void clearwaitpids(void);
|
||||||
int back(int);
|
|
||||||
void cleanhere(char*);
|
|
||||||
void codefree(code*);
|
void codefree(code*);
|
||||||
int compile(tree*);
|
int compile(tree*);
|
||||||
char * list2str(word*);
|
|
||||||
int count(word*);
|
int count(word*);
|
||||||
char* deglob(char*);
|
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*);
|
||||||
word* globlist(word*);
|
void globword(word*);
|
||||||
int havewaitpid(int);
|
int havewaitpid(int);
|
||||||
int idchr(int);
|
int idchr(int);
|
||||||
void inttoascii(char*, long);
|
void inttoascii(char*, int);
|
||||||
void kinit(void);
|
void kinit(void);
|
||||||
int mapfd(int);
|
int mapfd(int);
|
||||||
int match(char*, char*, int);
|
int match(char*, char*, int);
|
||||||
char** mkargv(word*);
|
char* makepath(char*, char*);
|
||||||
void clearwaitpids(void);
|
|
||||||
void panic(char*, int);
|
void panic(char*, int);
|
||||||
void pathinit(void);
|
void pfln(io*, char*, int);
|
||||||
void poplist(void);
|
void poplist(void);
|
||||||
void popword(void);
|
void popword(void);
|
||||||
void pprompt(void);
|
void pprompt(void);
|
||||||
|
void Prompt(char*);
|
||||||
|
void psubst(io *f, uchar *s);
|
||||||
void pushlist(void);
|
void pushlist(void);
|
||||||
void pushredir(int, int, int);
|
void pushredir(int, int, int);
|
||||||
word* pushword(char*);
|
word* pushword(char*);
|
||||||
void readhere(void);
|
char* readhere(tree*, io*);
|
||||||
word* searchpath(char*, char*);
|
|
||||||
void setstatus(char*);
|
void setstatus(char*);
|
||||||
void setvar(char*, word*);
|
|
||||||
void shuffleredir(void);
|
|
||||||
void skipnl(void);
|
void skipnl(void);
|
||||||
void start(code*, int, var*);
|
void start(code*, int, var*, redir*);
|
||||||
int truestatus(void);
|
int truestatus(void);
|
||||||
void usage(char*);
|
void usage(char*);
|
||||||
int wordchr(int);
|
int wordchr(int);
|
||||||
|
|
|
@ -5,18 +5,19 @@
|
||||||
/*
|
/*
|
||||||
* delete all the GLOB marks from s, in place
|
* delete all the GLOB marks from s, in place
|
||||||
*/
|
*/
|
||||||
|
|
||||||
char*
|
char*
|
||||||
deglob(char *s)
|
deglob(char *s)
|
||||||
{
|
{
|
||||||
char *b = s;
|
char *r = strchr(s, GLOB);
|
||||||
char *t = s;
|
if(r){
|
||||||
do{
|
char *w = r++;
|
||||||
if(*t==GLOB)
|
do{
|
||||||
t++;
|
if(*r==GLOB)
|
||||||
*s++=*t;
|
r++;
|
||||||
}while(*t++);
|
*w++=*r;
|
||||||
return b;
|
}while(*r++);
|
||||||
|
}
|
||||||
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
|
@ -55,93 +56,86 @@ matchfn(char *s, char *p)
|
||||||
return match(s, p, '/');
|
return match(s, p, '/');
|
||||||
}
|
}
|
||||||
|
|
||||||
static word*
|
static void
|
||||||
globdir(word *list, char *p, char *name, char *namep)
|
pappend(char **pdir, char *name)
|
||||||
{
|
{
|
||||||
char *t, *newp;
|
char *path = makepath(*pdir, name);
|
||||||
int f;
|
free(*pdir);
|
||||||
|
*pdir = path;
|
||||||
|
}
|
||||||
|
|
||||||
|
static word*
|
||||||
|
globdir(word *list, char *pattern, char *name)
|
||||||
|
{
|
||||||
|
char *slash, *glob, *entry;
|
||||||
|
void *dir;
|
||||||
|
|
||||||
/* append slashes, Readdir() already filtered directories */
|
/* append slashes, Readdir() already filtered directories */
|
||||||
while(*p=='/'){
|
while(*pattern=='/'){
|
||||||
*namep++=*p++;
|
pappend(&name, "/");
|
||||||
*namep='\0';
|
pattern++;
|
||||||
}
|
}
|
||||||
if(*p=='\0')
|
if(*pattern=='\0')
|
||||||
return newword(name, list);
|
return Newword(name, list);
|
||||||
|
|
||||||
/* scan the pattern looking for a component with a metacharacter in it */
|
/* scan the pattern looking for a component with a metacharacter in it */
|
||||||
t = namep;
|
glob=strchr(pattern, GLOB);
|
||||||
newp = p;
|
|
||||||
while(*newp){
|
|
||||||
if(*newp==GLOB)
|
|
||||||
break;
|
|
||||||
*t=*newp++;
|
|
||||||
if(*t++=='/'){
|
|
||||||
namep = t;
|
|
||||||
p = newp;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* 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(glob==0){
|
||||||
*t='\0';
|
pappend(&name, pattern);
|
||||||
if(access(name, 0)==0)
|
if(access(name, 0)==0)
|
||||||
list = newword(name, list);
|
return Newword(name, list);
|
||||||
return list;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
*glob='\0';
|
||||||
|
slash=strrchr(pattern, '/');
|
||||||
|
if(slash){
|
||||||
|
*slash='\0';
|
||||||
|
pappend(&name, pattern);
|
||||||
|
*slash='/';
|
||||||
|
pattern=slash+1;
|
||||||
|
}
|
||||||
|
*glob=GLOB;
|
||||||
|
|
||||||
/* read the directory and recur for any entry that matches */
|
/* read the directory and recur for any entry that matches */
|
||||||
*namep='\0';
|
dir = Opendir(name[0]?name:".");
|
||||||
if((f = Opendir(name[0]?name:".")) >= 0){
|
if(dir==0)
|
||||||
while(*newp!='/' && *newp!='\0') newp++;
|
goto out;
|
||||||
while(Readdir(f, namep, *newp=='/')){
|
slash=strchr(glob, '/');
|
||||||
if(matchfn(namep, p)){
|
while((entry=Readdir(dir, slash!=0)) != 0){
|
||||||
for(t = namep;*t;t++);
|
if(matchfn(entry, pattern))
|
||||||
list = globdir(list, newp, name, t);
|
list = globdir(list, slash?slash:"", makepath(name, entry));
|
||||||
}
|
|
||||||
}
|
|
||||||
Closedir(f);
|
|
||||||
}
|
}
|
||||||
|
Closedir(dir);
|
||||||
|
out:
|
||||||
|
free(name);
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Subsitute a word with its glob in place.
|
* Subsitute a word with its glob in place.
|
||||||
*/
|
*/
|
||||||
|
void
|
||||||
static void
|
|
||||||
globword(word *w)
|
globword(word *w)
|
||||||
{
|
{
|
||||||
word *left, *right;
|
word *left, *right;
|
||||||
char *name;
|
|
||||||
|
|
||||||
if(w->glob == 0)
|
if(w==0 || strchr(w->word, GLOB)==0)
|
||||||
return;
|
return;
|
||||||
name = emalloc(w->glob);
|
|
||||||
memset(name, 0, w->glob);
|
|
||||||
right = w->next;
|
right = w->next;
|
||||||
left = globdir(right, w->word, name, name);
|
left = globdir(right, w->word, estrdup(""));
|
||||||
free(name);
|
|
||||||
if(left == right) {
|
if(left == right) {
|
||||||
deglob(w->word);
|
deglob(w->word);
|
||||||
w->glob = 0;
|
|
||||||
} else {
|
} else {
|
||||||
free(w->word);
|
free(w->word);
|
||||||
globsort(left, right);
|
globsort(left, right);
|
||||||
*w = *left;
|
w->next = left->next;
|
||||||
free(left);
|
w->word = Freeword(left);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
word*
|
|
||||||
globlist(word *l)
|
|
||||||
{
|
|
||||||
word *p, *q;
|
|
||||||
|
|
||||||
for(p=l;p;p=q){
|
|
||||||
q = p->next;
|
|
||||||
globword(p);
|
|
||||||
}
|
|
||||||
return l;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Return a pointer to the next utf code in the string,
|
* Return a pointer to the next utf code in the string,
|
||||||
* not jumping past nuls in broken utf codes!
|
* not jumping past nuls in broken utf codes!
|
||||||
|
|
|
@ -4,32 +4,61 @@
|
||||||
#include "io.h"
|
#include "io.h"
|
||||||
#include "fns.h"
|
#include "fns.h"
|
||||||
|
|
||||||
|
static int *waitpids;
|
||||||
|
static int nwaitpids;
|
||||||
|
|
||||||
|
void
|
||||||
|
addwaitpid(int pid)
|
||||||
|
{
|
||||||
|
waitpids = erealloc(waitpids, (nwaitpids+1)*sizeof waitpids[0]);
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Xasync(void)
|
Xasync(void)
|
||||||
{
|
{
|
||||||
int null = open("/dev/null", 0);
|
|
||||||
int pid;
|
int pid;
|
||||||
char npid[10];
|
char npid[10];
|
||||||
|
|
||||||
if(null<0){
|
switch(pid = Fork()){
|
||||||
Xerror("Can't open /dev/null\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Updenv();
|
|
||||||
switch(pid = rfork(RFFDG|RFPROC|RFNOTEG)){
|
|
||||||
case -1:
|
case -1:
|
||||||
close(null);
|
|
||||||
Xerror("try again");
|
Xerror("try again");
|
||||||
break;
|
break;
|
||||||
case 0:
|
case 0:
|
||||||
clearwaitpids();
|
clearwaitpids();
|
||||||
pushredir(ROPEN, null, 0);
|
start(runq->code, runq->pc+1, runq->local, runq->redir);
|
||||||
start(runq->code, runq->pc+1, runq->local);
|
|
||||||
runq->ret = 0;
|
runq->ret = 0;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
addwaitpid(pid);
|
addwaitpid(pid);
|
||||||
close(null);
|
|
||||||
runq->pc = runq->code[runq->pc].i;
|
runq->pc = runq->code[runq->pc].i;
|
||||||
inttoascii(npid, pid);
|
inttoascii(npid, pid);
|
||||||
setvar("apid", newword(npid, (word *)0));
|
setvar("apid", newword(npid, (word *)0));
|
||||||
|
@ -40,8 +69,8 @@ Xasync(void)
|
||||||
void
|
void
|
||||||
Xpipe(void)
|
Xpipe(void)
|
||||||
{
|
{
|
||||||
struct thread *p = runq;
|
thread *p = runq;
|
||||||
int pc = p->pc, forkid;
|
int pid, pc = p->pc;
|
||||||
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];
|
||||||
|
@ -50,25 +79,24 @@ Xpipe(void)
|
||||||
Xerror("can't get pipe");
|
Xerror("can't get pipe");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Updenv();
|
switch(pid = Fork()){
|
||||||
switch(forkid = fork()){
|
|
||||||
case -1:
|
case -1:
|
||||||
Xerror("try again");
|
Xerror("try again");
|
||||||
break;
|
break;
|
||||||
case 0:
|
case 0:
|
||||||
clearwaitpids();
|
clearwaitpids();
|
||||||
start(p->code, pc+2, runq->local);
|
Close(pfd[PRD]);
|
||||||
|
start(p->code, pc+2, runq->local, runq->redir);
|
||||||
runq->ret = 0;
|
runq->ret = 0;
|
||||||
close(pfd[PRD]);
|
|
||||||
pushredir(ROPEN, pfd[PWR], lfd);
|
pushredir(ROPEN, pfd[PWR], lfd);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
addwaitpid(forkid);
|
addwaitpid(pid);
|
||||||
start(p->code, p->code[pc].i, runq->local);
|
Close(pfd[PWR]);
|
||||||
close(pfd[PWR]);
|
start(p->code, p->code[pc].i, runq->local, runq->redir);
|
||||||
pushredir(ROPEN, pfd[PRD], rfd);
|
pushredir(ROPEN, pfd[PRD], rfd);
|
||||||
p->pc = p->code[pc+1].i;
|
p->pc = p->code[pc+1].i;
|
||||||
p->pid = forkid;
|
p->pid = pid;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -76,74 +104,50 @@ 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 c, l, pid;
|
int pid, pfd[2];
|
||||||
int pfd[2];
|
char *s, *split;
|
||||||
char *s, *wd, *ewd, *stop;
|
word *end, **link;
|
||||||
struct io *f;
|
io *f;
|
||||||
word *v, *nextv;
|
|
||||||
|
|
||||||
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");
|
||||||
close(pfd[PRD]);
|
Close(pfd[PRD]);
|
||||||
close(pfd[PWR]);
|
Close(pfd[PWR]);
|
||||||
return;
|
return;
|
||||||
case 0:
|
case 0:
|
||||||
clearwaitpids();
|
clearwaitpids();
|
||||||
close(pfd[PRD]);
|
Close(pfd[PRD]);
|
||||||
start(runq->code, runq->pc+1, runq->local);
|
start(runq->code, runq->pc+1, runq->local, runq->redir);
|
||||||
pushredir(ROPEN, pfd[PWR], 1);
|
pushredir(ROPEN, pfd[PWR], 1);
|
||||||
return;
|
return;
|
||||||
default:
|
default:
|
||||||
addwaitpid(pid);
|
addwaitpid(pid);
|
||||||
close(pfd[PWR]);
|
Close(pfd[PWR]);
|
||||||
f = openfd(pfd[PRD]);
|
|
||||||
s = wd = ewd = 0;
|
split = Popword();
|
||||||
v = 0;
|
poplist();
|
||||||
while((c = rchr(f))!=EOF){
|
f = openiofd(pfd[PRD]);
|
||||||
if(s==ewd){
|
end = runq->argv->words;
|
||||||
l = s-wd;
|
link = &runq->argv->words;
|
||||||
wd = erealloc(wd, l+Stralloc);
|
while((s = rstr(f, split)) != 0){
|
||||||
ewd = wd+l+Stralloc-1;
|
*link = Newword(s, (word*)0);
|
||||||
s = wd+l;
|
link = &(*link)->next;
|
||||||
}
|
|
||||||
if(strchr(stop, c)){
|
|
||||||
if(s!=wd){
|
|
||||||
*s='\0';
|
|
||||||
v = newword(wd, v);
|
|
||||||
s = wd;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else *s++=c;
|
|
||||||
}
|
}
|
||||||
if(s!=wd){
|
*link = end;
|
||||||
*s='\0';
|
|
||||||
v = newword(wd, v);
|
|
||||||
}
|
|
||||||
free(wd);
|
|
||||||
closeio(f);
|
closeio(f);
|
||||||
|
free(split);
|
||||||
|
|
||||||
Waitfor(pid, 0);
|
Waitfor(pid, 0);
|
||||||
poplist(); /* ditch split in "stop" */
|
|
||||||
/* 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 = runq->code[runq->pc].i;
|
runq->pc = runq->code[runq->pc].i;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -152,8 +156,8 @@ Xbackq(void)
|
||||||
void
|
void
|
||||||
Xpipefd(void)
|
Xpipefd(void)
|
||||||
{
|
{
|
||||||
struct thread *p = runq;
|
thread *p = runq;
|
||||||
int pc = p->pc, pid;
|
int pid, pc = p->pc;
|
||||||
char name[40];
|
char name[40];
|
||||||
int pfd[2];
|
int pfd[2];
|
||||||
int sidefd, mainfd;
|
int sidefd, mainfd;
|
||||||
|
@ -170,23 +174,22 @@ 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");
|
||||||
break;
|
break;
|
||||||
case 0:
|
case 0:
|
||||||
clearwaitpids();
|
clearwaitpids();
|
||||||
start(p->code, pc+2, runq->local);
|
Close(mainfd);
|
||||||
close(mainfd);
|
start(p->code, pc+2, runq->local, runq->redir);
|
||||||
pushredir(ROPEN, sidefd, p->code[pc].i==READ?1:0);
|
pushredir(ROPEN, sidefd, p->code[pc].i==READ?1:0);
|
||||||
runq->ret = 0;
|
runq->ret = 0;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
addwaitpid(pid);
|
addwaitpid(pid);
|
||||||
close(sidefd);
|
Close(sidefd);
|
||||||
pushredir(ROPEN, mainfd, mainfd);
|
pushredir(ROPEN, mainfd, mainfd);
|
||||||
shuffleredir(); /* shuffle redir to bottom of stack for turfredir() */
|
shuffleredir(); /* shuffle redir to bottom of stack for Xpopredir() */
|
||||||
strcpy(name, Fdprefix);
|
strcpy(name, Fdprefix);
|
||||||
inttoascii(name+strlen(name), mainfd);
|
inttoascii(name+strlen(name), mainfd);
|
||||||
pushword(name);
|
pushword(name);
|
||||||
|
@ -200,14 +203,13 @@ Xsubshell(void)
|
||||||
{
|
{
|
||||||
int pid;
|
int pid;
|
||||||
|
|
||||||
Updenv();
|
switch(pid = Fork()){
|
||||||
switch(pid = fork()){
|
|
||||||
case -1:
|
case -1:
|
||||||
Xerror("try again");
|
Xerror("try again");
|
||||||
break;
|
break;
|
||||||
case 0:
|
case 0:
|
||||||
clearwaitpids();
|
clearwaitpids();
|
||||||
start(runq->code, runq->pc+1, runq->local);
|
start(runq->code, runq->pc+1, runq->local, runq->redir);
|
||||||
runq->ret = 0;
|
runq->ret = 0;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -222,20 +224,15 @@ int
|
||||||
execforkexec(void)
|
execforkexec(void)
|
||||||
{
|
{
|
||||||
int pid;
|
int pid;
|
||||||
int n;
|
|
||||||
char buf[ERRMAX];
|
|
||||||
|
|
||||||
switch(pid = fork()){
|
switch(pid = Fork()){
|
||||||
case -1:
|
case -1:
|
||||||
return -1;
|
return -1;
|
||||||
case 0:
|
case 0:
|
||||||
clearwaitpids();
|
clearwaitpids();
|
||||||
pushword("exec");
|
pushword("exec");
|
||||||
execexec();
|
execexec();
|
||||||
strcpy(buf, "can't exec: ");
|
/* does not return */
|
||||||
n = strlen(buf);
|
|
||||||
errstr(buf+n, ERRMAX-n);
|
|
||||||
Exit(buf);
|
|
||||||
}
|
}
|
||||||
addwaitpid(pid);
|
addwaitpid(pid);
|
||||||
return pid;
|
return pid;
|
||||||
|
|
|
@ -2,93 +2,49 @@
|
||||||
#include "exec.h"
|
#include "exec.h"
|
||||||
#include "io.h"
|
#include "io.h"
|
||||||
#include "fns.h"
|
#include "fns.h"
|
||||||
struct here *here, **ehere;
|
|
||||||
int ser = 0;
|
|
||||||
char tmp[]="/tmp/here0000.0000";
|
|
||||||
char hex[]="0123456789abcdef";
|
|
||||||
|
|
||||||
void psubst(io*, uchar*);
|
void psubst(io*, uchar*);
|
||||||
void pstrs(io*, word*);
|
void pstrs(io*, word*);
|
||||||
|
|
||||||
void
|
char*
|
||||||
hexnum(char *p, int n)
|
readhere(tree *tag, io *in)
|
||||||
{
|
{
|
||||||
*p++=hex[(n>>12)&0xF];
|
io *out;
|
||||||
*p++=hex[(n>>8)&0xF];
|
char c, *m;
|
||||||
*p++=hex[(n>>4)&0xF];
|
|
||||||
*p = hex[n&0xF];
|
|
||||||
}
|
|
||||||
|
|
||||||
tree*
|
|
||||||
heredoc(tree *tag)
|
|
||||||
{
|
|
||||||
struct here *h;
|
|
||||||
|
|
||||||
if(tag->type!=WORD){
|
if(tag->type!=WORD){
|
||||||
yyerror("Bad here tag");
|
yyerror("Bad here tag");
|
||||||
return nil;
|
return 0;
|
||||||
}
|
}
|
||||||
h = new(struct here);
|
pprompt();
|
||||||
h->next = 0;
|
out = openiostr();
|
||||||
if(here)
|
m = tag->str;
|
||||||
*ehere = h;
|
while((c = rchr(in)) != EOF){
|
||||||
else
|
if(c=='\0'){
|
||||||
here = h;
|
yyerror("NUL bytes in here doc");
|
||||||
ehere=&h->next;
|
closeio(out);
|
||||||
h->tag = tag;
|
return 0;
|
||||||
hexnum(&tmp[9], getpid());
|
|
||||||
hexnum(&tmp[14], ser++);
|
|
||||||
h->name = estrdup(tmp);
|
|
||||||
return token(tmp, WORD);
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* bug: lines longer than NLINE get split -- this can cause spurious
|
|
||||||
* missubstitution, or a misrecognized EOF marker.
|
|
||||||
*/
|
|
||||||
#define NLINE 4096
|
|
||||||
|
|
||||||
void
|
|
||||||
readhere(void)
|
|
||||||
{
|
|
||||||
struct here *h, *nexth;
|
|
||||||
io *f;
|
|
||||||
char *s, *tag;
|
|
||||||
int c, subst;
|
|
||||||
char line[NLINE+1];
|
|
||||||
for(h = here;h;h = nexth){
|
|
||||||
subst=!h->tag->quoted;
|
|
||||||
tag = h->tag->str;
|
|
||||||
c = Creat(h->name);
|
|
||||||
if(c<0)
|
|
||||||
yyerror("can't create here document");
|
|
||||||
f = openfd(c);
|
|
||||||
s = line;
|
|
||||||
pprompt();
|
|
||||||
while((c = rchr(runq->cmdfd))!=EOF){
|
|
||||||
if(c=='\n' || s==&line[NLINE]){
|
|
||||||
*s='\0';
|
|
||||||
if(tag && strcmp(line, tag)==0) break;
|
|
||||||
if(subst)
|
|
||||||
psubst(f, (uchar *)line);
|
|
||||||
else
|
|
||||||
pstr(f, line);
|
|
||||||
s = line;
|
|
||||||
if(c=='\n'){
|
|
||||||
pprompt();
|
|
||||||
pchr(f, c);
|
|
||||||
}
|
|
||||||
else *s++=c;
|
|
||||||
}
|
|
||||||
else *s++=c;
|
|
||||||
}
|
}
|
||||||
flush(f);
|
if(c=='\n'){
|
||||||
closeio(f);
|
lex->line++;
|
||||||
cleanhere(h->name);
|
if(m && *m=='\0'){
|
||||||
nexth = h->next;
|
out->bufp -= m - tag->str;
|
||||||
free(h);
|
*out->bufp='\0';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
pprompt();
|
||||||
|
m = tag->str;
|
||||||
|
} else if(m){
|
||||||
|
if(*m == c){
|
||||||
|
m++;
|
||||||
|
} else {
|
||||||
|
m = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pchr(out, c);
|
||||||
}
|
}
|
||||||
here = 0;
|
|
||||||
doprompt = 1;
|
doprompt = 1;
|
||||||
|
return closeiostr(out);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -3,18 +3,13 @@
|
||||||
#include "io.h"
|
#include "io.h"
|
||||||
#include "fns.h"
|
#include "fns.h"
|
||||||
|
|
||||||
enum { Stralloc = 100, };
|
enum {
|
||||||
|
NBUF = 8192,
|
||||||
int pfmtnest = 0;
|
};
|
||||||
|
|
||||||
void
|
void
|
||||||
pfmt(io *f, char *fmt, ...)
|
vpfmt(io *f, char *fmt, va_list ap)
|
||||||
{
|
{
|
||||||
va_list ap;
|
|
||||||
char err[ERRMAX];
|
|
||||||
|
|
||||||
va_start(ap, fmt);
|
|
||||||
pfmtnest++;
|
|
||||||
for(;*fmt;fmt++) {
|
for(;*fmt;fmt++) {
|
||||||
if(*fmt!='%') {
|
if(*fmt!='%') {
|
||||||
pchr(f, *fmt);
|
pchr(f, *fmt);
|
||||||
|
@ -42,51 +37,103 @@ pfmt(io *f, char *fmt, ...)
|
||||||
pwrd(f, va_arg(ap, char *));
|
pwrd(f, va_arg(ap, char *));
|
||||||
break;
|
break;
|
||||||
case 'r':
|
case 'r':
|
||||||
errstr(err, sizeof err); pstr(f, err);
|
pstr(f, Errstr());
|
||||||
break;
|
break;
|
||||||
case 's':
|
case 's':
|
||||||
pstr(f, va_arg(ap, char *));
|
pstr(f, va_arg(ap, char *));
|
||||||
break;
|
break;
|
||||||
case 't':
|
case 't':
|
||||||
pcmd(f, va_arg(ap, struct tree *));
|
pcmd(f, va_arg(ap, tree *));
|
||||||
break;
|
break;
|
||||||
case 'v':
|
case 'v':
|
||||||
pval(f, va_arg(ap, struct word *));
|
pval(f, va_arg(ap, word *));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
pchr(f, *fmt);
|
pchr(f, *fmt);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
pfmt(io *f, char *fmt, ...)
|
||||||
|
{
|
||||||
|
va_list ap;
|
||||||
|
va_start(ap, fmt);
|
||||||
|
vpfmt(f, fmt, ap);
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
if(--pfmtnest==0)
|
|
||||||
flush(f);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
pchr(io *b, int c)
|
pchr(io *b, int c)
|
||||||
{
|
{
|
||||||
if(b->bufp==b->ebuf)
|
if(b->bufp>=b->ebuf)
|
||||||
fullbuf(b, c);
|
flushio(b);
|
||||||
else *b->bufp++=c;
|
*b->bufp++=c;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
rchr(io *b)
|
rchr(io *b)
|
||||||
{
|
{
|
||||||
if(b->bufp==b->ebuf)
|
if(b->bufp>=b->ebuf)
|
||||||
return emptybuf(b);
|
return emptyiobuf(b);
|
||||||
return *b->bufp++;
|
return *b->bufp++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char*
|
||||||
|
rstr(io *b, char *stop)
|
||||||
|
{
|
||||||
|
char *s, *p;
|
||||||
|
int l, m, n;
|
||||||
|
|
||||||
|
do {
|
||||||
|
l = rchr(b);
|
||||||
|
if(l == EOF)
|
||||||
|
return 0;
|
||||||
|
} while(strchr(stop, l));
|
||||||
|
b->bufp--;
|
||||||
|
|
||||||
|
s = 0;
|
||||||
|
l = 0;
|
||||||
|
for(;;){
|
||||||
|
p = (char*)b->bufp;
|
||||||
|
n = (char*)b->ebuf - p;
|
||||||
|
if(n > 0){
|
||||||
|
for(m = 0; m < n; m++){
|
||||||
|
if(strchr(stop, p[m])==0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
b->bufp += m+1;
|
||||||
|
if(m > 0 || s==0){
|
||||||
|
s = erealloc(s, l+m+1);
|
||||||
|
memmove(s+l, p, m);
|
||||||
|
l += m;
|
||||||
|
}
|
||||||
|
s[l]='\0';
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
s = erealloc(s, l+m+1);
|
||||||
|
memmove(s+l, p, m);
|
||||||
|
l += m;
|
||||||
|
b->bufp += m;
|
||||||
|
}
|
||||||
|
if(emptyiobuf(b) == EOF){
|
||||||
|
if(s) s[l]='\0';
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
b->bufp--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
pquo(io *f, char *s)
|
pquo(io *f, char *s)
|
||||||
{
|
{
|
||||||
pchr(f, '\'');
|
pchr(f, '\'');
|
||||||
for(;*s;s++)
|
for(;*s;s++){
|
||||||
if(*s=='\'')
|
if(*s=='\'')
|
||||||
pfmt(f, "''");
|
pchr(f, *s);
|
||||||
else pchr(f, *s);
|
pchr(f, *s);
|
||||||
|
}
|
||||||
pchr(f, '\'');
|
pchr(f, '\'');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -154,37 +201,82 @@ poct(io *f, unsigned n)
|
||||||
void
|
void
|
||||||
pval(io *f, word *a)
|
pval(io *f, word *a)
|
||||||
{
|
{
|
||||||
if(a){
|
if(a==0)
|
||||||
while(a->next && a->next->word){
|
return;
|
||||||
pwrd(f, (char *)a->word);
|
while(a->next && a->next->word){
|
||||||
pchr(f, ' ');
|
|
||||||
a = a->next;
|
|
||||||
}
|
|
||||||
pwrd(f, (char *)a->word);
|
pwrd(f, (char *)a->word);
|
||||||
|
pchr(f, ' ');
|
||||||
|
a = a->next;
|
||||||
}
|
}
|
||||||
|
pwrd(f, (char *)a->word);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
io*
|
||||||
fullbuf(io *f, int c)
|
newio(uchar *buf, int len, int fd)
|
||||||
{
|
{
|
||||||
flush(f);
|
io *f = new(io);
|
||||||
return *f->bufp++=c;
|
f->buf = buf;
|
||||||
|
f->bufp = buf;
|
||||||
|
f->ebuf = buf+len;
|
||||||
|
f->fd = fd;
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Open a string buffer for writing.
|
||||||
|
*/
|
||||||
|
io*
|
||||||
|
openiostr(void)
|
||||||
|
{
|
||||||
|
uchar *buf = emalloc(100+1);
|
||||||
|
memset(buf, '\0', 100+1);
|
||||||
|
return newio(buf, 100, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return the buf, free the io
|
||||||
|
*/
|
||||||
|
char*
|
||||||
|
closeiostr(io *f)
|
||||||
|
{
|
||||||
|
void *buf = f->buf;
|
||||||
|
free(f);
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Use a open file descriptor for reading.
|
||||||
|
*/
|
||||||
|
io*
|
||||||
|
openiofd(int fd)
|
||||||
|
{
|
||||||
|
return newio(emalloc(NBUF), 0, fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Open a corebuffer to read. EOF occurs after reading len
|
||||||
|
* characters from buf.
|
||||||
|
*/
|
||||||
|
io*
|
||||||
|
openiocore(uchar *buf, int len)
|
||||||
|
{
|
||||||
|
return newio(buf, len, -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
flush(io *f)
|
flushio(io *f)
|
||||||
{
|
{
|
||||||
int n;
|
int n;
|
||||||
|
|
||||||
if(f->strp){
|
if(f->fd<0){
|
||||||
n = f->ebuf - f->strp;
|
n = f->ebuf - f->buf;
|
||||||
f->strp = erealloc(f->strp, n+Stralloc+1);
|
f->buf = erealloc(f->buf, n+n+1);
|
||||||
f->bufp = f->strp + n;
|
f->bufp = f->buf + n;
|
||||||
f->ebuf = f->bufp + Stralloc;
|
f->ebuf = f->bufp + n;
|
||||||
memset(f->bufp, '\0', Stralloc+1);
|
memset(f->bufp, '\0', n+1);
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
n = f->bufp-f->buf;
|
n = f->bufp - f->buf;
|
||||||
if(n && Write(f->fd, f->buf, n) != n){
|
if(n && Write(f->fd, f->buf, n) != n){
|
||||||
Write(2, "Write error\n", 12);
|
Write(2, "Write error\n", 12);
|
||||||
if(ntrap)
|
if(ntrap)
|
||||||
|
@ -195,71 +287,18 @@ flush(io *f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
io*
|
|
||||||
openfd(int fd)
|
|
||||||
{
|
|
||||||
io *f = new(struct io);
|
|
||||||
f->fd = fd;
|
|
||||||
f->bufp = f->ebuf = f->buf;
|
|
||||||
f->strp = 0;
|
|
||||||
return f;
|
|
||||||
}
|
|
||||||
|
|
||||||
io*
|
|
||||||
openstr(void)
|
|
||||||
{
|
|
||||||
io *f = new(struct io);
|
|
||||||
|
|
||||||
f->fd = -1;
|
|
||||||
f->bufp = f->strp = emalloc(Stralloc+1);
|
|
||||||
f->ebuf = f->bufp + Stralloc;
|
|
||||||
memset(f->bufp, '\0', Stralloc+1);
|
|
||||||
return f;
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* Open a corebuffer to read. EOF occurs after reading len
|
|
||||||
* characters from buf.
|
|
||||||
*/
|
|
||||||
|
|
||||||
io*
|
|
||||||
opencore(char *s, int len)
|
|
||||||
{
|
|
||||||
io *f = new(struct io);
|
|
||||||
uchar *buf = emalloc(len);
|
|
||||||
|
|
||||||
f->fd = -1 /*open("/dev/null", 0)*/;
|
|
||||||
f->bufp = f->strp = buf;
|
|
||||||
f->ebuf = buf+len;
|
|
||||||
memmove(buf, s, len);
|
|
||||||
return f;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
rewind(io *io)
|
closeio(io *f)
|
||||||
{
|
{
|
||||||
if(io->fd==-1)
|
if(f->fd>=0) Close(f->fd);
|
||||||
io->bufp = io->strp;
|
free(closeiostr(f));
|
||||||
else{
|
|
||||||
io->bufp = io->ebuf = io->buf;
|
|
||||||
Seek(io->fd, 0L, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
closeio(io *io)
|
|
||||||
{
|
|
||||||
if(io->fd>=0)
|
|
||||||
close(io->fd);
|
|
||||||
if(io->strp)
|
|
||||||
free(io->strp);
|
|
||||||
free(io);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
emptybuf(io *f)
|
emptyiobuf(io *f)
|
||||||
{
|
{
|
||||||
int n;
|
int n;
|
||||||
if(f->fd==-1 || (n = Read(f->fd, f->buf, NBUF))<=0) return EOF;
|
if(f->fd<0 || (n = Read(f->fd, f->buf, NBUF))<=0) return EOF;
|
||||||
f->bufp = f->buf;
|
f->bufp = f->buf;
|
||||||
f->ebuf = f->buf + n;
|
f->ebuf = f->buf + n;
|
||||||
return *f->bufp++;
|
return *f->bufp++;
|
||||||
|
|
|
@ -1,20 +1,20 @@
|
||||||
#define EOF (-1)
|
#define EOF (-1)
|
||||||
#define NBUF 512
|
|
||||||
|
|
||||||
struct io{
|
struct io{
|
||||||
int fd;
|
int fd;
|
||||||
uchar *bufp, *ebuf, *strp;
|
uchar *buf, *bufp, *ebuf;
|
||||||
uchar buf[NBUF];
|
io *next;
|
||||||
};
|
};
|
||||||
io *err;
|
io *err;
|
||||||
|
|
||||||
io *openfd(int), *openstr(void), *opencore(char *, int);
|
io *openiofd(int), *openiostr(void), *openiocore(uchar*, int);
|
||||||
int emptybuf(io*);
|
|
||||||
void pchr(io*, int);
|
void pchr(io*, int);
|
||||||
int rchr(io*);
|
int rchr(io*);
|
||||||
|
char *rstr(io*, char*);
|
||||||
|
char *closeiostr(io*);
|
||||||
void closeio(io*);
|
void closeio(io*);
|
||||||
void flush(io*);
|
int emptyiobuf(io*);
|
||||||
int fullbuf(io*, int);
|
void flushio(io*);
|
||||||
void pdec(io*, int);
|
void pdec(io*, int);
|
||||||
void poct(io*, unsigned);
|
void poct(io*, unsigned);
|
||||||
void pptr(io*, void*);
|
void pptr(io*, void*);
|
||||||
|
@ -23,5 +23,7 @@ void pwrd(io*, char*);
|
||||||
void pstr(io*, char*);
|
void pstr(io*, char*);
|
||||||
void pcmd(io*, tree*);
|
void pcmd(io*, tree*);
|
||||||
void pval(io*, word*);
|
void pval(io*, word*);
|
||||||
|
void pfun(io*, void(*)(void));
|
||||||
void pfnc(io*, thread*);
|
void pfnc(io*, thread*);
|
||||||
void pfmt(io*, char*, ...);
|
void pfmt(io*, char*, ...);
|
||||||
|
void vpfmt(io*, char*, va_list);
|
||||||
|
|
|
@ -1,9 +1,12 @@
|
||||||
#include "rc.h"
|
#include "rc.h"
|
||||||
#include "exec.h"
|
|
||||||
#include "io.h"
|
#include "io.h"
|
||||||
#include "getflags.h"
|
#include "getflags.h"
|
||||||
#include "fns.h"
|
#include "fns.h"
|
||||||
int getnext(void);
|
|
||||||
|
lexer *lex;
|
||||||
|
|
||||||
|
int doprompt = 1;
|
||||||
|
int nerror;
|
||||||
|
|
||||||
int
|
int
|
||||||
wordchr(int c)
|
wordchr(int c)
|
||||||
|
@ -21,105 +24,109 @@ idchr(int c)
|
||||||
*/
|
*/
|
||||||
return c>' ' && !strchr("!\"#$%&'()+,-./:;<=>?@[\\]^`{|}~", c);
|
return c>' ' && !strchr("!\"#$%&'()+,-./:;<=>?@[\\]^`{|}~", c);
|
||||||
}
|
}
|
||||||
int future = EOF;
|
|
||||||
int doprompt = 1;
|
|
||||||
int inquote;
|
|
||||||
int incomm;
|
|
||||||
int lastc;
|
|
||||||
int ndot;
|
|
||||||
int nerror;
|
|
||||||
int nlexpath;
|
|
||||||
int lexpathsz;
|
|
||||||
|
|
||||||
/*
|
lexer*
|
||||||
* Look ahead in the input stream
|
newlexer(io *input, char *file)
|
||||||
*/
|
{
|
||||||
|
lexer *n = new(struct lexer);
|
||||||
|
n->input = input;
|
||||||
|
n->file = file;
|
||||||
|
n->line = 1;
|
||||||
|
n->eof = 0;
|
||||||
|
n->future = EOF;
|
||||||
|
n->peekc = '{';
|
||||||
|
n->epilog = "}\n";
|
||||||
|
n->lastc = 0;
|
||||||
|
n->inquote = 0;
|
||||||
|
n->incomm = 0;
|
||||||
|
n->lastword = 0;
|
||||||
|
n->lastdol = 0;
|
||||||
|
n->iflast = 0;
|
||||||
|
n->qflag = 0;
|
||||||
|
n->tok[0] = 0;
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
int
|
void
|
||||||
nextc(void)
|
freelexer(lexer *p)
|
||||||
{
|
{
|
||||||
if(future==EOF)
|
closeio(p->input);
|
||||||
future = getnext();
|
free(p->file);
|
||||||
return future;
|
free(p);
|
||||||
}
|
|
||||||
/*
|
|
||||||
* Consume the lookahead character.
|
|
||||||
*/
|
|
||||||
int
|
|
||||||
advance(void)
|
|
||||||
{
|
|
||||||
int c = nextc();
|
|
||||||
lastc = future;
|
|
||||||
future = EOF;
|
|
||||||
if(c == '\n')
|
|
||||||
runq->lexline++;
|
|
||||||
return c;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* read a character from the input stream
|
* read a character from the input stream
|
||||||
*/
|
*/
|
||||||
|
static int
|
||||||
int
|
|
||||||
getnext(void)
|
getnext(void)
|
||||||
{
|
{
|
||||||
int c;
|
int c;
|
||||||
static int peekc = EOF;
|
|
||||||
if(peekc!=EOF){
|
if(lex->peekc!=EOF){
|
||||||
c = peekc;
|
c = lex->peekc;
|
||||||
peekc = EOF;
|
lex->peekc = EOF;
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
if(runq->eof)
|
if(lex->eof){
|
||||||
|
epilog:
|
||||||
|
if(*lex->epilog)
|
||||||
|
return *lex->epilog++;
|
||||||
|
doprompt = 1;
|
||||||
return EOF;
|
return EOF;
|
||||||
|
}
|
||||||
if(doprompt)
|
if(doprompt)
|
||||||
pprompt();
|
pprompt();
|
||||||
c = rchr(runq->cmdfd);
|
c = rchr(lex->input);
|
||||||
if(!inquote && c=='\\'){
|
if(c=='\\' && !lex->inquote){
|
||||||
c = rchr(runq->cmdfd);
|
c = rchr(lex->input);
|
||||||
if(c=='\n' && !incomm){ /* don't continue a comment */
|
if(c=='\n' && !lex->incomm){ /* don't continue a comment */
|
||||||
doprompt = 1;
|
doprompt = 1;
|
||||||
c=' ';
|
c=' ';
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
peekc = c;
|
lex->peekc = c;
|
||||||
c='\\';
|
c='\\';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
doprompt = doprompt || c=='\n' || c==EOF;
|
if(c==EOF){
|
||||||
if(c==EOF)
|
lex->eof = 1;
|
||||||
runq->eof++;
|
goto epilog;
|
||||||
else if(flag['V'] || ndot>=2 && flag['v']) pchr(err, c);
|
} else {
|
||||||
|
if(c=='\n')
|
||||||
|
doprompt = 1;
|
||||||
|
if((!lex->qflag && flag['v']!=0) || flag['V'])
|
||||||
|
pchr(err, c);
|
||||||
|
}
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
/*
|
||||||
pprompt(void)
|
* Look ahead in the input stream
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
nextc(void)
|
||||||
{
|
{
|
||||||
var *prompt;
|
if(lex->future==EOF)
|
||||||
if(runq->iflag){
|
lex->future = getnext();
|
||||||
pstr(err, promptstr);
|
return lex->future;
|
||||||
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");
|
|
||||||
if(prompt->val && prompt->val->next)
|
|
||||||
promptstr = prompt->val->next->word;
|
|
||||||
else
|
|
||||||
promptstr="\t";
|
|
||||||
}
|
|
||||||
runq->lineno++;
|
|
||||||
doprompt = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
/*
|
||||||
|
* Consume the lookahead character.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
advance(void)
|
||||||
|
{
|
||||||
|
int c = nextc();
|
||||||
|
lex->lastc = lex->future;
|
||||||
|
lex->future = EOF;
|
||||||
|
if(c == '\n')
|
||||||
|
lex->line++;
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
skipwhite(void)
|
skipwhite(void)
|
||||||
{
|
{
|
||||||
int c;
|
int c;
|
||||||
|
@ -127,11 +134,11 @@ skipwhite(void)
|
||||||
c = nextc();
|
c = nextc();
|
||||||
/* Why did this used to be if(!inquote && c=='#') ?? */
|
/* Why did this used to be if(!inquote && c=='#') ?? */
|
||||||
if(c=='#'){
|
if(c=='#'){
|
||||||
incomm = 1;
|
lex->incomm = 1;
|
||||||
for(;;){
|
for(;;){
|
||||||
c = nextc();
|
c = nextc();
|
||||||
if(c=='\n' || c==EOF) {
|
if(c=='\n' || c==EOF) {
|
||||||
incomm = 0;
|
lex->incomm = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
advance();
|
advance();
|
||||||
|
@ -156,7 +163,7 @@ skipnl(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
static int
|
||||||
nextis(int c)
|
nextis(int c)
|
||||||
{
|
{
|
||||||
if(nextc()==c){
|
if(nextc()==c){
|
||||||
|
@ -166,12 +173,12 @@ nextis(int c)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
char*
|
static char*
|
||||||
addtok(char *p, int val)
|
addtok(char *p, int val)
|
||||||
{
|
{
|
||||||
if(p==0)
|
if(p==0)
|
||||||
return 0;
|
return 0;
|
||||||
if(p==&tok[NTOK-1]){
|
if(p==&lex->tok[NTOK-1]){
|
||||||
*p = 0;
|
*p = 0;
|
||||||
yyerror("token buffer too short");
|
yyerror("token buffer too short");
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -180,7 +187,7 @@ addtok(char *p, int val)
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
char*
|
static char*
|
||||||
addutf(char *p, int c)
|
addutf(char *p, int c)
|
||||||
{
|
{
|
||||||
uchar b, m;
|
uchar b, m;
|
||||||
|
@ -202,16 +209,16 @@ addutf(char *p, int c)
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
int lastdol; /* was the last token read '$' or '$#' or '"'? */
|
|
||||||
int lastword; /* was the last token read a word or compound word terminator? */
|
|
||||||
|
|
||||||
int
|
int
|
||||||
yylex(void)
|
yylex(void)
|
||||||
{
|
{
|
||||||
int c, d = nextc();
|
int glob, c, d = nextc();
|
||||||
|
char *tok = lex->tok;
|
||||||
char *w = tok;
|
char *w = tok;
|
||||||
struct tree *t;
|
tree *t;
|
||||||
|
|
||||||
yylval.tree = 0;
|
yylval.tree = 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Embarassing sneakiness: if the last token read was a quoted or unquoted
|
* Embarassing sneakiness: if the last token read was a quoted or unquoted
|
||||||
* WORD then we alter the meaning of what follows. If the next character
|
* WORD then we alter the meaning of what follows. If the next character
|
||||||
|
@ -219,8 +226,8 @@ yylex(void)
|
||||||
* if the next character is the first character of a simple or compound word,
|
* if the next character is the first character of a simple or compound word,
|
||||||
* we insert a `^' before it.
|
* we insert a `^' before it.
|
||||||
*/
|
*/
|
||||||
if(lastword){
|
if(lex->lastword){
|
||||||
lastword = 0;
|
lex->lastword = 0;
|
||||||
if(d=='('){
|
if(d=='('){
|
||||||
advance();
|
advance();
|
||||||
strcpy(tok, "( [SUB]");
|
strcpy(tok, "( [SUB]");
|
||||||
|
@ -231,15 +238,15 @@ yylex(void)
|
||||||
return '^';
|
return '^';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
inquote = 0;
|
lex->inquote = 0;
|
||||||
skipwhite();
|
skipwhite();
|
||||||
switch(c = advance()){
|
switch(c = advance()){
|
||||||
case EOF:
|
case EOF:
|
||||||
lastdol = 0;
|
lex->lastdol = 0;
|
||||||
strcpy(tok, "EOF");
|
strcpy(tok, "EOF");
|
||||||
return EOF;
|
return EOF;
|
||||||
case '$':
|
case '$':
|
||||||
lastdol = 1;
|
lex->lastdol = 1;
|
||||||
if(nextis('#')){
|
if(nextis('#')){
|
||||||
strcpy(tok, "$#");
|
strcpy(tok, "$#");
|
||||||
return COUNT;
|
return COUNT;
|
||||||
|
@ -251,7 +258,7 @@ yylex(void)
|
||||||
strcpy(tok, "$");
|
strcpy(tok, "$");
|
||||||
return '$';
|
return '$';
|
||||||
case '&':
|
case '&':
|
||||||
lastdol = 0;
|
lex->lastdol = 0;
|
||||||
if(nextis('&')){
|
if(nextis('&')){
|
||||||
skipnl();
|
skipnl();
|
||||||
strcpy(tok, "&&");
|
strcpy(tok, "&&");
|
||||||
|
@ -260,7 +267,7 @@ yylex(void)
|
||||||
strcpy(tok, "&");
|
strcpy(tok, "&");
|
||||||
return '&';
|
return '&';
|
||||||
case '|':
|
case '|':
|
||||||
lastdol = 0;
|
lex->lastdol = 0;
|
||||||
if(nextis(c)){
|
if(nextis(c)){
|
||||||
skipnl();
|
skipnl();
|
||||||
strcpy(tok, "||");
|
strcpy(tok, "||");
|
||||||
|
@ -268,7 +275,7 @@ yylex(void)
|
||||||
}
|
}
|
||||||
case '<':
|
case '<':
|
||||||
case '>':
|
case '>':
|
||||||
lastdol = 0;
|
lex->lastdol = 0;
|
||||||
/*
|
/*
|
||||||
* funny redirection tokens:
|
* funny redirection tokens:
|
||||||
* redir: arrow | arrow '[' fd ']'
|
* redir: arrow | arrow '[' fd ']'
|
||||||
|
@ -355,9 +362,9 @@ yylex(void)
|
||||||
skipnl();
|
skipnl();
|
||||||
return t->type;
|
return t->type;
|
||||||
case '\'':
|
case '\'':
|
||||||
lastdol = 0;
|
lex->lastdol = 0;
|
||||||
lastword = 1;
|
lex->lastword = 1;
|
||||||
inquote = 1;
|
lex->inquote = 1;
|
||||||
for(;;){
|
for(;;){
|
||||||
c = advance();
|
c = advance();
|
||||||
if(c==EOF)
|
if(c==EOF)
|
||||||
|
@ -377,28 +384,51 @@ yylex(void)
|
||||||
return t->type;
|
return t->type;
|
||||||
}
|
}
|
||||||
if(!wordchr(c)){
|
if(!wordchr(c)){
|
||||||
lastdol = 0;
|
lex->lastdol = 0;
|
||||||
tok[0] = c;
|
tok[0] = c;
|
||||||
tok[1]='\0';
|
tok[1]='\0';
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
glob = 0;
|
||||||
for(;;){
|
for(;;){
|
||||||
if(c=='*' || c=='[' || c=='?' || c==GLOB)
|
if(c=='*' || c=='[' || c=='?' || c==GLOB){
|
||||||
|
glob = 1;
|
||||||
w = addtok(w, GLOB);
|
w = addtok(w, GLOB);
|
||||||
|
}
|
||||||
w = addutf(w, c);
|
w = addutf(w, c);
|
||||||
c = nextc();
|
c = nextc();
|
||||||
if(lastdol?!idchr(c):!wordchr(c)) break;
|
if(lex->lastdol?!idchr(c):!wordchr(c)) break;
|
||||||
advance();
|
advance();
|
||||||
}
|
}
|
||||||
|
|
||||||
lastword = 1;
|
lex->lastword = 1;
|
||||||
lastdol = 0;
|
lex->lastdol = 0;
|
||||||
if(w!=0)
|
if(w!=0)
|
||||||
*w='\0';
|
*w='\0';
|
||||||
t = klook(tok);
|
t = klook(tok);
|
||||||
if(t->type!=WORD)
|
if(t->type!=WORD)
|
||||||
lastword = 0;
|
lex->lastword = 0;
|
||||||
|
else
|
||||||
|
t->glob = glob;
|
||||||
t->quoted = 0;
|
t->quoted = 0;
|
||||||
yylval.tree = t;
|
yylval.tree = t;
|
||||||
return t->type;
|
return t->type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
yyerror(char *m)
|
||||||
|
{
|
||||||
|
pfln(err, lex->file, lex->line);
|
||||||
|
pstr(err, ": ");
|
||||||
|
if(lex->tok[0] && lex->tok[0]!='\n')
|
||||||
|
pfmt(err, "token %q: ", lex->tok);
|
||||||
|
pfmt(err, "%s\n", m);
|
||||||
|
flushio(err);
|
||||||
|
|
||||||
|
lex->lastword = 0;
|
||||||
|
lex->lastdol = 0;
|
||||||
|
while(lex->lastc!='\n' && lex->lastc!=EOF) advance();
|
||||||
|
nerror++;
|
||||||
|
|
||||||
|
setstatus(m);
|
||||||
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
#define c1 t->child[1]
|
#define c1 t->child[1]
|
||||||
#define c2 t->child[2]
|
#define c2 t->child[2]
|
||||||
|
|
||||||
void
|
static void
|
||||||
pdeglob(io *f, char *s)
|
pdeglob(io *f, char *s)
|
||||||
{
|
{
|
||||||
while(*s){
|
while(*s){
|
||||||
|
@ -16,6 +16,14 @@ pdeglob(io *f, char *s)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int ntab = 0;
|
||||||
|
|
||||||
|
static char*
|
||||||
|
tabs(void)
|
||||||
|
{
|
||||||
|
return "\t\t\t\t\t\t\t\t"+8-(ntab%8);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
pcmd(io *f, tree *t)
|
pcmd(io *f, tree *t)
|
||||||
{
|
{
|
||||||
|
@ -38,7 +46,11 @@ pcmd(io *f, tree *t)
|
||||||
break;
|
break;
|
||||||
case BANG: pfmt(f, "! %t", c0);
|
case BANG: pfmt(f, "! %t", c0);
|
||||||
break;
|
break;
|
||||||
case BRACE: pfmt(f, "{%t}", c0);
|
case BRACE:
|
||||||
|
ntab++;
|
||||||
|
pfmt(f, "{\n%s%t", tabs(), c0);
|
||||||
|
ntab--;
|
||||||
|
pfmt(f, "\n%s}", tabs());
|
||||||
break;
|
break;
|
||||||
case COUNT: pfmt(f, "$#%t", c0);
|
case COUNT: pfmt(f, "$#%t", c0);
|
||||||
break;
|
break;
|
||||||
|
@ -75,9 +87,14 @@ pcmd(io *f, tree *t)
|
||||||
break;
|
break;
|
||||||
case ';':
|
case ';':
|
||||||
if(c0){
|
if(c0){
|
||||||
if(c1)
|
pfmt(f, "%t", c0);
|
||||||
pfmt(f, "%t\n%t", c0, c1);
|
if(c1){
|
||||||
else pfmt(f, "%t", c0);
|
if(c0->line==c1->line)
|
||||||
|
pstr(f, "; ");
|
||||||
|
else
|
||||||
|
pfmt(f, "\n%s", tabs());
|
||||||
|
pfmt(f, "%t", c1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else pfmt(f, "%t", c1);
|
else pfmt(f, "%t", c1);
|
||||||
break;
|
break;
|
||||||
|
@ -109,6 +126,8 @@ pcmd(io *f, tree *t)
|
||||||
pchr(f, ' ');
|
pchr(f, ' ');
|
||||||
switch(t->rtype){
|
switch(t->rtype){
|
||||||
case HERE:
|
case HERE:
|
||||||
|
if(c1)
|
||||||
|
pfmt(f, "%t ", c1);
|
||||||
pchr(f, '<');
|
pchr(f, '<');
|
||||||
case READ:
|
case READ:
|
||||||
case RDWR:
|
case RDWR:
|
||||||
|
@ -127,7 +146,9 @@ pcmd(io *f, tree *t)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
pfmt(f, "%t", c0);
|
pfmt(f, "%t", c0);
|
||||||
if(c1)
|
if(t->rtype == HERE)
|
||||||
|
pfmt(f, "\n%s%t\n", t->str, c0);
|
||||||
|
else if(c1)
|
||||||
pfmt(f, " %t", c1);
|
pfmt(f, " %t", c1);
|
||||||
break;
|
break;
|
||||||
case '=':
|
case '=':
|
||||||
|
|
|
@ -18,8 +18,10 @@ struct{
|
||||||
Xjump, "Xjump",
|
Xjump, "Xjump",
|
||||||
Xmark, "Xmark",
|
Xmark, "Xmark",
|
||||||
Xpopm, "Xpopm",
|
Xpopm, "Xpopm",
|
||||||
|
Xpush, "Xpush",
|
||||||
Xrdwr, "Xrdwr",
|
Xrdwr, "Xrdwr",
|
||||||
Xread, "Xread",
|
Xread, "Xread",
|
||||||
|
Xhere, "Xhere",
|
||||||
Xreturn, "Xreturn",
|
Xreturn, "Xreturn",
|
||||||
Xtrue, "Xtrue",
|
Xtrue, "Xtrue",
|
||||||
Xif, "Xif",
|
Xif, "Xif",
|
||||||
|
@ -44,31 +46,33 @@ struct{
|
||||||
Xbackq, "Xbackq",
|
Xbackq, "Xbackq",
|
||||||
Xpipefd, "Xpipefd",
|
Xpipefd, "Xpipefd",
|
||||||
Xsubshell, "Xsubshell",
|
Xsubshell, "Xsubshell",
|
||||||
Xdelhere, "Xdelhere",
|
|
||||||
Xfor, "Xfor",
|
Xfor, "Xfor",
|
||||||
Xglob, "Xglob",
|
Xglob, "Xglob",
|
||||||
Xglobs, "Xglobs",
|
|
||||||
Xrdfn, "Xrdfn",
|
|
||||||
Xsimple, "Xsimple",
|
Xsimple, "Xsimple",
|
||||||
Xqw, "Xqw",
|
Xqw, "Xqw",
|
||||||
Xsrcline, "Xsrcline",
|
Xsrcline, "Xsrcline",
|
||||||
0};
|
0};
|
||||||
|
|
||||||
void
|
void
|
||||||
pfnc(io *fd, thread *t)
|
pfun(io *f, void (*fn)(void))
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
void (*fn)(void) = t->code[t->pc].f;
|
for(i = 0;fname[i].f;i++) if(fname[i].f==fn){
|
||||||
|
pstr(f, fname[i].name);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
pfmt(f, "%p", fn);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
pfnc(io *f, thread *t)
|
||||||
|
{
|
||||||
list *a;
|
list *a;
|
||||||
|
|
||||||
pfmt(fd, "%s:%d: pid %d cycle %p %d ", t->cmdfile, t->line, getpid(), t->code, t->pc);
|
pfln(f, srcfile(t), t->line);
|
||||||
for(i = 0;fname[i].f;i++) if(fname[i].f==fn){
|
pfmt(f, " pid %d cycle %p %d ", getpid(), t->code, t->pc);
|
||||||
pstr(fd, fname[i].name);
|
pfun(f, t->code[t->pc].f);
|
||||||
break;
|
for(a = t->argv;a;a = a->next) pfmt(f, " (%v)", a->words);
|
||||||
}
|
pchr(f, '\n');
|
||||||
if(!fname[i].f)
|
flushio(f);
|
||||||
pfmt(fd, "%p", fn);
|
|
||||||
for(a = t->argv;a;a = a->next) pfmt(fd, " (%v)", a->words);
|
|
||||||
pchr(fd, '\n');
|
|
||||||
flush(fd);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,16 +9,33 @@
|
||||||
#include "fns.h"
|
#include "fns.h"
|
||||||
#include "getflags.h"
|
#include "getflags.h"
|
||||||
|
|
||||||
enum {
|
static void execrfork(void);
|
||||||
Maxenvname = 128, /* undocumented limit */
|
static void execfinit(void);
|
||||||
|
|
||||||
|
builtin Builtin[] = {
|
||||||
|
"cd", execcd,
|
||||||
|
"whatis", execwhatis,
|
||||||
|
"eval", execeval,
|
||||||
|
"exec", execexec, /* but with popword first */
|
||||||
|
"exit", execexit,
|
||||||
|
"shift", execshift,
|
||||||
|
"wait", execwait,
|
||||||
|
".", execdot,
|
||||||
|
"flag", execflag,
|
||||||
|
"finit", execfinit,
|
||||||
|
"rfork", execrfork,
|
||||||
|
0
|
||||||
};
|
};
|
||||||
|
|
||||||
|
char Rcmain[]="/rc/lib/rcmain";
|
||||||
|
char Fdprefix[]="/fd/";
|
||||||
|
|
||||||
char *Signame[] = {
|
char *Signame[] = {
|
||||||
"sigexit", "sighup", "sigint", "sigquit",
|
"sigexit", "sighup", "sigint", "sigquit",
|
||||||
"sigalrm", "sigkill", "sigfpe", "sigterm",
|
"sigalrm", "sigkill", "sigfpe", "sigterm",
|
||||||
0
|
0
|
||||||
};
|
};
|
||||||
char *syssigname[] = {
|
static char *syssigname[] = {
|
||||||
"exit", /* can't happen */
|
"exit", /* can't happen */
|
||||||
"hangup",
|
"hangup",
|
||||||
"interrupt",
|
"interrupt",
|
||||||
|
@ -29,32 +46,24 @@ char *syssigname[] = {
|
||||||
"term",
|
"term",
|
||||||
0
|
0
|
||||||
};
|
};
|
||||||
char Rcmain[]="/rc/lib/rcmain";
|
|
||||||
char Fdprefix[]="/fd/";
|
|
||||||
void execfinit(void);
|
|
||||||
void execbind(void);
|
|
||||||
void execmount(void);
|
|
||||||
void execnewpgrp(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,
|
|
||||||
"rfork", execnewpgrp,
|
|
||||||
0
|
|
||||||
};
|
|
||||||
|
|
||||||
void
|
static void
|
||||||
execnewpgrp(void)
|
execfinit(void)
|
||||||
|
{
|
||||||
|
char *cmds = estrdup("for(i in '/env/fn#'*){. -bq $i}\n");
|
||||||
|
int line = runq->line;
|
||||||
|
poplist();
|
||||||
|
execcmds(openiocore((uchar*)cmds, strlen(cmds)), estrdup(srcfile(runq)), runq->local, runq->redir);
|
||||||
|
runq->lex->line = line;
|
||||||
|
runq->lex->qflag = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
execrfork(void)
|
||||||
{
|
{
|
||||||
int arg;
|
int arg;
|
||||||
char *s;
|
char *s;
|
||||||
|
|
||||||
switch(count(runq->argv->words)){
|
switch(count(runq->argv->words)){
|
||||||
case 1:
|
case 1:
|
||||||
arg = RFENVG|RFNAMEG|RFNOTEG;
|
arg = RFENVG|RFNAMEG|RFNOTEG;
|
||||||
|
@ -91,11 +100,11 @@ execnewpgrp(void)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if(rfork(arg)==-1){
|
if(rfork(arg)==-1){
|
||||||
pfmt(err, "rc: %s failed\n", runq->argv->words->word);
|
pfmt(err, "%s: %s failed\n", argv0, runq->argv->words->word);
|
||||||
setstatus("rfork failed");
|
setstatus("rfork failed");
|
||||||
} else {
|
} else {
|
||||||
if(arg & RFCFDG){
|
if(arg & RFCFDG){
|
||||||
struct redir *rp;
|
redir *rp;
|
||||||
for(rp = runq->redir; rp; rp = rp->next)
|
for(rp = runq->redir; rp; rp = rp->next)
|
||||||
rp->type = 0;
|
rp->type = 0;
|
||||||
}
|
}
|
||||||
|
@ -104,93 +113,59 @@ execnewpgrp(void)
|
||||||
poplist();
|
poplist();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char*
|
||||||
|
Env(char *name, int fn)
|
||||||
|
{
|
||||||
|
static char buf[128];
|
||||||
|
|
||||||
|
strcpy(buf, "/env/");
|
||||||
|
if(fn) strcat(buf, "fn#");
|
||||||
|
return strncat(buf, name, sizeof(buf)-1);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Vinit(void)
|
Vinit(void)
|
||||||
{
|
{
|
||||||
int dir, f, len, i, n, nent;
|
int dir, fd, i, n;
|
||||||
char *buf, *s;
|
|
||||||
char envname[Maxenvname];
|
|
||||||
word *val;
|
|
||||||
Dir *ent;
|
Dir *ent;
|
||||||
|
|
||||||
dir = open("/env", OREAD);
|
dir = Open(Env("", 0), 0);
|
||||||
if(dir<0){
|
if(dir<0){
|
||||||
pfmt(err, "rc: can't open /env: %r\n");
|
pfmt(err, "%s: can't open: %r\n", argv0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ent = nil;
|
|
||||||
for(;;){
|
for(;;){
|
||||||
nent = dirread(dir, &ent);
|
ent = 0;
|
||||||
if(nent <= 0)
|
n = dirread(dir, &ent);
|
||||||
|
if(n <= 0)
|
||||||
break;
|
break;
|
||||||
for(i = 0; i<nent; i++){
|
for(i = 0; i<n; i++){
|
||||||
len = ent[i].length;
|
if(ent[i].length<=0 || strncmp(ent[i].name, "fn#", 3)==0)
|
||||||
if(len && strncmp(ent[i].name, "fn#", 3)!=0){
|
continue;
|
||||||
snprint(envname, sizeof envname, "/env/%s", ent[i].name);
|
if((fd = Open(Env(ent[i].name, 0), 0))>=0){
|
||||||
if((f = open(envname, 0))>=0){
|
io *f = openiofd(fd);
|
||||||
buf = emalloc(len+1);
|
word *w = 0, **wp = &w;
|
||||||
n = readn(f, buf, len);
|
char *s;
|
||||||
if (n <= 0)
|
while((s = rstr(f, "")) != 0){
|
||||||
buf[0] = '\0';
|
*wp = Newword(s, (word*)0);
|
||||||
else
|
wp = &(*wp)->next;
|
||||||
buf[n] = '\0';
|
|
||||||
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);
|
|
||||||
free(buf);
|
|
||||||
}
|
}
|
||||||
|
closeio(f);
|
||||||
|
setvar(ent[i].name, w);
|
||||||
|
vlook(ent[i].name)->changed = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
free(ent);
|
free(ent);
|
||||||
}
|
}
|
||||||
close(dir);
|
Close(dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
char*
|
||||||
Xrdfn(void)
|
Errstr(void)
|
||||||
{
|
{
|
||||||
if(runq->argv->words == 0)
|
static char err[ERRMAX];
|
||||||
poplist();
|
rerrstr(err, sizeof err);
|
||||||
else {
|
return err;
|
||||||
free(runq->cmdfile);
|
|
||||||
int f = open(runq->argv->words->word, 0);
|
|
||||||
runq->cmdfile = strdup(runq->argv->words->word);
|
|
||||||
runq->lexline = 1;
|
|
||||||
runq->pc--;
|
|
||||||
popword();
|
|
||||||
if(f>=0) execcmds(openfd(f));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
union code rdfns[8];
|
|
||||||
|
|
||||||
void
|
|
||||||
execfinit(void)
|
|
||||||
{
|
|
||||||
static int first = 1;
|
|
||||||
if(first){
|
|
||||||
rdfns[0].i = 1;
|
|
||||||
rdfns[1].f = Xmark;
|
|
||||||
rdfns[2].f = Xglobs;
|
|
||||||
rdfns[4].i = Globsize(rdfns[3].s = "/env/fn#\001*");
|
|
||||||
rdfns[5].f = Xglob;
|
|
||||||
rdfns[6].f = Xrdfn;
|
|
||||||
rdfns[7].f = Xreturn;
|
|
||||||
first = 0;
|
|
||||||
}
|
|
||||||
poplist();
|
|
||||||
start(rdfns, 1, runq->local);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
|
@ -198,7 +173,6 @@ Waitfor(int pid, int)
|
||||||
{
|
{
|
||||||
thread *p;
|
thread *p;
|
||||||
Waitmsg *w;
|
Waitmsg *w;
|
||||||
char errbuf[ERRMAX];
|
|
||||||
|
|
||||||
if(pid >= 0 && !havewaitpid(pid))
|
if(pid >= 0 && !havewaitpid(pid))
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -218,54 +192,46 @@ Waitfor(int pid, int)
|
||||||
free(w);
|
free(w);
|
||||||
}
|
}
|
||||||
|
|
||||||
errstr(errbuf, sizeof errbuf);
|
if(strcmp(Errstr(), "interrupted")==0) return -1;
|
||||||
if(strcmp(errbuf, "interrupted")==0) return -1;
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
char **
|
static void
|
||||||
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)
|
addenv(var *v)
|
||||||
{
|
{
|
||||||
char envname[Maxenvname];
|
|
||||||
word *w;
|
word *w;
|
||||||
int f;
|
int fd;
|
||||||
io *fd;
|
io *f;
|
||||||
|
|
||||||
if(v->changed){
|
if(v->changed){
|
||||||
v->changed = 0;
|
v->changed = 0;
|
||||||
snprint(envname, sizeof envname, "/env/%s", v->name);
|
if((fd = Creat(Env(v->name, 0)))<0)
|
||||||
if((f = Creat(envname))<0)
|
pfmt(err, "%s: can't open: %r\n", argv0);
|
||||||
pfmt(err, "rc: can't open %s: %r\n", envname);
|
|
||||||
else{
|
else{
|
||||||
for(w = v->val;w;w = w->next)
|
f = openiofd(fd);
|
||||||
write(f, w->word, strlen(w->word)+1L);
|
for(w = v->val;w;w = w->next){
|
||||||
close(f);
|
pstr(f, w->word);
|
||||||
|
pchr(f, '\0');
|
||||||
|
}
|
||||||
|
flushio(f);
|
||||||
|
closeio(f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(v->fnchanged){
|
if(v->fnchanged){
|
||||||
v->fnchanged = 0;
|
v->fnchanged = 0;
|
||||||
snprint(envname, sizeof envname, "/env/fn#%s", v->name);
|
if((fd = Creat(Env(v->name, 1)))<0)
|
||||||
if((f = Creat(envname))<0)
|
pfmt(err, "%s: can't open: %r\n", argv0);
|
||||||
pfmt(err, "rc: can't open %s: %r\n", envname);
|
|
||||||
else{
|
else{
|
||||||
fd = openfd(f);
|
f = openiofd(fd);
|
||||||
if(v->fn)
|
if(v->fn)
|
||||||
pfmt(fd, "fn %q %s\n", v->name, v->fn[v->pc-1].s);
|
pfmt(f, "fn %q %s\n", v->name, v->fn[v->pc-1].s);
|
||||||
closeio(fd);
|
flushio(f);
|
||||||
|
closeio(f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
static void
|
||||||
updenvlocal(var *v)
|
updenvlocal(var *v)
|
||||||
{
|
{
|
||||||
if(v){
|
if(v){
|
||||||
|
@ -283,80 +249,43 @@ Updenv(void)
|
||||||
addenv(v);
|
addenv(v);
|
||||||
if(runq)
|
if(runq)
|
||||||
updenvlocal(runq->local);
|
updenvlocal(runq->local);
|
||||||
}
|
flushio(err);
|
||||||
|
|
||||||
/* not used on plan 9 */
|
|
||||||
int
|
|
||||||
ForkExecute(char *, char **, int, int, int)
|
|
||||||
{
|
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Execute(word *args, word *path)
|
Exec(char **argv)
|
||||||
{
|
{
|
||||||
char **argv = mkargv(args);
|
exec(argv[0], argv+1);
|
||||||
char file[1024];
|
}
|
||||||
int nc, mc;
|
|
||||||
|
|
||||||
|
int
|
||||||
|
Fork(void)
|
||||||
|
{
|
||||||
Updenv();
|
Updenv();
|
||||||
mc = strlen(argv[1])+1;
|
return rfork(RFPROC|RFFDG|RFREND);
|
||||||
for(;path;path = path->next){
|
|
||||||
nc = strlen(path->word);
|
|
||||||
if(nc + mc >= sizeof file - 1){ /* 1 for / */
|
|
||||||
werrstr("command path name too long");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if(nc > 0){
|
|
||||||
memmove(file, path->word, nc);
|
|
||||||
file[nc++] = '/';
|
|
||||||
}
|
|
||||||
memmove(file+nc, argv[1], mc);
|
|
||||||
exec(file, argv+1);
|
|
||||||
}
|
|
||||||
rerrstr(file, sizeof file);
|
|
||||||
setstatus(file);
|
|
||||||
pfmt(err, "%s: %s\n", argv[1], file);
|
|
||||||
free(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
|
|
||||||
|
|
||||||
struct{
|
typedef struct readdir readdir;
|
||||||
|
struct readdir {
|
||||||
Dir *dbuf;
|
Dir *dbuf;
|
||||||
int i;
|
int i, n;
|
||||||
int n;
|
int fd;
|
||||||
}dir[NFD];
|
};
|
||||||
|
|
||||||
int
|
void*
|
||||||
Opendir(char *name)
|
Opendir(char *name)
|
||||||
{
|
{
|
||||||
int f;
|
readdir *rd;
|
||||||
|
int fd;
|
||||||
if((f = open(name, 0)) < 0)
|
if((fd = Open(name, 0))<0)
|
||||||
return f;
|
return 0;
|
||||||
if(f<NFD){
|
rd = new(readdir);
|
||||||
dir[f].i = 0;
|
rd->dbuf = 0;
|
||||||
dir[f].n = 0;
|
rd->i = 0;
|
||||||
}
|
rd->n = 0;
|
||||||
return f;
|
rd->fd = fd;
|
||||||
|
return rd;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
|
@ -370,57 +299,52 @@ trimdirs(Dir *d, int nd)
|
||||||
return w;
|
return w;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
char*
|
||||||
Readdir(int f, void *p, int onlydirs)
|
Readdir(void *arg, int onlydirs)
|
||||||
{
|
{
|
||||||
|
readdir *rd = arg;
|
||||||
int n;
|
int n;
|
||||||
|
|
||||||
if(f<0 || f>=NFD)
|
|
||||||
return 0;
|
|
||||||
Again:
|
Again:
|
||||||
if(dir[f].i==dir[f].n){ /* read */
|
if(rd->i>=rd->n){ /* read */
|
||||||
free(dir[f].dbuf);
|
free(rd->dbuf);
|
||||||
dir[f].dbuf = 0;
|
rd->dbuf = 0;
|
||||||
n = dirread(f, &dir[f].dbuf);
|
n = dirread(rd->fd, &rd->dbuf);
|
||||||
if(n>0){
|
if(n>0){
|
||||||
if(onlydirs){
|
if(onlydirs){
|
||||||
n = trimdirs(dir[f].dbuf, n);
|
n = trimdirs(rd->dbuf, n);
|
||||||
if(n == 0)
|
if(n == 0)
|
||||||
goto Again;
|
goto Again;
|
||||||
}
|
}
|
||||||
dir[f].n = n;
|
rd->n = n;
|
||||||
}else
|
}else
|
||||||
dir[f].n = 0;
|
rd->n = 0;
|
||||||
dir[f].i = 0;
|
rd->i = 0;
|
||||||
}
|
}
|
||||||
if(dir[f].i == dir[f].n)
|
if(rd->i>=rd->n)
|
||||||
return 0;
|
return 0;
|
||||||
strncpy((char*)p, dir[f].dbuf[dir[f].i].name, NDIR);
|
return rd->dbuf[rd->i++].name;
|
||||||
dir[f].i++;
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Closedir(int f)
|
Closedir(void *arg)
|
||||||
{
|
{
|
||||||
if(f>=0 && f<NFD){
|
readdir *rd = arg;
|
||||||
free(dir[f].dbuf);
|
Close(rd->fd);
|
||||||
dir[f].i = 0;
|
free(rd->dbuf);
|
||||||
dir[f].n = 0;
|
free(rd);
|
||||||
dir[f].dbuf = 0;
|
|
||||||
}
|
|
||||||
close(f);
|
|
||||||
}
|
}
|
||||||
int interrupted = 0;
|
|
||||||
void
|
static int interrupted = 0;
|
||||||
|
|
||||||
|
static void
|
||||||
notifyf(void*, char *s)
|
notifyf(void*, char *s)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for(i = 0;syssigname[i];i++) if(strncmp(s, syssigname[i], strlen(syssigname[i]))==0){
|
for(i = 0;syssigname[i];i++) if(strncmp(s, syssigname[i], strlen(syssigname[i]))==0){
|
||||||
if(strncmp(s, "sys: ", 5)!=0) interrupted = 1;
|
if(strncmp(s, "sys: ", 5)!=0) interrupted = 1;
|
||||||
goto Out;
|
goto Out;
|
||||||
}
|
}
|
||||||
pfmt(err, "rc: note: %s\n", s);
|
|
||||||
noted(NDFLT);
|
noted(NDFLT);
|
||||||
return;
|
return;
|
||||||
Out:
|
Out:
|
||||||
|
@ -428,10 +352,6 @@ Out:
|
||||||
trap[i]++;
|
trap[i]++;
|
||||||
ntrap++;
|
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);
|
noted(NCONT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -441,12 +361,6 @@ Trapinit(void)
|
||||||
notify(notifyf);
|
notify(notifyf);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
Unlink(char *name)
|
|
||||||
{
|
|
||||||
remove(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
long
|
long
|
||||||
Write(int fd, void *buf, long cnt)
|
Write(int fd, void *buf, long cnt)
|
||||||
{
|
{
|
||||||
|
@ -479,10 +393,23 @@ Executable(char *file)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
Open(char *file, int mode)
|
||||||
|
{
|
||||||
|
static int tab[] = {OREAD,OWRITE,ORDWR,OREAD|ORCLOSE};
|
||||||
|
return open(file, tab[mode&3]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Close(int fd)
|
||||||
|
{
|
||||||
|
close(fd);
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
Creat(char *file)
|
Creat(char *file)
|
||||||
{
|
{
|
||||||
return create(file, 1, 0666L);
|
return create(file, OWRITE, 0666L);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
|
@ -524,11 +451,6 @@ Isatty(int fd)
|
||||||
|
|
||||||
if(fd2path(fd, buf, sizeof buf) != 0)
|
if(fd2path(fd, buf, sizeof buf) != 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* might be #c/cons during boot - fixed 22 april 2005, remove this later */
|
|
||||||
if(strcmp(buf, "#c/cons") == 0)
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
/* might be /mnt/term/dev/cons */
|
/* might be /mnt/term/dev/cons */
|
||||||
return strlen(buf) >= 9 && strcmp(buf+strlen(buf)-9, "/dev/cons") == 0;
|
return strlen(buf) >= 9 && strcmp(buf+strlen(buf)-9, "/dev/cons") == 0;
|
||||||
}
|
}
|
||||||
|
@ -537,51 +459,32 @@ void
|
||||||
Abort(void)
|
Abort(void)
|
||||||
{
|
{
|
||||||
pfmt(err, "aborting\n");
|
pfmt(err, "aborting\n");
|
||||||
flush(err);
|
|
||||||
Exit("aborting");
|
Exit("aborting");
|
||||||
}
|
}
|
||||||
|
|
||||||
int *waitpids;
|
static int newwdir;
|
||||||
int nwaitpids;
|
|
||||||
|
|
||||||
void
|
|
||||||
addwaitpid(int pid)
|
|
||||||
{
|
|
||||||
waitpids = erealloc(waitpids, (nwaitpids+1)*sizeof waitpids[0]);
|
|
||||||
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
|
int
|
||||||
havewaitpid(int pid)
|
Chdir(char *dir)
|
||||||
{
|
{
|
||||||
int i;
|
newwdir = 1;
|
||||||
|
return chdir(dir);
|
||||||
for(i=0; i<nwaitpids; i++)
|
|
||||||
if(waitpids[i] == pid)
|
|
||||||
return 1;
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* avoid loading any floating-point library code */
|
void
|
||||||
int
|
Prompt(char *s)
|
||||||
_efgfmt(Fmt *)
|
|
||||||
{
|
{
|
||||||
return -1;
|
pstr(err, s);
|
||||||
|
flushio(err);
|
||||||
|
|
||||||
|
if(newwdir){
|
||||||
|
char dir[4096];
|
||||||
|
int fd;
|
||||||
|
if((fd=Creat("/dev/wdir"))>=0){
|
||||||
|
getwd(dir, sizeof(dir));
|
||||||
|
Write(fd, dir, strlen(dir));
|
||||||
|
Close(fd);
|
||||||
|
}
|
||||||
|
newwdir = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,6 +30,7 @@ typedef struct io io;
|
||||||
typedef union code code;
|
typedef union code code;
|
||||||
typedef struct var var;
|
typedef struct var var;
|
||||||
typedef struct list list;
|
typedef struct list list;
|
||||||
|
typedef struct lexer lexer;
|
||||||
typedef struct redir redir;
|
typedef struct redir redir;
|
||||||
typedef struct thread thread;
|
typedef struct thread thread;
|
||||||
typedef struct builtin builtin;
|
typedef struct builtin builtin;
|
||||||
|
@ -40,10 +41,11 @@ typedef struct builtin builtin;
|
||||||
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 */
|
||||||
char *str;
|
|
||||||
int quoted;
|
|
||||||
int iskw;
|
|
||||||
int line;
|
int line;
|
||||||
|
char glob; /* 0=string, 1=glob, -1=pattern see globprop() and noglobs() */
|
||||||
|
char quoted;
|
||||||
|
char iskw;
|
||||||
|
char *str;
|
||||||
tree *child[3];
|
tree *child[3];
|
||||||
tree *next;
|
tree *next;
|
||||||
};
|
};
|
||||||
|
@ -52,12 +54,15 @@ tree *token(char*, int), *klook(char*), *tree1(int, tree*);
|
||||||
tree *tree2(int, tree*, tree*), *tree3(int, tree*, tree*, tree*);
|
tree *tree2(int, tree*, tree*), *tree3(int, tree*, tree*, tree*);
|
||||||
tree *mung1(tree*, tree*), *mung2(tree*, tree*, tree*);
|
tree *mung1(tree*, tree*), *mung2(tree*, tree*, tree*);
|
||||||
tree *mung3(tree*, tree*, tree*, tree*), *epimung(tree*, tree*);
|
tree *mung3(tree*, tree*, tree*, tree*), *epimung(tree*, tree*);
|
||||||
tree *simplemung(tree*), *heredoc(tree*);
|
tree *simplemung(tree*);
|
||||||
void freetree(tree*);
|
tree *globprop(tree*);
|
||||||
tree *cmdtree;
|
char *fnstr(tree*);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The first word of any code vector is a reference count.
|
* The first word of any code vector is a reference count
|
||||||
|
* and the second word is a string for srcfile().
|
||||||
|
* Code starts at pc 2. The last code word must be a zero
|
||||||
|
* terminator for codefree().
|
||||||
* Always create a new reference to a code vector by calling codecopy(.).
|
* Always create a new reference to a code vector by calling codecopy(.).
|
||||||
* Always call codefree(.) when deleting a reference.
|
* Always call codefree(.) when deleting a reference.
|
||||||
*/
|
*/
|
||||||
|
@ -67,13 +72,34 @@ union code{
|
||||||
char *s;
|
char *s;
|
||||||
};
|
};
|
||||||
|
|
||||||
int newwdir;
|
|
||||||
char *promptstr;
|
|
||||||
int doprompt;
|
|
||||||
|
|
||||||
#define NTOK 8192
|
#define NTOK 8192
|
||||||
|
|
||||||
char tok[NTOK];
|
struct lexer{
|
||||||
|
io *input;
|
||||||
|
char *file;
|
||||||
|
int line;
|
||||||
|
|
||||||
|
char *prolog;
|
||||||
|
char *epilog;
|
||||||
|
|
||||||
|
int peekc;
|
||||||
|
int future;
|
||||||
|
int lastc;
|
||||||
|
|
||||||
|
char eof;
|
||||||
|
char inquote;
|
||||||
|
char incomm;
|
||||||
|
char lastword; /* was the last token read a word or compound word terminator? */
|
||||||
|
char lastdol; /* was the last token read '$' or '$#' or '"'? */
|
||||||
|
char iflast; /* static `if not' checking */
|
||||||
|
|
||||||
|
char qflag;
|
||||||
|
|
||||||
|
char tok[NTOK];
|
||||||
|
};
|
||||||
|
extern lexer *lex; /* current lexer */
|
||||||
|
lexer *newlexer(io*, char*);
|
||||||
|
void freelexer(lexer*);
|
||||||
|
|
||||||
#define APPEND 1
|
#define APPEND 1
|
||||||
#define WRITE 2
|
#define WRITE 2
|
||||||
|
@ -84,15 +110,16 @@ char tok[NTOK];
|
||||||
#define RDWR 7
|
#define RDWR 7
|
||||||
|
|
||||||
struct var{
|
struct var{
|
||||||
char *name; /* ascii name */
|
|
||||||
word *val; /* value */
|
|
||||||
int changed;
|
|
||||||
code *fn; /* pointer to function's code vector */
|
|
||||||
int fnchanged;
|
|
||||||
int pc; /* pc of start of function */
|
|
||||||
var *next; /* next on hash or local list */
|
var *next; /* next on hash or local list */
|
||||||
|
word *val; /* value */
|
||||||
|
code *fn; /* pointer to function's code vector */
|
||||||
|
int pc; /* pc of start of function */
|
||||||
|
char fnchanged;
|
||||||
|
char changed;
|
||||||
|
char name[];
|
||||||
};
|
};
|
||||||
var *vlook(char*), *gvlook(char*), *newvar(char*, var*);
|
var *vlook(char*), *gvlook(char*), *newvar(char*, var*);
|
||||||
|
void setvar(char*, word*), freevar(var*);
|
||||||
|
|
||||||
#define NVAR 521
|
#define NVAR 521
|
||||||
|
|
||||||
|
@ -104,13 +131,6 @@ void *emalloc(long);
|
||||||
void *erealloc(void *, long);
|
void *erealloc(void *, long);
|
||||||
char *estrdup(char*);
|
char *estrdup(char*);
|
||||||
|
|
||||||
#define NOFILE 128 /* should come from <param.h> */
|
|
||||||
|
|
||||||
struct here{
|
|
||||||
tree *tag;
|
|
||||||
char *name;
|
|
||||||
struct here *next;
|
|
||||||
};
|
|
||||||
int mypid;
|
int mypid;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -141,12 +161,4 @@ extern int doprompt; /* is it time for a prompt? */
|
||||||
*/
|
*/
|
||||||
#define PRD 0
|
#define PRD 0
|
||||||
#define PWR 1
|
#define PWR 1
|
||||||
char Rcmain[], Fdprefix[];
|
extern char Rcmain[], Fdprefix[];
|
||||||
/*
|
|
||||||
* How many dot commands have we executed?
|
|
||||||
* Used to ensure that -v flag doesn't print rcmain.
|
|
||||||
*/
|
|
||||||
extern int ndot;
|
|
||||||
extern int lastc;
|
|
||||||
extern int lastword;
|
|
||||||
char *getstatus(void);
|
|
||||||
|
|
|
@ -6,32 +6,63 @@
|
||||||
#include "exec.h"
|
#include "exec.h"
|
||||||
#include "io.h"
|
#include "io.h"
|
||||||
#include "fns.h"
|
#include "fns.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Search through the following code to see if we're just going to exit.
|
* Search through the following code to see if we're just going to exit.
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
exitnext(void){
|
exitnext(void){
|
||||||
code *c=&runq->code[runq->pc];
|
int i=ifnot;
|
||||||
|
thread *p=runq;
|
||||||
|
code *c;
|
||||||
|
loop:
|
||||||
|
c=&p->code[p->pc];
|
||||||
while(1){
|
while(1){
|
||||||
if(c->f==Xpopredir || c->f==Xunlocal)
|
if(c->f==Xpopredir || c->f==Xunlocal)
|
||||||
c++;
|
c++;
|
||||||
else if(c->f==Xsrcline || c->f==Xsrcfile)
|
else if(c->f==Xsrcline)
|
||||||
c += 2;
|
c += 2;
|
||||||
else
|
else if(c->f==Xwastrue){
|
||||||
|
c++;
|
||||||
|
i=0;
|
||||||
|
}
|
||||||
|
else if(c->f==Xifnot){
|
||||||
|
if(i)
|
||||||
|
c += 2;
|
||||||
|
else
|
||||||
|
c = &p->code[c[1].i];
|
||||||
|
}
|
||||||
|
else if(c->f==Xreturn){
|
||||||
|
p = p->ret;
|
||||||
|
if(p==0)
|
||||||
|
return 1;
|
||||||
|
goto loop;
|
||||||
|
}else
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return c->f==Xexit;
|
return c->f==Xexit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void (*builtinfunc(char *name))(void)
|
||||||
|
{
|
||||||
|
extern builtin Builtin[];
|
||||||
|
builtin *bp;
|
||||||
|
|
||||||
|
for(bp = Builtin;bp->name;bp++)
|
||||||
|
if(strcmp(name, bp->name)==0)
|
||||||
|
return bp->fnc;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Xsimple(void)
|
Xsimple(void)
|
||||||
{
|
{
|
||||||
|
void (*f)(void);
|
||||||
word *a;
|
word *a;
|
||||||
var *v;
|
var *v;
|
||||||
struct builtin *bp;
|
|
||||||
int pid;
|
int pid;
|
||||||
|
|
||||||
a = globlist(runq->argv->words);
|
a = runq->argv->words;
|
||||||
if(a==0){
|
if(a==0){
|
||||||
Xerror1("empty argument list");
|
Xerror1("empty argument list");
|
||||||
return;
|
return;
|
||||||
|
@ -43,28 +74,25 @@ Xsimple(void)
|
||||||
execfunc(v);
|
execfunc(v);
|
||||||
else{
|
else{
|
||||||
if(strcmp(a->word, "builtin")==0){
|
if(strcmp(a->word, "builtin")==0){
|
||||||
if(count(a)==1){
|
|
||||||
pfmt(err, "builtin: empty argument list\n");
|
|
||||||
setstatus("empty arg list");
|
|
||||||
poplist();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
a = a->next;
|
a = a->next;
|
||||||
popword();
|
if(a==0){
|
||||||
}
|
Xerror1("builtin: empty argument list");
|
||||||
for(bp = Builtin;bp->name;bp++)
|
|
||||||
if(strcmp(a->word, bp->name)==0){
|
|
||||||
(*bp->fnc)();
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
popword(); /* "builtin" */
|
||||||
|
}
|
||||||
|
f = builtinfunc(a->word);
|
||||||
|
if(f){
|
||||||
|
(*f)();
|
||||||
|
return;
|
||||||
|
}
|
||||||
if(exitnext()){
|
if(exitnext()){
|
||||||
/* fork and wait is redundant */
|
/* fork and wait is redundant */
|
||||||
pushword("exec");
|
pushword("exec");
|
||||||
execexec();
|
execexec();
|
||||||
|
/* does not return */
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
flush(err);
|
|
||||||
Updenv(); /* necessary so changes don't go out again */
|
|
||||||
if((pid = execforkexec()) < 0){
|
if((pid = execforkexec()) < 0){
|
||||||
Xerror("try again");
|
Xerror("try again");
|
||||||
return;
|
return;
|
||||||
|
@ -78,7 +106,7 @@ Xsimple(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
static void
|
||||||
doredir(redir *rp)
|
doredir(redir *rp)
|
||||||
{
|
{
|
||||||
if(rp){
|
if(rp){
|
||||||
|
@ -87,14 +115,14 @@ doredir(redir *rp)
|
||||||
case ROPEN:
|
case ROPEN:
|
||||||
if(rp->from!=rp->to){
|
if(rp->from!=rp->to){
|
||||||
Dup(rp->from, rp->to);
|
Dup(rp->from, rp->to);
|
||||||
close(rp->from);
|
Close(rp->from);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case RDUP:
|
case RDUP:
|
||||||
Dup(rp->from, rp->to);
|
Dup(rp->from, rp->to);
|
||||||
break;
|
break;
|
||||||
case RCLOSE:
|
case RCLOSE:
|
||||||
close(rp->from);
|
Close(rp->from);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -115,42 +143,61 @@ searchpath(char *w, char *v)
|
||||||
return &nullpath;
|
return &nullpath;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char*
|
||||||
|
makepath(char *dir, char *file)
|
||||||
|
{
|
||||||
|
char *path;
|
||||||
|
int m, n = strlen(dir);
|
||||||
|
if(n==0) return estrdup(file);
|
||||||
|
while (n > 0 && dir[n-1]=='/') n--;
|
||||||
|
while (file[0]=='/') file++;
|
||||||
|
m = strlen(file);
|
||||||
|
path = emalloc(n + m + 2);
|
||||||
|
if(n>0) memmove(path, dir, n);
|
||||||
|
path[n++]='/';
|
||||||
|
memmove(path+n, file, m+1);
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char**
|
||||||
|
mkargv(word *a)
|
||||||
|
{
|
||||||
|
char **argv = (char **)emalloc((count(a)+2)*sizeof(char *));
|
||||||
|
char **argp = argv+1;
|
||||||
|
for(;a;a = a->next) *argp++=a->word;
|
||||||
|
*argp = 0;
|
||||||
|
return argv;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
execexec(void)
|
execexec(void)
|
||||||
{
|
{
|
||||||
|
char **argv;
|
||||||
|
word *path;
|
||||||
|
|
||||||
popword(); /* "exec" */
|
popword(); /* "exec" */
|
||||||
if(runq->argv->words==0){
|
if(runq->argv->words==0){
|
||||||
Xerror1("empty argument list");
|
Xerror1("empty argument list");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
argv = mkargv(runq->argv->words);
|
||||||
|
Updenv();
|
||||||
doredir(runq->redir);
|
doredir(runq->redir);
|
||||||
Execute(runq->argv->words, searchpath(runq->argv->words->word, "path"));
|
for(path = searchpath(argv[1], "path"); path; path = path->next){
|
||||||
poplist();
|
argv[0] = makepath(path->word, argv[1]);
|
||||||
|
Exec(argv);
|
||||||
|
}
|
||||||
|
setstatus(Errstr());
|
||||||
|
pfln(err, srcfile(runq), runq->line);
|
||||||
|
pfmt(err, ": %s: %r\n", argv[1]);
|
||||||
Xexit();
|
Xexit();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
execfunc(var *func)
|
execfunc(var *func)
|
||||||
{
|
{
|
||||||
word *starval;
|
popword(); /* name */
|
||||||
popword();
|
startfunc(func, Poplist(), runq->local, runq->redir);
|
||||||
starval = runq->argv->words;
|
|
||||||
runq->argv->words = 0;
|
|
||||||
poplist();
|
|
||||||
start(func->fn, func->pc, runq->local);
|
|
||||||
runq->local = newvar("*", runq->local);
|
|
||||||
runq->local->val = starval;
|
|
||||||
runq->local->changed = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
dochdir(char *word)
|
|
||||||
{
|
|
||||||
/* report to /dev/wdir if it exists and we're interactive */
|
|
||||||
if(chdir(word)<0)
|
|
||||||
return -1;
|
|
||||||
newwdir = 1;
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -168,11 +215,8 @@ execcd(void)
|
||||||
case 2:
|
case 2:
|
||||||
a = a->next;
|
a = a->next;
|
||||||
for(cdpath = searchpath(a->word, "cdpath"); cdpath; cdpath = cdpath->next){
|
for(cdpath = searchpath(a->word, "cdpath"); cdpath; cdpath = cdpath->next){
|
||||||
if(cdpath->word[0] != '\0')
|
dir = makepath(cdpath->word, a->word);
|
||||||
dir = smprint("%s/%s", cdpath->word, a->word);
|
if(Chdir(dir)>=0){
|
||||||
else
|
|
||||||
dir = estrdup(a->word);
|
|
||||||
if(dochdir(dir) >= 0){
|
|
||||||
if(cdpath->word[0] != '\0' && strcmp(cdpath->word, ".") != 0)
|
if(cdpath->word[0] != '\0' && strcmp(cdpath->word, ".") != 0)
|
||||||
pfmt(err, "%s\n", dir);
|
pfmt(err, "%s\n", dir);
|
||||||
free(dir);
|
free(dir);
|
||||||
|
@ -186,8 +230,8 @@ execcd(void)
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
a = vlook("home")->val;
|
a = vlook("home")->val;
|
||||||
if(count(a)>=1){
|
if(a){
|
||||||
if(dochdir(a->word)>=0)
|
if(Chdir(a->word)>=0)
|
||||||
setstatus("");
|
setstatus("");
|
||||||
else
|
else
|
||||||
pfmt(err, "Can't cd %s: %r\n", a->word);
|
pfmt(err, "Can't cd %s: %r\n", a->word);
|
||||||
|
@ -233,8 +277,7 @@ execshift(void)
|
||||||
star = vlook("*");
|
star = vlook("*");
|
||||||
for(;n>0 && star->val;--n){
|
for(;n>0 && star->val;--n){
|
||||||
a = star->val->next;
|
a = star->val->next;
|
||||||
free(star->val->word);
|
free(Freeword(star->val));
|
||||||
free(star->val);
|
|
||||||
star->val = a;
|
star->val = a;
|
||||||
star->changed = 1;
|
star->changed = 1;
|
||||||
}
|
}
|
||||||
|
@ -261,94 +304,98 @@ mapfd(int fd)
|
||||||
}
|
}
|
||||||
return fd;
|
return fd;
|
||||||
}
|
}
|
||||||
union code rdcmds[4];
|
|
||||||
|
|
||||||
void
|
void
|
||||||
execcmds(io *f)
|
execcmds(io *input, char *file, var *local, redir *redir)
|
||||||
{
|
{
|
||||||
static int first = 1;
|
static union code rdcmds[5];
|
||||||
|
|
||||||
if(first){
|
if(rdcmds[0].i==0){
|
||||||
rdcmds[0].i = 1;
|
rdcmds[0].i = 1;
|
||||||
rdcmds[1].f = Xrdcmds;
|
rdcmds[1].s="*rdcmds*";
|
||||||
rdcmds[2].f = Xreturn;
|
rdcmds[2].f = Xrdcmds;
|
||||||
first = 0;
|
rdcmds[3].f = Xreturn;
|
||||||
|
rdcmds[4].f = 0;
|
||||||
}
|
}
|
||||||
start(rdcmds, 1, runq->local);
|
|
||||||
runq->cmdfd = f;
|
if(exitnext()) turfstack(local);
|
||||||
runq->iflast = 0;
|
|
||||||
|
start(rdcmds, 2, local, redir);
|
||||||
|
runq->lex = newlexer(input, file);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
execeval(void)
|
execeval(void)
|
||||||
{
|
{
|
||||||
char *cmdline;
|
char *cmds;
|
||||||
int len;
|
int len;
|
||||||
if(count(runq->argv->words)<=1){
|
io *f;
|
||||||
|
|
||||||
|
popword(); /* "eval" */
|
||||||
|
|
||||||
|
if(runq->argv->words==0){
|
||||||
Xerror1("Usage: eval cmd ...");
|
Xerror1("Usage: eval cmd ...");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
eflagok = 1;
|
Xqw(); /* make into single word */
|
||||||
cmdline = list2str(runq->argv->words->next);
|
cmds = Popword();
|
||||||
len = strlen(cmdline);
|
len = strlen(cmds);
|
||||||
cmdline[len] = '\n';
|
cmds[len++] = '\n';
|
||||||
poplist();
|
poplist();
|
||||||
execcmds(opencore(cmdline, len+1));
|
|
||||||
free(cmdline);
|
f = openiostr();
|
||||||
|
pfln(f, srcfile(runq), runq->line);
|
||||||
|
pstr(f, " *eval*");
|
||||||
|
|
||||||
|
execcmds(openiocore((uchar*)cmds, len), closeiostr(f), runq->local, runq->redir);
|
||||||
}
|
}
|
||||||
union code dotcmds[14];
|
|
||||||
|
|
||||||
void
|
void
|
||||||
execdot(void)
|
execdot(void)
|
||||||
{
|
{
|
||||||
int iflag = 0;
|
int fd, bflag, iflag, qflag;
|
||||||
int fd;
|
word *path, *argv;
|
||||||
list *av;
|
char *file;
|
||||||
thread *p = runq;
|
|
||||||
char *zero, *file;
|
|
||||||
word *path;
|
|
||||||
static int first = 1;
|
|
||||||
|
|
||||||
if(first){
|
popword(); /* "." */
|
||||||
dotcmds[0].i = 1;
|
|
||||||
dotcmds[1].f = Xmark;
|
|
||||||
dotcmds[2].f = Xword;
|
|
||||||
dotcmds[3].s="0";
|
|
||||||
dotcmds[4].f = Xlocal;
|
|
||||||
dotcmds[5].f = Xmark;
|
|
||||||
dotcmds[6].f = Xword;
|
|
||||||
dotcmds[7].s="*";
|
|
||||||
dotcmds[8].f = Xlocal;
|
|
||||||
dotcmds[9].f = Xrdcmds;
|
|
||||||
dotcmds[10].f = Xunlocal;
|
|
||||||
dotcmds[11].f = Xunlocal;
|
|
||||||
dotcmds[12].f = Xreturn;
|
|
||||||
first = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
eflagok = 1;
|
|
||||||
|
|
||||||
popword();
|
bflag = iflag = qflag = 0;
|
||||||
if(p->argv->words && strcmp(p->argv->words->word, "-i")==0){
|
while(runq->argv->words && runq->argv->words->word[0]=='-'){
|
||||||
iflag = 1;
|
char *f = runq->argv->words->word+1;
|
||||||
|
if(*f == '-'){
|
||||||
|
popword();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
for(; *f; f++){
|
||||||
|
switch(*f){
|
||||||
|
case 'b':
|
||||||
|
bflag = 1;
|
||||||
|
continue;
|
||||||
|
case 'i':
|
||||||
|
iflag = 1;
|
||||||
|
continue;
|
||||||
|
case 'q':
|
||||||
|
qflag = 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
goto Usage;
|
||||||
|
}
|
||||||
popword();
|
popword();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* get input file */
|
/* get input file */
|
||||||
if(p->argv->words==0){
|
if(runq->argv->words==0){
|
||||||
Xerror1("Usage: . [-i] file [arg ...]");
|
Usage:
|
||||||
|
Xerror1("Usage: . [-biq] file [arg ...]");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
zero = estrdup(p->argv->words->word);
|
argv = Poplist();
|
||||||
popword();
|
|
||||||
fd = -1;
|
|
||||||
for(path = searchpath(zero, "path"); path; path = path->next){
|
|
||||||
if(path->word[0] != '\0')
|
|
||||||
file = smprint("%s/%s", path->word, zero);
|
|
||||||
else
|
|
||||||
file = estrdup(zero);
|
|
||||||
|
|
||||||
fd = open(file, 0);
|
file = 0;
|
||||||
free(file);
|
fd = -1;
|
||||||
|
for(path = searchpath(argv->word, "path"); path; path = path->next){
|
||||||
|
file = makepath(path->word, argv->word);
|
||||||
|
fd = Open(file, 0);
|
||||||
if(fd >= 0)
|
if(fd >= 0)
|
||||||
break;
|
break;
|
||||||
if(strcmp(file, "/dev/stdin")==0){ /* for sun & ucb */
|
if(strcmp(file, "/dev/stdin")==0){ /* for sun & ucb */
|
||||||
|
@ -356,33 +403,31 @@ execdot(void)
|
||||||
if(fd>=0)
|
if(fd>=0)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
free(file);
|
||||||
}
|
}
|
||||||
if(fd<0){
|
if(fd<0){
|
||||||
pfmt(err, "%s: ", zero);
|
if(!qflag) Xerror(".: can't open");
|
||||||
setstatus("can't open");
|
freewords(argv);
|
||||||
Xerror(".: can't open");
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* set up for a new command loop */
|
execcmds(openiofd(fd), file, (var*)0, runq->redir);
|
||||||
start(dotcmds, 1, (struct var *)0);
|
|
||||||
pushredir(RCLOSE, fd, 0);
|
pushredir(RCLOSE, fd, 0);
|
||||||
runq->cmdfile = zero;
|
runq->lex->qflag = qflag;
|
||||||
runq->cmdfd = openfd(fd);
|
|
||||||
runq->lexline = 1;
|
|
||||||
runq->iflag = iflag;
|
runq->iflag = iflag;
|
||||||
runq->iflast = 0;
|
if(iflag || !bflag && flag['b']==0){
|
||||||
/* push $* value */
|
runq->lex->peekc=EOF;
|
||||||
pushlist();
|
runq->lex->epilog="";
|
||||||
runq->argv->words = p->argv->words;
|
}
|
||||||
/* free caller's copy of $* */
|
|
||||||
av = p->argv;
|
runq->local = newvar("*", runq->local);
|
||||||
p->argv = av->next;
|
runq->local->val = argv->next;
|
||||||
free(av);
|
argv->next=0;
|
||||||
/* push $0 value */
|
runq->local->changed = 1;
|
||||||
pushlist();
|
|
||||||
pushword(zero);
|
runq->local = newvar("0", runq->local);
|
||||||
ndot++;
|
runq->local->val = argv;
|
||||||
|
runq->local->changed = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -417,9 +462,8 @@ void
|
||||||
execwhatis(void){ /* mildly wrong -- should fork before writing */
|
execwhatis(void){ /* mildly wrong -- should fork before writing */
|
||||||
word *a, *b, *path;
|
word *a, *b, *path;
|
||||||
var *v;
|
var *v;
|
||||||
struct builtin *bp;
|
|
||||||
char *file;
|
char *file;
|
||||||
struct io out[1];
|
io *out;
|
||||||
int found, sep;
|
int found, sep;
|
||||||
a = runq->argv->words->next;
|
a = runq->argv->words->next;
|
||||||
if(a==0){
|
if(a==0){
|
||||||
|
@ -427,10 +471,7 @@ execwhatis(void){ /* mildly wrong -- should fork before writing */
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
setstatus("");
|
setstatus("");
|
||||||
out->fd = mapfd(1);
|
out = openiofd(mapfd(1));
|
||||||
out->bufp = out->buf;
|
|
||||||
out->ebuf = &out->buf[NBUF];
|
|
||||||
out->strp = 0;
|
|
||||||
for(;a;a = a->next){
|
for(;a;a = a->next){
|
||||||
v = vlook(a->word);
|
v = vlook(a->word);
|
||||||
if(v->val){
|
if(v->val){
|
||||||
|
@ -443,7 +484,7 @@ execwhatis(void){ /* mildly wrong -- should fork before writing */
|
||||||
pfmt(out, "%c%q", sep, b->word);
|
pfmt(out, "%c%q", sep, b->word);
|
||||||
sep=' ';
|
sep=' ';
|
||||||
}
|
}
|
||||||
pfmt(out, ")\n");
|
pstr(out, ")\n");
|
||||||
}
|
}
|
||||||
found = 1;
|
found = 1;
|
||||||
}
|
}
|
||||||
|
@ -453,19 +494,11 @@ execwhatis(void){ /* mildly wrong -- should fork before writing */
|
||||||
if(v->fn)
|
if(v->fn)
|
||||||
pfmt(out, "fn %q %s\n", v->name, v->fn[v->pc-1].s);
|
pfmt(out, "fn %q %s\n", v->name, v->fn[v->pc-1].s);
|
||||||
else{
|
else{
|
||||||
for(bp = Builtin;bp->name;bp++)
|
if(builtinfunc(a->word))
|
||||||
if(strcmp(a->word, bp->name)==0){
|
pfmt(out, "builtin %s\n", a->word);
|
||||||
pfmt(out, "builtin %s\n", a->word);
|
else {
|
||||||
break;
|
for(path = searchpath(a->word, "path"); path; path = path->next){
|
||||||
}
|
file = makepath(path->word, a->word);
|
||||||
if(!bp->name){
|
|
||||||
for(path = searchpath(a->word, "path"); path;
|
|
||||||
path = path->next){
|
|
||||||
if(path->word[0] != '\0')
|
|
||||||
file = smprint("%s/%s",
|
|
||||||
path->word, a->word);
|
|
||||||
else
|
|
||||||
file = estrdup(a->word);
|
|
||||||
if(Executable(file)){
|
if(Executable(file)){
|
||||||
pfmt(out, "%s\n", file);
|
pfmt(out, "%s\n", file);
|
||||||
free(file);
|
free(file);
|
||||||
|
@ -479,9 +512,10 @@ execwhatis(void){ /* mildly wrong -- should fork before writing */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
flushio(out);
|
||||||
}
|
}
|
||||||
poplist();
|
poplist();
|
||||||
flush(err);
|
free(closeiostr(out)); /* don't close fd */
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -9,7 +9,6 @@ emalloc(long 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);
|
||||||
setmalloctag(p, getcallerpc(&n));
|
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,44 +18,29 @@ erealloc(void *p, long n)
|
||||||
p = realloc(p, n);
|
p = realloc(p, n);
|
||||||
if(p==0 && n!=0)
|
if(p==0 && n!=0)
|
||||||
panic("Can't realloc %d bytes\n", n);
|
panic("Can't realloc %d bytes\n", n);
|
||||||
setrealloctag(p, getcallerpc(&p));
|
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
char*
|
char*
|
||||||
estrdup(char *s)
|
estrdup(char *s)
|
||||||
{
|
{
|
||||||
char *d;
|
int n = strlen(s)+1;
|
||||||
int n;
|
char *d = emalloc(n);
|
||||||
|
|
||||||
n = strlen(s)+1;
|
|
||||||
d = emalloc(n);
|
|
||||||
memmove(d, s, n);
|
memmove(d, s, n);
|
||||||
return d;
|
return d;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern int lastword, lastdol;
|
|
||||||
|
|
||||||
void
|
void
|
||||||
yyerror(char *m)
|
pfln(io *fd, char *file, int line)
|
||||||
{
|
{
|
||||||
pfmt(err, "rc: ");
|
if(file && line)
|
||||||
if(runq->cmdfile && !runq->iflag)
|
pfmt(fd, "%s:%d", file, line);
|
||||||
pfmt(err, "%s:%d: ", runq->cmdfile, runq->lineno);
|
else if(file)
|
||||||
else if(runq->cmdfile)
|
pstr(fd, file);
|
||||||
pfmt(err, "%s: ", runq->cmdfile);
|
else
|
||||||
else if(!runq->iflag)
|
pstr(fd, argv0);
|
||||||
pfmt(err, "line %d: ", runq->lineno);
|
|
||||||
if(tok[0] && tok[0]!='\n')
|
|
||||||
pfmt(err, "token %q: ", tok);
|
|
||||||
pfmt(err, "%s\n", m);
|
|
||||||
flush(err);
|
|
||||||
lastword = 0;
|
|
||||||
lastdol = 0;
|
|
||||||
while(lastc!='\n' && lastc!=EOF) advance();
|
|
||||||
nerror++;
|
|
||||||
setvar("status", newword(m, (word *)0));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
char *bp;
|
char *bp;
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -72,7 +56,7 @@ iacvt(int n)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
inttoascii(char *s, long n)
|
inttoascii(char *s, int n)
|
||||||
{
|
{
|
||||||
bp = s;
|
bp = s;
|
||||||
iacvt(n);
|
iacvt(n);
|
||||||
|
@ -82,9 +66,8 @@ inttoascii(char *s, long n)
|
||||||
void
|
void
|
||||||
panic(char *s, int n)
|
panic(char *s, int n)
|
||||||
{
|
{
|
||||||
pfmt(err, "rc: ");
|
pfmt(err, "%s: ", argv0);
|
||||||
pfmt(err, s, n);
|
pfmt(err, s, n);
|
||||||
pchr(err, '\n');
|
pchr(err, '\n');
|
||||||
flush(err);
|
|
||||||
Abort();
|
Abort();
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,7 +36,7 @@ paren: '(' body ')' {$$=tree1(PCMD, $2);}
|
||||||
assign: first '=' word {$$=tree2('=', $1, $3);}
|
assign: first '=' word {$$=tree2('=', $1, $3);}
|
||||||
epilog: {$$=0;}
|
epilog: {$$=0;}
|
||||||
| redir epilog {$$=mung2($1, $1->child[0], $2);}
|
| redir epilog {$$=mung2($1, $1->child[0], $2);}
|
||||||
redir: REDIR word {$$=mung1($1, $1->rtype==HERE?heredoc($2):$2);}
|
redir: REDIR word {($$=mung1($1, $2))->str=$1->rtype==HERE?readhere($2,lex->input):0;}
|
||||||
| DUP
|
| DUP
|
||||||
cmd: {$$=0;}
|
cmd: {$$=0;}
|
||||||
| brace epilog {$$=epimung($1, $2);}
|
| brace epilog {$$=epimung($1, $2);}
|
||||||
|
@ -54,7 +54,7 @@ cmd: {$$=0;}
|
||||||
*/
|
*/
|
||||||
{$$=mung3($1, $3, $5 ? $5 : tree1(PAREN, $5), $8);}
|
{$$=mung3($1, $3, $5 ? $5 : tree1(PAREN, $5), $8);}
|
||||||
| FOR '(' word ')' {skipnl();} cmd
|
| FOR '(' word ')' {skipnl();} cmd
|
||||||
{$$=mung3($1, $3, (struct tree *)0, $6);}
|
{$$=mung3($1, $3, (tree*)0, $6);}
|
||||||
| WHILE paren {skipnl();} cmd
|
| WHILE paren {skipnl();} cmd
|
||||||
{$$=mung2($1, $2, $4);}
|
{$$=mung2($1, $2, $4);}
|
||||||
| SWITCH word {skipnl();} brace
|
| SWITCH word {skipnl();} brace
|
||||||
|
@ -74,19 +74,19 @@ simple: first
|
||||||
| simple word {$$=tree2(ARGLIST, $1, $2);}
|
| simple word {$$=tree2(ARGLIST, $1, $2);}
|
||||||
| simple redir {$$=tree2(ARGLIST, $1, $2);}
|
| simple redir {$$=tree2(ARGLIST, $1, $2);}
|
||||||
first: comword
|
first: comword
|
||||||
| first '^' word {$$=tree2('^', $1, $3);}
|
| first '^' word {$$=globprop(tree2('^', $1, $3));}
|
||||||
word: keyword {lastword=1; $1->type=WORD;}
|
word: keyword {lex->lastword=1; $1->type=WORD;}
|
||||||
| comword
|
| comword
|
||||||
| word '^' word {$$=tree2('^', $1, $3);}
|
| word '^' word {$$=globprop(tree2('^', $1, $3));}
|
||||||
comword: '$' word {$$=tree1('$', $2);}
|
comword: '$' word {$$=tree1('$', $2);}
|
||||||
| '$' word SUB words ')' {$$=tree2(SUB, $2, $4);}
|
| '$' word SUB words ')' {$$=tree2(SUB, $2, $4);}
|
||||||
| '"' word {$$=tree1('"', $2);}
|
| '"' word {$$=tree1('"', $2);}
|
||||||
| COUNT word {$$=tree1(COUNT, $2);}
|
| COUNT word {$$=tree1(COUNT, $2);}
|
||||||
| WORD
|
| WORD
|
||||||
| '`' brace {$$=tree2('`', (struct tree*)0, $2);}
|
| '`' brace {$$=tree2('`', (tree*)0, $2);}
|
||||||
| '`' word brace {$$=tree2('`', $2, $3);}
|
| '`' 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
|
||||||
words: {$$=(struct tree*)0;}
|
words: {$$=(tree*)0;}
|
||||||
| words word {$$=tree2(WORDS, $1, $2);}
|
| words word {$$=tree2(WORDS, $1, $2);}
|
||||||
|
|
|
@ -8,21 +8,16 @@ void
|
||||||
dotrap(void)
|
dotrap(void)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
struct var *trapreq;
|
var *trapreq;
|
||||||
struct word *starval;
|
word *starval;
|
||||||
starval = vlook("*")->val;
|
starval = vlook("*")->val;
|
||||||
while(ntrap) for(i = 0;i!=NSIG;i++) while(trap[i]){
|
while(ntrap) for(i = 0;i!=NSIG;i++) while(trap[i]){
|
||||||
--trap[i];
|
--trap[i];
|
||||||
--ntrap;
|
--ntrap;
|
||||||
if(getpid()!=mypid) Exit(getstatus());
|
if(getpid()!=mypid) Exit(getstatus());
|
||||||
trapreq = vlook(Signame[i]);
|
trapreq = vlook(Signame[i]);
|
||||||
if(trapreq->fn){
|
if(trapreq->fn)
|
||||||
start(trapreq->fn, trapreq->pc, (struct var *)0);
|
startfunc(trapreq, copywords(starval, (word*)0), (var*)0, (redir*)0);
|
||||||
runq->local = newvar("*", runq->local);
|
|
||||||
runq->local->val = copywords(starval, (struct word *)0);
|
|
||||||
runq->local->changed = 1;
|
|
||||||
runq->redir = runq->startredir = 0;
|
|
||||||
}
|
|
||||||
else if(i==SIGINT || i==SIGQUIT){
|
else if(i==SIGINT || i==SIGQUIT){
|
||||||
/*
|
/*
|
||||||
* run the stack down until we uncover the
|
* run the stack down until we uncover the
|
||||||
|
|
|
@ -1,22 +1,30 @@
|
||||||
#include "rc.h"
|
#include "rc.h"
|
||||||
#include "exec.h"
|
|
||||||
#include "io.h"
|
#include "io.h"
|
||||||
#include "fns.h"
|
#include "fns.h"
|
||||||
tree *treenodes;
|
|
||||||
/*
|
/*
|
||||||
* create and clear a new tree node, and add it
|
* create and clear a new tree node, and add it
|
||||||
* to the node list.
|
* to the node list.
|
||||||
*/
|
*/
|
||||||
|
static tree *treefree, *treenodes;
|
||||||
|
|
||||||
tree*
|
tree*
|
||||||
newtree(void)
|
newtree(void)
|
||||||
{
|
{
|
||||||
tree *t = new(tree);
|
tree *t;
|
||||||
|
|
||||||
|
t = treefree;
|
||||||
|
if(t==0)
|
||||||
|
t = new(tree);
|
||||||
|
else
|
||||||
|
treefree = t->next;
|
||||||
|
t->quoted = 0;
|
||||||
|
t->glob = 0;
|
||||||
t->iskw = 0;
|
t->iskw = 0;
|
||||||
t->str = 0;
|
t->str = 0;
|
||||||
t->child[0] = t->child[1] = t->child[2] = 0;
|
t->child[0] = t->child[1] = t->child[2] = 0;
|
||||||
|
t->line = lex->line;
|
||||||
t->next = treenodes;
|
t->next = treenodes;
|
||||||
t->line = runq->lexline;
|
|
||||||
treenodes = t;
|
treenodes = t;
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
@ -24,12 +32,21 @@ newtree(void)
|
||||||
void
|
void
|
||||||
freenodes(void)
|
freenodes(void)
|
||||||
{
|
{
|
||||||
tree *t, *u;
|
tree *t;
|
||||||
for(t = treenodes;t;t = u){
|
|
||||||
u = t->next;
|
t = treenodes;
|
||||||
if(t->str)
|
while(t){
|
||||||
|
if(t->str){
|
||||||
free(t->str);
|
free(t->str);
|
||||||
free(t);
|
t->str = 0;
|
||||||
|
}
|
||||||
|
t->child[0] = t->child[1] = t->child[2] = 0;
|
||||||
|
if(t->next==0){
|
||||||
|
t->next = treefree;
|
||||||
|
treefree = treenodes;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
t = t->next;
|
||||||
}
|
}
|
||||||
treenodes = 0;
|
treenodes = 0;
|
||||||
}
|
}
|
||||||
|
@ -61,6 +78,13 @@ tree3(int type, tree *c0, tree *c1, tree *c2)
|
||||||
t->child[0] = c0;
|
t->child[0] = c0;
|
||||||
t->child[1] = c1;
|
t->child[1] = c1;
|
||||||
t->child[2] = c2;
|
t->child[2] = c2;
|
||||||
|
|
||||||
|
if(c0)
|
||||||
|
t->line = c0->line;
|
||||||
|
else if(c1)
|
||||||
|
t->line = c1->line;
|
||||||
|
else if(c2)
|
||||||
|
t->line = c2->line;
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -98,22 +122,18 @@ epimung(tree *comp, tree *epi)
|
||||||
p->child[1] = comp;
|
p->child[1] = comp;
|
||||||
return epi;
|
return epi;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Add a SIMPLE node at the root of t and percolate all the redirections
|
* Add a SIMPLE node at the root of t and percolate all the redirections
|
||||||
* up to the root.
|
* up to the root.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
tree*
|
tree*
|
||||||
simplemung(tree *t)
|
simplemung(tree *t)
|
||||||
{
|
{
|
||||||
tree *u;
|
tree *u;
|
||||||
struct io *s;
|
|
||||||
|
|
||||||
t = tree1(SIMPLE, t);
|
t = tree1(SIMPLE, t);
|
||||||
s = openstr();
|
t->str = fnstr(t);
|
||||||
pfmt(s, "%t", t);
|
|
||||||
t->str = estrdup((char *)s->strp);
|
|
||||||
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
|
||||||
|| u->child[1]->type==REDIR){
|
|| u->child[1]->type==REDIR){
|
||||||
|
@ -125,25 +145,36 @@ simplemung(tree *t)
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char*
|
||||||
|
fnstr(tree *t)
|
||||||
|
{
|
||||||
|
io *f = openiostr();
|
||||||
|
pfmt(f, "%t", t);
|
||||||
|
return closeiostr(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
tree*
|
||||||
|
globprop(tree *t)
|
||||||
|
{
|
||||||
|
tree *c0 = t->child[0];
|
||||||
|
tree *c1 = t->child[1];
|
||||||
|
if(t->glob==0){
|
||||||
|
if(c0->glob || c1->glob){
|
||||||
|
if(c0->glob)
|
||||||
|
c0->glob=-1;
|
||||||
|
if(c1->glob)
|
||||||
|
c1->glob=-1;
|
||||||
|
t->glob=1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
tree*
|
tree*
|
||||||
token(char *str, int type)
|
token(char *str, int type)
|
||||||
{
|
{
|
||||||
tree *t = newtree();
|
tree *t = newtree();
|
||||||
|
t->str = estrdup(str);
|
||||||
t->type = type;
|
t->type = type;
|
||||||
t->str = strdup(str);
|
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
freetree(tree *p)
|
|
||||||
{
|
|
||||||
if(p==0)
|
|
||||||
return;
|
|
||||||
freetree(p->child[0]);
|
|
||||||
freetree(p->child[1]);
|
|
||||||
freetree(p->child[2]);
|
|
||||||
if(p->str)
|
|
||||||
free(p->str);
|
|
||||||
free(p);
|
|
||||||
}
|
|
||||||
|
|
|
@ -57,6 +57,20 @@ klook(char *name)
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var*
|
||||||
|
newvar(char *name, var *next)
|
||||||
|
{
|
||||||
|
int n = strlen(name)+1;
|
||||||
|
var *v = emalloc(sizeof(var)+n);
|
||||||
|
memmove(v->name, name, n);
|
||||||
|
v->next = next;
|
||||||
|
v->val = 0;
|
||||||
|
v->fn = 0;
|
||||||
|
v->changed = 0;
|
||||||
|
v->fnchanged = 0;
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
var*
|
var*
|
||||||
gvlook(char *name)
|
gvlook(char *name)
|
||||||
{
|
{
|
||||||
|
@ -79,8 +93,15 @@ vlook(char *name)
|
||||||
void
|
void
|
||||||
setvar(char *name, word *val)
|
setvar(char *name, word *val)
|
||||||
{
|
{
|
||||||
struct var *v = vlook(name);
|
var *v = vlook(name);
|
||||||
freewords(v->val);
|
freewords(v->val);
|
||||||
v->val = val;
|
v->val = val;
|
||||||
v->changed = 1;
|
v->changed = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
freevar(var *v)
|
||||||
|
{
|
||||||
|
freewords(v->val);
|
||||||
|
free(v);
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue