sync with plan 9

This commit is contained in:
rsc 2007-03-26 12:02:41 +00:00
parent 79049567a0
commit c8f538425f
23 changed files with 1962 additions and 1227 deletions

View File

@ -17,18 +17,28 @@ void codeswitch(tree*, int);
int iscase(tree*); int iscase(tree*);
code *codecopy(code*); code *codecopy(code*);
void codefree(code*); void codefree(code*);
int morecode(void){
int
morecode(void)
{
ncode+=100; ncode+=100;
codebuf = (code *)realloc((char *)codebuf, ncode*sizeof codebuf[0]); codebuf = (code *)realloc((char *)codebuf, ncode*sizeof codebuf[0]);
if(codebuf==0) panic("Can't realloc %d bytes in morecode!", if(codebuf==0)
panic("Can't realloc %d bytes in morecode!",
ncode*sizeof codebuf[0]); ncode*sizeof codebuf[0]);
return 0; return 0;
} }
void stuffdot(int a){
if(a<0 || codep<=a) panic("Bad address %d in stuffdot", a); void
stuffdot(int a)
{
if(a<0 || codep<=a)
panic("Bad address %d in stuffdot", a);
codebuf[a].i = codep; codebuf[a].i = codep;
} }
int compile(tree *t)
int
compile(tree *t)
{ {
ncode = 100; ncode = 100;
codebuf = (code *)emalloc(ncode*sizeof codebuf[0]); codebuf = (code *)emalloc(ncode*sizeof codebuf[0]);
@ -44,12 +54,16 @@ int compile(tree *t)
emitf(0); emitf(0);
return 1; return 1;
} }
void cleanhere(char *f)
void
cleanhere(char *f)
{ {
emitf(Xdelhere); emitf(Xdelhere);
emits(strdup(f)); emits(strdup(f));
} }
char *fnstr(tree *t)
char*
fnstr(tree *t)
{ {
io *f = openstr(); io *f = openstr();
char *v; char *v;
@ -63,12 +77,16 @@ char *fnstr(tree *t)
closeio(f); closeio(f);
return v; return v;
} }
void outcode(tree *t, int eflag)
void
outcode(tree *t, int eflag)
{ {
int p, q; int p, q;
tree *tt; tree *tt;
if(t==0) return; if(t==0)
if(t->type!=NOT && t->type!=';') runq->iflast=0; return;
if(t->type!=NOT && t->type!=';')
runq->iflast = 0;
switch(t->type){ switch(t->type){
default: default:
pfmt(err, "bad type %d in outcode\n", t->type); pfmt(err, "bad type %d in outcode\n", t->type);
@ -92,10 +110,13 @@ void outcode(tree *t, int eflag)
break; break;
case '&': case '&':
emitf(Xasync); emitf(Xasync);
if(havefork){
p = emiti(0); p = emiti(0);
outcode(c0, eflag); outcode(c0, eflag);
emitf(Xexit); emitf(Xexit);
stuffdot(p); stuffdot(p);
} else
emits(fnstr(c0));
break; break;
case ';': case ';':
outcode(c0, eflag); outcode(c0, eflag);
@ -110,10 +131,13 @@ void outcode(tree *t, int eflag)
break; break;
case '`': case '`':
emitf(Xbackq); emitf(Xbackq);
if(havefork){
p = emiti(0); p = emiti(0);
outcode(c0, 0); outcode(c0, 0);
emitf(Xexit); emitf(Xexit);
stuffdot(p); stuffdot(p);
} else
emits(fnstr(c0));
break; break;
case ANDAND: case ANDAND:
outcode(c0, 0); outcode(c0, 0);
@ -163,7 +187,8 @@ void outcode(tree *t, int eflag)
stuffdot(p); stuffdot(p);
break; break;
case NOT: case NOT:
if(!runq->iflast) yyerror("`if not' does not follow `if(...)'"); if(!runq->iflast)
yyerror("`if not' does not follow `if(...)'");
emitf(Xifnot); emitf(Xifnot);
p = emiti(0); p = emiti(0);
outcode(c0, eflag); outcode(c0, eflag);
@ -183,15 +208,20 @@ void outcode(tree *t, int eflag)
emitf(Xmark); emitf(Xmark);
outcode(c0, eflag); outcode(c0, eflag);
emitf(Xsimple); emitf(Xsimple);
if(eflag) emitf(Xeflag); if(eflag)
emitf(Xeflag);
break; break;
case SUBSHELL: case SUBSHELL:
emitf(Xsubshell); emitf(Xsubshell);
if(havefork){
p = emiti(0); p = emiti(0);
outcode(c0, eflag); outcode(c0, eflag);
emitf(Xexit); emitf(Xexit);
stuffdot(p); stuffdot(p);
if(eflag) emitf(Xeflag); } else
emits(fnstr(c0));
if(eflag)
emitf(Xeflag);
break; break;
case SWITCH: case SWITCH:
codeswitch(t, eflag); codeswitch(t, eflag);
@ -202,12 +232,14 @@ void outcode(tree *t, int eflag)
emitf(Xmark); emitf(Xmark);
outcode(c0, eflag); outcode(c0, eflag);
emitf(Xmatch); emitf(Xmatch);
if(eflag) emitf(Xeflag); if(eflag)
emitf(Xeflag);
break; break;
case WHILE: case WHILE:
q = codep; q = codep;
outcode(c0, 0); outcode(c0, 0);
if(q==codep) emitf(Xsettrue); /* empty condition == while(true) */ if(q==codep)
emitf(Xsettrue); /* empty condition == while(true) */
emitf(Xtrue); emitf(Xtrue);
p = emiti(0); p = emiti(0);
outcode(c1, eflag); outcode(c1, eflag);
@ -263,10 +295,14 @@ void outcode(tree *t, int eflag)
case PIPEFD: case PIPEFD:
emitf(Xpipefd); emitf(Xpipefd);
emiti(t->rtype); emiti(t->rtype);
if(havefork){
p = emiti(0); p = emiti(0);
outcode(c0, eflag); outcode(c0, eflag);
emitf(Xexit); emitf(Xexit);
stuffdot(p); stuffdot(p);
} else {
emits(fnstr(c0));
}
break; break;
case REDIR: case REDIR:
emitf(Xmark); emitf(Xmark);
@ -283,6 +319,9 @@ void outcode(tree *t, int eflag)
case HERE: case HERE:
emitf(Xread); emitf(Xread);
break; break;
case RDWR:
emitf(Xrdwr);
break;
} }
emiti(t->fd0); emiti(t->fd0);
outcode(c1, eflag); outcode(c1, eflag);
@ -318,11 +357,16 @@ void outcode(tree *t, int eflag)
emitf(Xpipe); emitf(Xpipe);
emiti(t->fd0); emiti(t->fd0);
emiti(t->fd1); emiti(t->fd1);
if(havefork){
p = emiti(0); p = emiti(0);
q = emiti(0); q = emiti(0);
outcode(c0, eflag); outcode(c0, eflag);
emitf(Xexit); emitf(Xexit);
stuffdot(p); stuffdot(p);
} else {
emits(fnstr(c0));
q = emiti(0);
}
outcode(c1, eflag); outcode(c1, eflag);
emitf(Xreturn); emitf(Xreturn);
stuffdot(q); stuffdot(q);
@ -353,7 +397,9 @@ void outcode(tree *t, int eflag)
* leave: * leave:
* Xpopm * Xpopm
*/ */
void codeswitch(tree *t, int eflag)
void
codeswitch(tree *t, int eflag)
{ {
int leave; /* patch jump address to leave switch */ int leave; /* patch jump address to leave switch */
int out; /* jump here to leave switch */ int out; /* jump here to leave switch */
@ -398,23 +444,32 @@ void codeswitch(tree *t, int eflag)
stuffdot(leave); stuffdot(leave);
emitf(Xpopm); emitf(Xpopm);
} }
int iscase(tree *t)
int
iscase(tree *t)
{ {
if(t->type!=SIMPLE) return 0; if(t->type!=SIMPLE)
return 0;
do t = c0; while(t->type==ARGLIST); do t = c0; while(t->type==ARGLIST);
return t->type==WORD && !t->quoted && strcmp(t->str, "case")==0; return t->type==WORD && !t->quoted && strcmp(t->str, "case")==0;
} }
code *codecopy(code *cp)
code*
codecopy(code *cp)
{ {
cp[0].i++; cp[0].i++;
return cp; return cp;
} }
void codefree(code *cp)
void
codefree(code *cp)
{ {
code *p; code *p;
if(--cp[0].i!=0) return; if(--cp[0].i!=0)
return;
for(p = cp+1;p->f;p++){ for(p = cp+1;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==Xasync || p->f==Xbackq || p->f==Xcase || p->f==Xfalse || p->f==Xasync || p->f==Xbackq || p->f==Xcase || p->f==Xfalse
|| p->f==Xfor || p->f==Xjump || p->f==Xfor || p->f==Xjump
|| p->f==Xsubshell || p->f==Xtrue) p++; || p->f==Xsubshell || p->f==Xtrue) p++;

View File

@ -1,9 +1,3 @@
#include <u.h>
#include <signal.h>
#if defined(PLAN9PORT) && defined(__sun__)
# define BSD_COMP /* sigh. for TIOCNOTTY */
#endif
#include <sys/ioctl.h>
#include "rc.h" #include "rc.h"
#include "getflags.h" #include "getflags.h"
#include "exec.h" #include "exec.h"
@ -13,9 +7,12 @@
* Start executing the given code at the given pc with the given redirection * Start executing the given code at the given pc with the given redirection
*/ */
char *argv0="rc"; char *argv0="rc";
void start(code *c, int pc, var *local)
void
start(code *c, int pc, var *local)
{ {
struct thread *p = new(struct thread); struct thread *p = new(struct thread);
p->code = codecopy(c); p->code = codecopy(c);
p->pc = pc; p->pc = pc;
p->argv = 0; p->argv = 0;
@ -26,32 +23,43 @@ void start(code *c, int pc, var *local)
p->eof = 0; p->eof = 0;
p->iflag = 0; p->iflag = 0;
p->lineno = 1; p->lineno = 1;
p->pid=-1;
p->ret = runq; p->ret = runq;
runq = p; runq = p;
} }
word *newword(char *wd, word *next)
word*
newword(char *wd, word *next)
{ {
word *p = new(word); word *p = new(word);
p->word = strdup(wd); p->word = strdup(wd);
p->next = next; p->next = next;
return p; return p;
} }
void pushword(char *wd)
void
pushword(char *wd)
{ {
if(runq->argv==0) panic("pushword but no argv!", 0); if(runq->argv==0)
panic("pushword but no argv!", 0);
runq->argv->words = newword(wd, runq->argv->words); runq->argv->words = newword(wd, runq->argv->words);
} }
void popword(void){
void
popword(void)
{
word *p; word *p;
if(runq->argv==0) panic("popword but no argv!", 0); if(runq->argv==0)
panic("popword but no argv!", 0);
p = runq->argv->words; p = runq->argv->words;
if(p==0) panic("popword but no word!", 0); if(p==0)
panic("popword but no word!", 0);
runq->argv->words = p->next; runq->argv->words = p->next;
efree(p->word); efree(p->word);
efree((char *)p); efree((char *)p);
} }
void freelist(word *w)
void
freelist(word *w)
{ {
word *nw; word *nw;
while(w){ while(w){
@ -61,26 +69,38 @@ void freelist(word *w)
w = nw; w = nw;
} }
} }
void pushlist(void){
void
pushlist(void)
{
list *p = new(list); list *p = new(list);
p->next = runq->argv; p->next = runq->argv;
p->words = 0; p->words = 0;
runq->argv = p; runq->argv = p;
} }
void poplist(void){
void
poplist(void)
{
list *p = runq->argv; list *p = runq->argv;
if(p==0) panic("poplist but no argv", 0); if(p==0)
panic("poplist but no argv", 0);
freelist(p->words); freelist(p->words);
runq->argv = p->next; runq->argv = p->next;
efree((char *)p); efree((char *)p);
} }
int count(word *w)
int
count(word *w)
{ {
int n; int n;
for(n = 0;w;n++) w = w->next; for(n = 0;w;n++) w = w->next;
return n; return n;
} }
void pushredir(int type, int from, int to){
void
pushredir(int type, int from, int to)
{
redir * rp = new(redir); redir * rp = new(redir);
rp->type = type; rp->type = type;
rp->from = from; rp->from = from;
@ -88,7 +108,9 @@ void pushredir(int type, int from, int to){
rp->next = runq->redir; rp->next = runq->redir;
runq->redir = rp; runq->redir = rp;
} }
var *newvar(char *name, var *next)
var*
newvar(char *name, var *next)
{ {
var *v = new(var); var *v = new(var);
v->name = name; v->name = name;
@ -97,7 +119,6 @@ var *newvar(char *name, var *next)
v->changed = 0; v->changed = 0;
v->fnchanged = 0; v->fnchanged = 0;
v->next = next; v->next = next;
v->changefn = 0;
return v; return v;
} }
/* /*
@ -117,17 +138,20 @@ main(int argc, char *argv[])
/* needed for rcmain later */ /* needed for rcmain later */
putenv("PLAN9", unsharp("#9")); putenv("PLAN9", unsharp("#9"));
argc=getflags(argc, argv, "srdiIlxepvVc:1m:1[command]", 1); argc = getflags(argc, argv, "SsrdiIlxepvVc:1m:1[command]", 1);
if(argc==-1) usage("[file [arg ...]]"); if(argc==-1)
if(argv[0][0]=='-') flag['l']=flagset; usage("[file [arg ...]]");
if(flag['I']) flag['i'] = 0; if(argv[0][0]=='-')
flag['l'] = flagset;
if(flag['I'])
flag['i'] = 0;
else if(flag['i']==0 && argc==1 && Isatty(0)) flag['i'] = flagset; else if(flag['i']==0 && argc==1 && Isatty(0)) flag['i'] = flagset;
rcmain = flag['m'] ? flag['m'][0] : Rcmain(); rcmain = flag['m'] ? flag['m'][0] : Rcmain();
err = openfd(2); err = openfd(2);
kinit(); kinit();
Trapinit(); Trapinit();
Vinit(); Vinit();
itoa(num, mypid=getpid()); inttoascii(num, mypid = getpid());
pathinit(); pathinit();
setvar("pid", newword(num, (word *)0)); setvar("pid", newword(num, (word *)0));
setvar("cflag", flag['c']?newword(flag['c'][0], (word *)0) setvar("cflag", flag['c']?newword(flag['c'][0], (word *)0)
@ -157,10 +181,12 @@ main(int argc, char *argv[])
argv0 = strdup(argv[0]); argv0 = strdup(argv[0]);
for(i = argc-1;i!=0;--i) pushword(argv[i]); for(i = argc-1;i!=0;--i) pushword(argv[i]);
for(;;){ for(;;){
if(flag['r']) pfnc(err, runq); if(flag['r'])
pfnc(err, runq);
runq->pc++; runq->pc++;
(*runq->code[runq->pc-1].f)(); (*runq->code[runq->pc-1].f)();
if(ntrap) dotrap(); if(ntrap)
dotrap();
} }
} }
/* /*
@ -197,6 +223,7 @@ main(int argc, char *argv[])
* Xpipefd[type]{... Xreturn} connect {} to pipe (input or output, * Xpipefd[type]{... Xreturn} connect {} to pipe (input or output,
* depending on type), push /dev/fd/?? * depending on type), push /dev/fd/??
* Xpopm(value) pop value from stack * Xpopm(value) pop value from stack
* Xrdwr(file)[fd] open file for reading and writing
* Xread(file)[fd] open file to read * Xread(file)[fd] open file to read
* Xsettraps(names){... Xreturn} define trap functions * Xsettraps(names){... Xreturn} define trap functions
* Xshowtraps print trap list * Xshowtraps print trap list
@ -208,13 +235,21 @@ main(int argc, char *argv[])
* Xword[string] push string * Xword[string] push string
* Xwrite(file)[fd] open file to write * Xwrite(file)[fd] open file to write
*/ */
void Xappend(void){
void
Xappend(void)
{
char *file; char *file;
int f; int f;
switch(count(runq->argv->words)){ switch(count(runq->argv->words)){
default: Xerror1(">> requires singleton"); return; default:
case 0: Xerror1(">> requires file"); return; Xerror1(">> requires singleton");
case 1: break; return;
case 0:
Xerror1(">> requires file");
return;
case 1:
break;
} }
file = runq->argv->words->word; file = runq->argv->words->word;
if((f = open(file, 1))<0 && (f = Creat(file))<0){ if((f = open(file, 1))<0 && (f = Creat(file))<0){
@ -227,77 +262,42 @@ void Xappend(void){
runq->pc++; runq->pc++;
poplist(); poplist();
} }
void Xasync(void){
int null=open("/dev/null", 0); void
int tty; Xsettrue(void)
int pid; {
char npid[10];
if(null<0){
Xerror("Can't open /dev/null\n");
return;
}
switch(pid=rfork(RFFDG|RFPROC|RFNOTEG)){
case -1:
close(null);
Xerror("try again");
break;
case 0:
/*
* I don't know what the right thing to do here is,
* so this is all experimentally determined.
* If we just dup /dev/null onto 0, then running
* ssh foo & will reopen /dev/tty, try to read a password,
* get a signal, and repeat, in a tight loop, forever.
* Arguably this is a bug in ssh (it behaves the same
* way under bash as under rc) but I'm fixing it here
* anyway. If we dissociate the process from the tty,
* then it won't be able to open /dev/tty ever again.
* The SIG_IGN on SIGTTOU makes writing the tty
* (via fd 1 or 2, for example) succeed even though
* our pgrp is not the terminal's controlling pgrp.
*/
if((tty=open("/dev/tty", OREAD)) >= 0){
/*
* Should make reads of tty fail, writes succeed.
*/
signal(SIGTTIN, SIG_IGN);
signal(SIGTTOU, SIG_IGN);
ioctl(tty, TIOCNOTTY);
close(tty);
}
if(isatty(0))
pushredir(ROPEN, null, 0);
else
close(null);
start(runq->code, runq->pc+1, runq->local);
runq->ret=0;
break;
default:
close(null);
runq->pc=runq->code[runq->pc].i;
itoa(npid, pid);
setvar("apid", newword(npid, (word *)0));
break;
}
}
void Xsettrue(void){
setstatus(""); setstatus("");
} }
void Xbang(void){
void
Xbang(void)
{
setstatus(truestatus()?"false":""); setstatus(truestatus()?"false":"");
} }
void Xclose(void){
void
Xclose(void)
{
pushredir(RCLOSE, runq->code[runq->pc].i, 0); pushredir(RCLOSE, runq->code[runq->pc].i, 0);
runq->pc++; runq->pc++;
} }
void Xdup(void){
void
Xdup(void)
{
pushredir(RDUP, runq->code[runq->pc].i, runq->code[runq->pc+1].i); pushredir(RDUP, runq->code[runq->pc].i, runq->code[runq->pc+1].i);
runq->pc+=2; runq->pc+=2;
} }
void Xeflag(void){
void
Xeflag(void)
{
if(eflagok && !truestatus()) Xexit(); if(eflagok && !truestatus()) Xexit();
} }
void Xexit(void){
void
Xexit(void)
{
struct var *trapreq; struct var *trapreq;
struct word *starval; struct word *starval;
static int beenhere = 0; static int beenhere = 0;
@ -317,33 +317,56 @@ void Xexit(void){
} }
Exit(getstatus()); Exit(getstatus());
} }
void Xfalse(void){
void
Xfalse(void)
{
if(truestatus()) runq->pc = runq->code[runq->pc].i; if(truestatus()) runq->pc = runq->code[runq->pc].i;
else runq->pc++; else runq->pc++;
} }
int ifnot; /* dynamic if not flag */ int ifnot; /* dynamic if not flag */
void Xifnot(void){
void
Xifnot(void)
{
if(ifnot) if(ifnot)
runq->pc++; runq->pc++;
else else
runq->pc = runq->code[runq->pc].i; runq->pc = runq->code[runq->pc].i;
} }
void Xjump(void){
void
Xjump(void)
{
runq->pc = runq->code[runq->pc].i; runq->pc = runq->code[runq->pc].i;
} }
void Xmark(void){
void
Xmark(void)
{
pushlist(); pushlist();
} }
void Xpopm(void){
void
Xpopm(void)
{
poplist(); poplist();
} }
void Xread(void){
void
Xread(void)
{
char *file; char *file;
int f; int f;
switch(count(runq->argv->words)){ switch(count(runq->argv->words)){
default: Xerror1("< requires singleton\n"); return; default:
case 0: Xerror1("< requires file\n"); return; Xerror1("< requires singleton\n");
case 1: break; return;
case 0:
Xerror1("< requires file\n");
return;
case 1:
break;
} }
file = runq->argv->words->word; file = runq->argv->words->word;
if((f = open(file, 0))<0){ if((f = open(file, 0))<0){
@ -355,48 +378,107 @@ void Xread(void){
runq->pc++; runq->pc++;
poplist(); poplist();
} }
void turfredir(void){
void
Xrdwr(void)
{
char *file;
int f;
switch(count(runq->argv->words)){
default:
Xerror1("<> requires singleton\n");
return;
case 0:
Xerror1("<> requires file\n");
return;
case 1:
break;
}
file = runq->argv->words->word;
if((f = open(file, ORDWR))<0){
pfmt(err, "%s: ", file);
Xerror("can't open");
return;
}
pushredir(ROPEN, f, runq->code[runq->pc].i);
runq->pc++;
poplist();
}
void
turfredir(void)
{
while(runq->redir!=runq->startredir) while(runq->redir!=runq->startredir)
Xpopredir(); Xpopredir();
} }
void Xpopredir(void){
void
Xpopredir(void)
{
struct redir *rp = runq->redir; struct redir *rp = runq->redir;
if(rp==0) panic("turfredir null!", 0); if(rp==0)
panic("turfredir null!", 0);
runq->redir = rp->next; runq->redir = rp->next;
if(rp->type==ROPEN) close(rp->from); if(rp->type==ROPEN)
close(rp->from);
efree((char *)rp); efree((char *)rp);
} }
void Xreturn(void){
void
Xreturn(void)
{
struct thread *p = runq; struct thread *p = runq;
turfredir(); turfredir();
while(p->argv) poplist(); while(p->argv) poplist();
codefree(p->code); codefree(p->code);
runq = p->ret; runq = p->ret;
efree((char *)p); efree((char *)p);
if(runq==0) Exit(getstatus()); if(runq==0)
Exit(getstatus());
} }
void Xtrue(void){
void
Xtrue(void)
{
if(truestatus()) runq->pc++; if(truestatus()) runq->pc++;
else runq->pc = runq->code[runq->pc].i; else runq->pc = runq->code[runq->pc].i;
} }
void Xif(void){
void
Xif(void)
{
ifnot = 1; ifnot = 1;
if(truestatus()) runq->pc++; if(truestatus()) runq->pc++;
else runq->pc = runq->code[runq->pc].i; else runq->pc = runq->code[runq->pc].i;
} }
void Xwastrue(void){
void
Xwastrue(void)
{
ifnot = 0; ifnot = 0;
} }
void Xword(void){
void
Xword(void)
{
pushword(runq->code[runq->pc++].s); pushword(runq->code[runq->pc++].s);
} }
void Xwrite(void){
void
Xwrite(void)
{
char *file; char *file;
int f; int f;
switch(count(runq->argv->words)){ switch(count(runq->argv->words)){
default: Xerror1("> requires singleton\n"); return; default:
case 0: Xerror1("> requires file\n"); return; Xerror1("> requires singleton\n");
case 1: break; return;
case 0:
Xerror1("> requires file\n");
return;
case 1:
break;
} }
file = runq->argv->words->word; file = runq->argv->words->word;
if((f = Creat(file))<0){ if((f = Creat(file))<0){
@ -408,7 +490,10 @@ void Xwrite(void){
runq->pc++; runq->pc++;
poplist(); poplist();
} }
char *_list2str(word *words, int c){
char*
list2str(word *words)
{
char *value, *s, *t; char *value, *s, *t;
int len = 0; int len = 0;
word *ap; word *ap;
@ -418,16 +503,17 @@ char *_list2str(word *words, int c){
s = value; s = value;
for(ap = words;ap;ap = ap->next){ for(ap = words;ap;ap = ap->next){
for(t = ap->word;*t;) *s++=*t++; for(t = ap->word;*t;) *s++=*t++;
*s++=c; *s++=' ';
} }
if(s==value) *s='\0'; if(s==value)
*s='\0';
else s[-1]='\0'; else s[-1]='\0';
return value; return value;
} }
char *list2str(word *words){
return _list2str(words, ' '); void
} Xmatch(void)
void Xmatch(void){ {
word *p; word *p;
char *subject; char *subject;
subject = list2str(runq->argv->words); subject = list2str(runq->argv->words);
@ -441,7 +527,10 @@ void Xmatch(void){
poplist(); poplist();
poplist(); poplist();
} }
void Xcase(void){
void
Xcase(void)
{
word *p; word *p;
char *s; char *s;
int ok = 0; int ok = 0;
@ -459,7 +548,9 @@ void Xcase(void){
runq->pc = runq->code[runq->pc].i; runq->pc = runq->code[runq->pc].i;
poplist(); poplist();
} }
word *conclist(word *lp, word *rp, word *tail)
word*
conclist(word *lp, word *rp, word *tail)
{ {
char *buf; char *buf;
word *v; word *v;
@ -473,7 +564,10 @@ word *conclist(word *lp, word *rp, word *tail)
efree(buf); efree(buf);
return v; return v;
} }
void Xconc(void){
void
Xconc(void)
{
word *lp = runq->argv->words; word *lp = runq->argv->words;
word *rp = runq->argv->next->words; word *rp = runq->argv->next->words;
word *vp = runq->argv->next->next->words; word *vp = runq->argv->next->next->words;
@ -493,7 +587,10 @@ void Xconc(void){
poplist(); poplist();
runq->argv->words = vp; runq->argv->words = vp;
} }
void Xassign(void){
void
Xassign(void)
{
var *v; var *v;
if(count(runq->argv->words)!=1){ if(count(runq->argv->words)!=1){
Xerror1("variable name not singleton!"); Xerror1("variable name not singleton!");
@ -506,15 +603,15 @@ void Xassign(void){
freewords(v->val); freewords(v->val);
v->val = runq->argv->words; v->val = runq->argv->words;
v->changed = 1; v->changed = 1;
if(v->changefn)
v->changefn(v);
runq->argv->words = 0; runq->argv->words = 0;
poplist(); poplist();
} }
/* /*
* copy arglist a, adding the copy to the front of tail * copy arglist a, adding the copy to the front of tail
*/ */
word *copywords(word *a, word *tail)
word*
copywords(word *a, word *tail)
{ {
word *v = 0, **end; word *v = 0, **end;
for(end=&v;a;a = a->next,end=&(*end)->next) for(end=&v;a;a = a->next,end=&(*end)->next)
@ -522,7 +619,10 @@ word *copywords(word *a, word *tail)
*end = tail; *end = tail;
return v; return v;
} }
void Xdol(void){
void
Xdol(void)
{
word *a, *star; word *a, *star;
char *s, *t; char *s, *t;
int n; int n;
@ -547,7 +647,10 @@ void Xdol(void){
poplist(); poplist();
runq->argv->words = a; runq->argv->words = a;
} }
void Xqdol(void){
void
Xqdol(void)
{
word *a, *p; word *a, *p;
char *s; char *s;
int n; int n;
@ -578,21 +681,28 @@ void Xqdol(void){
pushword(s); pushword(s);
efree(s); efree(s);
} }
word *subwords(word *val, int len, word *sub, word *a)
word*
subwords(word *val, int len, word *sub, word *a)
{ {
int n; int n;
char *s; char *s;
if(!sub) return a; if(!sub)
return a;
a = subwords(val, len, sub->next, a); a = subwords(val, len, sub->next, a);
s = sub->word; s = sub->word;
deglob(s); deglob(s);
n = 0; n = 0;
while('0'<=*s && *s<='9') n = n*10+ *s++ -'0'; while('0'<=*s && *s<='9') n = n*10+ *s++ -'0';
if(n<1 || len<n) return a; if(n<1 || len<n)
return a;
for(;n!=1;--n) val = val->next; for(;n!=1;--n) val = val->next;
return newword(val->word, a); return newword(val->word, a);
} }
void Xsub(void){
void
Xsub(void)
{
word *a, *v; word *a, *v;
char *s; char *s;
if(count(runq->argv->next->words)!=1){ if(count(runq->argv->next->words)!=1){
@ -608,7 +718,10 @@ void Xsub(void){
poplist(); poplist();
runq->argv->words = a; runq->argv->words = a;
} }
void Xcount(void){
void
Xcount(void)
{
word *a; word *a;
char *s, *t; char *s, *t;
int n; int n;
@ -623,16 +736,19 @@ void Xcount(void){
for(t = s;'0'<=*t && *t<='9';t++) n = n*10+*t-'0'; for(t = s;'0'<=*t && *t<='9';t++) n = n*10+*t-'0';
if(n==0 || *t){ if(n==0 || *t){
a = vlook(s)->val; a = vlook(s)->val;
itoa(num, count(a)); inttoascii(num, count(a));
} }
else{ else{
a = vlook("*")->val; a = vlook("*")->val;
itoa(num, a && 1<=n && n<=count(a)?1:0); inttoascii(num, a && 1<=n && n<=count(a)?1:0);
} }
poplist(); poplist();
pushword(num); pushword(num);
} }
void Xlocal(void){
void
Xlocal(void)
{
if(count(runq->argv->words)!=1){ if(count(runq->argv->words)!=1){
Xerror1("variable name must be singleton\n"); Xerror1("variable name must be singleton\n");
return; return;
@ -644,9 +760,13 @@ void Xlocal(void){
poplist(); poplist();
poplist(); poplist();
} }
void Xunlocal(void){
void
Xunlocal(void)
{
var *v = runq->local, *hid; var *v = runq->local, *hid;
if(v==0) panic("Xunlocal: no locals!", 0); if(v==0)
panic("Xunlocal: no locals!", 0);
runq->local = v->next; runq->local = v->next;
hid = vlook(v->name); hid = vlook(v->name);
hid->changed = 1; hid->changed = 1;
@ -654,7 +774,9 @@ void Xunlocal(void){
freewords(v->val); freewords(v->val);
efree((char *)v); efree((char *)v);
} }
void freewords(word *w)
void
freewords(word *w)
{ {
word *nw; word *nw;
while(w){ while(w){
@ -664,14 +786,18 @@ void freewords(word *w)
w = nw; w = nw;
} }
} }
void Xfn(void){
void
Xfn(void)
{
var *v; var *v;
word *a; word *a;
int end; int end;
end = runq->code[runq->pc].i; end = runq->code[runq->pc].i;
for(a = runq->argv->words;a;a = a->next){ for(a = runq->argv->words;a;a = a->next){
v = gvlook(a->word); v = gvlook(a->word);
if(v->fn) codefree(v->fn); if(v->fn)
codefree(v->fn);
v->fn = codecopy(runq->code); v->fn = codecopy(runq->code);
v->pc = runq->pc+2; v->pc = runq->pc+2;
v->fnchanged = 1; v->fnchanged = 1;
@ -679,47 +805,24 @@ void Xfn(void){
runq->pc = end; runq->pc = end;
poplist(); poplist();
} }
void Xdelfn(void){
void
Xdelfn(void)
{
var *v; var *v;
word *a; word *a;
for(a = runq->argv->words;a;a = a->next){ for(a = runq->argv->words;a;a = a->next){
v = gvlook(a->word); v = gvlook(a->word);
if(v->fn) codefree(v->fn); if(v->fn)
codefree(v->fn);
v->fn = 0; v->fn = 0;
v->fnchanged = 1; v->fnchanged = 1;
} }
poplist(); poplist();
} }
void Xpipe(void){
struct thread *p=runq; char*
int pc=p->pc, forkid; concstatus(char *s, char *t)
int lfd=p->code[pc++].i;
int rfd=p->code[pc++].i;
int pfd[2];
if(pipe(pfd)<0){
Xerror("can't get pipe");
return;
}
switch(forkid=fork()){
case -1:
Xerror("try again");
break;
case 0:
start(p->code, pc+2, runq->local);
runq->ret=0;
close(pfd[PRD]);
pushredir(ROPEN, pfd[PWR], lfd);
break;
default:
start(p->code, p->code[pc].i, runq->local);
close(pfd[PWR]);
pushredir(ROPEN, pfd[PRD], rfd);
p->pc=p->code[pc+1].i;
p->pid=forkid;
break;
}
}
char *concstatus(char *s, char *t)
{ {
static char v[NSTATUS+1]; static char v[NSTATUS+1];
int n = strlen(s); int n = strlen(s);
@ -731,7 +834,10 @@ char *concstatus(char *s, char *t)
v[NSTATUS]='\0'; v[NSTATUS]='\0';
return v; return v;
} }
void Xpipewait(void){
void
Xpipewait(void)
{
char status[NSTATUS+1]; char status[NSTATUS+1];
if(runq->pid==-1) if(runq->pid==-1)
setstatus(concstatus(runq->status, getstatus())); setstatus(concstatus(runq->status, getstatus()));
@ -743,7 +849,10 @@ void Xpipewait(void){
setstatus(concstatus(getstatus(), status)); setstatus(concstatus(getstatus(), status));
} }
} }
void Xrdcmds(void){
void
Xrdcmds(void)
{
struct thread *p = runq; struct thread *p = runq;
word *prompt; word *prompt;
flush(err); flush(err);
@ -760,7 +869,8 @@ void Xrdcmds(void){
Noerror(); Noerror();
if(yyparse()){ if(yyparse()){
if(!p->iflag || p->eof && !Eintr()){ if(!p->iflag || p->eof && !Eintr()){
if(p->cmdfile) efree(p->cmdfile); if(p->cmdfile)
efree(p->cmdfile);
closeio(p->cmdfd); closeio(p->cmdfd);
Xreturn(); /* should this be omitted? */ Xreturn(); /* should this be omitted? */
} }
@ -779,7 +889,9 @@ void Xrdcmds(void){
} }
freenodes(); freenodes();
} }
void Xerror(char *s)
void
Xerror(char *s)
{ {
if(strcmp(argv0, "rc")==0 || strcmp(argv0, "/bin/rc")==0) if(strcmp(argv0, "rc")==0 || strcmp(argv0, "/bin/rc")==0)
pfmt(err, "rc: %s: %r\n", s); pfmt(err, "rc: %s: %r\n", s);
@ -789,7 +901,9 @@ void Xerror(char *s)
setstatus("error"); setstatus("error");
while(!runq->iflag) Xreturn(); while(!runq->iflag) Xreturn();
} }
void Xerror1(char *s)
void
Xerror1(char *s)
{ {
if(strcmp(argv0, "rc")==0 || strcmp(argv0, "/bin/rc")==0) if(strcmp(argv0, "rc")==0 || strcmp(argv0, "/bin/rc")==0)
pfmt(err, "rc: %s\n", s); pfmt(err, "rc: %s\n", s);
@ -799,137 +913,39 @@ void Xerror1(char *s)
setstatus("error"); setstatus("error");
while(!runq->iflag) Xreturn(); while(!runq->iflag) Xreturn();
} }
void Xbackq(void){
char wd[8193]; void
int c; setstatus(char *s)
char *s, *ewd=&wd[8192], *stop;
struct io *f;
var *ifs=vlook("ifs");
word *v, *nextv;
int pfd[2];
int pid;
stop=ifs->val?ifs->val->word:"";
if(pipe(pfd)<0){
Xerror("can't make pipe");
return;
}
switch(pid=fork()){
case -1: Xerror("try again");
close(pfd[PRD]);
close(pfd[PWR]);
return;
case 0:
close(pfd[PRD]);
start(runq->code, runq->pc+1, runq->local);
pushredir(ROPEN, pfd[PWR], 1);
return;
default:
close(pfd[PWR]);
f=openfd(pfd[PRD]);
s=wd;
v=0;
while((c=rchr(f))!=EOF){
if(strchr(stop, c) || s==ewd){
if(s!=wd){
*s='\0';
v=newword(wd, v);
s=wd;
}
}
else *s++=c;
}
if(s!=wd){
*s='\0';
v=newword(wd, v);
}
closeio(f);
Waitfor(pid, 0);
/* 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;
return;
}
}
/*
* Who should wait for the exit from the fork?
*/
void Xpipefd(void){
struct thread *p=runq;
int pc=p->pc;
char name[40];
int pfd[2];
int sidefd, mainfd;
if(pipe(pfd)<0){
Xerror("can't get pipe");
return;
}
if(p->code[pc].i==READ){
sidefd=pfd[PWR];
mainfd=pfd[PRD];
}
else{
sidefd=pfd[PRD];
mainfd=pfd[PWR];
}
switch(fork()){
case -1:
Xerror("try again");
break;
case 0:
start(p->code, pc+2, runq->local);
close(mainfd);
pushredir(ROPEN, sidefd, p->code[pc].i==READ?1:0);
runq->ret=0;
break;
default:
close(sidefd);
pushredir(ROPEN, mainfd, mainfd); /* isn't this a noop? */
strcpy(name, Fdprefix);
itoa(name+strlen(name), mainfd);
pushword(name);
p->pc=p->code[pc+1].i;
break;
}
}
void Xsubshell(void){
int pid;
switch(pid=fork()){
case -1:
Xerror("try again");
break;
case 0:
start(runq->code, runq->pc+1, runq->local);
runq->ret=0;
break;
default:
Waitfor(pid, 1);
runq->pc=runq->code[runq->pc].i;
break;
}
}
void setstatus(char *s)
{ {
setvar("status", newword(s, (word *)0)); setvar("status", newword(s, (word *)0));
} }
char *getstatus(void){
char*
getstatus(void)
{
var *status = vlook("status"); var *status = vlook("status");
return status->val?status->val->word:""; return status->val?status->val->word:"";
} }
int truestatus(void){
int
truestatus(void)
{
char *s; char *s;
for(s = getstatus();*s;s++) for(s = getstatus();*s;s++)
if(*s!='|' && *s!='0') return 0; if(*s!='|' && *s!='0')
return 0;
return 1; return 1;
} }
void Xdelhere(void){
void
Xdelhere(void)
{
Unlink(runq->code[runq->pc++].s); Unlink(runq->code[runq->pc++].s);
} }
void Xfor(void){
void
Xfor(void)
{
if(runq->argv->words==0){ if(runq->argv->words==0){
poplist(); poplist();
runq->pc = runq->code[runq->pc].i; runq->pc = runq->code[runq->pc].i;
@ -943,6 +959,9 @@ void Xfor(void){
runq->pc++; runq->pc++;
} }
} }
void Xglob(void){
void
Xglob(void)
{
globlist(); globlist();
} }

View File

@ -5,6 +5,7 @@ extern void Xappend(void), Xasync(void), Xbackq(void), Xbang(void), Xclose(void)
extern void Xconc(void), Xcount(void), Xdelfn(void), Xdol(void), Xqdol(void), Xdup(void); extern void Xconc(void), Xcount(void), Xdelfn(void), Xdol(void), Xqdol(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);
extern void Xrdwr(void);
extern void Xrdfn(void), Xunredir(void), Xstar(void), Xreturn(void), Xsubshell(void); extern void Xrdfn(void), Xunredir(void), Xstar(void), Xreturn(void), Xsubshell(void);
extern void Xtrue(void), Xword(void), Xwrite(void), Xpipefd(void), Xcase(void); extern void Xtrue(void), Xword(void), 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);
@ -51,7 +52,6 @@ struct thread{
int iflag; /* interactive? */ int iflag; /* interactive? */
int lineno; /* linenumber */ int lineno; /* linenumber */
int pid; /* process for Xpipewait to wait for */ int pid; /* process for Xpipewait to wait for */
int done; /* have we seen a wait message for this process? */
char status[NSTATUS]; /* status for Xpipewait */ char status[NSTATUS]; /* status for Xpipewait */
tree *treenodes; /* tree nodes created by this process */ tree *treenodes; /* tree nodes created by this process */
thread *ret; /* who continues when this finishes */ thread *ret; /* who continues when this finishes */
@ -61,12 +61,16 @@ code *codecopy(code*);
code *codebuf; /* compiler output */ code *codebuf; /* compiler output */
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 */
extern struct builtin{ struct builtin{
char *name; char *name;
void (*fnc)(void); void (*fnc)(void);
}Builtin[]; };
extern struct builtin Builtin[];
int eflagok; /* kludge flag so that -e doesn't exit in startup */ int eflagok; /* kludge flag so that -e doesn't exit in startup */
int havefork;
void execcd(void), execwhatis(void), execeval(void), execexec(void); void execcd(void), execwhatis(void), execeval(void), execexec(void);
int execforkexec(void);
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 *);

View File

@ -7,13 +7,14 @@ int Eintr(void);
int Executable(char*); int Executable(char*);
void Execute(word*, word*); void Execute(word*, word*);
void Exit(char*); void Exit(char*);
int ForkExecute(char*, char**, int, int, int);
int Globsize(char*); int Globsize(char*);
int Isatty(int); int Isatty(int);
void Memcpy(char*, char*, long); void Memcpy(char*, char*, long);
void Noerror(void); void Noerror(void);
int Opendir(char*); int Opendir(char*);
long Read(int, char*, long); long Read(int, char*, long);
int Readdir(int, char*); int Readdir(int, char*, int);
long Seek(int, long, long); long Seek(int, long, long);
void Trapinit(void); void Trapinit(void);
void Unlink(char*); void Unlink(char*);
@ -27,7 +28,6 @@ void cleanhere(char*);
void codefree(code*); void codefree(code*);
int compile(tree*); int compile(tree*);
char * list2str(word*); char * list2str(word*);
char * _list2str(word*, int);
int count(word*); int count(word*);
void deglob(char*); void deglob(char*);
void dotrap(void); void dotrap(void);
@ -35,10 +35,12 @@ void freenodes(void);
void freewords(word*); void freewords(word*);
void globlist(void); void globlist(void);
int idchr(int); int idchr(int);
void itoa(char*, long); void inttoascii(char*, long);
void kinit(void); void kinit(void);
int mapfd(int);
int match(char*, char*, int); int match(char*, char*, int);
int matchfn(char*, char*); int matchfn(char*, char*);
char** mkargv(word*);
void panic(char*, int); void panic(char*, int);
void pathinit(void); void pathinit(void);
void poplist(void); void poplist(void);
@ -48,9 +50,9 @@ void pushlist(void);
void pushredir(int, int, int); void pushredir(int, int, int);
void pushword(char*); void pushword(char*);
void readhere(void); void readhere(void);
word* searchpath(char*);
void setstatus(char*); void setstatus(char*);
void setvar(char*, word*); void setvar(char*, word*);
void _setvar(char*, word*, int);
void skipnl(void); void skipnl(void);
void start(code*, int, var*); void start(code*, int, var*);
int truestatus(void); int truestatus(void);

View File

@ -19,12 +19,15 @@ static int reason;
#define FLAGSYN 3 #define FLAGSYN 3
#define BADFLAG 4 #define BADFLAG 4
static int badflag; static int badflag;
int getflags(int argc, char *argv[], char *flags, int stop)
int
getflags(int argc, char *argv[], char *flags, int stop)
{ {
char *s, *t; char *s, *t;
int i, j, c, count; int i, j, c, count;
flagarg = flags; flagarg = flags;
if(cmdname==0) cmdname=argv[0]; if(cmdname==0)
cmdname = argv[0];
s = cmdline; s = cmdline;
for(i = 0;i!=argc;i++){ for(i = 0;i!=argc;i++){
for(t = argv[i];*t;t++) for(t = argv[i];*t;t++)
@ -37,7 +40,8 @@ int getflags(int argc, char *argv[], char *flags, int stop)
i = 1; i = 1;
while(i!=argc){ while(i!=argc){
if(argv[i][0]!='-' || argv[i][1]=='\0'){ if(argv[i][0]!='-' || argv[i][1]=='\0'){
if(stop) return argc; if(stop)
return argc;
i++; i++;
continue; continue;
} }
@ -45,7 +49,8 @@ int getflags(int argc, char *argv[], char *flags, int stop)
while(*s){ while(*s){
c=*s++; c=*s++;
count = scanflag(c, flags); count = scanflag(c, flags);
if(count==-1) return -1; if(count==-1)
return -1;
if(flag[c]){ reason = RESET; badflag = c; return -1; } if(flag[c]){ reason = RESET; badflag = c; return -1; }
if(count==0){ if(count==0){
flag[c] = flagset; flag[c] = flagset;
@ -79,15 +84,20 @@ int getflags(int argc, char *argv[], char *flags, int stop)
} }
return argc; return argc;
} }
static void reverse(char **p, char **q)
static void
reverse(char **p, char **q)
{ {
char *t; char *t;
for(;p<q;p++,--q){ t=*p; *p=*q; *q = t; } for(;p<q;p++,--q){ t=*p; *p=*q; *q = t; }
} }
static int scanflag(int c, char *f)
static int
scanflag(int c, char *f)
{ {
int fc, count; int fc, count;
if(0<=c && c<NFLAG) while(*f){ if(0<=c && c<NFLAG)
while(*f){
if(*f==' '){ if(*f==' '){
f++; f++;
continue; continue;
@ -108,13 +118,16 @@ static int scanflag(int c, char *f)
}while(*f!=']'); }while(*f!=']');
f++; f++;
} }
if(c==fc) return count; if(c==fc)
return count;
} }
reason = BADFLAG; reason = BADFLAG;
badflag = c; badflag = c;
return -1; return -1;
} }
void usage(char *tail)
void
usage(char *tail)
{ {
char *s, *t, c; char *s, *t, c;
int count, nflag = 0; int count, nflag = 0;
@ -142,7 +155,8 @@ void usage(char *tail)
errs(cmdname); errs(cmdname);
for(s = flagarg;*s;){ for(s = flagarg;*s;){
c=*s; c=*s;
if(*s++==' ') continue; if(*s++==' ')
continue;
if(*s==':'){ if(*s==':'){
s++; s++;
count = 0; count = 0;
@ -150,20 +164,24 @@ void usage(char *tail)
} }
else count = 0; else count = 0;
if(count==0){ if(count==0){
if(nflag==0) errs(" [-"); if(nflag==0)
errs(" [-");
nflag++; nflag++;
errc(c); errc(c);
} }
if(*s=='['){ if(*s=='['){
s++; s++;
while(*s!=']' && *s!='\0') s++; while(*s!=']' && *s!='\0') s++;
if(*s==']') s++; if(*s==']')
s++;
} }
} }
if(nflag) errs("]"); if(nflag)
errs("]");
for(s = flagarg;*s;){ for(s = flagarg;*s;){
c=*s; c=*s;
if(*s++==' ') continue; if(*s++==' ')
continue;
if(*s==':'){ if(*s==':'){
s++; s++;
count = 0; count = 0;
@ -179,7 +197,8 @@ void usage(char *tail)
while(*s!=']' && *s!='\0') s++; while(*s!=']' && *s!='\0') s++;
errs(" "); errs(" ");
errn(t, s-t); errn(t, s-t);
if(*s==']') s++; if(*s==']')
s++;
} }
else else
while(count--) errs(" arg"); while(count--) errs(" arg");
@ -188,7 +207,8 @@ void usage(char *tail)
else if(*s=='['){ else if(*s=='['){
s++; s++;
while(*s!=']' && *s!='\0') s++; while(*s!=']' && *s!='\0') s++;
if(*s==']') s++; if(*s==']')
s++;
} }
} }
if(tail){ if(tail){
@ -198,17 +218,24 @@ void usage(char *tail)
errs("\n"); errs("\n");
Exit("bad flags"); Exit("bad flags");
} }
static void errn(char *s, int count)
static void
errn(char *s, int count)
{ {
while(count){ errc(*s++); --count; } while(count){ errc(*s++); --count; }
} }
static void errs(char *s)
static void
errs(char *s)
{ {
while(*s) errc(*s++); while(*s) errc(*s++);
} }
#define NBUF 80 #define NBUF 80
static char buf[NBUF], *bufp = buf; static char buf[NBUF], *bufp = buf;
static void errc(int c){
static void
errc(int c)
{
*bufp++=c; *bufp++=c;
if(bufp==&buf[NBUF] || c=='\n'){ if(bufp==&buf[NBUF] || c=='\n'){
Write(2, buf, bufp-buf); Write(2, buf, bufp-buf);

View File

@ -6,19 +6,26 @@ struct word *globv;
/* /*
* delete all the GLOB marks from s, in place * delete all the GLOB marks from s, in place
*/ */
void deglob(char *s)
void
deglob(char *s)
{ {
char *t = s; char *t = s;
do{ do{
if(*t==GLOB) t++; if(*t==GLOB)
t++;
*s++=*t; *s++=*t;
}while(*t++); }while(*t++);
} }
int globcmp(const void *s, const void *t)
int
globcmp(const void *s, const void *t)
{ {
return strcmp(*(char**)s, *(char**)t); return strcmp(*(char**)s, *(char**)t);
} }
void globsort(word *left, word *right)
void
globsort(word *left, word *right)
{ {
char **list; char **list;
word *a; word *a;
@ -26,7 +33,7 @@ void globsort(word *left, word *right)
for(a = left;a!=right;a = a->next) n++; for(a = left;a!=right;a = a->next) n++;
list = (char **)emalloc(n*sizeof(char *)); list = (char **)emalloc(n*sizeof(char *));
for(a = left,n = 0;a!=right;a = a->next,n++) list[n] = a->word; for(a = left,n = 0;a!=right;a = a->next,n++) list[n] = a->word;
qsort((char *)list, n, sizeof(char *), globcmp); qsort((void *)list, n, sizeof(void *), globcmp);
for(a = left,n = 0;a!=right;a = a->next,n++) a->word = list[n]; for(a = left,n = 0;a!=right;a = a->next,n++) a->word = list[n];
efree((char *)list); efree((char *)list);
} }
@ -34,7 +41,9 @@ void globsort(word *left, word *right)
* Push names prefixed by globname and suffixed by a match of p onto the astack. * Push names prefixed by globname and suffixed by a match of p onto the astack.
* namep points to the end of the prefix in globname. * namep points to the end of the prefix in globname.
*/ */
void globdir(char *p, char *namep)
void
globdir(char *p, char *namep)
{ {
char *t, *newp; char *t, *newp;
int f; int f;
@ -65,7 +74,7 @@ void globdir(char *p, char *namep)
*namep='\0'; *namep='\0';
if((f = Opendir(globname[0]?globname:"."))<0) return; if((f = Opendir(globname[0]?globname:"."))<0) return;
while(*newp!='/' && *newp!='\0') newp++; while(*newp!='/' && *newp!='\0') newp++;
while(Readdir(f, namep)){ while(Readdir(f, namep, *newp=='/')){
if(matchfn(namep, p)){ if(matchfn(namep, p)){
for(t = namep;*t;t++); for(t = namep;*t;t++);
globdir(newp, t); globdir(newp, t);
@ -77,7 +86,9 @@ void globdir(char *p, char *namep)
* Push all file names matched by p on the current thread's stack. * Push all file names matched by p on the current thread's stack.
* If there are no matches, the list consists of p. * If there are no matches, the list consists of p.
*/ */
void glob(char *p)
void
glob(char *p)
{ {
word *svglobv = globv; word *svglobv = globv;
int globlen = Globsize(p); int globlen = Globsize(p);
@ -100,12 +111,18 @@ void glob(char *p)
/* /*
* Do p and q point at equal utf codes * Do p and q point at equal utf codes
*/ */
int equtf(char *p, char *q){
if(*p!=*q) return 0; int
equtf(char *p, char *q)
{
if(*p!=*q)
return 0;
if(twobyte(*p)) return p[1]==q[1]; if(twobyte(*p)) return p[1]==q[1];
if(threebyte(*p)){ if(threebyte(*p)){
if(p[1]!=q[1]) return 0; if(p[1]!=q[1])
if(p[1]=='\0') return 1; /* broken code at end of string! */ return 0;
if(p[1]=='\0')
return 1; /* broken code at end of string! */
return p[2]==q[2]; return p[2]==q[2];
} }
return 1; return 1;
@ -114,7 +131,10 @@ int equtf(char *p, char *q){
* 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!
*/ */
char *nextutf(char *p){
char*
nextutf(char *p)
{
if(twobyte(*p)) return p[1]=='\0'?p+1:p+2; if(twobyte(*p)) return p[1]=='\0'?p+1:p+2;
if(threebyte(*p)) return p[1]=='\0'?p+1:p[2]=='\0'?p+2:p+3; if(threebyte(*p)) return p[1]=='\0'?p+1:p[2]=='\0'?p+2:p+3;
return p+1; return p+1;
@ -122,7 +142,10 @@ char *nextutf(char *p){
/* /*
* Convert the utf code at *p to a unicode value * Convert the utf code at *p to a unicode value
*/ */
int unicode(char *p){
int
unicode(char *p)
{
int u=*p&0xff; int u=*p&0xff;
if(twobyte(u)) return ((u&0x1f)<<6)|(p[1]&0x3f); if(twobyte(u)) return ((u&0x1f)<<6)|(p[1]&0x3f);
if(threebyte(u)) return (u<<12)|((p[1]&0x3f)<<6)|(p[2]&0x3f); if(threebyte(u)) return (u<<12)|((p[1]&0x3f)<<6)|(p[2]&0x3f);
@ -135,13 +158,17 @@ int unicode(char *p){
* ? matches any single character * ? matches any single character
* [...] matches the enclosed list of characters * [...] matches the enclosed list of characters
*/ */
int matchfn(char *s, char *p)
int
matchfn(char *s, char *p)
{ {
if(s[0]=='.' && (s[1]=='\0' || s[1]=='.' && s[2]=='\0') && p[0]!='.') if(s[0]=='.' && (s[1]=='\0' || s[1]=='.' && s[2]=='\0') && p[0]!='.')
return 0; return 0;
return match(s, p, '/'); return match(s, p, '/');
} }
int match(char *s, char *p, int stop)
int
match(char *s, char *p, int stop)
{ {
int compl, hit, lo, hi, t, c; int compl, hit, lo, hi, t, c;
for(;*p!=stop && *p!='\0';s = nextutf(s),p = nextutf(p)){ for(;*p!=stop && *p!='\0';s = nextutf(s),p = nextutf(p)){
@ -150,54 +177,70 @@ int match(char *s, char *p, int stop)
} }
else switch(*++p){ else switch(*++p){
case GLOB: case GLOB:
if(*s!=GLOB) return 0; if(*s!=GLOB)
return 0;
break; break;
case '*': case '*':
for(;;){ for(;;){
if(match(s, nextutf(p), stop)) return 1; if(match(s, nextutf(p), stop)) return 1;
if(!*s) break; if(!*s)
break;
s = nextutf(s); s = nextutf(s);
} }
return 0; return 0;
case '?': case '?':
if(*s=='\0') return 0; if(*s=='\0')
return 0;
break; break;
case '[': case '[':
if(*s=='\0') return 0; if(*s=='\0')
return 0;
c = unicode(s); c = unicode(s);
p++; p++;
compl=*p=='~'; compl=*p=='~';
if(compl) p++; if(compl)
p++;
hit = 0; hit = 0;
while(*p!=']'){ while(*p!=']'){
if(*p=='\0') return 0; /* syntax error */ if(*p=='\0')
return 0; /* syntax error */
lo = unicode(p); lo = unicode(p);
p = nextutf(p); p = nextutf(p);
if(*p!='-') hi=lo; if(*p!='-')
hi = lo;
else{ else{
p++; p++;
if(*p=='\0') return 0; /* syntax error */ if(*p=='\0')
return 0; /* syntax error */
hi = unicode(p); hi = unicode(p);
p = nextutf(p); p = nextutf(p);
if(hi<lo){ t = lo; lo = hi; hi = t; } if(hi<lo){ t = lo; lo = hi; hi = t; }
} }
if(lo<=c && c<=hi) hit=1; if(lo<=c && c<=hi)
hit = 1;
} }
if(compl) hit=!hit; if(compl)
if(!hit) return 0; hit=!hit;
if(!hit)
return 0;
break; break;
} }
} }
return *s=='\0'; return *s=='\0';
} }
void globlist1(word *gl)
void
globlist1(word *gl)
{ {
if(gl){ if(gl){
globlist1(gl->next); globlist1(gl->next);
glob(gl->word); glob(gl->word);
} }
} }
void globlist(void){
void
globlist(void)
{
word *a; word *a;
globv = 0; globv = 0;
globlist1(runq->argv->words); globlist1(runq->argv->words);

View File

@ -1,5 +1,3 @@
#include <u.h>
#include <signal.h>
#include "rc.h" #include "rc.h"
#include "getflags.h" #include "getflags.h"
#include "exec.h" #include "exec.h"
@ -13,9 +11,7 @@ Xasync(void)
{ {
int null = open("/dev/null", 0); int null = open("/dev/null", 0);
int pid; int pid;
int tcpgrp, pgrp;
char npid[10]; char npid[10];
if(null<0){ if(null<0){
Xerror("Can't open /dev/null\n"); Xerror("Can't open /dev/null\n");
return; return;
@ -26,12 +22,6 @@ Xasync(void)
Xerror("try again"); Xerror("try again");
break; break;
case 0: case 0:
/*
* Should make reads of tty fail, writes succeed.
*/
signal(SIGTTIN, SIG_IGN);
signal(SIGTTOU, SIG_IGN);
pushredir(ROPEN, null, 0); pushredir(ROPEN, null, 0);
start(runq->code, runq->pc+1, runq->local); start(runq->code, runq->pc+1, runq->local);
runq->ret = 0; runq->ret = 0;

246
src/cmd/rc/havep9p.c Normal file
View File

@ -0,0 +1,246 @@
#include <u.h>
#include <signal.h>
#if defined(PLAN9PORT) && defined(__sun__)
# define BSD_COMP /* sigh. for TIOCNOTTY */
#endif
#include <sys/ioctl.h>
#include "rc.h"
#include "getflags.h"
#include "exec.h"
#include "io.h"
#include "fns.h"
int havefork = 1;
void
Xasync(void)
{
int null=open("/dev/null", 0);
int tty;
int pid;
char npid[10];
if(null<0){
Xerror("Can't open /dev/null\n");
return;
}
switch(pid=rfork(RFFDG|RFPROC|RFNOTEG)){
case -1:
close(null);
Xerror("try again");
break;
case 0:
/*
* I don't know what the right thing to do here is,
* so this is all experimentally determined.
* If we just dup /dev/null onto 0, then running
* ssh foo & will reopen /dev/tty, try to read a password,
* get a signal, and repeat, in a tight loop, forever.
* Arguably this is a bug in ssh (it behaves the same
* way under bash as under rc) but I'm fixing it here
* anyway. If we dissociate the process from the tty,
* then it won't be able to open /dev/tty ever again.
* The SIG_IGN on SIGTTOU makes writing the tty
* (via fd 1 or 2, for example) succeed even though
* our pgrp is not the terminal's controlling pgrp.
*/
if((tty=open("/dev/tty", OREAD)) >= 0){
/*
* Should make reads of tty fail, writes succeed.
*/
signal(SIGTTIN, SIG_IGN);
signal(SIGTTOU, SIG_IGN);
ioctl(tty, TIOCNOTTY);
close(tty);
}
if(isatty(0))
pushredir(ROPEN, null, 0);
else
close(null);
start(runq->code, runq->pc+1, runq->local);
runq->ret=0;
break;
default:
close(null);
runq->pc=runq->code[runq->pc].i;
inttoascii(npid, pid);
setvar("apid", newword(npid, (word *)0));
break;
}
}
void
Xpipe(void)
{
struct thread *p = runq;
int pc = p->pc, forkid;
int lfd = p->code[pc++].i;
int rfd = p->code[pc++].i;
int pfd[2];
if(pipe(pfd)<0){
Xerror("can't get pipe");
return;
}
switch(forkid=fork()){
case -1:
Xerror("try again");
break;
case 0:
start(p->code, pc+2, runq->local);
runq->ret=0;
close(pfd[PRD]);
pushredir(ROPEN, pfd[PWR], lfd);
break;
default:
start(p->code, p->code[pc].i, runq->local);
close(pfd[PWR]);
pushredir(ROPEN, pfd[PRD], rfd);
p->pc=p->code[pc+1].i;
p->pid=forkid;
break;
}
}
void
Xbackq(void)
{
char wd[8193];
int c;
char *s, *ewd = &wd[8192], *stop;
struct io *f;
var *ifs = vlook("ifs");
word *v, *nextv;
int pfd[2];
int pid;
stop = ifs->val?ifs->val->word:"";
if(pipe(pfd)<0){
Xerror("can't make pipe");
return;
}
switch(pid = fork()){
case -1: Xerror("try again");
close(pfd[PRD]);
close(pfd[PWR]);
return;
case 0:
close(pfd[PRD]);
start(runq->code, runq->pc+1, runq->local);
pushredir(ROPEN, pfd[PWR], 1);
return;
default:
close(pfd[PWR]);
f=openfd(pfd[PRD]);
s=wd;
v=0;
while((c=rchr(f))!=EOF){
if(strchr(stop, c) || s==ewd){
if(s!=wd){
*s='\0';
v=newword(wd, v);
s=wd;
}
}
else *s++=c;
}
if(s!=wd){
*s='\0';
v=newword(wd, v);
}
closeio(f);
Waitfor(pid, 0);
/* 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;
return;
}
}
/*
* Who should wait for the exit from the fork?
*/
void
Xpipefd(void)
{
struct thread *p=runq;
int pc=p->pc;
char name[40];
int pfd[2];
int sidefd, mainfd;
if(pipe(pfd)<0){
Xerror("can't get pipe");
return;
}
if(p->code[pc].i==READ){
sidefd=pfd[PWR];
mainfd=pfd[PRD];
}
else{
sidefd=pfd[PRD];
mainfd=pfd[PWR];
}
switch(fork()){
case -1:
Xerror("try again");
break;
case 0:
start(p->code, pc+2, runq->local);
close(mainfd);
pushredir(ROPEN, sidefd, p->code[pc].i==READ?1:0);
runq->ret=0;
break;
default:
close(sidefd);
pushredir(ROPEN, mainfd, mainfd); /* isn't this a noop? */
strcpy(name, Fdprefix);
inttoascii(name+strlen(name), mainfd);
pushword(name);
p->pc=p->code[pc+1].i;
break;
}
}
void
Xsubshell(void)
{
int pid;
switch(pid=fork()){
case -1:
Xerror("try again");
break;
case 0:
start(runq->code, runq->pc+1, runq->local);
runq->ret=0;
break;
default:
Waitfor(pid, 1);
runq->pc=runq->code[runq->pc].i;
break;
}
}
int
execforkexec(void)
{
int pid;
int n;
char buf[ERRMAX];
switch(pid = fork()){
case -1:
return -1;
case 0:
pushword("exec");
execexec();
strcpy(buf, "can't exec: ");
n = strlen(buf);
errstr(buf+n, ERRMAX-n);
Exit(buf);
}
return pid;
}

View File

@ -8,17 +8,22 @@ char tmp[]="/tmp/here0000.0000";
char hex[]="0123456789abcdef"; char hex[]="0123456789abcdef";
void psubst(io*, char*); void psubst(io*, char*);
void pstrs(io*, word*); void pstrs(io*, word*);
void hexnum(char *p, int n)
void
hexnum(char *p, int n)
{ {
*p++=hex[(n>>12)&0xF]; *p++=hex[(n>>12)&0xF];
*p++=hex[(n>>8)&0xF]; *p++=hex[(n>>8)&0xF];
*p++=hex[(n>>4)&0xF]; *p++=hex[(n>>4)&0xF];
*p = hex[n&0xF]; *p = hex[n&0xF];
} }
tree *heredoc(tree *tag)
tree*
heredoc(tree *tag)
{ {
struct here *h = new(struct here); struct here *h = new(struct here);
if(tag->type!=WORD) yyerror("Bad here tag"); if(tag->type!=WORD)
yyerror("Bad here tag");
h->next = 0; h->next = 0;
if(here) if(here)
*ehere = h; *ehere = h;
@ -36,7 +41,10 @@ tree *heredoc(tree *tag)
* missubstitution, or a misrecognized EOF marker. * missubstitution, or a misrecognized EOF marker.
*/ */
#define NLINE 4096 #define NLINE 4096
void readhere(void){
void
readhere(void)
{
struct here *h, *nexth; struct here *h, *nexth;
io *f; io *f;
char *s, *tag; char *s, *tag;
@ -46,15 +54,17 @@ void readhere(void){
subst=!h->tag->quoted; subst=!h->tag->quoted;
tag = h->tag->str; tag = h->tag->str;
c = Creat(h->name); c = Creat(h->name);
if(c<0) yyerror("can't create here document"); if(c<0)
yyerror("can't create here document");
f = openfd(c); f = openfd(c);
s = line; s = line;
pprompt(); pprompt();
while((c = rchr(runq->cmdfd))!=EOF){ while((c = rchr(runq->cmdfd))!=EOF){
if(c=='\n' || s==&line[NLINE]){ if(c=='\n' || s==&line[NLINE]){
*s='\0'; *s='\0';
if(strcmp(line, tag)==0) break; if(tag && strcmp(line, tag)==0) break;
if(subst) psubst(f, line); if(subst)
psubst(f, line);
else pstr(f, line); else pstr(f, line);
s = line; s = line;
if(c=='\n'){ if(c=='\n'){
@ -74,7 +84,9 @@ void readhere(void){
here = 0; here = 0;
doprompt = 1; doprompt = 1;
} }
void psubst(io *f, char *s)
void
psubst(io *f, char *s)
{ {
char *t, *u; char *t, *u;
int savec, n; int savec, n;
@ -83,19 +95,23 @@ void psubst(io *f, char *s)
if(*s!='$'){ if(*s!='$'){
if(0xa0<=(*s&0xff) && (*s&0xff)<=0xf5){ if(0xa0<=(*s&0xff) && (*s&0xff)<=0xf5){
pchr(f, *s++); pchr(f, *s++);
if(*s=='\0') break; if(*s=='\0')
break;
} }
else if(0xf6<=(*s&0xff) && (*s&0xff)<=0xf7){ else if(0xf6<=(*s&0xff) && (*s&0xff)<=0xf7){
pchr(f, *s++); pchr(f, *s++);
if(*s=='\0') break; if(*s=='\0')
break;
pchr(f, *s++); pchr(f, *s++);
if(*s=='\0') break; if(*s=='\0')
break;
} }
pchr(f, *s++); pchr(f, *s++);
} }
else{ else{
t=++s; t=++s;
if(*t=='$') pchr(f, *t++); if(*t=='$')
pchr(f, *t++);
else{ else{
while(*t && idchr(*t)) t++; while(*t && idchr(*t)) t++;
savec=*t; savec=*t;
@ -112,13 +128,16 @@ void psubst(io *f, char *s)
else else
pstrs(f, vlook(s)->val); pstrs(f, vlook(s)->val);
*t = savec; *t = savec;
if(savec=='^') t++; if(savec=='^')
t++;
} }
s = t; s = t;
} }
} }
} }
void pstrs(io *f, word *a)
void
pstrs(io *f, word *a)
{ {
if(a){ if(a){
while(a->next && a->next->word){ while(a->next && a->next->word){

View File

@ -3,67 +3,120 @@
#include "io.h" #include "io.h"
#include "fns.h" #include "fns.h"
int pfmtnest = 0; int pfmtnest = 0;
void pfmt(io *f, char *fmt, ...){
void
pfmt(io *f, char *fmt, ...)
{
va_list ap; va_list ap;
char err[ERRMAX]; char err[ERRMAX];
va_start(ap, fmt); va_start(ap, fmt);
pfmtnest++; pfmtnest++;
for(;*fmt;fmt++) for(;*fmt;fmt++)
if(*fmt!='%') pchr(f, *fmt); if(*fmt!='%')
pchr(f, *fmt);
else switch(*++fmt){ else switch(*++fmt){
case '\0': va_end(ap); return; case '\0':
case 'c': pchr(f, va_arg(ap, int)); break; va_end(ap);
case 'd': pdec(f, va_arg(ap, int)); break; return;
case 'o': poct(f, va_arg(ap, unsigned)); break; case 'c':
case 'p': phex(f, (long)va_arg(ap, char *)); break; /*unportable*/ pchr(f, va_arg(ap, int));
case 'Q': pquo(f, va_arg(ap, char *)); break; break;
case 'q': pwrd(f, va_arg(ap, char *)); break; case 'd':
case 'r': errstr(err, sizeof err); pstr(f, err); break; pdec(f, va_arg(ap, int));
case 's': pstr(f, va_arg(ap, char *)); break; break;
case 't': pcmd(f, va_arg(ap, struct tree *)); break; case 'o':
case 'v': pval(f, va_arg(ap, struct word *)); break; poct(f, va_arg(ap, unsigned));
default: pchr(f, *fmt); break; break;
case 'p':
pptr(f, va_arg(ap, void*));
break;
case 'Q':
pquo(f, va_arg(ap, char *));
break;
case 'q':
pwrd(f, va_arg(ap, char *));
break;
case 'r':
errstr(err, sizeof err); pstr(f, err);
break;
case 's':
pstr(f, va_arg(ap, char *));
break;
case 't':
pcmd(f, va_arg(ap, struct tree *));
break;
case 'v':
pval(f, va_arg(ap, struct word *));
break;
default:
pchr(f, *fmt);
break;
} }
va_end(ap); va_end(ap);
if(--pfmtnest==0) flush(f); if(--pfmtnest==0)
flush(f);
} }
void pchr(io *b, int c)
void
pchr(io *b, int c)
{ {
if(b->bufp==b->ebuf) fullbuf(b, c); if(b->bufp==b->ebuf)
fullbuf(b, c);
else *b->bufp++=c; else *b->bufp++=c;
} }
int rchr(io *b)
int
rchr(io *b)
{ {
if(b->bufp==b->ebuf) return emptybuf(b); if(b->bufp==b->ebuf)
return emptybuf(b);
return *b->bufp++ & 0xFF; return *b->bufp++ & 0xFF;
} }
void pquo(io *f, char *s) void
pquo(io *f, char *s)
{ {
pchr(f, '\''); pchr(f, '\'');
for(;*s;s++) for(;*s;s++)
if(*s=='\'') pfmt(f, "''"); if(*s=='\'')
pfmt(f, "''");
else pchr(f, *s); else pchr(f, *s);
pchr(f, '\''); pchr(f, '\'');
} }
void pwrd(io *f, char *s)
void
pwrd(io *f, char *s)
{ {
char *t; char *t;
for(t = s;*t;t++) if(!wordchr(*t)) break; for(t = s;*t;t++) if(!wordchr(*t)) break;
if(t==s || *t) pquo(f, s); if(t==s || *t)
pquo(f, s);
else pstr(f, s); else pstr(f, s);
} }
void phex(io *f, long p)
void
pptr(io *f, void *v)
{ {
int n; int n;
uintptr p;
p = (uintptr)v;
if(sizeof(uintptr) == sizeof(uvlong) && p>>32)
for(n = 60;n>=32;n-=4) pchr(f, "0123456789ABCDEF"[(p>>n)&0xF]);
for(n = 28;n>=0;n-=4) pchr(f, "0123456789ABCDEF"[(p>>n)&0xF]); for(n = 28;n>=0;n-=4) pchr(f, "0123456789ABCDEF"[(p>>n)&0xF]);
} }
void pstr(io *f, char *s)
void
pstr(io *f, char *s)
{ {
if(s==0) s="(null)"; if(s==0)
s="(null)";
while(*s) pchr(f, *s++); while(*s) pchr(f, *s++);
} }
void pdec(io *f, long n)
void
pdec(io *f, int n)
{ {
if(n<0){ if(n<0){
n=-n; n=-n;
@ -79,15 +132,21 @@ void pdec(io *f, long n)
pchr(f, n%10+'1'); pchr(f, n%10+'1');
return; return;
} }
if(n>9) pdec(f, n/10); if(n>9)
pdec(f, n/10);
pchr(f, n%10+'0'); pchr(f, n%10+'0');
} }
void poct(io *f, ulong n)
void
poct(io *f, unsigned n)
{ {
if(n>7) poct(f, n>>3); if(n>7)
poct(f, n>>3);
pchr(f, (n&7)+'0'); pchr(f, (n&7)+'0');
} }
void pval(io *f, word *a)
void
pval(io *f, word *a)
{ {
if(a){ if(a){
while(a->next && a->next->word){ while(a->next && a->next->word){
@ -98,19 +157,24 @@ void pval(io *f, word *a)
pwrd(f, a->word); pwrd(f, a->word);
} }
} }
int fullbuf(io *f, int c)
int
fullbuf(io *f, int c)
{ {
flush(f); flush(f);
return *f->bufp++=c; return *f->bufp++=c;
} }
void flush(io *f)
void
flush(io *f)
{ {
int n; int n;
char *s; char *s;
if(f->strp){ if(f->strp){
n = f->ebuf-f->strp; n = f->ebuf-f->strp;
f->strp = realloc(f->strp, n+101); f->strp = realloc(f->strp, n+101);
if(f->strp==0) panic("Can't realloc %d bytes in flush!", n+101); if(f->strp==0)
panic("Can't realloc %d bytes in flush!", n+101);
f->bufp = f->strp+n; f->bufp = f->strp+n;
f->ebuf = f->bufp+100; f->ebuf = f->bufp+100;
for(s = f->bufp;s<=f->ebuf;s++) *s='\0'; for(s = f->bufp;s<=f->ebuf;s++) *s='\0';
@ -119,21 +183,27 @@ void flush(io *f)
n = f->bufp-f->buf; n = f->bufp-f->buf;
if(n && Write(f->fd, f->buf, n) < 0){ if(n && Write(f->fd, f->buf, n) < 0){
Write(3, "Write error\n", 12); Write(3, "Write error\n", 12);
if(ntrap) dotrap(); if(ntrap)
dotrap();
} }
f->bufp = f->buf; f->bufp = f->buf;
f->ebuf = f->buf+NBUF; f->ebuf = f->buf+NBUF;
} }
} }
io *openfd(int fd){
io *f; io*
f=new(struct io); openfd(int fd)
{
io *f = new(struct io);
f->fd = fd; f->fd = fd;
f->bufp = f->ebuf = f->buf; f->bufp = f->ebuf = f->buf;
f->strp = 0; f->strp = 0;
return f; return f;
} }
io *openstr(void){
io*
openstr(void)
{
io *f = new(struct io); io *f = new(struct io);
char *s; char *s;
f->fd=-1; f->fd=-1;
@ -146,7 +216,9 @@ io *openstr(void){
* Open a corebuffer to read. EOF occurs after reading len * Open a corebuffer to read. EOF occurs after reading len
* characters from buf. * characters from buf.
*/ */
io *opencore(char *s, int len)
io*
opencore(char *s, int len)
{ {
io *f = new(struct io); io *f = new(struct io);
char *buf = emalloc(len); char *buf = emalloc(len);
@ -156,23 +228,30 @@ io *opencore(char *s, int len)
Memcpy(buf, s, len); Memcpy(buf, s, len);
return f; return f;
} }
/*
void rewind(io *io) void
rewind(io *io)
{ {
if(io->fd==-1) io->bufp=io->strp; if(io->fd==-1)
io->bufp = io->strp;
else{ else{
io->bufp = io->ebuf = io->buf; io->bufp = io->ebuf = io->buf;
Seek(io->fd, 0L, 0); Seek(io->fd, 0L, 0);
} }
} }
*/
void closeio(io *io) void
closeio(io *io)
{ {
if(io->fd>=0) close(io->fd); if(io->fd>=0)
if(io->strp) efree(io->strp); close(io->fd);
if(io->strp)
efree(io->strp);
efree((char *)io); efree((char *)io);
} }
int emptybuf(io *f)
int
emptybuf(io *f)
{ {
int n; int n;
if(f->fd==-1 || (n = Read(f->fd, f->buf, NBUF))<=0) return EOF; if(f->fd==-1 || (n = Read(f->fd, f->buf, NBUF))<=0) return EOF;

View File

@ -18,9 +18,9 @@ int rchr(io*);
void closeio(io*); void closeio(io*);
void flush(io*); void flush(io*);
int fullbuf(io*, int); int fullbuf(io*, int);
void pdec(io*, long); void pdec(io*, int);
void poct(io*, ulong); void poct(io*, unsigned);
void phex(io*, long); void pptr(io*, void*);
void pquo(io*, char*); void pquo(io*, char*);
void pwrd(io*, char*); void pwrd(io*, char*);
void pstr(io*, char*); void pstr(io*, char*);

View File

@ -4,11 +4,15 @@
#include "getflags.h" #include "getflags.h"
#include "fns.h" #include "fns.h"
int getnext(void); int getnext(void);
int wordchr(int c)
int
wordchr(int c)
{ {
return !strchr("\n \t#;&|^$=`'{}()<>", c) && c!=EOF; return !strchr("\n \t#;&|^$=`'{}()<>", c) && c!=EOF;
} }
int idchr(int c)
int
idchr(int c)
{ {
/* /*
* Formerly: * Formerly:
@ -20,17 +24,25 @@ int idchr(int c)
int future = EOF; int future = EOF;
int doprompt = 1; int doprompt = 1;
int inquote; int inquote;
int incomm;
/* /*
* Look ahead in the input stream * Look ahead in the input stream
*/ */
int nextc(void){
if(future==EOF) future=getnext(); int
nextc(void)
{
if(future==EOF)
future = getnext();
return future; return future;
} }
/* /*
* Consume the lookahead character. * Consume the lookahead character.
*/ */
int advance(void){
int
advance(void)
{
int c = nextc(); int c = nextc();
lastc = future; lastc = future;
future = EOF; future = EOF;
@ -39,20 +51,25 @@ int advance(void){
/* /*
* read a character from the input stream * read a character from the input stream
*/ */
int getnext(void){
register int c; int
getnext(void)
{
int c;
static int peekc = EOF; static int peekc = EOF;
if(peekc!=EOF){ if(peekc!=EOF){
c = peekc; c = peekc;
peekc = EOF; peekc = EOF;
return c; return c;
} }
if(runq->eof) return EOF; if(runq->eof)
if(doprompt) pprompt(); return EOF;
if(doprompt)
pprompt();
c = rchr(runq->cmdfd); c = rchr(runq->cmdfd);
if(!inquote && c=='\\'){ if(!inquote && c=='\\'){
c = rchr(runq->cmdfd); c = rchr(runq->cmdfd);
if(c=='\n'){ if(c=='\n' && !incomm){ /* don't continue a comment */
doprompt = 1; doprompt = 1;
c=' '; c=' ';
} }
@ -62,11 +79,15 @@ int getnext(void){
} }
} }
doprompt = doprompt || c=='\n' || c==EOF; doprompt = doprompt || c=='\n' || c==EOF;
if(c==EOF) runq->eof++; if(c==EOF)
runq->eof++;
else if(flag['V'] || ndot>=2 && flag['v']) pchr(err, c); else if(flag['V'] || ndot>=2 && flag['v']) pchr(err, c);
return c; return c;
} }
void pprompt(void){
void
pprompt(void)
{
var *prompt; var *prompt;
if(runq->iflag){ if(runq->iflag){
pstr(err, promptstr); pstr(err, promptstr);
@ -80,39 +101,59 @@ void pprompt(void){
runq->lineno++; runq->lineno++;
doprompt = 0; doprompt = 0;
} }
void skipwhite(void){
void
skipwhite(void)
{
int c; int c;
for(;;){ for(;;){
c = nextc(); c = nextc();
if(c=='#'){ /* Why did this used to be if(!inquote && c=='#') ?? */ /* Why did this used to be if(!inquote && c=='#') ?? */
if(c=='#'){
incomm = 1;
for(;;){ for(;;){
c = nextc(); c = nextc();
if(c=='\n' || c==EOF) break; if(c=='\n' || c==EOF) {
incomm = 0;
break;
}
advance(); advance();
} }
} }
if(c==' ' || c=='\t') advance(); if(c==' ' || c=='\t')
advance();
else return; else return;
} }
} }
void skipnl(void){
register int c; void
skipnl(void)
{
int c;
for(;;){ for(;;){
skipwhite(); skipwhite();
c = nextc(); c = nextc();
if(c!='\n') return; if(c!='\n')
return;
advance(); advance();
} }
} }
int nextis(int c){
int
nextis(int c)
{
if(nextc()==c){ if(nextc()==c){
advance(); advance();
return 1; return 1;
} }
return 0; return 0;
} }
char *addtok(char *p, int val){
if(p==0) return 0; char*
addtok(char *p, int val)
{
if(p==0)
return 0;
if(p==&tok[NTOK-1]){ if(p==&tok[NTOK-1]){
*p = 0; *p = 0;
yyerror("token buffer too short"); yyerror("token buffer too short");
@ -121,7 +162,10 @@ char *addtok(char *p, int val){
*p++=val; *p++=val;
return p; return p;
} }
char *addutf(char *p, int c){
char*
addutf(char *p, int c)
{
p = addtok(p, c); p = addtok(p, c);
if(twobyte(c)) /* 2-byte escape */ if(twobyte(c)) /* 2-byte escape */
return addtok(p, advance()); return addtok(p, advance());
@ -133,10 +177,13 @@ char *addutf(char *p, int c){
} }
int lastdol; /* was the last token read '$' or '$#' or '"'? */ int lastdol; /* was the last token read '$' or '$#' or '"'? */
int lastword; /* was the last token read a word or compound word terminator? */ int lastword; /* was the last token read a word or compound word terminator? */
int yylex(void){
register int c, d=nextc(); int
register char *w=tok; yylex(void)
register struct tree *t; {
int c, d = nextc();
char *w = tok;
struct 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
@ -225,17 +272,19 @@ int yylex(void){
if(nextis(c)){ if(nextis(c)){
t->rtype = HERE; t->rtype = HERE;
*w++=c; *w++=c;
} } else if (nextis('>')){
else t->rtype=READ; t->rtype = RDWR;
*w++=c;
} else t->rtype = READ;
t->fd0 = 0; t->fd0 = 0;
break; break;
} }
if(nextis('[')){ if(nextis('[')){
*w++='['; *w++='[';
c = advance(); c = advance();
*w++=c;
if(c<'0' || '9'<c){ if(c<'0' || '9'<c){
RedirErr: RedirErr:
*w++ = c;
*w = 0; *w = 0;
yyerror(t->type==PIPE?"pipe syntax" yyerror(t->type==PIPE?"pipe syntax"
:"redirection syntax"); :"redirection syntax");
@ -249,7 +298,8 @@ int yylex(void){
}while('0'<=c && c<='9'); }while('0'<=c && c<='9');
if(c=='='){ if(c=='='){
*w++='='; *w++='=';
if(t->type==REDIR) t->type=DUP; if(t->type==REDIR)
t->type = DUP;
c = advance(); c = advance();
if('0'<=c && c<='9'){ if('0'<=c && c<='9'){
t->rtype = DUPFD; t->rtype = DUPFD;
@ -262,11 +312,11 @@ int yylex(void){
}while('0'<=c && c<='9'); }while('0'<=c && c<='9');
} }
else{ else{
if(t->type==PIPE) goto RedirErr; if(t->type==PIPE)
goto RedirErr;
t->rtype = CLOSE; t->rtype = CLOSE;
} }
} }
*w=0;
if(c!=']' if(c!=']'
|| t->type==DUP && (t->rtype==HERE || t->rtype==APPEND)) || t->type==DUP && (t->rtype==HERE || t->rtype==APPEND))
goto RedirErr; goto RedirErr;
@ -274,7 +324,8 @@ int yylex(void){
} }
*w='\0'; *w='\0';
yylval.tree = t; yylval.tree = t;
if(t->type==PIPE) skipnl(); if(t->type==PIPE)
skipnl();
return t->type; return t->type;
case '\'': case '\'':
lastdol = 0; lastdol = 0;
@ -282,7 +333,8 @@ int yylex(void){
inquote = 1; inquote = 1;
for(;;){ for(;;){
c = advance(); c = advance();
if(c==EOF) break; if(c==EOF)
break;
if(c=='\''){ if(c=='\''){
if(nextc()!='\'') if(nextc()!='\'')
break; break;
@ -290,7 +342,8 @@ int yylex(void){
} }
w = addutf(w, c); w = addutf(w, c);
} }
if(w!=0) *w='\0'; if(w!=0)
*w='\0';
t = token(tok, WORD); t = token(tok, WORD);
t->quoted = 1; t->quoted = 1;
yylval.tree = t; yylval.tree = t;
@ -314,11 +367,12 @@ int yylex(void){
lastword = 1; lastword = 1;
lastdol = 0; lastdol = 0;
if(w!=0) *w='\0'; if(w!=0)
*w='\0';
t = klook(tok); t = klook(tok);
if(t->type!=WORD) lastword=0; if(t->type!=WORD)
lastword = 0;
t->quoted = 0; t->quoted = 0;
yylval.tree = t; yylval.tree = t;
return t->type; return t->type;
} }

View File

@ -20,6 +20,7 @@ OFILES=\
var.$O\ var.$O\
y.tab.$O\ y.tab.$O\
plan9ish.$O\ plan9ish.$O\
havep9p.$O\
HFILES=\ HFILES=\
rc.h\ rc.h\

View File

@ -5,39 +5,66 @@ char nl='\n'; /* change to semicolon for bourne-proofing */
#define c0 t->child[0] #define c0 t->child[0]
#define c1 t->child[1] #define c1 t->child[1]
#define c2 t->child[2] #define c2 t->child[2]
void pdeglob(io *f, char *s)
void
pdeglob(io *f, char *s)
{ {
while(*s){ while(*s){
if(*s==GLOB) s++; if(*s==GLOB)
s++;
pchr(f, *s++); pchr(f, *s++);
} }
} }
void pcmd(io *f, tree *t)
void
pcmd(io *f, tree *t)
{ {
if(t==0) return; if(t==0)
return;
switch(t->type){ switch(t->type){
default: pfmt(f, "bad %d %p %p %p", t->type, c0, c1, c2); break; default: pfmt(f, "bad %d %p %p %p", t->type, c0, c1, c2);
case '$': pfmt(f, "$%t", c0); break; break;
case '"': pfmt(f, "$\"%t", c0); break; case '$': pfmt(f, "$%t", c0);
case '&': pfmt(f, "%t&", c0); break; break;
case '^': pfmt(f, "%t^%t", c0, c1); break; case '"': pfmt(f, "$\"%t", c0);
case '`': pfmt(f, "`%t", c0); break; break;
case ANDAND: pfmt(f, "%t && %t", c0, c1); break; case '&': pfmt(f, "%t&", c0);
case BANG: pfmt(f, "! %t", c0); break; break;
case BRACE: pfmt(f, "{%t}", c0); break; case '^': pfmt(f, "%t^%t", c0, c1);
case COUNT: pfmt(f, "$#%t", c0); break; break;
case FN: pfmt(f, "fn %t %t", c0, c1); break; case '`': pfmt(f, "`%t", c0);
case IF: pfmt(f, "if%t%t", c0, c1); break; break;
case NOT: pfmt(f, "if not %t", c0); break; case ANDAND: pfmt(f, "%t && %t", c0, c1);
case OROR: pfmt(f, "%t || %t", c0, c1); break; break;
case BANG: pfmt(f, "! %t", c0);
break;
case BRACE: pfmt(f, "{%t}", c0);
break;
case COUNT: pfmt(f, "$#%t", c0);
break;
case FN: pfmt(f, "fn %t %t", c0, c1);
break;
case IF: pfmt(f, "if%t%t", c0, c1);
break;
case NOT: pfmt(f, "if not %t", c0);
break;
case OROR: pfmt(f, "%t || %t", c0, c1);
break;
case PCMD: case PCMD:
case PAREN: pfmt(f, "(%t)", c0); break; case PAREN: pfmt(f, "(%t)", c0);
case SUB: pfmt(f, "$%t(%t)", c0, c1); break; break;
case SIMPLE: pfmt(f, "%t", c0); break; case SUB: pfmt(f, "$%t(%t)", c0, c1);
case SUBSHELL: pfmt(f, "@ %t", c0); break; break;
case SWITCH: pfmt(f, "switch %t %t", c0, c1); break; case SIMPLE: pfmt(f, "%t", c0);
case TWIDDLE: pfmt(f, "~ %t %t", c0, c1); break; break;
case WHILE: pfmt(f, "while %t%t", c0, c1); break; case SUBSHELL: pfmt(f, "@ %t", c0);
break;
case SWITCH: pfmt(f, "switch %t %t", c0, c1);
break;
case TWIDDLE: pfmt(f, "~ %t %t", c0, c1);
break;
case WHILE: pfmt(f, "while %t%t", c0, c1);
break;
case ARGLIST: case ARGLIST:
if(c0==0) if(c0==0)
pfmt(f, "%t", c1); pfmt(f, "%t", c1);
@ -48,22 +75,26 @@ void pcmd(io *f, tree *t)
break; break;
case ';': case ';':
if(c0){ if(c0){
if(c1) pfmt(f, "%t%c%t", c0, nl, c1); if(c1)
pfmt(f, "%t%c%t", c0, nl, c1);
else pfmt(f, "%t", c0); else pfmt(f, "%t", c0);
} }
else pfmt(f, "%t", c1); else pfmt(f, "%t", c1);
break; break;
case WORDS: case WORDS:
if(c0) pfmt(f, "%t ", c0); if(c0)
pfmt(f, "%t ", c0);
pfmt(f, "%t", c1); pfmt(f, "%t", c1);
break; break;
case FOR: case FOR:
pfmt(f, "for(%t", c0); pfmt(f, "for(%t", c0);
if(c1) pfmt(f, " in %t", c1); if(c1)
pfmt(f, " in %t", c1);
pfmt(f, ")%t", c2); pfmt(f, ")%t", c2);
break; break;
case WORD: case WORD:
if(t->quoted) pfmt(f, "%Q", t->str); if(t->quoted)
pfmt(f, "%Q", t->str);
else pdeglob(f, t->str); else pdeglob(f, t->str);
break; break;
case DUP: case DUP:
@ -79,27 +110,35 @@ void pcmd(io *f, tree *t)
case HERE: case HERE:
pchr(f, '<'); pchr(f, '<');
case READ: case READ:
case RDWR:
pchr(f, '<'); pchr(f, '<');
if(t->fd0!=0) pfmt(f, "[%d]", t->fd0); if(t->rtype==RDWR)
pchr(f, '>');
if(t->fd0!=0)
pfmt(f, "[%d]", t->fd0);
break; break;
case APPEND: case APPEND:
pchr(f, '>'); pchr(f, '>');
case WRITE: case WRITE:
pchr(f, '>'); pchr(f, '>');
if(t->fd0!=1) pfmt(f, "[%d]", t->fd0); if(t->fd0!=1)
pfmt(f, "[%d]", t->fd0);
break; break;
} }
pfmt(f, "%t", c0); pfmt(f, "%t", c0);
if(c1) pfmt(f, " %t", c1); if(c1)
pfmt(f, " %t", c1);
break; break;
case '=': case '=':
pfmt(f, "%t=%t", c0, c1); pfmt(f, "%t=%t", c0, c1);
if(c2) pfmt(f, " %t", c2); if(c2)
pfmt(f, " %t", c2);
break; break;
case PIPE: case PIPE:
pfmt(f, "%t|", c0); pfmt(f, "%t|", c0);
if(t->fd1==0){ if(t->fd1==0){
if(t->fd0!=1) pfmt(f, "[%d]", t->fd0); if(t->fd0!=1)
pfmt(f, "[%d]", t->fd0);
} }
else pfmt(f, "[%d=%d]", t->fd0, t->fd1); else pfmt(f, "[%d=%d]", t->fd0, t->fd1);
pfmt(f, "%t", c1); pfmt(f, "%t", c1);

View File

@ -18,6 +18,7 @@ struct{
Xjump, "Xjump", Xjump, "Xjump",
Xmark, "Xmark", Xmark, "Xmark",
Xpopm, "Xpopm", Xpopm, "Xpopm",
Xrdwr, "Xrdwr",
Xread, "Xread", Xread, "Xread",
Xreturn, "Xreturn", Xreturn, "Xreturn",
Xtrue, "Xtrue", Xtrue, "Xtrue",
@ -50,7 +51,9 @@ struct{
Xrdfn, "Xrdfn", Xrdfn, "Xrdfn",
Xqdol, "Xqdol", Xqdol, "Xqdol",
0}; 0};
void pfnc(io *fd, thread *t)
void
pfnc(io *fd, thread *t)
{ {
int i; int i;
void (*fn)(void) = t->code[t->pc].f; void (*fn)(void) = t->code[t->pc].f;
@ -60,7 +63,8 @@ void pfnc(io *fd, thread *t)
pstr(fd, fname[i].name); pstr(fd, fname[i].name);
break; break;
} }
if(!fname[i].f) pfmt(fd, "%p", fn); if(!fname[i].f)
pfmt(fd, "%p", fn);
for(a = t->argv;a;a = a->next) pfmt(fd, " (%v)", a->words); for(a = t->argv;a;a = a->next) pfmt(fd, " (%v)", a->words);
pchr(fd, '\n'); pchr(fd, '\n');
flush(fd); flush(fd);

View File

@ -411,9 +411,11 @@ int Opendir(char *name)
close(f); close(f);
return -1; return -1;
} }
int Readdir(int f, char *p) int Readdir(int f, char *p, int onlydirs)
{ {
int n; int n;
USED(onlydirs); /* only advisory */
if(f<0 || f>=NFD) if(f<0 || f>=NFD)
return 0; return 0;
if(dir[f].i==dir[f].n){ /* read */ if(dir[f].i==dir[f].n){ /* read */

View File

@ -80,6 +80,7 @@ char tok[NTOK];
#define HERE 4 #define HERE 4
#define DUPFD 5 #define DUPFD 5
#define CLOSE 6 #define CLOSE 6
#define RDWR 7
struct var{ struct var{
char *name; /* ascii name */ char *name; /* ascii name */
word *val; /* value */ word *val; /* value */

View File

@ -15,13 +15,15 @@ exitnext(void){
while(c->f==Xpopredir) c++; while(c->f==Xpopredir) c++;
return c->f==Xexit; return c->f==Xexit;
} }
void Xsimple(void){
void
Xsimple(void)
{
word *a; word *a;
thread *p = runq; thread *p = runq;
var *v; var *v;
struct builtin *bp; struct builtin *bp;
int pid, n; int pid;
char buf[ERRMAX];
globlist(); globlist();
a = runq->argv->words; a = runq->argv->words;
if(a==0){ if(a==0){
@ -58,30 +60,22 @@ void Xsimple(void){
else{ else{
flush(err); flush(err);
Updenv(); /* necessary so changes don't go out again */ Updenv(); /* necessary so changes don't go out again */
switch(pid=fork()){ if((pid = execforkexec()) < 0){
case -1:
Xerror("try again"); Xerror("try again");
return; return;
case 0: }
pushword("exec");
execexec();
strcpy(buf, "can't exec: ");
n = strlen(buf);
errstr(buf+n, ERRMAX-n);
Exit(buf);
default:
kidpid = pid;
poplist();
/* interrupts don't get us out */ /* interrupts don't get us out */
poplist();
while(Waitfor(pid, 1) < 0) while(Waitfor(pid, 1) < 0)
; ;
kidpid = 0;
}
} }
} }
} }
struct word nullpath = { "", 0}; struct word nullpath = { "", 0};
void doredir(redir *rp)
void
doredir(redir *rp)
{ {
if(rp){ if(rp){
doredir(rp->next); doredir(rp->next);
@ -92,12 +86,19 @@ void doredir(redir *rp)
close(rp->from); close(rp->from);
} }
break; break;
case RDUP: Dup(rp->from, rp->to); break; case RDUP:
case RCLOSE: close(rp->from); break; Dup(rp->from, rp->to);
break;
case RCLOSE:
close(rp->from);
break;
} }
} }
} }
word *searchpath(char *w){
word*
searchpath(char *w)
{
word *path; word *path;
if(strncmp(w, "/", 1)==0 if(strncmp(w, "/", 1)==0
/* || strncmp(w, "#", 1)==0 */ /* || strncmp(w, "#", 1)==0 */
@ -107,7 +108,10 @@ word *searchpath(char *w){
path=&nullpath; path=&nullpath;
return path; return path;
} }
void execexec(void){
void
execexec(void)
{
popword(); /* "exec" */ popword(); /* "exec" */
if(runq->argv->words==0){ if(runq->argv->words==0){
Xerror1("empty argument list"); Xerror1("empty argument list");
@ -117,7 +121,9 @@ void execexec(void){
Execute(runq->argv->words, searchpath(runq->argv->words->word)); Execute(runq->argv->words, searchpath(runq->argv->words->word));
poplist(); poplist();
} }
void execfunc(var *func)
void
execfunc(var *func)
{ {
word *starval; word *starval;
popword(); popword();
@ -129,7 +135,10 @@ void execfunc(var *func)
runq->local->val = starval; runq->local->val = starval;
runq->local->changed = 1; runq->local->changed = 1;
} }
int dochdir(char *word){
int
dochdir(char *word)
{
/* report to /dev/wdir if it exists and we're interactive */ /* report to /dev/wdir if it exists and we're interactive */
static int wdirfd = -2; static int wdirfd = -2;
if(chdir(word)<0) return -1; if(chdir(word)<0) return -1;
@ -141,7 +150,10 @@ int dochdir(char *word){
} }
return 1; return 1;
} }
void execcd(void){
void
execcd(void)
{
word *a = runq->argv->words; word *a = runq->argv->words;
word *cdpath; word *cdpath;
char dir[512]; char dir[512];
@ -152,10 +164,12 @@ void execcd(void){
pfmt(err, "Usage: cd [directory]\n"); pfmt(err, "Usage: cd [directory]\n");
break; break;
case 2: case 2:
if(a->next->word[0]=='/' || cdpath==0) cdpath=&nullpath; if(a->next->word[0]=='/' || cdpath==0)
cdpath=&nullpath;
for(;cdpath;cdpath = cdpath->next){ for(;cdpath;cdpath = cdpath->next){
strcpy(dir, cdpath->word); strcpy(dir, cdpath->word);
if(dir[0]) strcat(dir, "/"); if(dir[0])
strcat(dir, "/");
strcat(dir, a->next->word); strcat(dir, a->next->word);
if(dochdir(dir)>=0){ if(dochdir(dir)>=0){
if(strlen(cdpath->word) if(strlen(cdpath->word)
@ -165,10 +179,11 @@ void execcd(void){
break; break;
} }
} }
if(cdpath==0) pfmt(err, "Can't cd %s: %r\n", a->next->word); if(cdpath==0)
pfmt(err, "Can't cd %s: %r\n", a->next->word);
break; break;
case 1: case 1:
a=vlook("HOME")->val; a = vlook("home")->val;
if(count(a)>=1){ if(count(a)>=1){
if(dochdir(a->word)>=0) if(dochdir(a->word)>=0)
setstatus(""); setstatus("");
@ -181,14 +196,22 @@ void execcd(void){
} }
poplist(); poplist();
} }
void execexit(void){
void
execexit(void)
{
switch(count(runq->argv->words)){ switch(count(runq->argv->words)){
default: pfmt(err, "Usage: exit [status]\nExiting anyway\n"); default:
case 2: setstatus(runq->argv->words->next->word); pfmt(err, "Usage: exit [status]\nExiting anyway\n");
case 2:
setstatus(runq->argv->words->next->word);
case 1: Xexit(); case 1: Xexit();
} }
} }
void execshift(void){
void
execshift(void)
{
int n; int n;
word *a; word *a;
var *star; var *star;
@ -198,8 +221,12 @@ void execshift(void){
setstatus("shift usage"); setstatus("shift usage");
poplist(); poplist();
return; return;
case 2: n=atoi(runq->argv->words->next->word); break; case 2:
case 1: n=1; break; n = atoi(runq->argv->words->next->word);
break;
case 1:
n = 1;
break;
} }
star = vlook("*"); star = vlook("*");
for(;n && star->val;--n){ for(;n && star->val;--n){
@ -212,31 +239,39 @@ void execshift(void){
setstatus(""); setstatus("");
poplist(); poplist();
} }
int octal(char *s)
int
octal(char *s)
{ {
int n = 0; int n = 0;
while(*s==' ' || *s=='\t' || *s=='\n') s++; while(*s==' ' || *s=='\t' || *s=='\n') s++;
while('0'<=*s && *s<='7') n = n*8+*s++-'0'; while('0'<=*s && *s<='7') n = n*8+*s++-'0';
return n; return n;
} }
int mapfd(int fd)
int
mapfd(int fd)
{ {
redir *rp; redir *rp;
for(rp = runq->redir;rp;rp = rp->next){ for(rp = runq->redir;rp;rp = rp->next){
switch(rp->type){ switch(rp->type){
case RCLOSE: case RCLOSE:
if(rp->from==fd) fd=-1; if(rp->from==fd)
fd=-1;
break; break;
case RDUP: case RDUP:
case ROPEN: case ROPEN:
if(rp->to==fd) fd=rp->from; if(rp->to==fd)
fd = rp->from;
break; break;
} }
} }
return fd; return fd;
} }
union code rdcmds[4]; union code rdcmds[4];
void execcmds(io *f)
void
execcmds(io *f)
{ {
static int first = 1; static int first = 1;
if(first){ if(first){
@ -249,7 +284,10 @@ void execcmds(io *f)
runq->cmdfd = f; runq->cmdfd = f;
runq->iflast = 0; runq->iflast = 0;
} }
void execeval(void){
void
execeval(void)
{
char *cmdline, *s, *t; char *cmdline, *s, *t;
int len = 0; int len = 0;
word *ap; word *ap;
@ -272,7 +310,10 @@ void execeval(void){
efree(cmdline); efree(cmdline);
} }
union code dotcmds[14]; union code dotcmds[14];
void execdot(void){
void
execdot(void)
{
int iflag = 0; int iflag = 0;
int fd; int fd;
list *av; list *av;
@ -314,13 +355,15 @@ void execdot(void){
fd=-1; fd=-1;
for(path = searchpath(zero);path;path = path->next){ for(path = searchpath(zero);path;path = path->next){
strcpy(file, path->word); strcpy(file, path->word);
if(file[0]) strcat(file, "/"); if(file[0])
strcat(file, "/");
strcat(file, zero); strcat(file, zero);
if((fd = open(file, 0))>=0) break;
if(strcmp(file, "/dev/stdin")==0){ /* for sun & ucb */ if(strcmp(file, "/dev/stdin")==0){ /* for sun & ucb */
fd = Dup1(0); fd = Dup1(0);
if(fd>=0) break; if(fd>=0)
break;
} }
if((fd=open(file, 0))>=0) break;
} }
if(fd<0){ if(fd<0){
pfmt(err, "%s: ", zero); pfmt(err, "%s: ", zero);
@ -347,7 +390,10 @@ void execdot(void){
pushword(zero); pushword(zero);
ndot++; ndot++;
} }
void execflag(void){
void
execflag(void)
{
char *letter, *val; char *letter, *val;
switch(count(runq->argv->words)){ switch(count(runq->argv->words)){
case 2: case 2:
@ -372,7 +418,9 @@ void execflag(void){
} }
poplist(); poplist();
} }
void execwhatis(void){ /* mildly wrong -- should fork before writing */
void
execwhatis(void){ /* mildly wrong -- should fork before writing */
word *a, *b, *path; word *a, *b, *path;
var *v; var *v;
struct builtin *bp; struct builtin *bp;
@ -408,7 +456,8 @@ void execwhatis(void){ /* mildly wrong -- should fork before writing */
else else
found = 0; found = 0;
v = gvlook(a->word); v = gvlook(a->word);
if(v->fn) pfmt(out, "fn %s %s\n", v->name, v->fn[v->pc-1].s); if(v->fn)
pfmt(out, "fn %s %s\n", v->name, v->fn[v->pc-1].s);
else{ else{
for(bp = Builtin;bp->name;bp++) for(bp = Builtin;bp->name;bp++)
if(strcmp(a->word, bp->name)==0){ if(strcmp(a->word, bp->name)==0){
@ -418,7 +467,8 @@ void execwhatis(void){ /* mildly wrong -- should fork before writing */
if(!bp->name){ if(!bp->name){
for(path = searchpath(a->word);path;path = path->next){ for(path = searchpath(a->word);path;path = path->next){
strcpy(file, path->word); strcpy(file, path->word);
if(file[0]) strcat(file, "/"); if(file[0])
strcat(file, "/");
strcat(file, a->word); strcat(file, a->word);
if(Executable(file)){ if(Executable(file)){
pfmt(out, "%s\n", file); pfmt(out, "%s\n", file);
@ -435,11 +485,20 @@ void execwhatis(void){ /* mildly wrong -- should fork before writing */
poplist(); poplist();
flush(err); flush(err);
} }
void execwait(void){
void
execwait(void)
{
switch(count(runq->argv->words)){ switch(count(runq->argv->words)){
default: Xerror1("Usage: wait [pid]"); return; default:
case 2: Waitfor(atoi(runq->argv->words->next->word), 0); break; Xerror1("Usage: wait [pid]");
case 1: Waitfor(-1, 0); break; return;
case 2:
Waitfor(atoi(runq->argv->words->next->word), 0);
break;
case 1:
Waitfor(-1, 0);
break;
} }
poplist(); poplist();
} }

View File

@ -2,20 +2,29 @@
#include "exec.h" #include "exec.h"
#include "io.h" #include "io.h"
#include "fns.h" #include "fns.h"
char *emalloc(long n){
char*
emalloc(long n)
{
char *p = (char *)Malloc(n); char *p = (char *)Malloc(n);
if(p==0) panic("Can't malloc %d bytes", n); if(p==0)
/* if(err){ pfmt(err, "malloc %d->%p\n", n, p); flush(err); } */ panic("Can't malloc %d bytes", n);
/* if(err){ pfmt(err, "malloc %d->%p\n", n, p); flush(err); } /**/
return p; return p;
} }
void efree(char *p)
void
efree(char *p)
{ {
/* pfmt(err, "free %p\n", p); flush(err); */ /* pfmt(err, "free %p\n", p); flush(err); /**/
if(p) free(p); if(p)
free(p);
else pfmt(err, "free 0\n"); else pfmt(err, "free 0\n");
} }
extern int lastword, lastdol; extern int lastword, lastdol;
void yyerror(char *m)
void
yyerror(char *m)
{ {
pfmt(err, "rc: "); pfmt(err, "rc: ");
if(runq->cmdfile && !runq->iflag) if(runq->cmdfile && !runq->iflag)
@ -24,7 +33,8 @@ void yyerror(char *m)
pfmt(err, "%s: ", runq->cmdfile); pfmt(err, "%s: ", runq->cmdfile);
else if(!runq->iflag) else if(!runq->iflag)
pfmt(err, "line %d: ", runq->lineno); pfmt(err, "line %d: ", runq->lineno);
if(tok[0] && tok[0]!='\n') pfmt(err, "token %q: ", tok); if(tok[0] && tok[0]!='\n')
pfmt(err, "token %q: ", tok);
pfmt(err, "%s\n", m); pfmt(err, "%s\n", m);
flush(err); flush(err);
lastword = 0; lastword = 0;
@ -34,7 +44,10 @@ void yyerror(char *m)
setvar("status", newword(m, (word *)0)); setvar("status", newword(m, (word *)0));
} }
char *bp; char *bp;
void iacvt(int n){
static void
iacvt(int n)
{
if(n<0){ if(n<0){
*bp++='-'; *bp++='-';
n=-n; /* doesn't work for n==-inf */ n=-n; /* doesn't work for n==-inf */
@ -43,13 +56,17 @@ void iacvt(int n){
iacvt(n/10); iacvt(n/10);
*bp++=n%10+'0'; *bp++=n%10+'0';
} }
void itoa(char *s, long n)
void
inttoascii(char *s, long n)
{ {
bp = s; bp = s;
iacvt(n); iacvt(n);
*bp='\0'; *bp='\0';
} }
void panic(char *s, int n)
void
panic(char *s, int n)
{ {
pfmt(err, "rc: "); pfmt(err, "rc: ");
pfmt(err, s, n); pfmt(err, s, n);

View File

@ -2,7 +2,6 @@
%term WORD REDIR DUP PIPE SUB %term WORD REDIR DUP PIPE SUB
%term SIMPLE ARGLIST WORDS BRACE PAREN PCMD PIPEFD /* not used in syntax */ %term SIMPLE ARGLIST WORDS BRACE PAREN PCMD PIPEFD /* not used in syntax */
/* operator priorities -- lowest first */ /* operator priorities -- lowest first */
%left LOW
%left IF WHILE FOR SWITCH ')' NOT %left IF WHILE FOR SWITCH ')' NOT
%left ANDAND OROR %left ANDAND OROR
%left BANG SUBSHELL %left BANG SUBSHELL
@ -10,7 +9,6 @@
%left '^' %left '^'
%right '$' COUNT '"' %right '$' COUNT '"'
%left SUB %left SUB
%left '='
%{ %{
#include "rc.h" #include "rc.h"
#include "fns.h" #include "fns.h"
@ -80,7 +78,6 @@ first: comword
word: keyword {lastword=1; $1->type=WORD;} word: keyword {lastword=1; $1->type=WORD;}
| comword | comword
| word '^' word {$$=tree2('^', $1, $3);} | word '^' word {$$=tree2('^', $1, $3);}
| word '=' word %prec LOW {$$=tree2('^', tree2('^', $1, token("=", WORD)), $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);}

View File

@ -3,10 +3,13 @@
#include "fns.h" #include "fns.h"
#include "io.h" #include "io.h"
extern char *Signame[]; extern char *Signame[];
void dotrap(void){
register int i; void
register struct var *trapreq; dotrap(void)
register struct word *starval; {
int i;
struct var *trapreq;
struct 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];

View File

@ -7,7 +7,10 @@ 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.
*/ */
tree *newtree(void){
tree*
newtree(void)
{
tree *t = new(tree); tree *t = new(tree);
t->iskw = 0; t->iskw = 0;
t->str = 0; t->str = 0;
@ -16,29 +19,41 @@ tree *newtree(void){
treenodes = t; treenodes = t;
return t; return t;
} }
void freenodes(void){
void
freenodes(void)
{
tree *t, *u; tree *t, *u;
for(t = treenodes;t;t = u){ for(t = treenodes;t;t = u){
u = t->next; u = t->next;
if(t->str) efree(t->str); if(t->str)
efree(t->str);
efree((char *)t); efree((char *)t);
} }
treenodes = 0; treenodes = 0;
} }
tree *tree1(int type, tree *c0)
tree*
tree1(int type, tree *c0)
{ {
return tree3(type, c0, (tree *)0, (tree *)0); return tree3(type, c0, (tree *)0, (tree *)0);
} }
tree *tree2(int type, tree *c0, tree *c1)
tree*
tree2(int type, tree *c0, tree *c1)
{ {
return tree3(type, c0, c1, (tree *)0); return tree3(type, c0, c1, (tree *)0);
} }
tree *tree3(int type, tree *c0, tree *c1, tree *c2)
tree*
tree3(int type, tree *c0, tree *c1, tree *c2)
{ {
tree *t; tree *t;
if(type==';'){ if(type==';'){
if(c0==0) return c1; if(c0==0)
if(c1==0) return c0; return c1;
if(c1==0)
return c0;
} }
t = newtree(); t = newtree();
t->type = type; t->type = type;
@ -47,28 +62,37 @@ tree *tree3(int type, tree *c0, tree *c1, tree *c2)
t->child[2] = c2; t->child[2] = c2;
return t; return t;
} }
tree *mung1(tree *t, tree *c0)
tree*
mung1(tree *t, tree *c0)
{ {
t->child[0] = c0; t->child[0] = c0;
return t; return t;
} }
tree *mung2(tree *t, tree *c0, tree *c1)
tree*
mung2(tree *t, tree *c0, tree *c1)
{ {
t->child[0] = c0; t->child[0] = c0;
t->child[1] = c1; t->child[1] = c1;
return t; return t;
} }
tree *mung3(tree *t, tree *c0, tree *c1, tree *c2)
tree*
mung3(tree *t, 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;
return t; return t;
} }
tree *epimung(tree *comp, tree *epi)
tree*
epimung(tree *comp, tree *epi)
{ {
tree *p; tree *p;
if(epi==0) return comp; if(epi==0)
return comp;
for(p = epi;p->child[1];p = p->child[1]); for(p = epi;p->child[1];p = p->child[1]);
p->child[1] = comp; p->child[1] = comp;
return epi; return epi;
@ -77,7 +101,9 @@ tree *epimung(tree *comp, tree *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 *simplemung(tree *t)
tree*
simplemung(tree *t)
{ {
tree *u; tree *u;
struct io *s; struct io *s;
@ -96,19 +122,25 @@ tree *simplemung(tree *t)
} }
return t; return t;
} }
tree *token(char *str, int type)
tree*
token(char *str, int type)
{ {
tree *t = newtree(); tree *t = newtree();
t->type = type; t->type = type;
t->str = strdup(str); t->str = strdup(str);
return t; return t;
} }
void freetree(tree *p)
void
freetree(tree *p)
{ {
if(p==0) return; if(p==0)
return;
freetree(p->child[0]); freetree(p->child[0]);
freetree(p->child[1]); freetree(p->child[1]);
freetree(p->child[2]); freetree(p->child[2]);
if(p->str) efree(p->str); if(p->str)
efree(p->str);
efree((char *)p); efree((char *)p);
} }

View File

@ -1,9 +1,11 @@
#include "rc.h" #include "rc.h"
#include "exec.h" #include "exec.h"
#include "fns.h" #include "fns.h"
int hash(char *s, int n)
int
hash(char *s, int n)
{ {
register int h=0, i=1; int h = 0, i = 1;
while(*s) h+=*s++*i++; while(*s) h+=*s++*i++;
h%=n; h%=n;
return h<0?h+n:h; return h<0?h+n:h;
@ -14,16 +16,21 @@ struct kw{
int type; int type;
struct kw *next; struct kw *next;
}*kw[NKW]; }*kw[NKW];
void kenter(int type, char *name)
void
kenter(int type, char *name)
{ {
register int h=hash(name, NKW); int h = hash(name, NKW);
register struct kw *p=new(struct kw); struct kw *p = new(struct kw);
p->type = type; p->type = type;
p->name = name; p->name = name;
p->next = kw[h]; p->next = kw[h];
kw[h] = p; kw[h] = p;
} }
void kinit(void){
void
kinit(void)
{
kenter(FOR, "for"); kenter(FOR, "for");
kenter(IN, "in"); kenter(IN, "in");
kenter(WHILE, "while"); kenter(WHILE, "while");
@ -35,7 +42,9 @@ void kinit(void){
kenter(SWITCH, "switch"); kenter(SWITCH, "switch");
kenter(FN, "fn"); kenter(FN, "fn");
} }
tree *klook(char *name)
tree*
klook(char *name)
{ {
struct kw *p; struct kw *p;
tree *t = token(name, WORD); tree *t = token(name, WORD);
@ -47,14 +56,18 @@ tree *klook(char *name)
} }
return t; return t;
} }
var *gvlook(char *name)
var*
gvlook(char *name)
{ {
int h = hash(name, NVAR); int h = hash(name, NVAR);
var *v; var *v;
for(v = gvar[h];v;v = v->next) if(strcmp(v->name, name)==0) return v; for(v = gvar[h];v;v = v->next) if(strcmp(v->name, name)==0) return v;
return gvar[h] = newvar(strdup(name), gvar[h]); return gvar[h] = newvar(strdup(name), gvar[h]);
} }
var *vlook(char *name)
var*
vlook(char *name)
{ {
var *v; var *v;
if(runq) if(runq)
@ -62,20 +75,26 @@ var *vlook(char *name)
if(strcmp(v->name, name)==0) return v; if(strcmp(v->name, name)==0) return v;
return gvlook(name); return gvlook(name);
} }
void _setvar(char *name, word *val, int callfn)
void
_setvar(char *name, word *val, int callfn)
{ {
register struct var *v=vlook(name); struct var *v = vlook(name);
freewords(v->val); freewords(v->val);
v->val=val; v->val=val;
v->changed=1; v->changed=1;
if(callfn && v->changefn) if(callfn && v->changefn)
v->changefn(v); v->changefn(v);
} }
void setvar(char *name, word *val)
void
setvar(char *name, word *val)
{ {
_setvar(name, val, 1); _setvar(name, val, 1);
} }
void bigpath(var *v)
void
bigpath(var *v)
{ {
/* convert $PATH to $path */ /* convert $PATH to $path */
char *p, *q; char *p, *q;
@ -107,19 +126,42 @@ void bigpath(var *v)
} }
_setvar("path", w, 0); _setvar("path", w, 0);
} }
void littlepath(var *v)
char*
list2strcolon(word *words)
{
char *value, *s, *t;
int len = 0;
word *ap;
for(ap = words;ap;ap = ap->next)
len+=1+strlen(ap->word);
value = emalloc(len+1);
s = value;
for(ap = words;ap;ap = ap->next){
for(t = ap->word;*t;) *s++=*t++;
*s++=':';
}
if(s==value)
*s='\0';
else s[-1]='\0';
return value;
}
void
littlepath(var *v)
{ {
/* convert $path to $PATH */ /* convert $path to $PATH */
char *p; char *p;
word *w; word *w;
p = _list2str(v->val, ':'); p = list2strcolon(v->val);
w = new(word); w = new(word);
w->word = p; w->word = p;
w->next = nil; w->next = nil;
_setvar("PATH", w, 1); /* 1: recompute $path to expose colon problems */ _setvar("PATH", w, 1); /* 1: recompute $path to expose colon problems */
} }
void pathinit(void)
void
pathinit(void)
{ {
var *v; var *v;