Plan 9's rc.
not a clear win over byron's, but at least it has the right syntax.
This commit is contained in:
parent
5993a8f275
commit
f08fdedcee
430
src/cmd/rc/code.c
Normal file
430
src/cmd/rc/code.c
Normal file
@ -0,0 +1,430 @@
|
|||||||
|
#include "rc.h"
|
||||||
|
#include "io.h"
|
||||||
|
#include "exec.h"
|
||||||
|
#include "fns.h"
|
||||||
|
#include "getflags.h"
|
||||||
|
#define c0 t->child[0]
|
||||||
|
#define c1 t->child[1]
|
||||||
|
#define c2 t->child[2]
|
||||||
|
int codep, ncode;
|
||||||
|
#define emitf(x) ((void)(codep!=ncode || morecode()), codebuf[codep].f=(x), codep++)
|
||||||
|
#define emiti(x) ((void)(codep!=ncode || morecode()), codebuf[codep].i=(x), codep++)
|
||||||
|
#define emits(x) ((void)(codep!=ncode || morecode()), codebuf[codep].s=(x), codep++)
|
||||||
|
void stuffdot(int);
|
||||||
|
char *fnstr(tree*);
|
||||||
|
void outcode(tree*, int);
|
||||||
|
void codeswitch(tree*, int);
|
||||||
|
int iscase(tree*);
|
||||||
|
code *codecopy(code*);
|
||||||
|
void codefree(code*);
|
||||||
|
int morecode(void){
|
||||||
|
ncode+=100;
|
||||||
|
codebuf=(code *)realloc((char *)codebuf, ncode*sizeof codebuf[0]);
|
||||||
|
if(codebuf==0) panic("Can't realloc %d bytes in morecode!",
|
||||||
|
ncode*sizeof codebuf[0]);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
void stuffdot(int a){
|
||||||
|
if(a<0 || codep<=a) panic("Bad address %d in stuffdot", a);
|
||||||
|
codebuf[a].i=codep;
|
||||||
|
}
|
||||||
|
int compile(tree *t)
|
||||||
|
{
|
||||||
|
ncode=100;
|
||||||
|
codebuf=(code *)emalloc(ncode*sizeof codebuf[0]);
|
||||||
|
codep=0;
|
||||||
|
emiti(0); /* reference count */
|
||||||
|
outcode(t, flag['e']?1:0);
|
||||||
|
if(nerror){
|
||||||
|
efree((char *)codebuf);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
readhere();
|
||||||
|
emitf(Xreturn);
|
||||||
|
emitf(0);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
void cleanhere(char *f)
|
||||||
|
{
|
||||||
|
emitf(Xdelhere);
|
||||||
|
emits(strdup(f));
|
||||||
|
}
|
||||||
|
char *fnstr(tree *t)
|
||||||
|
{
|
||||||
|
io *f=openstr();
|
||||||
|
char *v;
|
||||||
|
extern char nl;
|
||||||
|
char svnl=nl;
|
||||||
|
nl=';';
|
||||||
|
pfmt(f, "%t", t);
|
||||||
|
nl=svnl;
|
||||||
|
v=f->strp;
|
||||||
|
f->strp=0;
|
||||||
|
closeio(f);
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
void outcode(tree *t, int eflag)
|
||||||
|
{
|
||||||
|
int p, q;
|
||||||
|
tree *tt;
|
||||||
|
if(t==0) return;
|
||||||
|
if(t->type!=NOT && t->type!=';') runq->iflast=0;
|
||||||
|
switch(t->type){
|
||||||
|
default:
|
||||||
|
pfmt(err, "bad type %d in outcode\n", t->type);
|
||||||
|
break;
|
||||||
|
case '$':
|
||||||
|
emitf(Xmark);
|
||||||
|
outcode(c0, eflag);
|
||||||
|
emitf(Xdol);
|
||||||
|
break;
|
||||||
|
case '"':
|
||||||
|
emitf(Xmark);
|
||||||
|
outcode(c0, eflag);
|
||||||
|
emitf(Xqdol);
|
||||||
|
break;
|
||||||
|
case SUB:
|
||||||
|
emitf(Xmark);
|
||||||
|
outcode(c0, eflag);
|
||||||
|
emitf(Xmark);
|
||||||
|
outcode(c1, eflag);
|
||||||
|
emitf(Xsub);
|
||||||
|
break;
|
||||||
|
case '&':
|
||||||
|
emitf(Xasync);
|
||||||
|
p=emiti(0);
|
||||||
|
outcode(c0, eflag);
|
||||||
|
emitf(Xexit);
|
||||||
|
stuffdot(p);
|
||||||
|
break;
|
||||||
|
case ';':
|
||||||
|
outcode(c0, eflag);
|
||||||
|
outcode(c1, eflag);
|
||||||
|
break;
|
||||||
|
case '^':
|
||||||
|
emitf(Xmark);
|
||||||
|
outcode(c1, eflag);
|
||||||
|
emitf(Xmark);
|
||||||
|
outcode(c0, eflag);
|
||||||
|
emitf(Xconc);
|
||||||
|
break;
|
||||||
|
case '`':
|
||||||
|
emitf(Xbackq);
|
||||||
|
p=emiti(0);
|
||||||
|
outcode(c0, 0);
|
||||||
|
emitf(Xexit);
|
||||||
|
stuffdot(p);
|
||||||
|
break;
|
||||||
|
case ANDAND:
|
||||||
|
outcode(c0, 0);
|
||||||
|
emitf(Xtrue);
|
||||||
|
p=emiti(0);
|
||||||
|
outcode(c1, eflag);
|
||||||
|
stuffdot(p);
|
||||||
|
break;
|
||||||
|
case ARGLIST:
|
||||||
|
outcode(c1, eflag);
|
||||||
|
outcode(c0, eflag);
|
||||||
|
break;
|
||||||
|
case BANG:
|
||||||
|
outcode(c0, eflag);
|
||||||
|
emitf(Xbang);
|
||||||
|
break;
|
||||||
|
case PCMD:
|
||||||
|
case BRACE:
|
||||||
|
outcode(c0, eflag);
|
||||||
|
break;
|
||||||
|
case COUNT:
|
||||||
|
emitf(Xmark);
|
||||||
|
outcode(c0, eflag);
|
||||||
|
emitf(Xcount);
|
||||||
|
break;
|
||||||
|
case FN:
|
||||||
|
emitf(Xmark);
|
||||||
|
outcode(c0, eflag);
|
||||||
|
if(c1){
|
||||||
|
emitf(Xfn);
|
||||||
|
p=emiti(0);
|
||||||
|
emits(fnstr(c1));
|
||||||
|
outcode(c1, eflag);
|
||||||
|
emitf(Xunlocal); /* get rid of $* */
|
||||||
|
emitf(Xreturn);
|
||||||
|
stuffdot(p);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
emitf(Xdelfn);
|
||||||
|
break;
|
||||||
|
case IF:
|
||||||
|
outcode(c0, 0);
|
||||||
|
emitf(Xif);
|
||||||
|
p=emiti(0);
|
||||||
|
outcode(c1, eflag);
|
||||||
|
emitf(Xwastrue);
|
||||||
|
stuffdot(p);
|
||||||
|
break;
|
||||||
|
case NOT:
|
||||||
|
if(!runq->iflast) yyerror("`if not' does not follow `if(...)'");
|
||||||
|
emitf(Xifnot);
|
||||||
|
p=emiti(0);
|
||||||
|
outcode(c0, eflag);
|
||||||
|
stuffdot(p);
|
||||||
|
break;
|
||||||
|
case OROR:
|
||||||
|
outcode(c0, 0);
|
||||||
|
emitf(Xfalse);
|
||||||
|
p=emiti(0);
|
||||||
|
outcode(c1, eflag);
|
||||||
|
stuffdot(p);
|
||||||
|
break;
|
||||||
|
case PAREN:
|
||||||
|
outcode(c0, eflag);
|
||||||
|
break;
|
||||||
|
case SIMPLE:
|
||||||
|
emitf(Xmark);
|
||||||
|
outcode(c0, eflag);
|
||||||
|
emitf(Xsimple);
|
||||||
|
if(eflag) emitf(Xeflag);
|
||||||
|
break;
|
||||||
|
case SUBSHELL:
|
||||||
|
emitf(Xsubshell);
|
||||||
|
p=emiti(0);
|
||||||
|
outcode(c0, eflag);
|
||||||
|
emitf(Xexit);
|
||||||
|
stuffdot(p);
|
||||||
|
if(eflag) emitf(Xeflag);
|
||||||
|
break;
|
||||||
|
case SWITCH:
|
||||||
|
codeswitch(t, eflag);
|
||||||
|
break;
|
||||||
|
case TWIDDLE:
|
||||||
|
emitf(Xmark);
|
||||||
|
outcode(c1, eflag);
|
||||||
|
emitf(Xmark);
|
||||||
|
outcode(c0, eflag);
|
||||||
|
emitf(Xmatch);
|
||||||
|
if(eflag) emitf(Xeflag);
|
||||||
|
break;
|
||||||
|
case WHILE:
|
||||||
|
q=codep;
|
||||||
|
outcode(c0, 0);
|
||||||
|
if(q==codep) emitf(Xsettrue); /* empty condition == while(true) */
|
||||||
|
emitf(Xtrue);
|
||||||
|
p=emiti(0);
|
||||||
|
outcode(c1, eflag);
|
||||||
|
emitf(Xjump);
|
||||||
|
emiti(q);
|
||||||
|
stuffdot(p);
|
||||||
|
break;
|
||||||
|
case WORDS:
|
||||||
|
outcode(c1, eflag);
|
||||||
|
outcode(c0, eflag);
|
||||||
|
break;
|
||||||
|
case FOR:
|
||||||
|
emitf(Xmark);
|
||||||
|
if(c1){
|
||||||
|
outcode(c1, eflag);
|
||||||
|
emitf(Xglob);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
emitf(Xmark);
|
||||||
|
emitf(Xword);
|
||||||
|
emits(strdup("*"));
|
||||||
|
emitf(Xdol);
|
||||||
|
}
|
||||||
|
emitf(Xmark); /* dummy value for Xlocal */
|
||||||
|
emitf(Xmark);
|
||||||
|
outcode(c0, eflag);
|
||||||
|
emitf(Xlocal);
|
||||||
|
p=emitf(Xfor);
|
||||||
|
q=emiti(0);
|
||||||
|
outcode(c2, eflag);
|
||||||
|
emitf(Xjump);
|
||||||
|
emiti(p);
|
||||||
|
stuffdot(q);
|
||||||
|
emitf(Xunlocal);
|
||||||
|
break;
|
||||||
|
case WORD:
|
||||||
|
emitf(Xword);
|
||||||
|
emits(strdup(t->str));
|
||||||
|
break;
|
||||||
|
case DUP:
|
||||||
|
if(t->rtype==DUPFD){
|
||||||
|
emitf(Xdup);
|
||||||
|
emiti(t->fd0);
|
||||||
|
emiti(t->fd1);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
emitf(Xclose);
|
||||||
|
emiti(t->fd0);
|
||||||
|
}
|
||||||
|
outcode(c1, eflag);
|
||||||
|
emitf(Xpopredir);
|
||||||
|
break;
|
||||||
|
case PIPEFD:
|
||||||
|
emitf(Xpipefd);
|
||||||
|
emiti(t->rtype);
|
||||||
|
p=emiti(0);
|
||||||
|
outcode(c0, eflag);
|
||||||
|
emitf(Xexit);
|
||||||
|
stuffdot(p);
|
||||||
|
break;
|
||||||
|
case REDIR:
|
||||||
|
emitf(Xmark);
|
||||||
|
outcode(c0, eflag);
|
||||||
|
emitf(Xglob);
|
||||||
|
switch(t->rtype){
|
||||||
|
case APPEND:
|
||||||
|
emitf(Xappend);
|
||||||
|
break;
|
||||||
|
case WRITE:
|
||||||
|
emitf(Xwrite);
|
||||||
|
break;
|
||||||
|
case READ:
|
||||||
|
case HERE:
|
||||||
|
emitf(Xread);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
emiti(t->fd0);
|
||||||
|
outcode(c1, eflag);
|
||||||
|
emitf(Xpopredir);
|
||||||
|
break;
|
||||||
|
case '=':
|
||||||
|
tt=t;
|
||||||
|
for(;t && t->type=='=';t=c2);
|
||||||
|
if(t){
|
||||||
|
for(t=tt;t->type=='=';t=c2){
|
||||||
|
emitf(Xmark);
|
||||||
|
outcode(c1, eflag);
|
||||||
|
emitf(Xmark);
|
||||||
|
outcode(c0, eflag);
|
||||||
|
emitf(Xlocal);
|
||||||
|
}
|
||||||
|
t=tt;
|
||||||
|
outcode(c2, eflag);
|
||||||
|
for(;t->type=='=';t=c2) emitf(Xunlocal);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
for(t=tt;t;t=c2){
|
||||||
|
emitf(Xmark);
|
||||||
|
outcode(c1, eflag);
|
||||||
|
emitf(Xmark);
|
||||||
|
outcode(c0, eflag);
|
||||||
|
emitf(Xassign);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
t=tt; /* so tests below will work */
|
||||||
|
break;
|
||||||
|
case PIPE:
|
||||||
|
emitf(Xpipe);
|
||||||
|
emiti(t->fd0);
|
||||||
|
emiti(t->fd1);
|
||||||
|
p=emiti(0);
|
||||||
|
q=emiti(0);
|
||||||
|
outcode(c0, eflag);
|
||||||
|
emitf(Xexit);
|
||||||
|
stuffdot(p);
|
||||||
|
outcode(c1, eflag);
|
||||||
|
emitf(Xreturn);
|
||||||
|
stuffdot(q);
|
||||||
|
emitf(Xpipewait);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(t->type!=NOT && t->type!=';')
|
||||||
|
runq->iflast=t->type==IF;
|
||||||
|
else if(c0) runq->iflast=c0->type==IF;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* switch code looks like this:
|
||||||
|
* Xmark
|
||||||
|
* (get switch value)
|
||||||
|
* Xjump 1f
|
||||||
|
* out: Xjump leave
|
||||||
|
* 1: Xmark
|
||||||
|
* (get case values)
|
||||||
|
* Xcase 1f
|
||||||
|
* (commands)
|
||||||
|
* Xjump out
|
||||||
|
* 1: Xmark
|
||||||
|
* (get case values)
|
||||||
|
* Xcase 1f
|
||||||
|
* (commands)
|
||||||
|
* Xjump out
|
||||||
|
* 1:
|
||||||
|
* leave:
|
||||||
|
* Xpopm
|
||||||
|
*/
|
||||||
|
void codeswitch(tree *t, int eflag)
|
||||||
|
{
|
||||||
|
int leave; /* patch jump address to leave switch */
|
||||||
|
int out; /* jump here to leave switch */
|
||||||
|
int nextcase; /* patch jump address to next case */
|
||||||
|
tree *tt;
|
||||||
|
if(c1->child[0]==nil
|
||||||
|
|| c1->child[0]->type!=';'
|
||||||
|
|| !iscase(c1->child[0]->child[0])){
|
||||||
|
yyerror("case missing in switch");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
emitf(Xmark);
|
||||||
|
outcode(c0, eflag);
|
||||||
|
emitf(Xjump);
|
||||||
|
nextcase=emiti(0);
|
||||||
|
out=emitf(Xjump);
|
||||||
|
leave=emiti(0);
|
||||||
|
stuffdot(nextcase);
|
||||||
|
t=c1->child[0];
|
||||||
|
while(t->type==';'){
|
||||||
|
tt=c1;
|
||||||
|
emitf(Xmark);
|
||||||
|
for(t=c0->child[0];t->type==ARGLIST;t=c0) outcode(c1, eflag);
|
||||||
|
emitf(Xcase);
|
||||||
|
nextcase=emiti(0);
|
||||||
|
t=tt;
|
||||||
|
for(;;){
|
||||||
|
if(t->type==';'){
|
||||||
|
if(iscase(c0)) break;
|
||||||
|
outcode(c0, eflag);
|
||||||
|
t=c1;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
if(!iscase(t)) outcode(t, eflag);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
emitf(Xjump);
|
||||||
|
emiti(out);
|
||||||
|
stuffdot(nextcase);
|
||||||
|
}
|
||||||
|
stuffdot(leave);
|
||||||
|
emitf(Xpopm);
|
||||||
|
}
|
||||||
|
int iscase(tree *t)
|
||||||
|
{
|
||||||
|
if(t->type!=SIMPLE) return 0;
|
||||||
|
do t=c0; while(t->type==ARGLIST);
|
||||||
|
return t->type==WORD && !t->quoted && strcmp(t->str, "case")==0;
|
||||||
|
}
|
||||||
|
code *codecopy(code *cp)
|
||||||
|
{
|
||||||
|
cp[0].i++;
|
||||||
|
return cp;
|
||||||
|
}
|
||||||
|
void codefree(code *cp)
|
||||||
|
{
|
||||||
|
code *p;
|
||||||
|
if(--cp[0].i!=0) return;
|
||||||
|
for(p=cp+1;p->f;p++){
|
||||||
|
if(p->f==Xappend || p->f==Xclose || p->f==Xread || p->f==Xwrite
|
||||||
|
|| p->f==Xasync || p->f==Xbackq || p->f==Xcase || p->f==Xfalse
|
||||||
|
|| p->f==Xfor || p->f==Xjump
|
||||||
|
|| p->f==Xsubshell || p->f==Xtrue) p++;
|
||||||
|
else if(p->f==Xdup || p->f==Xpipefd) p+=2;
|
||||||
|
else if(p->f==Xpipe) p+=4;
|
||||||
|
else if(p->f==Xword || p->f==Xdelhere) efree((++p)->s);
|
||||||
|
else if(p->f==Xfn){
|
||||||
|
efree(p[2].s);
|
||||||
|
p+=2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
efree((char *)cp);
|
||||||
|
}
|
||||||
902
src/cmd/rc/exec.c
Normal file
902
src/cmd/rc/exec.c
Normal file
@ -0,0 +1,902 @@
|
|||||||
|
#include "rc.h"
|
||||||
|
#include "getflags.h"
|
||||||
|
#include "exec.h"
|
||||||
|
#include "io.h"
|
||||||
|
#include "fns.h"
|
||||||
|
/*
|
||||||
|
* Start executing the given code at the given pc with the given redirection
|
||||||
|
*/
|
||||||
|
char *argv0="rc";
|
||||||
|
void start(code *c, int pc, var *local)
|
||||||
|
{
|
||||||
|
struct thread *p=new(struct thread);
|
||||||
|
p->code=codecopy(c);
|
||||||
|
p->pc=pc;
|
||||||
|
p->argv=0;
|
||||||
|
p->redir=p->startredir=runq?runq->redir:0;
|
||||||
|
p->local=local;
|
||||||
|
p->cmdfile=0;
|
||||||
|
p->cmdfd=0;
|
||||||
|
p->eof=0;
|
||||||
|
p->iflag=0;
|
||||||
|
p->lineno=1;
|
||||||
|
p->ret=runq;
|
||||||
|
runq=p;
|
||||||
|
}
|
||||||
|
word *newword(char *wd, word *next)
|
||||||
|
{
|
||||||
|
word *p=new(word);
|
||||||
|
p->word=strdup(wd);
|
||||||
|
p->next=next;
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
void pushword(char *wd)
|
||||||
|
{
|
||||||
|
if(runq->argv==0) panic("pushword but no argv!", 0);
|
||||||
|
runq->argv->words=newword(wd, runq->argv->words);
|
||||||
|
}
|
||||||
|
void popword(void){
|
||||||
|
word *p;
|
||||||
|
if(runq->argv==0) panic("popword but no argv!", 0);
|
||||||
|
p=runq->argv->words;
|
||||||
|
if(p==0) panic("popword but no word!", 0);
|
||||||
|
runq->argv->words=p->next;
|
||||||
|
efree(p->word);
|
||||||
|
efree((char *)p);
|
||||||
|
}
|
||||||
|
void freelist(word *w)
|
||||||
|
{
|
||||||
|
word *nw;
|
||||||
|
while(w){
|
||||||
|
nw=w->next;
|
||||||
|
efree(w->word);
|
||||||
|
efree((char *)w);
|
||||||
|
w=nw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void pushlist(void){
|
||||||
|
list *p=new(list);
|
||||||
|
p->next=runq->argv;
|
||||||
|
p->words=0;
|
||||||
|
runq->argv=p;
|
||||||
|
}
|
||||||
|
void poplist(void){
|
||||||
|
list *p=runq->argv;
|
||||||
|
if(p==0) panic("poplist but no argv", 0);
|
||||||
|
freelist(p->words);
|
||||||
|
runq->argv=p->next;
|
||||||
|
efree((char *)p);
|
||||||
|
}
|
||||||
|
int count(word *w)
|
||||||
|
{
|
||||||
|
int n;
|
||||||
|
for(n=0;w;n++) w=w->next;
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
void pushredir(int type, int from, int to){
|
||||||
|
redir * rp=new(redir);
|
||||||
|
rp->type=type;
|
||||||
|
rp->from=from;
|
||||||
|
rp->to=to;
|
||||||
|
rp->next=runq->redir;
|
||||||
|
runq->redir=rp;
|
||||||
|
}
|
||||||
|
var *newvar(char *name, var *next)
|
||||||
|
{
|
||||||
|
var *v=new(var);
|
||||||
|
v->name=name;
|
||||||
|
v->val=0;
|
||||||
|
v->fn=0;
|
||||||
|
v->changed=0;
|
||||||
|
v->fnchanged=0;
|
||||||
|
v->next=next;
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* get command line flags, initialize keywords & traps.
|
||||||
|
* get values from environment.
|
||||||
|
* set $pid, $cflag, $*
|
||||||
|
* fabricate bootstrap code and start it (*=(argv);. /usr/lib/rcmain $*)
|
||||||
|
* start interpreting code
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
code bootstrap[32];
|
||||||
|
char num[12], *rcmain;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
argc=getflags(argc, argv, "srdiIlxepvVc:1m:1[command]", 1);
|
||||||
|
if(argc==-1) usage("[file [arg ...]]");
|
||||||
|
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;
|
||||||
|
rcmain=flag['m']?flag['m'][0]:Rcmain();
|
||||||
|
err=openfd(2);
|
||||||
|
kinit();
|
||||||
|
Trapinit();
|
||||||
|
Vinit();
|
||||||
|
itoa(num, mypid=getpid());
|
||||||
|
setvar("pid", newword(num, (word *)0));
|
||||||
|
setvar("cflag", flag['c']?newword(flag['c'][0], (word *)0)
|
||||||
|
:(word *)0);
|
||||||
|
setvar("rcname", newword(argv[0], (word *)0));
|
||||||
|
i=0;
|
||||||
|
bootstrap[i++].i=1;
|
||||||
|
bootstrap[i++].f=Xmark;
|
||||||
|
bootstrap[i++].f=Xword;
|
||||||
|
bootstrap[i++].s="*";
|
||||||
|
bootstrap[i++].f=Xassign;
|
||||||
|
bootstrap[i++].f=Xmark;
|
||||||
|
bootstrap[i++].f=Xmark;
|
||||||
|
bootstrap[i++].f=Xword;
|
||||||
|
bootstrap[i++].s="*";
|
||||||
|
bootstrap[i++].f=Xdol;
|
||||||
|
bootstrap[i++].f=Xword;
|
||||||
|
bootstrap[i++].s=rcmain;
|
||||||
|
bootstrap[i++].f=Xword;
|
||||||
|
bootstrap[i++].s=".";
|
||||||
|
bootstrap[i++].f=Xsimple;
|
||||||
|
bootstrap[i++].f=Xexit;
|
||||||
|
bootstrap[i].i=0;
|
||||||
|
start(bootstrap, 1, (var *)0);
|
||||||
|
/* prime bootstrap argv */
|
||||||
|
pushlist();
|
||||||
|
argv0 = strdup(argv[0]);
|
||||||
|
for(i=argc-1;i!=0;--i) pushword(argv[i]);
|
||||||
|
for(;;){
|
||||||
|
if(flag['r']) pfnc(err, runq);
|
||||||
|
runq->pc++;
|
||||||
|
(*runq->code[runq->pc-1].f)();
|
||||||
|
if(ntrap) dotrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* Opcode routines
|
||||||
|
* Arguments on stack (...)
|
||||||
|
* Arguments in line [...]
|
||||||
|
* Code in line with jump around {...}
|
||||||
|
*
|
||||||
|
* Xappend(file)[fd] open file to append
|
||||||
|
* Xassign(name, val) assign val to name
|
||||||
|
* Xasync{... Xexit} make thread for {}, no wait
|
||||||
|
* Xbackq{... Xreturn} make thread for {}, push stdout
|
||||||
|
* Xbang complement condition
|
||||||
|
* Xcase(pat, value){...} exec code on match, leave (value) on
|
||||||
|
* stack
|
||||||
|
* Xclose[i] close file descriptor
|
||||||
|
* Xconc(left, right) concatenate, push results
|
||||||
|
* Xcount(name) push var count
|
||||||
|
* Xdelfn(name) delete function definition
|
||||||
|
* Xdeltraps(names) delete named traps
|
||||||
|
* Xdol(name) get variable value
|
||||||
|
* Xqdol(name) concatenate variable components
|
||||||
|
* Xdup[i j] dup file descriptor
|
||||||
|
* Xexit rc exits with status
|
||||||
|
* Xfalse{...} execute {} if false
|
||||||
|
* Xfn(name){... Xreturn} define function
|
||||||
|
* Xfor(var, list){... Xreturn} for loop
|
||||||
|
* Xjump[addr] goto
|
||||||
|
* Xlocal(name, val) create local variable, assign value
|
||||||
|
* Xmark mark stack
|
||||||
|
* Xmatch(pat, str) match pattern, set status
|
||||||
|
* Xpipe[i j]{... Xreturn}{... Xreturn} construct a pipe between 2 new threads,
|
||||||
|
* wait for both
|
||||||
|
* Xpipefd[type]{... Xreturn} connect {} to pipe (input or output,
|
||||||
|
* depending on type), push /dev/fd/??
|
||||||
|
* Xpopm(value) pop value from stack
|
||||||
|
* Xread(file)[fd] open file to read
|
||||||
|
* Xsettraps(names){... Xreturn} define trap functions
|
||||||
|
* Xshowtraps print trap list
|
||||||
|
* Xsimple(args) run command and wait
|
||||||
|
* Xreturn kill thread
|
||||||
|
* Xsubshell{... Xexit} execute {} in a subshell and wait
|
||||||
|
* Xtrue{...} execute {} if true
|
||||||
|
* Xunlocal delete local variable
|
||||||
|
* Xword[string] push string
|
||||||
|
* Xwrite(file)[fd] open file to write
|
||||||
|
*/
|
||||||
|
void Xappend(void){
|
||||||
|
char *file;
|
||||||
|
int f;
|
||||||
|
switch(count(runq->argv->words)){
|
||||||
|
default: Xerror1(">> requires singleton"); return;
|
||||||
|
case 0: Xerror1(">> requires file"); return;
|
||||||
|
case 1: break;
|
||||||
|
}
|
||||||
|
file=runq->argv->words->word;
|
||||||
|
if((f=open(file, 1))<0 && (f=Creat(file))<0){
|
||||||
|
pfmt(err, "%s: ", file);
|
||||||
|
Xerror("can't open");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Seek(f, 0L, 2);
|
||||||
|
pushredir(ROPEN, f, runq->code[runq->pc].i);
|
||||||
|
runq->pc++;
|
||||||
|
poplist();
|
||||||
|
}
|
||||||
|
void Xasync(void){
|
||||||
|
int null=open("/dev/null", 0);
|
||||||
|
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:
|
||||||
|
pushredir(ROPEN, null, 0);
|
||||||
|
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("");
|
||||||
|
}
|
||||||
|
void Xbang(void){
|
||||||
|
setstatus(truestatus()?"false":"");
|
||||||
|
}
|
||||||
|
void Xclose(void){
|
||||||
|
pushredir(RCLOSE, runq->code[runq->pc].i, 0);
|
||||||
|
runq->pc++;
|
||||||
|
}
|
||||||
|
void Xdup(void){
|
||||||
|
pushredir(RDUP, runq->code[runq->pc].i, runq->code[runq->pc+1].i);
|
||||||
|
runq->pc+=2;
|
||||||
|
}
|
||||||
|
void Xeflag(void){
|
||||||
|
if(eflagok && !truestatus()) Xexit();
|
||||||
|
}
|
||||||
|
void Xexit(void){
|
||||||
|
struct var *trapreq;
|
||||||
|
struct word *starval;
|
||||||
|
static int beenhere=0;
|
||||||
|
if(getpid()==mypid && !beenhere){
|
||||||
|
trapreq=vlook("sigexit");
|
||||||
|
if(trapreq->fn){
|
||||||
|
beenhere=1;
|
||||||
|
--runq->pc;
|
||||||
|
starval=vlook("*")->val;
|
||||||
|
start(trapreq->fn, trapreq->pc, (struct var *)0);
|
||||||
|
runq->local=newvar(strdup("*"), runq->local);
|
||||||
|
runq->local->val=copywords(starval, (struct word *)0);
|
||||||
|
runq->local->changed=1;
|
||||||
|
runq->redir=runq->startredir=0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Exit(getstatus());
|
||||||
|
}
|
||||||
|
void Xfalse(void){
|
||||||
|
if(truestatus()) runq->pc=runq->code[runq->pc].i;
|
||||||
|
else runq->pc++;
|
||||||
|
}
|
||||||
|
int ifnot; /* dynamic if not flag */
|
||||||
|
void Xifnot(void){
|
||||||
|
if(ifnot)
|
||||||
|
runq->pc++;
|
||||||
|
else
|
||||||
|
runq->pc=runq->code[runq->pc].i;
|
||||||
|
}
|
||||||
|
void Xjump(void){
|
||||||
|
runq->pc=runq->code[runq->pc].i;
|
||||||
|
}
|
||||||
|
void Xmark(void){
|
||||||
|
pushlist();
|
||||||
|
}
|
||||||
|
void Xpopm(void){
|
||||||
|
poplist();
|
||||||
|
}
|
||||||
|
void Xread(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, 0))<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)
|
||||||
|
Xpopredir();
|
||||||
|
}
|
||||||
|
void Xpopredir(void){
|
||||||
|
struct redir *rp=runq->redir;
|
||||||
|
if(rp==0) panic("turfredir null!", 0);
|
||||||
|
runq->redir=rp->next;
|
||||||
|
if(rp->type==ROPEN) close(rp->from);
|
||||||
|
efree((char *)rp);
|
||||||
|
}
|
||||||
|
void Xreturn(void){
|
||||||
|
struct thread *p=runq;
|
||||||
|
turfredir();
|
||||||
|
while(p->argv) poplist();
|
||||||
|
codefree(p->code);
|
||||||
|
runq=p->ret;
|
||||||
|
efree((char *)p);
|
||||||
|
if(runq==0) Exit(getstatus());
|
||||||
|
}
|
||||||
|
void Xtrue(void){
|
||||||
|
if(truestatus()) runq->pc++;
|
||||||
|
else runq->pc=runq->code[runq->pc].i;
|
||||||
|
}
|
||||||
|
void Xif(void){
|
||||||
|
ifnot=1;
|
||||||
|
if(truestatus()) runq->pc++;
|
||||||
|
else runq->pc=runq->code[runq->pc].i;
|
||||||
|
}
|
||||||
|
void Xwastrue(void){
|
||||||
|
ifnot=0;
|
||||||
|
}
|
||||||
|
void Xword(void){
|
||||||
|
pushword(runq->code[runq->pc++].s);
|
||||||
|
}
|
||||||
|
void Xwrite(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=Creat(file))<0){
|
||||||
|
pfmt(err, "%s: ", file);
|
||||||
|
Xerror("can't open");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
pushredir(ROPEN, f, runq->code[runq->pc].i);
|
||||||
|
runq->pc++;
|
||||||
|
poplist();
|
||||||
|
}
|
||||||
|
char *list2str(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 Xmatch(void){
|
||||||
|
word *p;
|
||||||
|
char *subject;
|
||||||
|
subject=list2str(runq->argv->words);
|
||||||
|
setstatus("no match");
|
||||||
|
for(p=runq->argv->next->words;p;p=p->next)
|
||||||
|
if(match(subject, p->word, '\0')){
|
||||||
|
setstatus("");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
efree(subject);
|
||||||
|
poplist();
|
||||||
|
poplist();
|
||||||
|
}
|
||||||
|
void Xcase(void){
|
||||||
|
word *p;
|
||||||
|
char *s;
|
||||||
|
int ok=0;
|
||||||
|
s=list2str(runq->argv->next->words);
|
||||||
|
for(p=runq->argv->words;p;p=p->next){
|
||||||
|
if(match(s, p->word, '\0')){
|
||||||
|
ok=1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
efree(s);
|
||||||
|
if(ok)
|
||||||
|
runq->pc++;
|
||||||
|
else
|
||||||
|
runq->pc=runq->code[runq->pc].i;
|
||||||
|
poplist();
|
||||||
|
}
|
||||||
|
word *conclist(word *lp, word *rp, word *tail)
|
||||||
|
{
|
||||||
|
char *buf;
|
||||||
|
word *v;
|
||||||
|
if(lp->next || rp->next)
|
||||||
|
tail=conclist(lp->next==0?lp:lp->next, rp->next==0?rp:rp->next,
|
||||||
|
tail);
|
||||||
|
buf=emalloc(strlen(lp->word)+strlen(rp->word)+1);
|
||||||
|
strcpy(buf, lp->word);
|
||||||
|
strcat(buf, rp->word);
|
||||||
|
v=newword(buf, tail);
|
||||||
|
efree(buf);
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
void Xconc(void){
|
||||||
|
word *lp=runq->argv->words;
|
||||||
|
word *rp=runq->argv->next->words;
|
||||||
|
word *vp=runq->argv->next->next->words;
|
||||||
|
int lc=count(lp), rc=count(rp);
|
||||||
|
if(lc!=0 || rc!=0){
|
||||||
|
if(lc==0 || rc==0){
|
||||||
|
Xerror1("null list in concatenation");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(lc!=1 && rc!=1 && lc!=rc){
|
||||||
|
Xerror1("mismatched list lengths in concatenation");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
vp=conclist(lp, rp, vp);
|
||||||
|
}
|
||||||
|
poplist();
|
||||||
|
poplist();
|
||||||
|
runq->argv->words=vp;
|
||||||
|
}
|
||||||
|
void Xassign(void){
|
||||||
|
var *v;
|
||||||
|
if(count(runq->argv->words)!=1){
|
||||||
|
Xerror1("variable name not singleton!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
deglob(runq->argv->words->word);
|
||||||
|
v=vlook(runq->argv->words->word);
|
||||||
|
poplist();
|
||||||
|
globlist();
|
||||||
|
freewords(v->val);
|
||||||
|
v->val=runq->argv->words;
|
||||||
|
v->changed=1;
|
||||||
|
runq->argv->words=0;
|
||||||
|
poplist();
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* copy arglist a, adding the copy to the front of tail
|
||||||
|
*/
|
||||||
|
word *copywords(word *a, word *tail)
|
||||||
|
{
|
||||||
|
word *v=0, **end;
|
||||||
|
for(end=&v;a;a=a->next,end=&(*end)->next)
|
||||||
|
*end=newword(a->word, 0);
|
||||||
|
*end=tail;
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
void Xdol(void){
|
||||||
|
word *a, *star;
|
||||||
|
char *s, *t;
|
||||||
|
int n;
|
||||||
|
if(count(runq->argv->words)!=1){
|
||||||
|
Xerror1("variable name not singleton!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
s=runq->argv->words->word;
|
||||||
|
deglob(s);
|
||||||
|
n=0;
|
||||||
|
for(t=s;'0'<=*t && *t<='9';t++) n=n*10+*t-'0';
|
||||||
|
a=runq->argv->next->words;
|
||||||
|
if(n==0 || *t)
|
||||||
|
a=copywords(vlook(s)->val, a);
|
||||||
|
else{
|
||||||
|
star=vlook("*")->val;
|
||||||
|
if(star && 1<=n && n<=count(star)){
|
||||||
|
while(--n) star=star->next;
|
||||||
|
a=newword(star->word, a);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
poplist();
|
||||||
|
runq->argv->words=a;
|
||||||
|
}
|
||||||
|
void Xqdol(void){
|
||||||
|
word *a, *p;
|
||||||
|
char *s;
|
||||||
|
int n;
|
||||||
|
if(count(runq->argv->words)!=1){
|
||||||
|
Xerror1("variable name not singleton!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
s=runq->argv->words->word;
|
||||||
|
deglob(s);
|
||||||
|
a=vlook(s)->val;
|
||||||
|
poplist();
|
||||||
|
n=count(a);
|
||||||
|
if(n==0){
|
||||||
|
pushword("");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for(p=a;p;p=p->next) n+=strlen(p->word);
|
||||||
|
s=emalloc(n);
|
||||||
|
if(a){
|
||||||
|
strcpy(s, a->word);
|
||||||
|
for(p=a->next;p;p=p->next){
|
||||||
|
strcat(s, " ");
|
||||||
|
strcat(s, p->word);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
s[0]='\0';
|
||||||
|
pushword(s);
|
||||||
|
efree(s);
|
||||||
|
}
|
||||||
|
word *subwords(word *val, int len, word *sub, word *a)
|
||||||
|
{
|
||||||
|
int n;
|
||||||
|
char *s;
|
||||||
|
if(!sub) return a;
|
||||||
|
a=subwords(val, len, sub->next, a);
|
||||||
|
s=sub->word;
|
||||||
|
deglob(s);
|
||||||
|
n=0;
|
||||||
|
while('0'<=*s && *s<='9') n=n*10+ *s++ -'0';
|
||||||
|
if(n<1 || len<n) return a;
|
||||||
|
for(;n!=1;--n) val=val->next;
|
||||||
|
return newword(val->word, a);
|
||||||
|
}
|
||||||
|
void Xsub(void){
|
||||||
|
word *a, *v;
|
||||||
|
char *s;
|
||||||
|
if(count(runq->argv->next->words)!=1){
|
||||||
|
Xerror1("variable name not singleton!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
s=runq->argv->next->words->word;
|
||||||
|
deglob(s);
|
||||||
|
a=runq->argv->next->next->words;
|
||||||
|
v=vlook(s)->val;
|
||||||
|
a=subwords(v, count(v), runq->argv->words, a);
|
||||||
|
poplist();
|
||||||
|
poplist();
|
||||||
|
runq->argv->words=a;
|
||||||
|
}
|
||||||
|
void Xcount(void){
|
||||||
|
word *a;
|
||||||
|
char *s, *t;
|
||||||
|
int n;
|
||||||
|
char num[12];
|
||||||
|
if(count(runq->argv->words)!=1){
|
||||||
|
Xerror1("variable name not singleton!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
s=runq->argv->words->word;
|
||||||
|
deglob(s);
|
||||||
|
n=0;
|
||||||
|
for(t=s;'0'<=*t && *t<='9';t++) n=n*10+*t-'0';
|
||||||
|
if(n==0 || *t){
|
||||||
|
a=vlook(s)->val;
|
||||||
|
itoa(num, count(a));
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
a=vlook("*")->val;
|
||||||
|
itoa(num, a && 1<=n && n<=count(a)?1:0);
|
||||||
|
}
|
||||||
|
poplist();
|
||||||
|
pushword(num);
|
||||||
|
}
|
||||||
|
void Xlocal(void){
|
||||||
|
if(count(runq->argv->words)!=1){
|
||||||
|
Xerror1("variable name must be singleton\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
deglob(runq->argv->words->word);
|
||||||
|
runq->local=newvar(strdup(runq->argv->words->word), runq->local);
|
||||||
|
runq->local->val=copywords(runq->argv->next->words, (word *)0);
|
||||||
|
runq->local->changed=1;
|
||||||
|
poplist();
|
||||||
|
poplist();
|
||||||
|
}
|
||||||
|
void Xunlocal(void){
|
||||||
|
var *v=runq->local, *hid;
|
||||||
|
if(v==0) panic("Xunlocal: no locals!", 0);
|
||||||
|
runq->local=v->next;
|
||||||
|
hid=vlook(v->name);
|
||||||
|
hid->changed=1;
|
||||||
|
efree(v->name);
|
||||||
|
freewords(v->val);
|
||||||
|
efree((char *)v);
|
||||||
|
}
|
||||||
|
void freewords(word *w)
|
||||||
|
{
|
||||||
|
word *nw;
|
||||||
|
while(w){
|
||||||
|
efree(w->word);
|
||||||
|
nw=w->next;
|
||||||
|
efree((char *)w);
|
||||||
|
w=nw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void Xfn(void){
|
||||||
|
var *v;
|
||||||
|
word *a;
|
||||||
|
int end;
|
||||||
|
end=runq->code[runq->pc].i;
|
||||||
|
for(a=runq->argv->words;a;a=a->next){
|
||||||
|
v=gvlook(a->word);
|
||||||
|
if(v->fn) codefree(v->fn);
|
||||||
|
v->fn=codecopy(runq->code);
|
||||||
|
v->pc=runq->pc+2;
|
||||||
|
v->fnchanged=1;
|
||||||
|
}
|
||||||
|
runq->pc=end;
|
||||||
|
poplist();
|
||||||
|
}
|
||||||
|
void Xdelfn(void){
|
||||||
|
var *v;
|
||||||
|
word *a;
|
||||||
|
for(a=runq->argv->words;a;a=a->next){
|
||||||
|
v=gvlook(a->word);
|
||||||
|
if(v->fn) codefree(v->fn);
|
||||||
|
v->fn=0;
|
||||||
|
v->fnchanged=1;
|
||||||
|
}
|
||||||
|
poplist();
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
char *concstatus(char *s, char *t)
|
||||||
|
{
|
||||||
|
static char v[NSTATUS+1];
|
||||||
|
int n=strlen(s);
|
||||||
|
strncpy(v, s, NSTATUS);
|
||||||
|
if(n<NSTATUS){
|
||||||
|
v[n]='|';
|
||||||
|
strncpy(v+n+1, t, NSTATUS-n-1);
|
||||||
|
}
|
||||||
|
v[NSTATUS]='\0';
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
void Xpipewait(void){
|
||||||
|
char status[NSTATUS+1];
|
||||||
|
if(runq->pid==-1)
|
||||||
|
setstatus(concstatus(runq->status, getstatus()));
|
||||||
|
else{
|
||||||
|
strncpy(status, getstatus(), NSTATUS);
|
||||||
|
status[NSTATUS]='\0';
|
||||||
|
Waitfor(runq->pid, 1);
|
||||||
|
runq->pid=-1;
|
||||||
|
setstatus(concstatus(getstatus(), status));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void Xrdcmds(void){
|
||||||
|
struct thread *p=runq;
|
||||||
|
word *prompt;
|
||||||
|
flush(err);
|
||||||
|
nerror=0;
|
||||||
|
if(flag['s'] && !truestatus())
|
||||||
|
pfmt(err, "status=%v\n", vlook("status")->val);
|
||||||
|
if(runq->iflag){
|
||||||
|
prompt=vlook("prompt")->val;
|
||||||
|
if(prompt)
|
||||||
|
promptstr=prompt->word;
|
||||||
|
else
|
||||||
|
promptstr="% ";
|
||||||
|
}
|
||||||
|
Noerror();
|
||||||
|
if(yyparse()){
|
||||||
|
if(!p->iflag || p->eof && !Eintr()){
|
||||||
|
if(p->cmdfile) efree(p->cmdfile);
|
||||||
|
closeio(p->cmdfd);
|
||||||
|
Xreturn(); /* should this be omitted? */
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
if(Eintr()){
|
||||||
|
pchr(err, '\n');
|
||||||
|
p->eof=0;
|
||||||
|
}
|
||||||
|
--p->pc; /* go back for next command */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
ntrap = 0; /* avoid double-interrupts during blocked writes */
|
||||||
|
--p->pc; /* re-execute Xrdcmds after codebuf runs */
|
||||||
|
start(codebuf, 1, runq->local);
|
||||||
|
}
|
||||||
|
freenodes();
|
||||||
|
}
|
||||||
|
void Xerror(char *s)
|
||||||
|
{
|
||||||
|
if(strcmp(argv0, "rc")==0 || strcmp(argv0, "/bin/rc")==0)
|
||||||
|
pfmt(err, "rc: %s: %r\n", s);
|
||||||
|
else
|
||||||
|
pfmt(err, "rc (%s): %s: %r\n", argv0, s);
|
||||||
|
flush(err);
|
||||||
|
while(!runq->iflag) Xreturn();
|
||||||
|
}
|
||||||
|
void Xerror1(char *s)
|
||||||
|
{
|
||||||
|
if(strcmp(argv0, "rc")==0 || strcmp(argv0, "/bin/rc")==0)
|
||||||
|
pfmt(err, "rc: %s\n", s);
|
||||||
|
else
|
||||||
|
pfmt(err, "rc (%s): %s\n", argv0, s);
|
||||||
|
flush(err);
|
||||||
|
while(!runq->iflag) Xreturn();
|
||||||
|
}
|
||||||
|
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);
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
char *getstatus(void){
|
||||||
|
var *status=vlook("status");
|
||||||
|
return status->val?status->val->word:"";
|
||||||
|
}
|
||||||
|
int truestatus(void){
|
||||||
|
char *s;
|
||||||
|
for(s=getstatus();*s;s++)
|
||||||
|
if(*s!='|' && *s!='0') return 0;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
void Xdelhere(void){
|
||||||
|
Unlink(runq->code[runq->pc++].s);
|
||||||
|
}
|
||||||
|
void Xfor(void){
|
||||||
|
if(runq->argv->words==0){
|
||||||
|
poplist();
|
||||||
|
runq->pc=runq->code[runq->pc].i;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
freelist(runq->local->val);
|
||||||
|
runq->local->val=runq->argv->words;
|
||||||
|
runq->local->changed=1;
|
||||||
|
runq->argv->words=runq->argv->words->next;
|
||||||
|
runq->local->val->next=0;
|
||||||
|
runq->pc++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void Xglob(void){
|
||||||
|
globlist();
|
||||||
|
}
|
||||||
71
src/cmd/rc/exec.h
Normal file
71
src/cmd/rc/exec.h
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
/*
|
||||||
|
* Definitions used in the interpreter
|
||||||
|
*/
|
||||||
|
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 Xexit(void), Xfalse(void), Xfn(void), Xfor(void), Xglob(void);
|
||||||
|
extern void Xjump(void), Xmark(void), Xmatch(void), Xpipe(void), Xread(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 Xlocal(void), Xunlocal(void), Xassign(void), Xsimple(void), Xpopm(void);
|
||||||
|
extern void Xrdcmds(void), Xwastrue(void), Xif(void), Xifnot(void), Xpipewait(void);
|
||||||
|
extern void Xdelhere(void), Xpopredir(void), Xsub(void), Xeflag(void), Xsettrue(void);
|
||||||
|
extern void Xerror(char*);
|
||||||
|
extern void Xerror1(char*);
|
||||||
|
/*
|
||||||
|
* word lists are in correct order,
|
||||||
|
* i.e. word0->word1->word2->word3->0
|
||||||
|
*/
|
||||||
|
struct word{
|
||||||
|
char *word;
|
||||||
|
word *next;
|
||||||
|
};
|
||||||
|
struct list{
|
||||||
|
word *words;
|
||||||
|
list *next;
|
||||||
|
};
|
||||||
|
word *newword(char *, word *), *copywords(word *, word *);
|
||||||
|
struct redir{
|
||||||
|
char type; /* what to do */
|
||||||
|
short from, to; /* what to do it to */
|
||||||
|
struct redir *next; /* what else to do (reverse order) */
|
||||||
|
};
|
||||||
|
#define NSTATUS ERRMAX /* length of status (from plan 9) */
|
||||||
|
/*
|
||||||
|
* redir types
|
||||||
|
*/
|
||||||
|
#define ROPEN 1 /* dup2(from, to); close(from); */
|
||||||
|
#define RDUP 2 /* dup2(from, to); */
|
||||||
|
#define RCLOSE 3 /* close(from); */
|
||||||
|
struct thread{
|
||||||
|
union code *code; /* code for this thread */
|
||||||
|
int pc; /* code[pc] is the next instruction */
|
||||||
|
struct list *argv; /* argument stack */
|
||||||
|
struct redir *redir; /* redirection stack */
|
||||||
|
struct redir *startredir; /* redir inheritance point */
|
||||||
|
struct var *local; /* list of local variables */
|
||||||
|
char *cmdfile; /* file name in Xrdcmd */
|
||||||
|
struct io *cmdfd; /* file descriptor for Xrdcmd */
|
||||||
|
int iflast; /* static `if not' checking */
|
||||||
|
int eof; /* is cmdfd at eof? */
|
||||||
|
int iflag; /* interactive? */
|
||||||
|
int lineno; /* linenumber */
|
||||||
|
int pid; /* process for Xpipewait to wait for */
|
||||||
|
char status[NSTATUS]; /* status for Xpipewait */
|
||||||
|
tree *treenodes; /* tree nodes created by this process */
|
||||||
|
thread *ret; /* who continues when this finishes */
|
||||||
|
};
|
||||||
|
thread *runq;
|
||||||
|
code *codecopy(code*);
|
||||||
|
code *codebuf; /* compiler output */
|
||||||
|
int ntrap; /* number of outstanding traps */
|
||||||
|
int trap[NSIG]; /* number of outstanding traps per type */
|
||||||
|
extern struct builtin{
|
||||||
|
char *name;
|
||||||
|
void (*fnc)(void);
|
||||||
|
}Builtin[];
|
||||||
|
int eflagok; /* kludge flag so that -e doesn't exit in startup */
|
||||||
|
void execcd(void), execwhatis(void), execeval(void), execexec(void);
|
||||||
|
void execexit(void), execshift(void);
|
||||||
|
void execwait(void), execumask(void), execdot(void), execflag(void);
|
||||||
|
void execfunc(var*), execcmds(io *);
|
||||||
162
src/cmd/rc/fmtquote.c
Normal file
162
src/cmd/rc/fmtquote.c
Normal file
@ -0,0 +1,162 @@
|
|||||||
|
/*
|
||||||
|
* The authors of this software are Rob Pike and Ken Thompson.
|
||||||
|
* Copyright (c) 2002 by Lucent Technologies.
|
||||||
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
|
* purpose without fee is hereby granted, provided that this entire notice
|
||||||
|
* is included in all copies of any software which is or includes a copy
|
||||||
|
* or modification of this software and in all copies of the supporting
|
||||||
|
* documentation for such software.
|
||||||
|
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
|
||||||
|
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
|
||||||
|
* REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
|
||||||
|
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
|
||||||
|
*/
|
||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
#include "fmt.h"
|
||||||
|
#include "fmtdef.h"
|
||||||
|
|
||||||
|
extern int (*doquote)(int);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* How many bytes of output UTF will be produced by quoting (if necessary) this string?
|
||||||
|
* How many runes? How much of the input will be consumed?
|
||||||
|
* The parameter q is filled in by _quotesetup.
|
||||||
|
* The string may be UTF or Runes (s or r).
|
||||||
|
* Return count does not include NUL.
|
||||||
|
* Terminate the scan at the first of:
|
||||||
|
* NUL in input
|
||||||
|
* count exceeded in input
|
||||||
|
* count exceeded on output
|
||||||
|
* *ninp is set to number of input bytes accepted.
|
||||||
|
* nin may be <0 initially, to avoid checking input by count.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
__quotesetup(char *s, int nin, int nout, Quoteinfo *q, int sharp)
|
||||||
|
{
|
||||||
|
int c;
|
||||||
|
|
||||||
|
q->quoted = 0;
|
||||||
|
q->nbytesout = 0;
|
||||||
|
q->nrunesout = 0;
|
||||||
|
q->nbytesin = 0;
|
||||||
|
q->nrunesin = 0;
|
||||||
|
if(sharp || nin==0 || *s=='\0'){
|
||||||
|
if(nout < 2)
|
||||||
|
return;
|
||||||
|
q->quoted = 1;
|
||||||
|
q->nbytesout = 2;
|
||||||
|
q->nrunesout = 2;
|
||||||
|
}
|
||||||
|
for(; nin!=0; nin-=1){
|
||||||
|
c = *s;
|
||||||
|
|
||||||
|
if(c == '\0')
|
||||||
|
break;
|
||||||
|
if(q->nrunesout+1 > nout)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if((c <= L' ') || (c == L'\'') || (doquote!=nil && doquote(c))){
|
||||||
|
if(!q->quoted){
|
||||||
|
if(1+q->nrunesout+1+1 > nout) /* no room for quotes */
|
||||||
|
break;
|
||||||
|
q->nrunesout += 2; /* include quotes */
|
||||||
|
q->nbytesout += 2; /* include quotes */
|
||||||
|
q->quoted = 1;
|
||||||
|
}
|
||||||
|
if(c == '\'') {
|
||||||
|
q->nbytesout++;
|
||||||
|
q->nrunesout++; /* quotes reproduce as two characters */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* advance input */
|
||||||
|
s++;
|
||||||
|
q->nbytesin++;
|
||||||
|
q->nrunesin++;
|
||||||
|
|
||||||
|
/* advance output */
|
||||||
|
q->nbytesout++;
|
||||||
|
q->nrunesout++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
qstrfmt(char *sin, Quoteinfo *q, Fmt *f)
|
||||||
|
{
|
||||||
|
int r;
|
||||||
|
char *t, *s, *m, *me;
|
||||||
|
ulong fl;
|
||||||
|
int nc, w;
|
||||||
|
|
||||||
|
m = sin;
|
||||||
|
me = m + q->nbytesin;
|
||||||
|
|
||||||
|
w = f->width;
|
||||||
|
fl = f->flags;
|
||||||
|
if(!(fl & FmtLeft) && __fmtpad(f, w - q->nbytesout) < 0)
|
||||||
|
return -1;
|
||||||
|
t = f->to;
|
||||||
|
s = f->stop;
|
||||||
|
FMTCHAR(f, t, s, '\'');
|
||||||
|
for(nc = q->nrunesin; nc > 0; nc--){
|
||||||
|
r = *(uchar*)m++;
|
||||||
|
FMTCHAR(f, t, s, r);
|
||||||
|
if(r == '\'')
|
||||||
|
FMTCHAR(f, t, s, r);
|
||||||
|
}
|
||||||
|
|
||||||
|
FMTCHAR(f, t, s, '\'');
|
||||||
|
f->nfmt += t - (char *)f->to;
|
||||||
|
f->to = t;
|
||||||
|
if(fl & FmtLeft && __fmtpad(f, w - q->nbytesout) < 0)
|
||||||
|
return -1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
__quotestrfmt(int runesin, Fmt *f)
|
||||||
|
{
|
||||||
|
int outlen;
|
||||||
|
char *s;
|
||||||
|
Quoteinfo q;
|
||||||
|
|
||||||
|
f->flags &= ~FmtPrec; /* ignored for %q %Q, so disable for %s %S in easy case */
|
||||||
|
s = va_arg(f->args, char *);
|
||||||
|
if(!s)
|
||||||
|
return __fmtcpy(f, "<nil>", 5, 5);
|
||||||
|
|
||||||
|
if(f->flush)
|
||||||
|
outlen = 0x7FFFFFFF; /* if we can flush, no output limit */
|
||||||
|
else
|
||||||
|
outlen = (char*)f->stop - (char*)f->to;
|
||||||
|
|
||||||
|
__quotesetup(s, -1, outlen, &q, f->flags&FmtSharp);
|
||||||
|
|
||||||
|
if(!q.quoted)
|
||||||
|
return __fmtcpy(f, s, q.nrunesin, q.nbytesin);
|
||||||
|
return qstrfmt(s, &q, f);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
quotestrfmt(Fmt *f)
|
||||||
|
{
|
||||||
|
return __quotestrfmt(0, f);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
quotefmtinstall(void)
|
||||||
|
{
|
||||||
|
fmtinstall('q', quotestrfmt);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
__needsquotes(char *s, int *quotelenp)
|
||||||
|
{
|
||||||
|
Quoteinfo q;
|
||||||
|
|
||||||
|
__quotesetup(s, -1, 0x7FFFFFFF, &q, 0);
|
||||||
|
*quotelenp = q.nbytesout;
|
||||||
|
|
||||||
|
return q.quoted;
|
||||||
|
}
|
||||||
58
src/cmd/rc/fns.h
Normal file
58
src/cmd/rc/fns.h
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
void Abort(void);
|
||||||
|
void Closedir(int);
|
||||||
|
int Creat(char*);
|
||||||
|
int Dup(int, int);
|
||||||
|
int Dup1(int);
|
||||||
|
int Eintr(void);
|
||||||
|
int Executable(char*);
|
||||||
|
void Execute(word*, word*);
|
||||||
|
void Exit(char*);
|
||||||
|
int Globsize(char*);
|
||||||
|
int Isatty(int);
|
||||||
|
void Memcpy(char*, char*, long);
|
||||||
|
void Noerror(void);
|
||||||
|
int Opendir(char*);
|
||||||
|
long Read(int, char*, long);
|
||||||
|
int Readdir(int, char*);
|
||||||
|
long Seek(int, long, long);
|
||||||
|
void Trapinit(void);
|
||||||
|
void Unlink(char*);
|
||||||
|
void Updenv(void);
|
||||||
|
void Vinit(void);
|
||||||
|
int Waitfor(int, int);
|
||||||
|
long Write(int, char*, long);
|
||||||
|
int advance(void);
|
||||||
|
int back(int);
|
||||||
|
void cleanhere(char*);
|
||||||
|
void codefree(code*);
|
||||||
|
int compile(tree*);
|
||||||
|
char * list2str(word*);
|
||||||
|
int count(word*);
|
||||||
|
void deglob(char*);
|
||||||
|
void dotrap(void);
|
||||||
|
void freenodes(void);
|
||||||
|
void freewords(word*);
|
||||||
|
void globlist(void);
|
||||||
|
int idchr(int);
|
||||||
|
void itoa(char*, long);
|
||||||
|
void kinit(void);
|
||||||
|
int match(char*, char*, int);
|
||||||
|
int matchfn(char*, char*);
|
||||||
|
void panic(char*, int);
|
||||||
|
void poplist(void);
|
||||||
|
void popword(void);
|
||||||
|
void pprompt(void);
|
||||||
|
void pushlist(void);
|
||||||
|
void pushredir(int, int, int);
|
||||||
|
void pushword(char*);
|
||||||
|
void readhere(void);
|
||||||
|
void setstatus(char*);
|
||||||
|
void setvar(char*, word*);
|
||||||
|
void skipnl(void);
|
||||||
|
void start(code*, int, var*);
|
||||||
|
int truestatus(void);
|
||||||
|
void usage(char*);
|
||||||
|
int wordchr(int);
|
||||||
|
void yyerror(char*);
|
||||||
|
int yylex(void);
|
||||||
|
int yyparse(void);
|
||||||
217
src/cmd/rc/getflags.c
Normal file
217
src/cmd/rc/getflags.c
Normal file
@ -0,0 +1,217 @@
|
|||||||
|
/*% cyntax -DTEST % && cc -DTEST -go # %
|
||||||
|
*/
|
||||||
|
#include "rc.h"
|
||||||
|
#include "getflags.h"
|
||||||
|
#include "fns.h"
|
||||||
|
char *flagset[]={"<flag>"};
|
||||||
|
char **flag[NFLAG];
|
||||||
|
char cmdline[NCMDLINE+1];
|
||||||
|
char *cmdname;
|
||||||
|
static char *flagarg="";
|
||||||
|
static void reverse(char**, char**);
|
||||||
|
static int scanflag(int, char*);
|
||||||
|
static void errn(char*, int);
|
||||||
|
static void errs(char*);
|
||||||
|
static void errc(int);
|
||||||
|
static int reason;
|
||||||
|
#define RESET 1
|
||||||
|
#define FEWARGS 2
|
||||||
|
#define FLAGSYN 3
|
||||||
|
#define BADFLAG 4
|
||||||
|
static int badflag;
|
||||||
|
int getflags(int argc, char *argv[], char *flags, int stop)
|
||||||
|
{
|
||||||
|
char *s, *t;
|
||||||
|
int i, j, c, count;
|
||||||
|
flagarg=flags;
|
||||||
|
if(cmdname==0) cmdname=argv[0];
|
||||||
|
s=cmdline;
|
||||||
|
for(i=0;i!=argc;i++){
|
||||||
|
for(t=argv[i];*t;t++)
|
||||||
|
if(s!=&cmdline[NCMDLINE])
|
||||||
|
*s++=*t;
|
||||||
|
if(i!=argc-1 && s!=&cmdline[NCMDLINE])
|
||||||
|
*s++=' ';
|
||||||
|
}
|
||||||
|
*s='\0';
|
||||||
|
i=1;
|
||||||
|
while(i!=argc){
|
||||||
|
if(argv[i][0]!='-' || argv[i][1]=='\0'){
|
||||||
|
if(stop) return argc;
|
||||||
|
i++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
s=argv[i]+1;
|
||||||
|
while(*s){
|
||||||
|
c=*s++;
|
||||||
|
count=scanflag(c, flags);
|
||||||
|
if(count==-1) return -1;
|
||||||
|
if(flag[c]){ reason=RESET; badflag=c; return -1; }
|
||||||
|
if(count==0){
|
||||||
|
flag[c]=flagset;
|
||||||
|
if(*s=='\0'){
|
||||||
|
for(j=i+1;j<=argc;j++)
|
||||||
|
argv[j-1]=argv[j];
|
||||||
|
--argc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
if(*s=='\0'){
|
||||||
|
for(j=i+1;j<=argc;j++)
|
||||||
|
argv[j-1]=argv[j];
|
||||||
|
--argc;
|
||||||
|
s=argv[i];
|
||||||
|
}
|
||||||
|
if(argc-i<count){
|
||||||
|
reason=FEWARGS;
|
||||||
|
badflag=c;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
reverse(argv+i, argv+argc);
|
||||||
|
reverse(argv+i, argv+argc-count);
|
||||||
|
reverse(argv+argc-count+1, argv+argc);
|
||||||
|
argc-=count;
|
||||||
|
flag[c]=argv+argc+1;
|
||||||
|
flag[c][0]=s;
|
||||||
|
s="";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return argc;
|
||||||
|
}
|
||||||
|
static void reverse(char **p, char **q)
|
||||||
|
{
|
||||||
|
char *t;
|
||||||
|
for(;p<q;p++,--q){ t=*p; *p=*q; *q=t; }
|
||||||
|
}
|
||||||
|
static int scanflag(int c, char *f)
|
||||||
|
{
|
||||||
|
int fc, count;
|
||||||
|
if(0<=c && c<NFLAG) while(*f){
|
||||||
|
if(*f==' '){
|
||||||
|
f++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
fc=*f++;
|
||||||
|
if(*f==':'){
|
||||||
|
f++;
|
||||||
|
if(*f<'0' || '9'<*f){ reason=FLAGSYN; return -1; }
|
||||||
|
count=0;
|
||||||
|
while('0'<=*f && *f<='9') count=count*10+*f++-'0';
|
||||||
|
}
|
||||||
|
else
|
||||||
|
count=0;
|
||||||
|
if(*f=='['){
|
||||||
|
do{
|
||||||
|
f++;
|
||||||
|
if(*f=='\0'){ reason=FLAGSYN; return -1; }
|
||||||
|
}while(*f!=']');
|
||||||
|
f++;
|
||||||
|
}
|
||||||
|
if(c==fc) return count;
|
||||||
|
}
|
||||||
|
reason=BADFLAG;
|
||||||
|
badflag=c;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
void usage(char *tail)
|
||||||
|
{
|
||||||
|
char *s, *t, c;
|
||||||
|
int count, nflag=0;
|
||||||
|
switch(reason){
|
||||||
|
case RESET:
|
||||||
|
errs("Flag -");
|
||||||
|
errc(badflag);
|
||||||
|
errs(": set twice\n");
|
||||||
|
break;
|
||||||
|
case FEWARGS:
|
||||||
|
errs("Flag -");
|
||||||
|
errc(badflag);
|
||||||
|
errs(": too few arguments\n");
|
||||||
|
break;
|
||||||
|
case FLAGSYN:
|
||||||
|
errs("Bad argument to getflags!\n");
|
||||||
|
break;
|
||||||
|
case BADFLAG:
|
||||||
|
errs("Illegal flag -");
|
||||||
|
errc(badflag);
|
||||||
|
errc('\n');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
errs("Usage: ");
|
||||||
|
errs(cmdname);
|
||||||
|
for(s=flagarg;*s;){
|
||||||
|
c=*s;
|
||||||
|
if(*s++==' ') continue;
|
||||||
|
if(*s==':'){
|
||||||
|
s++;
|
||||||
|
count=0;
|
||||||
|
while('0'<=*s && *s<='9') count=count*10+*s++-'0';
|
||||||
|
}
|
||||||
|
else count=0;
|
||||||
|
if(count==0){
|
||||||
|
if(nflag==0) errs(" [-");
|
||||||
|
nflag++;
|
||||||
|
errc(c);
|
||||||
|
}
|
||||||
|
if(*s=='['){
|
||||||
|
s++;
|
||||||
|
while(*s!=']' && *s!='\0') s++;
|
||||||
|
if(*s==']') s++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(nflag) errs("]");
|
||||||
|
for(s=flagarg;*s;){
|
||||||
|
c=*s;
|
||||||
|
if(*s++==' ') continue;
|
||||||
|
if(*s==':'){
|
||||||
|
s++;
|
||||||
|
count=0;
|
||||||
|
while('0'<=*s && *s<='9') count=count*10+*s++-'0';
|
||||||
|
}
|
||||||
|
else count=0;
|
||||||
|
if(count!=0){
|
||||||
|
errs(" [-");
|
||||||
|
errc(c);
|
||||||
|
if(*s=='['){
|
||||||
|
s++;
|
||||||
|
t=s;
|
||||||
|
while(*s!=']' && *s!='\0') s++;
|
||||||
|
errs(" ");
|
||||||
|
errn(t, s-t);
|
||||||
|
if(*s==']') s++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
while(count--) errs(" arg");
|
||||||
|
errs("]");
|
||||||
|
}
|
||||||
|
else if(*s=='['){
|
||||||
|
s++;
|
||||||
|
while(*s!=']' && *s!='\0') s++;
|
||||||
|
if(*s==']') s++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(tail){
|
||||||
|
errs(" ");
|
||||||
|
errs(tail);
|
||||||
|
}
|
||||||
|
errs("\n");
|
||||||
|
Exit("bad flags");
|
||||||
|
}
|
||||||
|
static void errn(char *s, int count)
|
||||||
|
{
|
||||||
|
while(count){ errc(*s++); --count; }
|
||||||
|
}
|
||||||
|
static void errs(char *s)
|
||||||
|
{
|
||||||
|
while(*s) errc(*s++);
|
||||||
|
}
|
||||||
|
#define NBUF 80
|
||||||
|
static char buf[NBUF], *bufp=buf;
|
||||||
|
static void errc(int c){
|
||||||
|
*bufp++=c;
|
||||||
|
if(bufp==&buf[NBUF] || c=='\n'){
|
||||||
|
Write(2, buf, bufp-buf);
|
||||||
|
bufp=buf;
|
||||||
|
}
|
||||||
|
}
|
||||||
7
src/cmd/rc/getflags.h
Normal file
7
src/cmd/rc/getflags.h
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
#define NFLAG 128
|
||||||
|
#define NCMDLINE 512
|
||||||
|
extern char **flag[NFLAG];
|
||||||
|
extern char cmdline[NCMDLINE+1];
|
||||||
|
extern char *cmdname;
|
||||||
|
extern char *flagset[];
|
||||||
|
int getflags(int, char*[], char*, int);
|
||||||
211
src/cmd/rc/glob.c
Normal file
211
src/cmd/rc/glob.c
Normal file
@ -0,0 +1,211 @@
|
|||||||
|
#include "rc.h"
|
||||||
|
#include "exec.h"
|
||||||
|
#include "fns.h"
|
||||||
|
char *globname;
|
||||||
|
struct word *globv;
|
||||||
|
/*
|
||||||
|
* delete all the GLOB marks from s, in place
|
||||||
|
*/
|
||||||
|
void deglob(char *s)
|
||||||
|
{
|
||||||
|
char *t=s;
|
||||||
|
do{
|
||||||
|
if(*t==GLOB) t++;
|
||||||
|
*s++=*t;
|
||||||
|
}while(*t++);
|
||||||
|
}
|
||||||
|
int globcmp(const void *s, const void *t)
|
||||||
|
{
|
||||||
|
return strcmp(*(char**)s, *(char**)t);
|
||||||
|
}
|
||||||
|
void globsort(word *left, word *right)
|
||||||
|
{
|
||||||
|
char **list;
|
||||||
|
word *a;
|
||||||
|
int n=0;
|
||||||
|
for(a=left;a!=right;a=a->next) n++;
|
||||||
|
list=(char **)emalloc(n*sizeof(char *));
|
||||||
|
for(a=left,n=0;a!=right;a=a->next,n++) list[n]=a->word;
|
||||||
|
qsort((char *)list, n, sizeof(char *), globcmp);
|
||||||
|
for(a=left,n=0;a!=right;a=a->next,n++) a->word=list[n];
|
||||||
|
efree((char *)list);
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* Push names prefixed by globname and suffixed by a match of p onto the astack.
|
||||||
|
* namep points to the end of the prefix in globname.
|
||||||
|
*/
|
||||||
|
void globdir(char *p, char *namep)
|
||||||
|
{
|
||||||
|
char *t, *newp;
|
||||||
|
int f;
|
||||||
|
/* scan the pattern looking for a component with a metacharacter in it */
|
||||||
|
if(*p=='\0'){
|
||||||
|
globv=newword(globname, globv);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
t=namep;
|
||||||
|
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(*newp=='\0'){
|
||||||
|
*t='\0';
|
||||||
|
if(access(globname, 0)==0)
|
||||||
|
globv=newword(globname, globv);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
/* read the directory and recur for any entry that matches */
|
||||||
|
*namep='\0';
|
||||||
|
if((f=Opendir(globname[0]?globname:"."))<0) return;
|
||||||
|
while(*newp!='/' && *newp!='\0') newp++;
|
||||||
|
while(Readdir(f, namep)){
|
||||||
|
if(matchfn(namep, p)){
|
||||||
|
for(t=namep;*t;t++);
|
||||||
|
globdir(newp, t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Closedir(f);
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* Push all file names matched by p on the current thread's stack.
|
||||||
|
* If there are no matches, the list consists of p.
|
||||||
|
*/
|
||||||
|
void glob(char *p)
|
||||||
|
{
|
||||||
|
word *svglobv=globv;
|
||||||
|
int globlen=Globsize(p);
|
||||||
|
if(!globlen){
|
||||||
|
deglob(p);
|
||||||
|
globv=newword(p, globv);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
globname=emalloc(globlen);
|
||||||
|
globname[0]='\0';
|
||||||
|
globdir(p, globname);
|
||||||
|
efree(globname);
|
||||||
|
if(svglobv==globv){
|
||||||
|
deglob(p);
|
||||||
|
globv=newword(p, globv);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
globsort(globv, svglobv);
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* Do p and q point at equal utf codes
|
||||||
|
*/
|
||||||
|
int equtf(char *p, char *q){
|
||||||
|
if(*p!=*q) return 0;
|
||||||
|
if(twobyte(*p)) return p[1]==q[1];
|
||||||
|
if(threebyte(*p)){
|
||||||
|
if(p[1]!=q[1]) return 0;
|
||||||
|
if(p[1]=='\0') return 1; /* broken code at end of string! */
|
||||||
|
return p[2]==q[2];
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* Return a pointer to the next utf code in the string,
|
||||||
|
* not jumping past nuls in broken utf codes!
|
||||||
|
*/
|
||||||
|
char *nextutf(char *p){
|
||||||
|
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;
|
||||||
|
return p+1;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* Convert the utf code at *p to a unicode value
|
||||||
|
*/
|
||||||
|
int unicode(char *p){
|
||||||
|
int u=*p&0xff;
|
||||||
|
if(twobyte(u)) return ((u&0x1f)<<6)|(p[1]&0x3f);
|
||||||
|
if(threebyte(u)) return (u<<12)|((p[1]&0x3f)<<6)|(p[2]&0x3f);
|
||||||
|
return u;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* Does the string s match the pattern p
|
||||||
|
* . and .. are only matched by patterns starting with .
|
||||||
|
* * matches any sequence of characters
|
||||||
|
* ? matches any single character
|
||||||
|
* [...] matches the enclosed list of characters
|
||||||
|
*/
|
||||||
|
int matchfn(char *s, char *p)
|
||||||
|
{
|
||||||
|
if(s[0]=='.' && (s[1]=='\0' || s[1]=='.' && s[2]=='\0') && p[0]!='.')
|
||||||
|
return 0;
|
||||||
|
return match(s, p, '/');
|
||||||
|
}
|
||||||
|
int match(char *s, char *p, int stop)
|
||||||
|
{
|
||||||
|
int compl, hit, lo, hi, t, c;
|
||||||
|
for(;*p!=stop && *p!='\0';s=nextutf(s),p=nextutf(p)){
|
||||||
|
if(*p!=GLOB){
|
||||||
|
if(!equtf(p, s)) return 0;
|
||||||
|
}
|
||||||
|
else switch(*++p){
|
||||||
|
case GLOB:
|
||||||
|
if(*s!=GLOB) return 0;
|
||||||
|
break;
|
||||||
|
case '*':
|
||||||
|
for(;;){
|
||||||
|
if(match(s, nextutf(p), stop)) return 1;
|
||||||
|
if(!*s) break;
|
||||||
|
s=nextutf(s);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
case '?':
|
||||||
|
if(*s=='\0') return 0;
|
||||||
|
break;
|
||||||
|
case '[':
|
||||||
|
if(*s=='\0') return 0;
|
||||||
|
c=unicode(s);
|
||||||
|
p++;
|
||||||
|
compl=*p=='~';
|
||||||
|
if(compl) p++;
|
||||||
|
hit=0;
|
||||||
|
while(*p!=']'){
|
||||||
|
if(*p=='\0') return 0; /* syntax error */
|
||||||
|
lo=unicode(p);
|
||||||
|
p=nextutf(p);
|
||||||
|
if(*p!='-') hi=lo;
|
||||||
|
else{
|
||||||
|
p++;
|
||||||
|
if(*p=='\0') return 0; /* syntax error */
|
||||||
|
hi=unicode(p);
|
||||||
|
p=nextutf(p);
|
||||||
|
if(hi<lo){ t=lo; lo=hi; hi=t; }
|
||||||
|
}
|
||||||
|
if(lo<=c && c<=hi) hit=1;
|
||||||
|
}
|
||||||
|
if(compl) hit=!hit;
|
||||||
|
if(!hit) return 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return *s=='\0';
|
||||||
|
}
|
||||||
|
void globlist1(word *gl)
|
||||||
|
{
|
||||||
|
if(gl){
|
||||||
|
globlist1(gl->next);
|
||||||
|
glob(gl->word);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void globlist(void){
|
||||||
|
word *a;
|
||||||
|
globv=0;
|
||||||
|
globlist1(runq->argv->words);
|
||||||
|
poplist();
|
||||||
|
pushlist();
|
||||||
|
if(globv){
|
||||||
|
for(a=globv;a->next;a=a->next);
|
||||||
|
a->next=runq->argv->words;
|
||||||
|
runq->argv->words=globv;
|
||||||
|
}
|
||||||
|
}
|
||||||
212
src/cmd/rc/havefork.c
Normal file
212
src/cmd/rc/havefork.c
Normal file
@ -0,0 +1,212 @@
|
|||||||
|
#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 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:
|
||||||
|
pushredir(ROPEN, null, 0);
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Who should wait for the exit from the fork?
|
||||||
|
*/
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
211
src/cmd/rc/haventfork.c
Normal file
211
src/cmd/rc/haventfork.c
Normal file
@ -0,0 +1,211 @@
|
|||||||
|
#include "rc.h"
|
||||||
|
#include "getflags.h"
|
||||||
|
#include "exec.h"
|
||||||
|
#include "io.h"
|
||||||
|
#include "fns.h"
|
||||||
|
|
||||||
|
int havefork = 0;
|
||||||
|
|
||||||
|
static char **
|
||||||
|
rcargv(char *s)
|
||||||
|
{
|
||||||
|
int argc;
|
||||||
|
char **argv;
|
||||||
|
word *p;
|
||||||
|
|
||||||
|
p = vlook("*")->val;
|
||||||
|
argv = malloc((count(p)+6)*sizeof(char*));
|
||||||
|
argc = 0;
|
||||||
|
argv[argc++] = argv0;
|
||||||
|
if(flag['e'])
|
||||||
|
argv[argc++] = "-Se";
|
||||||
|
else
|
||||||
|
argv[argc++] = "-S";
|
||||||
|
argv[argc++] = "-c";
|
||||||
|
argv[argc++] = s;
|
||||||
|
for(p = vlook("*")->val; p; p = p->next)
|
||||||
|
argv[argc++] = p->word;
|
||||||
|
argv[argc] = 0;
|
||||||
|
return argv;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Xasync(void)
|
||||||
|
{
|
||||||
|
uint pid;
|
||||||
|
char buf[20], **argv;
|
||||||
|
|
||||||
|
Updenv();
|
||||||
|
|
||||||
|
argv = rcargv(runq->code[runq->pc].s);
|
||||||
|
pid = ForkExecute(argv0, argv, -1, 1, 2);
|
||||||
|
free(argv);
|
||||||
|
|
||||||
|
if(pid == 0) {
|
||||||
|
Xerror("proc failed");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
runq->pc++;
|
||||||
|
sprint(buf, "%d", pid);
|
||||||
|
setvar("apid", newword(buf, (word *)0));
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Xbackq(void)
|
||||||
|
{
|
||||||
|
char wd[8193], **argv;
|
||||||
|
int c;
|
||||||
|
char *s, *ewd=&wd[8192], *stop;
|
||||||
|
struct io *f;
|
||||||
|
var *ifs = vlook("ifs");
|
||||||
|
word *v, *nextv;
|
||||||
|
int pfd[2];
|
||||||
|
int pid;
|
||||||
|
|
||||||
|
stop = ifs->val?ifs->val->word:"";
|
||||||
|
if(pipe(pfd)<0){
|
||||||
|
Xerror("can't make pipe");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Updenv();
|
||||||
|
|
||||||
|
argv = rcargv(runq->code[runq->pc].s);
|
||||||
|
pid = ForkExecute(argv0, argv, -1, pfd[1], 2);
|
||||||
|
free(argv);
|
||||||
|
|
||||||
|
close(pfd[1]);
|
||||||
|
|
||||||
|
if(pid == 0) {
|
||||||
|
Xerror("proc failed");
|
||||||
|
close(pfd[0]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
f = openfd(pfd[0]);
|
||||||
|
s = wd;
|
||||||
|
v = 0;
|
||||||
|
while((c=rchr(f))!=EOF){
|
||||||
|
if(strchr(stop, c) || s==ewd){
|
||||||
|
if(s!=wd){
|
||||||
|
*s='\0';
|
||||||
|
v=newword(wd, v);
|
||||||
|
s=wd;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else *s++=c;
|
||||||
|
}
|
||||||
|
if(s!=wd){
|
||||||
|
*s='\0';
|
||||||
|
v=newword(wd, v);
|
||||||
|
}
|
||||||
|
closeio(f);
|
||||||
|
Waitfor(pid, 1);
|
||||||
|
/* v points to reversed arglist -- reverse it onto argv */
|
||||||
|
while(v){
|
||||||
|
nextv=v->next;
|
||||||
|
v->next=runq->argv->words;
|
||||||
|
runq->argv->words=v;
|
||||||
|
v=nextv;
|
||||||
|
}
|
||||||
|
runq->pc++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Xpipe(void)
|
||||||
|
{
|
||||||
|
thread *p=runq;
|
||||||
|
int pc=p->pc, pid;
|
||||||
|
int rfd=p->code[pc+1].i;
|
||||||
|
int pfd[2];
|
||||||
|
char **argv;
|
||||||
|
|
||||||
|
if(pipe(pfd)<0){
|
||||||
|
Xerror1("can't get pipe");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Updenv();
|
||||||
|
|
||||||
|
argv = rcargv(runq->code[pc+2].s);
|
||||||
|
pid = ForkExecute(argv0, argv, 0, pfd[1], 2);
|
||||||
|
free(argv);
|
||||||
|
close(pfd[1]);
|
||||||
|
|
||||||
|
if(pid == 0) {
|
||||||
|
Xerror("proc failed");
|
||||||
|
close(pfd[0]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
start(p->code, pc+4, runq->local);
|
||||||
|
pushredir(ROPEN, pfd[0], rfd);
|
||||||
|
p->pc=p->code[pc+3].i;
|
||||||
|
p->pid=pid;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Xpipefd(void)
|
||||||
|
{
|
||||||
|
Abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Xsubshell(void)
|
||||||
|
{
|
||||||
|
char **argv;
|
||||||
|
int pid;
|
||||||
|
|
||||||
|
Updenv();
|
||||||
|
|
||||||
|
argv = rcargv(runq->code[runq->pc].s);
|
||||||
|
pid = ForkExecute(argv0, argv, -1, 1, 2);
|
||||||
|
free(argv);
|
||||||
|
|
||||||
|
if(pid < 0) {
|
||||||
|
Xerror("proc failed");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Waitfor(pid, 1);
|
||||||
|
runq->pc++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* start a process running the cmd on the stack and return its pid.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
execforkexec(void)
|
||||||
|
{
|
||||||
|
char **argv;
|
||||||
|
char file[1024];
|
||||||
|
int nc;
|
||||||
|
word *path;
|
||||||
|
int pid;
|
||||||
|
|
||||||
|
if(runq->argv->words==0)
|
||||||
|
return -1;
|
||||||
|
argv = mkargv(runq->argv->words);
|
||||||
|
|
||||||
|
for(path = searchpath(runq->argv->words->word);path;path = path->next){
|
||||||
|
nc = strlen(path->word);
|
||||||
|
if(nc<sizeof(file)){
|
||||||
|
strcpy(file, path->word);
|
||||||
|
if(file[0]){
|
||||||
|
strcat(file, "/");
|
||||||
|
nc++;
|
||||||
|
}
|
||||||
|
if(nc+strlen(argv[1])<sizeof(file)){
|
||||||
|
strcat(file, argv[1]);
|
||||||
|
pid = ForkExecute(file, argv+1, mapfd(0), mapfd(1), mapfd(2));
|
||||||
|
if(pid >= 0){
|
||||||
|
free(argv);
|
||||||
|
return pid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(argv);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
131
src/cmd/rc/here.c
Normal file
131
src/cmd/rc/here.c
Normal file
@ -0,0 +1,131 @@
|
|||||||
|
#include "rc.h"
|
||||||
|
#include "exec.h"
|
||||||
|
#include "io.h"
|
||||||
|
#include "fns.h"
|
||||||
|
struct here *here, **ehere;
|
||||||
|
int ser=0;
|
||||||
|
char tmp[]="/tmp/here0000.0000";
|
||||||
|
char hex[]="0123456789abcdef";
|
||||||
|
void psubst(io*, char*);
|
||||||
|
void pstrs(io*, word*);
|
||||||
|
void hexnum(char *p, int n)
|
||||||
|
{
|
||||||
|
*p++=hex[(n>>12)&0xF];
|
||||||
|
*p++=hex[(n>>8)&0xF];
|
||||||
|
*p++=hex[(n>>4)&0xF];
|
||||||
|
*p=hex[n&0xF];
|
||||||
|
}
|
||||||
|
tree *heredoc(tree *tag)
|
||||||
|
{
|
||||||
|
struct here *h=new(struct here);
|
||||||
|
if(tag->type!=WORD) yyerror("Bad here tag");
|
||||||
|
h->next=0;
|
||||||
|
if(here)
|
||||||
|
*ehere=h;
|
||||||
|
else
|
||||||
|
here=h;
|
||||||
|
ehere=&h->next;
|
||||||
|
h->tag=tag;
|
||||||
|
hexnum(&tmp[9], getpid());
|
||||||
|
hexnum(&tmp[14], ser++);
|
||||||
|
h->name=strdup(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(strcmp(line, tag)==0) break;
|
||||||
|
if(subst) psubst(f, line);
|
||||||
|
else pstr(f, line);
|
||||||
|
s=line;
|
||||||
|
if(c=='\n'){
|
||||||
|
pprompt();
|
||||||
|
pchr(f, c);
|
||||||
|
}
|
||||||
|
else *s++=c;
|
||||||
|
}
|
||||||
|
else *s++=c;
|
||||||
|
}
|
||||||
|
flush(f);
|
||||||
|
closeio(f);
|
||||||
|
cleanhere(h->name);
|
||||||
|
nexth=h->next;
|
||||||
|
efree((char *)h);
|
||||||
|
}
|
||||||
|
here=0;
|
||||||
|
doprompt=1;
|
||||||
|
}
|
||||||
|
void psubst(io *f, char *s)
|
||||||
|
{
|
||||||
|
char *t, *u;
|
||||||
|
int savec, n;
|
||||||
|
word *star;
|
||||||
|
while(*s){
|
||||||
|
if(*s!='$'){
|
||||||
|
if(0xa0<=(*s&0xff) && (*s&0xff)<=0xf5){
|
||||||
|
pchr(f, *s++);
|
||||||
|
if(*s=='\0') break;
|
||||||
|
}
|
||||||
|
else if(0xf6<=(*s&0xff) && (*s&0xff)<=0xf7){
|
||||||
|
pchr(f, *s++);
|
||||||
|
if(*s=='\0') break;
|
||||||
|
pchr(f, *s++);
|
||||||
|
if(*s=='\0') break;
|
||||||
|
}
|
||||||
|
pchr(f, *s++);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
t=++s;
|
||||||
|
if(*t=='$') pchr(f, *t++);
|
||||||
|
else{
|
||||||
|
while(*t && idchr(*t)) t++;
|
||||||
|
savec=*t;
|
||||||
|
*t='\0';
|
||||||
|
n=0;
|
||||||
|
for(u=s;*u && '0'<=*u && *u<='9';u++) n=n*10+*u-'0';
|
||||||
|
if(n && *u=='\0'){
|
||||||
|
star=vlook("*")->val;
|
||||||
|
if(star && 1<=n && n<=count(star)){
|
||||||
|
while(--n) star=star->next;
|
||||||
|
pstr(f, star->word);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
pstrs(f, vlook(s)->val);
|
||||||
|
*t=savec;
|
||||||
|
if(savec=='^') t++;
|
||||||
|
}
|
||||||
|
s=t;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void pstrs(io *f, word *a)
|
||||||
|
{
|
||||||
|
if(a){
|
||||||
|
while(a->next && a->next->word){
|
||||||
|
pstr(f, a->word);
|
||||||
|
pchr(f, ' ');
|
||||||
|
a=a->next;
|
||||||
|
}
|
||||||
|
pstr(f, a->word);
|
||||||
|
}
|
||||||
|
}
|
||||||
179
src/cmd/rc/io.c
Normal file
179
src/cmd/rc/io.c
Normal file
@ -0,0 +1,179 @@
|
|||||||
|
#include "rc.h"
|
||||||
|
#include "exec.h"
|
||||||
|
#include "io.h"
|
||||||
|
#include "fns.h"
|
||||||
|
int pfmtnest=0;
|
||||||
|
void pfmt(io *f, char *fmt, ...){
|
||||||
|
va_list ap;
|
||||||
|
char err[ERRMAX];
|
||||||
|
va_start(ap, fmt);
|
||||||
|
pfmtnest++;
|
||||||
|
for(;*fmt;fmt++)
|
||||||
|
if(*fmt!='%') pchr(f, *fmt);
|
||||||
|
else switch(*++fmt){
|
||||||
|
case '\0': va_end(ap); return;
|
||||||
|
case 'c': pchr(f, va_arg(ap, int)); break;
|
||||||
|
case 'd': pdec(f, va_arg(ap, int)); break;
|
||||||
|
case 'o': poct(f, va_arg(ap, unsigned)); break;
|
||||||
|
case 'p': phex(f, (long)va_arg(ap, char *)); break; /*unportable*/
|
||||||
|
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);
|
||||||
|
if(--pfmtnest==0) flush(f);
|
||||||
|
}
|
||||||
|
void pchr(io *b, int c)
|
||||||
|
{
|
||||||
|
if(b->bufp==b->ebuf) fullbuf(b, c);
|
||||||
|
else *b->bufp++=c;
|
||||||
|
}
|
||||||
|
int rchr(io *b)
|
||||||
|
{
|
||||||
|
if(b->bufp==b->ebuf) return emptybuf(b);
|
||||||
|
return *b->bufp++ & 0xFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pquo(io *f, char *s)
|
||||||
|
{
|
||||||
|
pchr(f, '\'');
|
||||||
|
for(;*s;s++)
|
||||||
|
if(*s=='\'') pfmt(f, "''");
|
||||||
|
else pchr(f, *s);
|
||||||
|
pchr(f, '\'');
|
||||||
|
}
|
||||||
|
void pwrd(io *f, char *s)
|
||||||
|
{
|
||||||
|
char *t;
|
||||||
|
for(t=s;*t;t++) if(!wordchr(*t)) break;
|
||||||
|
if(t==s || *t) pquo(f, s);
|
||||||
|
else pstr(f, s);
|
||||||
|
}
|
||||||
|
void phex(io *f, long p)
|
||||||
|
{
|
||||||
|
int n;
|
||||||
|
for(n=28;n>=0;n-=4) pchr(f, "0123456789ABCDEF"[(p>>n)&0xF]);
|
||||||
|
}
|
||||||
|
void pstr(io *f, char *s)
|
||||||
|
{
|
||||||
|
if(s==0) s="(null)";
|
||||||
|
while(*s) pchr(f, *s++);
|
||||||
|
}
|
||||||
|
void pdec(io *f, long n)
|
||||||
|
{
|
||||||
|
if(n<0){
|
||||||
|
n=-n;
|
||||||
|
if(n>=0){
|
||||||
|
pchr(f, '-');
|
||||||
|
pdec(f, n);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
/* n is two's complement minimum integer */
|
||||||
|
n=1-n;
|
||||||
|
pchr(f, '-');
|
||||||
|
pdec(f, n/10);
|
||||||
|
pchr(f, n%10+'1');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(n>9) pdec(f, n/10);
|
||||||
|
pchr(f, n%10+'0');
|
||||||
|
}
|
||||||
|
void poct(io *f, ulong n)
|
||||||
|
{
|
||||||
|
if(n>7) poct(f, n>>3);
|
||||||
|
pchr(f, (n&7)+'0');
|
||||||
|
}
|
||||||
|
void pval(io *f, word *a)
|
||||||
|
{
|
||||||
|
if(a){
|
||||||
|
while(a->next && a->next->word){
|
||||||
|
pwrd(f, a->word);
|
||||||
|
pchr(f, ' ');
|
||||||
|
a=a->next;
|
||||||
|
}
|
||||||
|
pwrd(f, a->word);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int fullbuf(io *f, int c)
|
||||||
|
{
|
||||||
|
flush(f);
|
||||||
|
return *f->bufp++=c;
|
||||||
|
}
|
||||||
|
void flush(io *f)
|
||||||
|
{
|
||||||
|
int n;
|
||||||
|
char *s;
|
||||||
|
if(f->strp){
|
||||||
|
n=f->ebuf-f->strp;
|
||||||
|
f->strp=realloc(f->strp, n+101);
|
||||||
|
if(f->strp==0) panic("Can't realloc %d bytes in flush!", n+101);
|
||||||
|
f->bufp=f->strp+n;
|
||||||
|
f->ebuf=f->bufp+100;
|
||||||
|
for(s=f->bufp;s<=f->ebuf;s++) *s='\0';
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
n=f->bufp-f->buf;
|
||||||
|
if(n && Write(f->fd, f->buf, n) < 0){
|
||||||
|
Write(3, "Write error\n", 12);
|
||||||
|
if(ntrap) dotrap();
|
||||||
|
}
|
||||||
|
f->bufp=f->buf;
|
||||||
|
f->ebuf=f->buf+NBUF;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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);
|
||||||
|
char *s;
|
||||||
|
f->fd=-1;
|
||||||
|
f->bufp=f->strp=emalloc(101);
|
||||||
|
f->ebuf=f->bufp+100;
|
||||||
|
for(s=f->bufp;s<=f->ebuf;s++) *s='\0';
|
||||||
|
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);
|
||||||
|
char *buf=emalloc(len);
|
||||||
|
f->fd= -1 /*open("/dev/null", 0)*/;
|
||||||
|
f->bufp=f->strp=buf;
|
||||||
|
f->ebuf=buf+len;
|
||||||
|
Memcpy(buf, s, len);
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
void rewind(io *io)
|
||||||
|
{
|
||||||
|
if(io->fd==-1) io->bufp=io->strp;
|
||||||
|
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) efree(io->strp);
|
||||||
|
efree((char *)io);
|
||||||
|
}
|
||||||
|
int emptybuf(io *f)
|
||||||
|
{
|
||||||
|
int n;
|
||||||
|
if(f->fd==-1 || (n=Read(f->fd, f->buf, NBUF))<=0) return EOF;
|
||||||
|
f->bufp=f->buf;
|
||||||
|
f->ebuf=f->buf+n;
|
||||||
|
return *f->bufp++&0xff;
|
||||||
|
}
|
||||||
24
src/cmd/rc/io.h
Normal file
24
src/cmd/rc/io.h
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
#define EOF (-1)
|
||||||
|
#define NBUF 512
|
||||||
|
struct io{
|
||||||
|
int fd;
|
||||||
|
char *bufp, *ebuf, *strp, buf[NBUF];
|
||||||
|
};
|
||||||
|
io *err;
|
||||||
|
io *openfd(int), *openstr(void), *opencore(char *, int);
|
||||||
|
int emptybuf(io*);
|
||||||
|
void pchr(io*, int);
|
||||||
|
int rchr(io*);
|
||||||
|
void closeio(io*);
|
||||||
|
void flush(io*);
|
||||||
|
int fullbuf(io*, int);
|
||||||
|
void pdec(io*, long);
|
||||||
|
void poct(io*, ulong);
|
||||||
|
void phex(io*, long);
|
||||||
|
void pquo(io*, char*);
|
||||||
|
void pwrd(io*, char*);
|
||||||
|
void pstr(io*, char*);
|
||||||
|
void pcmd(io*, tree*);
|
||||||
|
void pval(io*, word*);
|
||||||
|
void pfnc(io*, thread*);
|
||||||
|
void pfmt(io*, char*, ...);
|
||||||
322
src/cmd/rc/lex.c
Normal file
322
src/cmd/rc/lex.c
Normal file
@ -0,0 +1,322 @@
|
|||||||
|
#include "rc.h"
|
||||||
|
#include "exec.h"
|
||||||
|
#include "io.h"
|
||||||
|
#include "getflags.h"
|
||||||
|
#include "fns.h"
|
||||||
|
int getnext(void);
|
||||||
|
int wordchr(int c)
|
||||||
|
{
|
||||||
|
return !strchr("\n \t#;&|^$=`'{}()<>", c) && c!=EOF;
|
||||||
|
}
|
||||||
|
int idchr(int c)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Formerly:
|
||||||
|
* return 'a'<=c && c<='z' || 'A'<=c && c<='Z' || '0'<=c && c<='9'
|
||||||
|
* || c=='_' || c=='*';
|
||||||
|
*/
|
||||||
|
return c>' ' && !strchr("!\"#$%&'()+,-./:;<=>?@[\\]^`{|}~", c);
|
||||||
|
}
|
||||||
|
int future=EOF;
|
||||||
|
int doprompt=1;
|
||||||
|
int inquote;
|
||||||
|
/*
|
||||||
|
* Look ahead in the input stream
|
||||||
|
*/
|
||||||
|
int nextc(void){
|
||||||
|
if(future==EOF) future=getnext();
|
||||||
|
return future;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* Consume the lookahead character.
|
||||||
|
*/
|
||||||
|
int advance(void){
|
||||||
|
int c=nextc();
|
||||||
|
lastc=future;
|
||||||
|
future=EOF;
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* read a character from the input stream
|
||||||
|
*/
|
||||||
|
int getnext(void){
|
||||||
|
register int c;
|
||||||
|
static int peekc=EOF;
|
||||||
|
if(peekc!=EOF){
|
||||||
|
c=peekc;
|
||||||
|
peekc=EOF;
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
if(runq->eof) return EOF;
|
||||||
|
if(doprompt) pprompt();
|
||||||
|
c=rchr(runq->cmdfd);
|
||||||
|
if(!inquote && c=='\\'){
|
||||||
|
c=rchr(runq->cmdfd);
|
||||||
|
if(c=='\n'){
|
||||||
|
doprompt=1;
|
||||||
|
c=' ';
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
peekc=c;
|
||||||
|
c='\\';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
doprompt=doprompt || c=='\n' || c==EOF;
|
||||||
|
if(c==EOF) runq->eof++;
|
||||||
|
else if(flag['V'] || ndot>=2 && flag['v']) pchr(err, c);
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
void pprompt(void){
|
||||||
|
var *prompt;
|
||||||
|
if(runq->iflag){
|
||||||
|
pstr(err, promptstr);
|
||||||
|
flush(err);
|
||||||
|
prompt=vlook("prompt");
|
||||||
|
if(prompt->val && prompt->val->next)
|
||||||
|
promptstr=prompt->val->next->word;
|
||||||
|
else
|
||||||
|
promptstr="\t";
|
||||||
|
}
|
||||||
|
runq->lineno++;
|
||||||
|
doprompt=0;
|
||||||
|
}
|
||||||
|
void skipwhite(void){
|
||||||
|
int c;
|
||||||
|
for(;;){
|
||||||
|
c=nextc();
|
||||||
|
if(c=='#'){ /* Why did this used to be if(!inquote && c=='#') ?? */
|
||||||
|
for(;;){
|
||||||
|
c=nextc();
|
||||||
|
if(c=='\n' || c==EOF) break;
|
||||||
|
advance();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(c==' ' || c=='\t') advance();
|
||||||
|
else return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void skipnl(void){
|
||||||
|
register int c;
|
||||||
|
for(;;){
|
||||||
|
skipwhite();
|
||||||
|
c=nextc();
|
||||||
|
if(c!='\n') return;
|
||||||
|
advance();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int nextis(int c){
|
||||||
|
if(nextc()==c){
|
||||||
|
advance();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
char *addtok(char *p, int val){
|
||||||
|
if(p==0) return 0;
|
||||||
|
if(p==&tok[NTOK]){
|
||||||
|
*p=0;
|
||||||
|
yyerror("token buffer too short");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
*p++=val;
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
char *addutf(char *p, int c){
|
||||||
|
p=addtok(p, c);
|
||||||
|
if(twobyte(c)) /* 2-byte escape */
|
||||||
|
return addtok(p, advance());
|
||||||
|
if(threebyte(c)){ /* 3-byte escape */
|
||||||
|
p=addtok(p, advance());
|
||||||
|
return addtok(p, advance());
|
||||||
|
}
|
||||||
|
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 yylex(void){
|
||||||
|
register int c, d=nextc();
|
||||||
|
register char *w=tok;
|
||||||
|
register struct tree *t;
|
||||||
|
yylval.tree=0;
|
||||||
|
/*
|
||||||
|
* 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
|
||||||
|
* is `(', we return SUB (a subscript paren) and consume the `('. Otherwise,
|
||||||
|
* if the next character is the first character of a simple or compound word,
|
||||||
|
* we insert a `^' before it.
|
||||||
|
*/
|
||||||
|
if(lastword){
|
||||||
|
lastword=0;
|
||||||
|
if(d=='('){
|
||||||
|
advance();
|
||||||
|
strcpy(tok, "( [SUB]");
|
||||||
|
return SUB;
|
||||||
|
}
|
||||||
|
if(wordchr(d) || d=='\'' || d=='`' || d=='$' || d=='"'){
|
||||||
|
strcpy(tok, "^");
|
||||||
|
return '^';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
inquote=0;
|
||||||
|
skipwhite();
|
||||||
|
switch(c=advance()){
|
||||||
|
case EOF:
|
||||||
|
lastdol=0;
|
||||||
|
strcpy(tok, "EOF");
|
||||||
|
return EOF;
|
||||||
|
case '$':
|
||||||
|
lastdol=1;
|
||||||
|
if(nextis('#')){
|
||||||
|
strcpy(tok, "$#");
|
||||||
|
return COUNT;
|
||||||
|
}
|
||||||
|
if(nextis('"')){
|
||||||
|
strcpy(tok, "$\"");
|
||||||
|
return '"';
|
||||||
|
}
|
||||||
|
strcpy(tok, "$");
|
||||||
|
return '$';
|
||||||
|
case '&':
|
||||||
|
lastdol=0;
|
||||||
|
if(nextis('&')){
|
||||||
|
skipnl();
|
||||||
|
strcpy(tok, "&&");
|
||||||
|
return ANDAND;
|
||||||
|
}
|
||||||
|
strcpy(tok, "&");
|
||||||
|
return '&';
|
||||||
|
case '|':
|
||||||
|
lastdol=0;
|
||||||
|
if(nextis(c)){
|
||||||
|
skipnl();
|
||||||
|
strcpy(tok, "||");
|
||||||
|
return OROR;
|
||||||
|
}
|
||||||
|
case '<':
|
||||||
|
case '>':
|
||||||
|
lastdol=0;
|
||||||
|
/*
|
||||||
|
* funny redirection tokens:
|
||||||
|
* redir: arrow | arrow '[' fd ']'
|
||||||
|
* arrow: '<' | '<<' | '>' | '>>' | '|'
|
||||||
|
* fd: digit | digit '=' | digit '=' digit
|
||||||
|
* digit: '0'|'1'|'2'|'3'|'4'|'5'|'6'|'7'|'8'|'9'
|
||||||
|
* some possibilities are nonsensical and get a message.
|
||||||
|
*/
|
||||||
|
*w++=c;
|
||||||
|
t=newtree();
|
||||||
|
switch(c){
|
||||||
|
case '|':
|
||||||
|
t->type=PIPE;
|
||||||
|
t->fd0=1;
|
||||||
|
t->fd1=0;
|
||||||
|
break;
|
||||||
|
case '>':
|
||||||
|
t->type=REDIR;
|
||||||
|
if(nextis(c)){
|
||||||
|
t->rtype=APPEND;
|
||||||
|
*w++=c;
|
||||||
|
}
|
||||||
|
else t->rtype=WRITE;
|
||||||
|
t->fd0=1;
|
||||||
|
break;
|
||||||
|
case '<':
|
||||||
|
t->type=REDIR;
|
||||||
|
if(nextis(c)){
|
||||||
|
t->rtype=HERE;
|
||||||
|
*w++=c;
|
||||||
|
}
|
||||||
|
else t->rtype=READ;
|
||||||
|
t->fd0=0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(nextis('[')){
|
||||||
|
*w++='[';
|
||||||
|
c=advance();
|
||||||
|
*w++=c;
|
||||||
|
if(c<'0' || '9'<c){
|
||||||
|
RedirErr:
|
||||||
|
*w=0;
|
||||||
|
yyerror(t->type==PIPE?"pipe syntax"
|
||||||
|
:"redirection syntax");
|
||||||
|
return EOF;
|
||||||
|
}
|
||||||
|
t->fd0=0;
|
||||||
|
do{
|
||||||
|
t->fd0=t->fd0*10+c-'0';
|
||||||
|
*w++=c;
|
||||||
|
c=advance();
|
||||||
|
}while('0'<=c && c<='9');
|
||||||
|
if(c=='='){
|
||||||
|
*w++='=';
|
||||||
|
if(t->type==REDIR) t->type=DUP;
|
||||||
|
c=advance();
|
||||||
|
if('0'<=c && c<='9'){
|
||||||
|
t->rtype=DUPFD;
|
||||||
|
t->fd1=t->fd0;
|
||||||
|
t->fd0=0;
|
||||||
|
do{
|
||||||
|
t->fd0=t->fd0*10+c-'0';
|
||||||
|
*w++=c;
|
||||||
|
c=advance();
|
||||||
|
}while('0'<=c && c<='9');
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
if(t->type==PIPE) goto RedirErr;
|
||||||
|
t->rtype=CLOSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(c!=']'
|
||||||
|
|| t->type==DUP && (t->rtype==HERE || t->rtype==APPEND))
|
||||||
|
goto RedirErr;
|
||||||
|
*w++=']';
|
||||||
|
}
|
||||||
|
*w='\0';
|
||||||
|
yylval.tree=t;
|
||||||
|
if(t->type==PIPE) skipnl();
|
||||||
|
return t->type;
|
||||||
|
case '\'':
|
||||||
|
lastdol=0;
|
||||||
|
lastword=1;
|
||||||
|
inquote=1;
|
||||||
|
for(;;){
|
||||||
|
c=advance();
|
||||||
|
if(c==EOF) break;
|
||||||
|
if(c=='\''){
|
||||||
|
if(nextc()!='\'')
|
||||||
|
break;
|
||||||
|
advance();
|
||||||
|
}
|
||||||
|
w=addutf(w, c);
|
||||||
|
}
|
||||||
|
if(w!=0) *w='\0';
|
||||||
|
t=token(tok, WORD);
|
||||||
|
t->quoted=1;
|
||||||
|
yylval.tree=t;
|
||||||
|
return t->type;
|
||||||
|
}
|
||||||
|
if(!wordchr(c)){
|
||||||
|
lastdol=0;
|
||||||
|
tok[0]=c;
|
||||||
|
tok[1]='\0';
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
for(;;){
|
||||||
|
/* next line should have (char)c==GLOB, but ken's compiler is broken */
|
||||||
|
if(c=='*' || c=='[' || c=='?' || c==(unsigned char)GLOB)
|
||||||
|
w=addtok(w, GLOB);
|
||||||
|
w=addutf(w, c);
|
||||||
|
c=nextc();
|
||||||
|
if(lastdol?!idchr(c):!wordchr(c)) break;
|
||||||
|
advance();
|
||||||
|
}
|
||||||
|
|
||||||
|
lastword=1;
|
||||||
|
lastdol=0;
|
||||||
|
if(w!=0) *w='\0';
|
||||||
|
t=klook(tok);
|
||||||
|
if(t->type!=WORD) lastword=0;
|
||||||
|
t->quoted=0;
|
||||||
|
yylval.tree=t;
|
||||||
|
return t->type;
|
||||||
|
}
|
||||||
39
src/cmd/rc/mkfile
Normal file
39
src/cmd/rc/mkfile
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
PLAN9=../../..
|
||||||
|
<$PLAN9/src/mkhdr
|
||||||
|
YACC=yacc -d
|
||||||
|
|
||||||
|
TARG=rc
|
||||||
|
|
||||||
|
OFILES=\
|
||||||
|
code.$O\
|
||||||
|
exec.$O\
|
||||||
|
getflags.$O\
|
||||||
|
glob.$O\
|
||||||
|
here.$O\
|
||||||
|
io.$O\
|
||||||
|
lex.$O\
|
||||||
|
pcmd.$O\
|
||||||
|
pfnc.$O\
|
||||||
|
simple.$O\
|
||||||
|
subr.$O\
|
||||||
|
trap.$O\
|
||||||
|
tree.$O\
|
||||||
|
var.$O\
|
||||||
|
y.tab.$O\
|
||||||
|
plan9ish.$O\
|
||||||
|
|
||||||
|
HFILES=\
|
||||||
|
rc.h\
|
||||||
|
x.tab.h\
|
||||||
|
io.h\
|
||||||
|
exec.h\
|
||||||
|
fns.h\
|
||||||
|
|
||||||
|
YFILES=syn.y
|
||||||
|
|
||||||
|
LDFLAGS=$LDFLAGS -l9 -lfmt -lutf
|
||||||
|
|
||||||
|
<$PLAN9/src/mkone
|
||||||
|
|
||||||
|
x.tab.h: y.tab.h
|
||||||
|
cmp -s x.tab.h y.tab.h || cp y.tab.h x.tab.h
|
||||||
108
src/cmd/rc/pcmd.c
Normal file
108
src/cmd/rc/pcmd.c
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
#include "rc.h"
|
||||||
|
#include "io.h"
|
||||||
|
#include "fns.h"
|
||||||
|
char nl='\n'; /* change to semicolon for bourne-proofing */
|
||||||
|
#define c0 t->child[0]
|
||||||
|
#define c1 t->child[1]
|
||||||
|
#define c2 t->child[2]
|
||||||
|
void pdeglob(io *f, char *s)
|
||||||
|
{
|
||||||
|
while(*s){
|
||||||
|
if(*s==GLOB) s++;
|
||||||
|
pchr(f, *s++);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void pcmd(io *f, tree *t)
|
||||||
|
{
|
||||||
|
if(t==0) return;
|
||||||
|
switch(t->type){
|
||||||
|
default: pfmt(f, "bad %d %p %p %p", t->type, c0, c1, c2); break;
|
||||||
|
case '$': pfmt(f, "$%t", c0); break;
|
||||||
|
case '"': pfmt(f, "$\"%t", c0); break;
|
||||||
|
case '&': pfmt(f, "%t&", c0); break;
|
||||||
|
case '^': pfmt(f, "%t^%t", c0, c1); break;
|
||||||
|
case '`': pfmt(f, "`%t", c0); break;
|
||||||
|
case ANDAND: pfmt(f, "%t && %t", c0, c1); 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 PAREN: pfmt(f, "(%t)", c0); break;
|
||||||
|
case SUB: pfmt(f, "$%t(%t)", c0, c1); break;
|
||||||
|
case SIMPLE: pfmt(f, "%t", c0); 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:
|
||||||
|
if(c0==0)
|
||||||
|
pfmt(f, "%t", c1);
|
||||||
|
else if(c1==0)
|
||||||
|
pfmt(f, "%t", c0);
|
||||||
|
else
|
||||||
|
pfmt(f, "%t %t", c0, c1);
|
||||||
|
break;
|
||||||
|
case ';':
|
||||||
|
if(c0){
|
||||||
|
if(c1) pfmt(f, "%t%c%t", c0, nl, c1);
|
||||||
|
else pfmt(f, "%t", c0);
|
||||||
|
}
|
||||||
|
else pfmt(f, "%t", c1);
|
||||||
|
break;
|
||||||
|
case WORDS:
|
||||||
|
if(c0) pfmt(f, "%t ", c0);
|
||||||
|
pfmt(f, "%t", c1);
|
||||||
|
break;
|
||||||
|
case FOR:
|
||||||
|
pfmt(f, "for(%t", c0);
|
||||||
|
if(c1) pfmt(f, " in %t", c1);
|
||||||
|
pfmt(f, ")%t", c2);
|
||||||
|
break;
|
||||||
|
case WORD:
|
||||||
|
if(t->quoted) pfmt(f, "%Q", t->str);
|
||||||
|
else pdeglob(f, t->str);
|
||||||
|
break;
|
||||||
|
case DUP:
|
||||||
|
if(t->rtype==DUPFD)
|
||||||
|
pfmt(f, ">[%d=%d]", t->fd1, t->fd0); /* yes, fd1, then fd0; read lex.c */
|
||||||
|
else
|
||||||
|
pfmt(f, ">[%d=]", t->fd0);
|
||||||
|
pfmt(f, "%t", c1);
|
||||||
|
break;
|
||||||
|
case PIPEFD:
|
||||||
|
case REDIR:
|
||||||
|
switch(t->rtype){
|
||||||
|
case HERE:
|
||||||
|
pchr(f, '<');
|
||||||
|
case READ:
|
||||||
|
pchr(f, '<');
|
||||||
|
if(t->fd0!=0) pfmt(f, "[%d]", t->fd0);
|
||||||
|
break;
|
||||||
|
case APPEND:
|
||||||
|
pchr(f, '>');
|
||||||
|
case WRITE:
|
||||||
|
pchr(f, '>');
|
||||||
|
if(t->fd0!=1) pfmt(f, "[%d]", t->fd0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
pfmt(f, "%t", c0);
|
||||||
|
if(c1) pfmt(f, " %t", c1);
|
||||||
|
break;
|
||||||
|
case '=':
|
||||||
|
pfmt(f, "%t=%t", c0, c1);
|
||||||
|
if(c2) pfmt(f, " %t", c2);
|
||||||
|
break;
|
||||||
|
case PIPE:
|
||||||
|
pfmt(f, "%t|", c0);
|
||||||
|
if(t->fd1==0){
|
||||||
|
if(t->fd0!=1) pfmt(f, "[%d]", t->fd0);
|
||||||
|
}
|
||||||
|
else pfmt(f, "[%d=%d]", t->fd0, t->fd1);
|
||||||
|
pfmt(f, "%t", c1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
67
src/cmd/rc/pfnc.c
Normal file
67
src/cmd/rc/pfnc.c
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
#include "rc.h"
|
||||||
|
#include "exec.h"
|
||||||
|
#include "io.h"
|
||||||
|
#include "fns.h"
|
||||||
|
struct{
|
||||||
|
void (*f)(void);
|
||||||
|
char *name;
|
||||||
|
}fname[]={
|
||||||
|
Xappend, "Xappend",
|
||||||
|
Xasync, "Xasync",
|
||||||
|
Xbang, "Xbang",
|
||||||
|
Xclose, "Xclose",
|
||||||
|
Xdup, "Xdup",
|
||||||
|
Xeflag, "Xeflag",
|
||||||
|
Xexit, "Xexit",
|
||||||
|
Xfalse, "Xfalse",
|
||||||
|
Xifnot, "Xifnot",
|
||||||
|
Xjump, "Xjump",
|
||||||
|
Xmark, "Xmark",
|
||||||
|
Xpopm, "Xpopm",
|
||||||
|
Xread, "Xread",
|
||||||
|
Xreturn, "Xreturn",
|
||||||
|
Xtrue, "Xtrue",
|
||||||
|
Xif, "Xif",
|
||||||
|
Xwastrue, "Xwastrue",
|
||||||
|
Xword, "Xword",
|
||||||
|
Xwrite, "Xwrite",
|
||||||
|
Xmatch, "Xmatch",
|
||||||
|
Xcase, "Xcase",
|
||||||
|
Xconc, "Xconc",
|
||||||
|
Xassign, "Xassign",
|
||||||
|
Xdol, "Xdol",
|
||||||
|
Xcount, "Xcount",
|
||||||
|
Xlocal, "Xlocal",
|
||||||
|
Xunlocal, "Xunlocal",
|
||||||
|
Xfn, "Xfn",
|
||||||
|
Xdelfn, "Xdelfn",
|
||||||
|
Xpipe, "Xpipe",
|
||||||
|
Xpipewait, "Xpipewait",
|
||||||
|
Xrdcmds, "Xrdcmds",
|
||||||
|
(void (*)(void))Xerror, "Xerror",
|
||||||
|
Xbackq, "Xbackq",
|
||||||
|
Xpipefd, "Xpipefd",
|
||||||
|
Xsubshell, "Xsubshell",
|
||||||
|
Xdelhere, "Xdelhere",
|
||||||
|
Xfor, "Xfor",
|
||||||
|
Xglob, "Xglob",
|
||||||
|
Xrdfn, "Xrdfn",
|
||||||
|
Xsimple, "Xsimple",
|
||||||
|
Xrdfn, "Xrdfn",
|
||||||
|
Xqdol, "Xqdol",
|
||||||
|
0};
|
||||||
|
void pfnc(io *fd, thread *t)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
void (*fn)(void)=t->code[t->pc].f;
|
||||||
|
list *a;
|
||||||
|
pfmt(fd, "pid %d cycle %p %d ", getpid(), t->code, t->pc);
|
||||||
|
for(i=0;fname[i].f;i++) if(fname[i].f==fn){
|
||||||
|
pstr(fd, fname[i].name);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(!fname[i].f) pfmt(fd, "%p", fn);
|
||||||
|
for(a=t->argv;a;a=a->next) pfmt(fd, " (%v)", a->words);
|
||||||
|
pchr(fd, '\n');
|
||||||
|
flush(fd);
|
||||||
|
}
|
||||||
480
src/cmd/rc/plan9ish.c
Normal file
480
src/cmd/rc/plan9ish.c
Normal file
@ -0,0 +1,480 @@
|
|||||||
|
/*
|
||||||
|
* Plan 9 versions of system-specific functions
|
||||||
|
* By convention, exported routines herein have names beginning with an
|
||||||
|
* upper case letter.
|
||||||
|
*/
|
||||||
|
#include "rc.h"
|
||||||
|
#include "exec.h"
|
||||||
|
#include "io.h"
|
||||||
|
#include "fns.h"
|
||||||
|
#include "getflags.h"
|
||||||
|
char *Signame[]={
|
||||||
|
"sigexit", "sighup", "sigint", "sigquit",
|
||||||
|
"sigalrm", "sigkill", "sigfpe", "sigterm",
|
||||||
|
0
|
||||||
|
};
|
||||||
|
char *syssigname[]={
|
||||||
|
"exit", /* can't happen */
|
||||||
|
"hangup",
|
||||||
|
"interrupt",
|
||||||
|
"quit", /* can't happen */
|
||||||
|
"alarm",
|
||||||
|
"kill",
|
||||||
|
"sys: fp: ",
|
||||||
|
"term",
|
||||||
|
0
|
||||||
|
};
|
||||||
|
char*
|
||||||
|
Rcmain(void)
|
||||||
|
{
|
||||||
|
static char buf[256];
|
||||||
|
char *root;
|
||||||
|
|
||||||
|
root = getenv("PLAN9");
|
||||||
|
if(root == nil)
|
||||||
|
root = "/usr/local/plan9";
|
||||||
|
snprint(buf, sizeof buf, "%s/rcmain", root);
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
char Fdprefix[]="/dev/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,
|
||||||
|
0
|
||||||
|
};
|
||||||
|
#define SEP '\1'
|
||||||
|
char **environp;
|
||||||
|
struct word *enval(s)
|
||||||
|
register char *s;
|
||||||
|
{
|
||||||
|
register char *t, c;
|
||||||
|
register struct word *v;
|
||||||
|
for(t=s;*t && *t!=SEP;t++);
|
||||||
|
c=*t;
|
||||||
|
*t='\0';
|
||||||
|
v=newword(s, c=='\0'?(struct word *)0:enval(t+1));
|
||||||
|
*t=c;
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
void Vinit(void){
|
||||||
|
extern char **environ;
|
||||||
|
register char *s;
|
||||||
|
register char **env=environ;
|
||||||
|
environp=env;
|
||||||
|
for(;*env;env++){
|
||||||
|
for(s=*env;*s && *s!='(' && *s!='=';s++);
|
||||||
|
switch(*s){
|
||||||
|
case '\0':
|
||||||
|
pfmt(err, "environment %q?\n", *env);
|
||||||
|
break;
|
||||||
|
case '=':
|
||||||
|
*s='\0';
|
||||||
|
setvar(*env, enval(s+1));
|
||||||
|
*s='=';
|
||||||
|
break;
|
||||||
|
case '(': /* ignore functions for now */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
char **envp;
|
||||||
|
void Xrdfn(void){
|
||||||
|
char *p;
|
||||||
|
register char *s;
|
||||||
|
register int len;
|
||||||
|
for(;*envp;envp++){
|
||||||
|
s = *envp;
|
||||||
|
if(strncmp(s, "fn#", 3) == 0){
|
||||||
|
p = strchr(s, '=');
|
||||||
|
if(p == nil)
|
||||||
|
continue;
|
||||||
|
*p = ' ';
|
||||||
|
s[2] = ' ';
|
||||||
|
len = strlen(s);
|
||||||
|
execcmds(opencore(s, len));
|
||||||
|
s[len] = '\0';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#if 0
|
||||||
|
for(s=*envp;*s && *s!='(' && *s!='=';s++);
|
||||||
|
switch(*s){
|
||||||
|
case '\0':
|
||||||
|
pfmt(err, "environment %q?\n", *envp);
|
||||||
|
break;
|
||||||
|
case '=': /* ignore variables */
|
||||||
|
break;
|
||||||
|
case '(': /* Bourne again */
|
||||||
|
s=*envp+3;
|
||||||
|
envp++;
|
||||||
|
len=strlen(s);
|
||||||
|
s[len]='\n';
|
||||||
|
execcmds(opencore(s, len+1));
|
||||||
|
s[len]='\0';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
Xreturn();
|
||||||
|
}
|
||||||
|
union code rdfns[4];
|
||||||
|
void execfinit(void){
|
||||||
|
static int first=1;
|
||||||
|
if(first){
|
||||||
|
rdfns[0].i=1;
|
||||||
|
rdfns[1].f=Xrdfn;
|
||||||
|
rdfns[2].f=Xjump;
|
||||||
|
rdfns[3].i=1;
|
||||||
|
first=0;
|
||||||
|
}
|
||||||
|
Xpopm();
|
||||||
|
envp=environp;
|
||||||
|
start(rdfns, 1, runq->local);
|
||||||
|
}
|
||||||
|
int Waitfor(int pid, int unused0){
|
||||||
|
thread *p;
|
||||||
|
Waitmsg *w;
|
||||||
|
char errbuf[ERRMAX];
|
||||||
|
|
||||||
|
while((w = wait()) != nil){
|
||||||
|
if(w->pid==pid){
|
||||||
|
setstatus(w->msg);
|
||||||
|
free(w);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
for(p=runq->ret;p;p=p->ret)
|
||||||
|
if(p->pid==w->pid){
|
||||||
|
p->pid=-1;
|
||||||
|
strcpy(p->status, w->msg);
|
||||||
|
}
|
||||||
|
free(w);
|
||||||
|
}
|
||||||
|
|
||||||
|
errstr(errbuf, sizeof errbuf);
|
||||||
|
if(strcmp(errbuf, "interrupted")==0) return -1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
char **mkargv(word *a)
|
||||||
|
{
|
||||||
|
char **argv=(char **)emalloc((count(a)+2)*sizeof(char *));
|
||||||
|
char **argp=argv+1; /* leave one at front for runcoms */
|
||||||
|
for(;a;a=a->next) *argp++=a->word;
|
||||||
|
*argp=0;
|
||||||
|
return argv;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
void addenv(var *v)
|
||||||
|
{
|
||||||
|
char envname[256];
|
||||||
|
word *w;
|
||||||
|
int f;
|
||||||
|
io *fd;
|
||||||
|
if(v->changed){
|
||||||
|
v->changed=0;
|
||||||
|
snprint(envname, sizeof envname, "/env/%s", v->name);
|
||||||
|
if((f=Creat(envname))<0)
|
||||||
|
pfmt(err, "rc: can't open %s: %r\n", envname);
|
||||||
|
else{
|
||||||
|
for(w=v->val;w;w=w->next)
|
||||||
|
write(f, w->word, strlen(w->word)+1L);
|
||||||
|
close(f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(v->fnchanged){
|
||||||
|
v->fnchanged=0;
|
||||||
|
snprint(envname, sizeof envname, "/env/fn#%s", v->name);
|
||||||
|
if((f=Creat(envname))<0)
|
||||||
|
pfmt(err, "rc: can't open %s: %r\n", envname);
|
||||||
|
else{
|
||||||
|
if(v->fn){
|
||||||
|
fd=openfd(f);
|
||||||
|
pfmt(fd, "fn %s %s\n", v->name, v->fn[v->pc-1].s);
|
||||||
|
closeio(fd);
|
||||||
|
}
|
||||||
|
close(f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void updenvlocal(var *v)
|
||||||
|
{
|
||||||
|
if(v){
|
||||||
|
updenvlocal(v->next);
|
||||||
|
addenv(v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void Updenv(void){
|
||||||
|
var *v, **h;
|
||||||
|
for(h=gvar;h!=&gvar[NVAR];h++)
|
||||||
|
for(v=*h;v;v=v->next)
|
||||||
|
addenv(v);
|
||||||
|
if(runq) updenvlocal(runq->local);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
cmpenv(a, b)
|
||||||
|
char **a, **b;
|
||||||
|
{
|
||||||
|
return strcmp(*a, *b);
|
||||||
|
}
|
||||||
|
char **mkenv(){
|
||||||
|
register char **env, **ep, *p, *q;
|
||||||
|
register struct var **h, *v;
|
||||||
|
register struct word *a;
|
||||||
|
register int nvar=0, nchr=0, sep;
|
||||||
|
/*
|
||||||
|
* Slightly kludgy loops look at locals then globals
|
||||||
|
*/
|
||||||
|
for(h=gvar-1;h!=&gvar[NVAR];h++) for(v=h>=gvar?*h:runq->local;v;v=v->next){
|
||||||
|
if((v==vlook(v->name)) && v->val){
|
||||||
|
nvar++;
|
||||||
|
nchr+=strlen(v->name)+1;
|
||||||
|
for(a=v->val;a;a=a->next)
|
||||||
|
nchr+=strlen(a->word)+1;
|
||||||
|
}
|
||||||
|
if(v->fn){
|
||||||
|
nvar++;
|
||||||
|
nchr+=strlen(v->name)+strlen(v->fn[v->pc-1].s)+8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
env=(char **)emalloc((nvar+1)*sizeof(char *)+nchr);
|
||||||
|
ep=env;
|
||||||
|
p=(char *)&env[nvar+1];
|
||||||
|
for(h=gvar-1;h!=&gvar[NVAR];h++) for(v=h>=gvar?*h:runq->local;v;v=v->next){
|
||||||
|
if((v==vlook(v->name)) && v->val){
|
||||||
|
*ep++=p;
|
||||||
|
q=v->name;
|
||||||
|
while(*q) *p++=*q++;
|
||||||
|
sep='=';
|
||||||
|
for(a=v->val;a;a=a->next){
|
||||||
|
*p++=sep;
|
||||||
|
sep=SEP;
|
||||||
|
q=a->word;
|
||||||
|
while(*q) *p++=*q++;
|
||||||
|
}
|
||||||
|
*p++='\0';
|
||||||
|
}
|
||||||
|
if(v->fn){
|
||||||
|
*ep++=p;
|
||||||
|
#if 0
|
||||||
|
*p++='#'; *p++='('; *p++=')'; /* to fool Bourne */
|
||||||
|
*p++='f'; *p++='n'; *p++=' ';
|
||||||
|
q=v->name;
|
||||||
|
while(*q) *p++=*q++;
|
||||||
|
*p++=' ';
|
||||||
|
#endif
|
||||||
|
*p++='f'; *p++='n'; *p++='#';
|
||||||
|
q=v->name;
|
||||||
|
while(*q) *p++=*q++;
|
||||||
|
*p++='=';
|
||||||
|
q=v->fn[v->pc-1].s;
|
||||||
|
while(*q) *p++=*q++;
|
||||||
|
*p++='\n';
|
||||||
|
*p++='\0';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*ep=0;
|
||||||
|
qsort((char *)env, nvar, sizeof ep[0], cmpenv);
|
||||||
|
return env;
|
||||||
|
}
|
||||||
|
void Updenv(void){}
|
||||||
|
void Execute(word *args, word *path)
|
||||||
|
{
|
||||||
|
char **argv=mkargv(args);
|
||||||
|
char **env=mkenv();
|
||||||
|
char file[1024];
|
||||||
|
int nc;
|
||||||
|
Updenv();
|
||||||
|
for(;path;path=path->next){
|
||||||
|
nc=strlen(path->word);
|
||||||
|
if(nc<1024){
|
||||||
|
strcpy(file, path->word);
|
||||||
|
if(file[0]){
|
||||||
|
strcat(file, "/");
|
||||||
|
nc++;
|
||||||
|
}
|
||||||
|
if(nc+strlen(argv[1])<1024){
|
||||||
|
strcat(file, argv[1]);
|
||||||
|
execve(file, argv+1, env);
|
||||||
|
}
|
||||||
|
else werrstr("command name too long");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rerrstr(file, sizeof file);
|
||||||
|
pfmt(err, "%s: %s\n", argv[1], file);
|
||||||
|
efree((char *)argv);
|
||||||
|
}
|
||||||
|
#define NDIR 256 /* shoud be a better way */
|
||||||
|
int Globsize(char *p)
|
||||||
|
{
|
||||||
|
ulong isglob=0, globlen=NDIR+1;
|
||||||
|
for(;*p;p++){
|
||||||
|
if(*p==GLOB){
|
||||||
|
p++;
|
||||||
|
if(*p!=GLOB) isglob++;
|
||||||
|
globlen+=*p=='*'?NDIR:1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
globlen++;
|
||||||
|
}
|
||||||
|
return isglob?globlen:0;
|
||||||
|
}
|
||||||
|
#define NFD 50
|
||||||
|
#define NDBUF 32
|
||||||
|
struct{
|
||||||
|
Dir *dbuf;
|
||||||
|
int i;
|
||||||
|
int n;
|
||||||
|
}dir[NFD];
|
||||||
|
int Opendir(char *name)
|
||||||
|
{
|
||||||
|
Dir *db;
|
||||||
|
int f;
|
||||||
|
f=open(name, 0);
|
||||||
|
if(f==-1)
|
||||||
|
return f;
|
||||||
|
db = dirfstat(f);
|
||||||
|
if(db!=nil && (db->mode&DMDIR)){
|
||||||
|
if(f<NFD){
|
||||||
|
dir[f].i=0;
|
||||||
|
dir[f].n=0;
|
||||||
|
}
|
||||||
|
free(db);
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
free(db);
|
||||||
|
close(f);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
int Readdir(int f, char *p)
|
||||||
|
{
|
||||||
|
int n;
|
||||||
|
if(f<0 || f>=NFD)
|
||||||
|
return 0;
|
||||||
|
if(dir[f].i==dir[f].n){ /* read */
|
||||||
|
free(dir[f].dbuf);
|
||||||
|
dir[f].dbuf=0;
|
||||||
|
n=dirread(f, &dir[f].dbuf);
|
||||||
|
if(n>=0)
|
||||||
|
dir[f].n=n;
|
||||||
|
else
|
||||||
|
dir[f].n=0;
|
||||||
|
dir[f].i=0;
|
||||||
|
}
|
||||||
|
if(dir[f].i==dir[f].n)
|
||||||
|
return 0;
|
||||||
|
strcpy(p, dir[f].dbuf[dir[f].i].name);
|
||||||
|
dir[f].i++;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
void Closedir(int f){
|
||||||
|
if(f>=0 && f<NFD){
|
||||||
|
free(dir[f].dbuf);
|
||||||
|
dir[f].i=0;
|
||||||
|
dir[f].n=0;
|
||||||
|
dir[f].dbuf=0;
|
||||||
|
}
|
||||||
|
close(f);
|
||||||
|
}
|
||||||
|
int interrupted = 0;
|
||||||
|
void
|
||||||
|
notifyf(void *unused0, char *s)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for(i=0;syssigname[i];i++) if(strncmp(s, syssigname[i], strlen(syssigname[i]))==0){
|
||||||
|
if(strncmp(s, "sys: ", 5)!=0) interrupted=1;
|
||||||
|
goto Out;
|
||||||
|
}
|
||||||
|
pfmt(err, "rc: note: %s\n", s);
|
||||||
|
noted(NDFLT);
|
||||||
|
return;
|
||||||
|
Out:
|
||||||
|
if(strcmp(s, "interrupt")!=0 || trap[i]==0){
|
||||||
|
trap[i]++;
|
||||||
|
ntrap++;
|
||||||
|
}
|
||||||
|
if(ntrap>=32){ /* rc is probably in a trap loop */
|
||||||
|
pfmt(err, "rc: Too many traps (trap %s), aborting\n", s);
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
noted(NCONT);
|
||||||
|
}
|
||||||
|
void Trapinit(void){
|
||||||
|
notify(notifyf);
|
||||||
|
}
|
||||||
|
void Unlink(char *name)
|
||||||
|
{
|
||||||
|
remove(name);
|
||||||
|
}
|
||||||
|
long Write(int fd, char *buf, long cnt)
|
||||||
|
{
|
||||||
|
return write(fd, buf, (long)cnt);
|
||||||
|
}
|
||||||
|
long Read(int fd, char *buf, long cnt)
|
||||||
|
{
|
||||||
|
return read(fd, buf, cnt);
|
||||||
|
}
|
||||||
|
long Seek(int fd, long cnt, long whence)
|
||||||
|
{
|
||||||
|
return seek(fd, cnt, whence);
|
||||||
|
}
|
||||||
|
int Executable(char *file)
|
||||||
|
{
|
||||||
|
Dir *statbuf;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
statbuf = dirstat(file);
|
||||||
|
if(statbuf == nil) return 0;
|
||||||
|
ret = ((statbuf->mode&0111)!=0 && (statbuf->mode&DMDIR)==0);
|
||||||
|
free(statbuf);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
int Creat(char *file)
|
||||||
|
{
|
||||||
|
return create(file, 1, 0666L);
|
||||||
|
}
|
||||||
|
int Dup(int a, int b){
|
||||||
|
return dup(a, b);
|
||||||
|
}
|
||||||
|
int Dup1(int unused0){
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
void Exit(char *stat)
|
||||||
|
{
|
||||||
|
Updenv();
|
||||||
|
setstatus(stat);
|
||||||
|
exits(truestatus()?"":getstatus());
|
||||||
|
}
|
||||||
|
int Eintr(void){
|
||||||
|
return interrupted;
|
||||||
|
}
|
||||||
|
void Noerror(void){
|
||||||
|
interrupted=0;
|
||||||
|
}
|
||||||
|
int
|
||||||
|
Isatty(fd){
|
||||||
|
return isatty(fd);
|
||||||
|
}
|
||||||
|
void Abort(void){
|
||||||
|
pfmt(err, "aborting\n");
|
||||||
|
flush(err);
|
||||||
|
Exit("aborting");
|
||||||
|
}
|
||||||
|
void Memcpy(char *a, char *b, long n)
|
||||||
|
{
|
||||||
|
memmove(a, b, (long)n);
|
||||||
|
}
|
||||||
|
void *Malloc(ulong n){
|
||||||
|
return malloc(n);
|
||||||
|
}
|
||||||
136
src/cmd/rc/rc.h
Normal file
136
src/cmd/rc/rc.h
Normal file
@ -0,0 +1,136 @@
|
|||||||
|
/*
|
||||||
|
* Plan9 is defined for plan 9
|
||||||
|
* V9 is defined for 9th edition
|
||||||
|
* Sun is defined for sun-os
|
||||||
|
* Please don't litter the code with ifdefs. The three below (and one in
|
||||||
|
* getflags) should be enough.
|
||||||
|
*/
|
||||||
|
#define Plan9
|
||||||
|
#ifdef Plan9
|
||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
#define NSIG 32
|
||||||
|
#define SIGINT 2
|
||||||
|
#define SIGQUIT 3
|
||||||
|
#endif
|
||||||
|
#ifdef V9
|
||||||
|
#include <signal.h>
|
||||||
|
#include <libc.h>
|
||||||
|
#endif
|
||||||
|
#ifdef Sun
|
||||||
|
#include <signal.h>
|
||||||
|
#endif
|
||||||
|
#define YYMAXDEPTH 500
|
||||||
|
#ifndef PAREN
|
||||||
|
#ifndef YYMAJOR
|
||||||
|
#include "x.tab.h"
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
typedef struct tree tree;
|
||||||
|
typedef struct word word;
|
||||||
|
typedef struct io io;
|
||||||
|
typedef union code code;
|
||||||
|
typedef struct var var;
|
||||||
|
typedef struct list list;
|
||||||
|
typedef struct redir redir;
|
||||||
|
typedef struct thread thread;
|
||||||
|
typedef struct builtin builtin;
|
||||||
|
|
||||||
|
struct tree{
|
||||||
|
int type;
|
||||||
|
int rtype, fd0, fd1; /* details of REDIR PIPE DUP tokens */
|
||||||
|
char *str;
|
||||||
|
int quoted;
|
||||||
|
int iskw;
|
||||||
|
tree *child[3];
|
||||||
|
tree *next;
|
||||||
|
};
|
||||||
|
tree *newtree(void);
|
||||||
|
tree *token(char*, int), *klook(char*), *tree1(int, tree*);
|
||||||
|
tree *tree2(int, tree*, tree*), *tree3(int, tree*, tree*, tree*);
|
||||||
|
tree *mung1(tree*, tree*), *mung2(tree*, tree*, tree*);
|
||||||
|
tree *mung3(tree*, tree*, tree*, tree*), *epimung(tree*, tree*);
|
||||||
|
tree *simplemung(tree*), *heredoc(tree*);
|
||||||
|
void freetree(tree*);
|
||||||
|
tree *cmdtree;
|
||||||
|
/*
|
||||||
|
* The first word of any code vector is a reference count.
|
||||||
|
* Always create a new reference to a code vector by calling codecopy(.).
|
||||||
|
* Always call codefree(.) when deleting a reference.
|
||||||
|
*/
|
||||||
|
union code{
|
||||||
|
void (*f)(void);
|
||||||
|
int i;
|
||||||
|
char *s;
|
||||||
|
};
|
||||||
|
char *promptstr;
|
||||||
|
int doprompt;
|
||||||
|
#define NTOK 8192
|
||||||
|
char tok[NTOK];
|
||||||
|
#define APPEND 1
|
||||||
|
#define WRITE 2
|
||||||
|
#define READ 3
|
||||||
|
#define HERE 4
|
||||||
|
#define DUPFD 5
|
||||||
|
#define CLOSE 6
|
||||||
|
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 *vlook(char*), *gvlook(char*), *newvar(char*, var*);
|
||||||
|
#define NVAR 521
|
||||||
|
var *gvar[NVAR]; /* hash for globals */
|
||||||
|
#define new(type) ((type *)emalloc(sizeof(type)))
|
||||||
|
char *emalloc(long);
|
||||||
|
void *Malloc(ulong);
|
||||||
|
void efree(char*);
|
||||||
|
#define NOFILE 128 /* should come from <param.h> */
|
||||||
|
struct here{
|
||||||
|
tree *tag;
|
||||||
|
char *name;
|
||||||
|
struct here *next;
|
||||||
|
};
|
||||||
|
int mypid;
|
||||||
|
/*
|
||||||
|
* Glob character escape in strings:
|
||||||
|
* In a string, GLOB must be followed by *?[ or GLOB.
|
||||||
|
* GLOB* matches any string
|
||||||
|
* GLOB? matches any single character
|
||||||
|
* GLOB[...] matches anything in the brackets
|
||||||
|
* GLOBGLOB matches GLOB
|
||||||
|
*/
|
||||||
|
#define GLOB ((char)0x01)
|
||||||
|
/*
|
||||||
|
* onebyte(c), twobyte(c), threebyte(c)
|
||||||
|
* Is c the first character of a one- two- or three-byte utf sequence?
|
||||||
|
*/
|
||||||
|
#define onebyte(c) ((c&0x80)==0x00)
|
||||||
|
#define twobyte(c) ((c&0xe0)==0xc0)
|
||||||
|
#define threebyte(c) ((c&0xf0)==0xe0)
|
||||||
|
char **argp;
|
||||||
|
char **args;
|
||||||
|
int nerror; /* number of errors encountered during compilation */
|
||||||
|
int doprompt; /* is it time for a prompt? */
|
||||||
|
/*
|
||||||
|
* Which fds are the reading/writing end of a pipe?
|
||||||
|
* Unfortunately, this can vary from system to system.
|
||||||
|
* 9th edition Unix doesn't care, the following defines
|
||||||
|
* work on plan 9.
|
||||||
|
*/
|
||||||
|
#define PRD 0
|
||||||
|
#define PWR 1
|
||||||
|
extern char *Rcmain(), Fdprefix[];
|
||||||
|
#define register
|
||||||
|
/*
|
||||||
|
* How many dot commands have we executed?
|
||||||
|
* Used to ensure that -v flag doesn't print rcmain.
|
||||||
|
*/
|
||||||
|
int ndot;
|
||||||
|
char *getstatus(void);
|
||||||
|
int lastc;
|
||||||
|
int lastword;
|
||||||
443
src/cmd/rc/simple.c
Normal file
443
src/cmd/rc/simple.c
Normal file
@ -0,0 +1,443 @@
|
|||||||
|
/*
|
||||||
|
* Maybe `simple' is a misnomer.
|
||||||
|
*/
|
||||||
|
#include "rc.h"
|
||||||
|
#include "getflags.h"
|
||||||
|
#include "exec.h"
|
||||||
|
#include "io.h"
|
||||||
|
#include "fns.h"
|
||||||
|
/*
|
||||||
|
* Search through the following code to see if we're just going to exit.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
exitnext(void){
|
||||||
|
union code *c=&runq->code[runq->pc];
|
||||||
|
while(c->f==Xpopredir) c++;
|
||||||
|
return c->f==Xexit;
|
||||||
|
}
|
||||||
|
void Xsimple(void){
|
||||||
|
word *a;
|
||||||
|
thread *p=runq;
|
||||||
|
var *v;
|
||||||
|
struct builtin *bp;
|
||||||
|
int pid, n;
|
||||||
|
char buf[ERRMAX];
|
||||||
|
globlist();
|
||||||
|
a=runq->argv->words;
|
||||||
|
if(a==0){
|
||||||
|
Xerror1("empty argument list");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(flag['x'])
|
||||||
|
pfmt(err, "%v\n", p->argv->words); /* wrong, should do redirs */
|
||||||
|
v=gvlook(a->word);
|
||||||
|
if(v->fn)
|
||||||
|
execfunc(v);
|
||||||
|
else{
|
||||||
|
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;
|
||||||
|
popword();
|
||||||
|
}
|
||||||
|
for(bp=Builtin;bp->name;bp++)
|
||||||
|
if(strcmp(a->word, bp->name)==0){
|
||||||
|
(*bp->fnc)();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(exitnext()){
|
||||||
|
/* fork and wait is redundant */
|
||||||
|
pushword("exec");
|
||||||
|
execexec();
|
||||||
|
Xexit();
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
flush(err);
|
||||||
|
Updenv(); /* necessary so changes don't go out again */
|
||||||
|
switch(pid=fork()){
|
||||||
|
case -1:
|
||||||
|
Xerror("try again");
|
||||||
|
return;
|
||||||
|
case 0:
|
||||||
|
pushword("exec");
|
||||||
|
execexec();
|
||||||
|
strcpy(buf, "can't exec: ");
|
||||||
|
n = strlen(buf);
|
||||||
|
errstr(buf+n, ERRMAX-n);
|
||||||
|
Exit(buf);
|
||||||
|
default:
|
||||||
|
poplist();
|
||||||
|
/* interrupts don't get us out */
|
||||||
|
while(Waitfor(pid, 1) < 0)
|
||||||
|
;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
struct word nullpath={ "", 0};
|
||||||
|
void doredir(redir *rp)
|
||||||
|
{
|
||||||
|
if(rp){
|
||||||
|
doredir(rp->next);
|
||||||
|
switch(rp->type){
|
||||||
|
case ROPEN:
|
||||||
|
if(rp->from!=rp->to){
|
||||||
|
Dup(rp->from, rp->to);
|
||||||
|
close(rp->from);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case RDUP: Dup(rp->from, rp->to); break;
|
||||||
|
case RCLOSE: close(rp->from); break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
word *searchpath(char *w){
|
||||||
|
word *path;
|
||||||
|
if(strncmp(w, "/", 1)==0
|
||||||
|
|| strncmp(w, "#", 1)==0
|
||||||
|
|| strncmp(w, "./", 2)==0
|
||||||
|
|| strncmp(w, "../", 3)==0
|
||||||
|
|| (path=vlook("path")->val)==0)
|
||||||
|
path=&nullpath;
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
void execexec(void){
|
||||||
|
popword(); /* "exec" */
|
||||||
|
if(runq->argv->words==0){
|
||||||
|
Xerror1("empty argument list");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
doredir(runq->redir);
|
||||||
|
Execute(runq->argv->words, searchpath(runq->argv->words->word));
|
||||||
|
poplist();
|
||||||
|
}
|
||||||
|
void execfunc(var *func)
|
||||||
|
{
|
||||||
|
word *starval;
|
||||||
|
popword();
|
||||||
|
starval=runq->argv->words;
|
||||||
|
runq->argv->words=0;
|
||||||
|
poplist();
|
||||||
|
start(func->fn, func->pc, (struct var *)0);
|
||||||
|
runq->local=newvar(strdup("*"), 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 */
|
||||||
|
static int wdirfd = -2;
|
||||||
|
if(chdir(word)<0) return -1;
|
||||||
|
if(flag['i']!=0){
|
||||||
|
if(wdirfd==-2) /* try only once */
|
||||||
|
wdirfd = open("/dev/wdir", OWRITE|OCEXEC);
|
||||||
|
if(wdirfd>=0)
|
||||||
|
write(wdirfd, word, strlen(word));
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
void execcd(void){
|
||||||
|
word *a=runq->argv->words;
|
||||||
|
word *cdpath;
|
||||||
|
char dir[512];
|
||||||
|
setstatus("can't cd");
|
||||||
|
cdpath=vlook("cdpath")->val;
|
||||||
|
switch(count(a)){
|
||||||
|
default:
|
||||||
|
pfmt(err, "Usage: cd [directory]\n");
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
if(a->next->word[0]=='/' || cdpath==0) cdpath=&nullpath;
|
||||||
|
for(;cdpath;cdpath=cdpath->next){
|
||||||
|
strcpy(dir, cdpath->word);
|
||||||
|
if(dir[0]) strcat(dir, "/");
|
||||||
|
strcat(dir, a->next->word);
|
||||||
|
if(dochdir(dir)>=0){
|
||||||
|
if(strlen(cdpath->word)
|
||||||
|
&& strcmp(cdpath->word, ".")!=0)
|
||||||
|
pfmt(err, "%s\n", dir);
|
||||||
|
setstatus("");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(cdpath==0) pfmt(err, "Can't cd %s: %r\n", a->next->word);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
a=vlook("home")->val;
|
||||||
|
if(count(a)>=1){
|
||||||
|
if(dochdir(a->word)>=0)
|
||||||
|
setstatus("");
|
||||||
|
else
|
||||||
|
pfmt(err, "Can't cd %s: %r\n", a->word);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
pfmt(err, "Can't cd -- $home empty\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
poplist();
|
||||||
|
}
|
||||||
|
void execexit(void){
|
||||||
|
switch(count(runq->argv->words)){
|
||||||
|
default: pfmt(err, "Usage: exit [status]\nExiting anyway\n");
|
||||||
|
case 2: setstatus(runq->argv->words->next->word);
|
||||||
|
case 1: Xexit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void execshift(void){
|
||||||
|
int n;
|
||||||
|
word *a;
|
||||||
|
var *star;
|
||||||
|
switch(count(runq->argv->words)){
|
||||||
|
default:
|
||||||
|
pfmt(err, "Usage: shift [n]\n");
|
||||||
|
setstatus("shift usage");
|
||||||
|
poplist();
|
||||||
|
return;
|
||||||
|
case 2: n=atoi(runq->argv->words->next->word); break;
|
||||||
|
case 1: n=1; break;
|
||||||
|
}
|
||||||
|
star=vlook("*");
|
||||||
|
for(;n && star->val;--n){
|
||||||
|
a=star->val->next;
|
||||||
|
efree(star->val->word);
|
||||||
|
efree((char *)star->val);
|
||||||
|
star->val=a;
|
||||||
|
star->changed=1;
|
||||||
|
}
|
||||||
|
setstatus("");
|
||||||
|
poplist();
|
||||||
|
}
|
||||||
|
int octal(char *s)
|
||||||
|
{
|
||||||
|
int n=0;
|
||||||
|
while(*s==' ' || *s=='\t' || *s=='\n') s++;
|
||||||
|
while('0'<=*s && *s<='7') n=n*8+*s++-'0';
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
int mapfd(int fd)
|
||||||
|
{
|
||||||
|
redir *rp;
|
||||||
|
for(rp=runq->redir;rp;rp=rp->next){
|
||||||
|
switch(rp->type){
|
||||||
|
case RCLOSE:
|
||||||
|
if(rp->from==fd) fd=-1;
|
||||||
|
break;
|
||||||
|
case RDUP:
|
||||||
|
case ROPEN:
|
||||||
|
if(rp->to==fd) fd=rp->from;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
union code rdcmds[4];
|
||||||
|
void execcmds(io *f)
|
||||||
|
{
|
||||||
|
static int first=1;
|
||||||
|
if(first){
|
||||||
|
rdcmds[0].i=1;
|
||||||
|
rdcmds[1].f=Xrdcmds;
|
||||||
|
rdcmds[2].f=Xreturn;
|
||||||
|
first=0;
|
||||||
|
}
|
||||||
|
start(rdcmds, 1, runq->local);
|
||||||
|
runq->cmdfd=f;
|
||||||
|
runq->iflast=0;
|
||||||
|
}
|
||||||
|
void execeval(void){
|
||||||
|
char *cmdline, *s, *t;
|
||||||
|
int len=0;
|
||||||
|
word *ap;
|
||||||
|
if(count(runq->argv->words)<=1){
|
||||||
|
Xerror1("Usage: eval cmd ...");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
eflagok=1;
|
||||||
|
for(ap=runq->argv->words->next;ap;ap=ap->next)
|
||||||
|
len+=1+strlen(ap->word);
|
||||||
|
cmdline=emalloc(len);
|
||||||
|
s=cmdline;
|
||||||
|
for(ap=runq->argv->words->next;ap;ap=ap->next){
|
||||||
|
for(t=ap->word;*t;) *s++=*t++;
|
||||||
|
*s++=' ';
|
||||||
|
}
|
||||||
|
s[-1]='\n';
|
||||||
|
poplist();
|
||||||
|
execcmds(opencore(cmdline, len));
|
||||||
|
efree(cmdline);
|
||||||
|
}
|
||||||
|
union code dotcmds[14];
|
||||||
|
void execdot(void){
|
||||||
|
int iflag=0;
|
||||||
|
int fd;
|
||||||
|
list *av;
|
||||||
|
thread *p=runq;
|
||||||
|
char *zero;
|
||||||
|
static int first=1;
|
||||||
|
char file[512];
|
||||||
|
word *path;
|
||||||
|
if(first){
|
||||||
|
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();
|
||||||
|
if(p->argv->words && strcmp(p->argv->words->word, "-i")==0){
|
||||||
|
iflag=1;
|
||||||
|
popword();
|
||||||
|
}
|
||||||
|
/* get input file */
|
||||||
|
if(p->argv->words==0){
|
||||||
|
Xerror1("Usage: . [-i] file [arg ...]");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
zero=strdup(p->argv->words->word);
|
||||||
|
popword();
|
||||||
|
fd=-1;
|
||||||
|
for(path=searchpath(zero);path;path=path->next){
|
||||||
|
strcpy(file, path->word);
|
||||||
|
if(file[0]) strcat(file, "/");
|
||||||
|
strcat(file, zero);
|
||||||
|
if((fd=open(file, 0))>=0) break;
|
||||||
|
if(strcmp(file, "/dev/stdin")==0){ /* for sun & ucb */
|
||||||
|
fd=Dup1(0);
|
||||||
|
if(fd>=0) break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(fd<0){
|
||||||
|
pfmt(err, "%s: ", zero);
|
||||||
|
setstatus("can't open");
|
||||||
|
Xerror(".: can't open");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
/* set up for a new command loop */
|
||||||
|
start(dotcmds, 1, (struct var *)0);
|
||||||
|
pushredir(RCLOSE, fd, 0);
|
||||||
|
runq->cmdfile=zero;
|
||||||
|
runq->cmdfd=openfd(fd);
|
||||||
|
runq->iflag=iflag;
|
||||||
|
runq->iflast=0;
|
||||||
|
/* push $* value */
|
||||||
|
pushlist();
|
||||||
|
runq->argv->words=p->argv->words;
|
||||||
|
/* free caller's copy of $* */
|
||||||
|
av=p->argv;
|
||||||
|
p->argv=av->next;
|
||||||
|
efree((char *)av);
|
||||||
|
/* push $0 value */
|
||||||
|
pushlist();
|
||||||
|
pushword(zero);
|
||||||
|
ndot++;
|
||||||
|
}
|
||||||
|
void execflag(void){
|
||||||
|
char *letter, *val;
|
||||||
|
switch(count(runq->argv->words)){
|
||||||
|
case 2:
|
||||||
|
setstatus(flag[(uchar)runq->argv->words->next->word[0]]?"":"flag not set");
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
letter=runq->argv->words->next->word;
|
||||||
|
val=runq->argv->words->next->next->word;
|
||||||
|
if(strlen(letter)==1){
|
||||||
|
if(strcmp(val, "+")==0){
|
||||||
|
flag[(uchar)letter[0]]=flagset;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(strcmp(val, "-")==0){
|
||||||
|
flag[(uchar)letter[0]]=0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
Xerror1("Usage: flag [letter] [+-]");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
poplist();
|
||||||
|
}
|
||||||
|
void execwhatis(void){ /* mildly wrong -- should fork before writing */
|
||||||
|
word *a, *b, *path;
|
||||||
|
var *v;
|
||||||
|
struct builtin *bp;
|
||||||
|
char file[512];
|
||||||
|
struct io out[1];
|
||||||
|
int found, sep;
|
||||||
|
a=runq->argv->words->next;
|
||||||
|
if(a==0){
|
||||||
|
Xerror1("Usage: whatis name ...");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setstatus("");
|
||||||
|
out->fd=mapfd(1);
|
||||||
|
out->bufp=out->buf;
|
||||||
|
out->ebuf=&out->buf[NBUF];
|
||||||
|
out->strp=0;
|
||||||
|
for(;a;a=a->next){
|
||||||
|
v=vlook(a->word);
|
||||||
|
if(v->val){
|
||||||
|
pfmt(out, "%s=", a->word);
|
||||||
|
if(v->val->next==0)
|
||||||
|
pfmt(out, "%q\n", v->val->word);
|
||||||
|
else{
|
||||||
|
sep='(';
|
||||||
|
for(b=v->val;b && b->word;b=b->next){
|
||||||
|
pfmt(out, "%c%q", sep, b->word);
|
||||||
|
sep=' ';
|
||||||
|
}
|
||||||
|
pfmt(out, ")\n");
|
||||||
|
}
|
||||||
|
found=1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
found=0;
|
||||||
|
v=gvlook(a->word);
|
||||||
|
if(v->fn) pfmt(out, "fn %s %s\n", v->name, v->fn[v->pc-1].s);
|
||||||
|
else{
|
||||||
|
for(bp=Builtin;bp->name;bp++)
|
||||||
|
if(strcmp(a->word, bp->name)==0){
|
||||||
|
pfmt(out, "builtin %s\n", a->word);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(!bp->name){
|
||||||
|
for(path=searchpath(a->word);path;path=path->next){
|
||||||
|
strcpy(file, path->word);
|
||||||
|
if(file[0]) strcat(file, "/");
|
||||||
|
strcat(file, a->word);
|
||||||
|
if(Executable(file)){
|
||||||
|
pfmt(out, "%s\n", file);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(!path && !found){
|
||||||
|
pfmt(err, "%s: not found\n", a->word);
|
||||||
|
setstatus("not found");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
poplist();
|
||||||
|
flush(err);
|
||||||
|
}
|
||||||
|
void execwait(void){
|
||||||
|
switch(count(runq->argv->words)){
|
||||||
|
default: Xerror1("Usage: wait [pid]"); return;
|
||||||
|
case 2: Waitfor(atoi(runq->argv->words->next->word), 0); break;
|
||||||
|
case 1: Waitfor(-1, 0); break;
|
||||||
|
}
|
||||||
|
poplist();
|
||||||
|
}
|
||||||
59
src/cmd/rc/subr.c
Normal file
59
src/cmd/rc/subr.c
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
#include "rc.h"
|
||||||
|
#include "exec.h"
|
||||||
|
#include "io.h"
|
||||||
|
#include "fns.h"
|
||||||
|
char *emalloc(long n){
|
||||||
|
char *p=(char *)Malloc(n);
|
||||||
|
if(p==0) panic("Can't malloc %d bytes", n);
|
||||||
|
/* if(err){ pfmt(err, "malloc %d->%p\n", n, p); flush(err); } *//**/
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
void efree(char *p)
|
||||||
|
{
|
||||||
|
/* pfmt(err, "free %p\n", p); flush(err); *//**/
|
||||||
|
if(p) free(p);
|
||||||
|
else pfmt(err, "free 0\n");
|
||||||
|
}
|
||||||
|
extern int lastword, lastdol;
|
||||||
|
void yyerror(char *m)
|
||||||
|
{
|
||||||
|
pfmt(err, "rc: ");
|
||||||
|
if(runq->cmdfile && !runq->iflag)
|
||||||
|
pfmt(err, "%s:%d: ", runq->cmdfile, runq->lineno);
|
||||||
|
else if(runq->cmdfile)
|
||||||
|
pfmt(err, "%s: ", runq->cmdfile);
|
||||||
|
else if(!runq->iflag)
|
||||||
|
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;
|
||||||
|
void iacvt(int n){
|
||||||
|
if(n<0){
|
||||||
|
*bp++='-';
|
||||||
|
n=-n; /* doesn't work for n==-inf */
|
||||||
|
}
|
||||||
|
if(n/10)
|
||||||
|
iacvt(n/10);
|
||||||
|
*bp++=n%10+'0';
|
||||||
|
}
|
||||||
|
void itoa(char *s, long n)
|
||||||
|
{
|
||||||
|
bp=s;
|
||||||
|
iacvt(n);
|
||||||
|
*bp='\0';
|
||||||
|
}
|
||||||
|
void panic(char *s, int n)
|
||||||
|
{
|
||||||
|
pfmt(err, "rc: ");
|
||||||
|
pfmt(err, s, n);
|
||||||
|
pchr(err, '\n');
|
||||||
|
flush(err);
|
||||||
|
Abort();
|
||||||
|
}
|
||||||
34
src/cmd/rc/trap.c
Normal file
34
src/cmd/rc/trap.c
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
#include "rc.h"
|
||||||
|
#include "exec.h"
|
||||||
|
#include "fns.h"
|
||||||
|
#include "io.h"
|
||||||
|
extern char *Signame[];
|
||||||
|
void dotrap(void){
|
||||||
|
register int i;
|
||||||
|
register struct var *trapreq;
|
||||||
|
register struct word *starval;
|
||||||
|
starval=vlook("*")->val;
|
||||||
|
while(ntrap) for(i=0;i!=NSIG;i++) while(trap[i]){
|
||||||
|
--trap[i];
|
||||||
|
--ntrap;
|
||||||
|
if(getpid()!=mypid) Exit(getstatus());
|
||||||
|
trapreq=vlook(Signame[i]);
|
||||||
|
if(trapreq->fn){
|
||||||
|
start(trapreq->fn, trapreq->pc, (struct var *)0);
|
||||||
|
runq->local=newvar(strdup("*"), 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){
|
||||||
|
/*
|
||||||
|
* run the stack down until we uncover the
|
||||||
|
* command reading loop. Xreturn will exit
|
||||||
|
* if there is none (i.e. if this is not
|
||||||
|
* an interactive rc.)
|
||||||
|
*/
|
||||||
|
while(!runq->iflag) Xreturn();
|
||||||
|
}
|
||||||
|
else Exit(getstatus());
|
||||||
|
}
|
||||||
|
}
|
||||||
114
src/cmd/rc/tree.c
Normal file
114
src/cmd/rc/tree.c
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
#include "rc.h"
|
||||||
|
#include "exec.h"
|
||||||
|
#include "io.h"
|
||||||
|
#include "fns.h"
|
||||||
|
tree *treenodes;
|
||||||
|
/*
|
||||||
|
* create and clear a new tree node, and add it
|
||||||
|
* to the node list.
|
||||||
|
*/
|
||||||
|
tree *newtree(void){
|
||||||
|
tree *t=new(tree);
|
||||||
|
t->iskw=0;
|
||||||
|
t->str=0;
|
||||||
|
t->child[0]=t->child[1]=t->child[2]=0;
|
||||||
|
t->next=treenodes;
|
||||||
|
treenodes=t;
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
void freenodes(void){
|
||||||
|
tree *t, *u;
|
||||||
|
for(t=treenodes;t;t=u){
|
||||||
|
u=t->next;
|
||||||
|
if(t->str) efree(t->str);
|
||||||
|
efree((char *)t);
|
||||||
|
}
|
||||||
|
treenodes=0;
|
||||||
|
}
|
||||||
|
tree *tree1(int type, tree *c0)
|
||||||
|
{
|
||||||
|
return tree3(type, c0, (tree *)0, (tree *)0);
|
||||||
|
}
|
||||||
|
tree *tree2(int type, tree *c0, tree *c1)
|
||||||
|
{
|
||||||
|
return tree3(type, c0, c1, (tree *)0);
|
||||||
|
}
|
||||||
|
tree *tree3(int type, tree *c0, tree *c1, tree *c2)
|
||||||
|
{
|
||||||
|
tree *t;
|
||||||
|
if(type==';'){
|
||||||
|
if(c0==0) return c1;
|
||||||
|
if(c1==0) return c0;
|
||||||
|
}
|
||||||
|
t=newtree();
|
||||||
|
t->type=type;
|
||||||
|
t->child[0]=c0;
|
||||||
|
t->child[1]=c1;
|
||||||
|
t->child[2]=c2;
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
tree *mung1(tree *t, tree *c0)
|
||||||
|
{
|
||||||
|
t->child[0]=c0;
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
tree *mung2(tree *t, tree *c0, tree *c1)
|
||||||
|
{
|
||||||
|
t->child[0]=c0;
|
||||||
|
t->child[1]=c1;
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
tree *mung3(tree *t, tree *c0, tree *c1, tree *c2)
|
||||||
|
{
|
||||||
|
t->child[0]=c0;
|
||||||
|
t->child[1]=c1;
|
||||||
|
t->child[2]=c2;
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
tree *epimung(tree *comp, tree *epi)
|
||||||
|
{
|
||||||
|
tree *p;
|
||||||
|
if(epi==0) return comp;
|
||||||
|
for(p=epi;p->child[1];p=p->child[1]);
|
||||||
|
p->child[1]=comp;
|
||||||
|
return epi;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* Add a SIMPLE node at the root of t and percolate all the redirections
|
||||||
|
* up to the root.
|
||||||
|
*/
|
||||||
|
tree *simplemung(tree *t)
|
||||||
|
{
|
||||||
|
tree *u;
|
||||||
|
struct io *s;
|
||||||
|
t=tree1(SIMPLE, t);
|
||||||
|
s=openstr();
|
||||||
|
pfmt(s, "%t", t);
|
||||||
|
t->str=strdup(s->strp);
|
||||||
|
closeio(s);
|
||||||
|
for(u=t->child[0];u->type==ARGLIST;u=u->child[0]){
|
||||||
|
if(u->child[1]->type==DUP
|
||||||
|
|| u->child[1]->type==REDIR){
|
||||||
|
u->child[1]->child[1]=t;
|
||||||
|
t=u->child[1];
|
||||||
|
u->child[1]=0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
tree *token(char *str, int type)
|
||||||
|
{
|
||||||
|
tree *t=newtree();
|
||||||
|
t->type=type;
|
||||||
|
t->str=strdup(str);
|
||||||
|
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) efree(p->str);
|
||||||
|
efree((char *)p);
|
||||||
|
}
|
||||||
71
src/cmd/rc/var.c
Normal file
71
src/cmd/rc/var.c
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
#include "rc.h"
|
||||||
|
#include "exec.h"
|
||||||
|
#include "fns.h"
|
||||||
|
int hash(char *s, int n)
|
||||||
|
{
|
||||||
|
register int h=0, i=1;
|
||||||
|
while(*s) h+=*s++*i++;
|
||||||
|
h%=n;
|
||||||
|
return h<0?h+n:h;
|
||||||
|
}
|
||||||
|
#define NKW 30
|
||||||
|
struct kw{
|
||||||
|
char *name;
|
||||||
|
int type;
|
||||||
|
struct kw *next;
|
||||||
|
}*kw[NKW];
|
||||||
|
void kenter(int type, char *name)
|
||||||
|
{
|
||||||
|
register int h=hash(name, NKW);
|
||||||
|
register struct kw *p=new(struct kw);
|
||||||
|
p->type=type;
|
||||||
|
p->name=name;
|
||||||
|
p->next=kw[h];
|
||||||
|
kw[h]=p;
|
||||||
|
}
|
||||||
|
void kinit(void){
|
||||||
|
kenter(FOR, "for");
|
||||||
|
kenter(IN, "in");
|
||||||
|
kenter(WHILE, "while");
|
||||||
|
kenter(IF, "if");
|
||||||
|
kenter(NOT, "not");
|
||||||
|
kenter(TWIDDLE, "~");
|
||||||
|
kenter(BANG, "!");
|
||||||
|
kenter(SUBSHELL, "@");
|
||||||
|
kenter(SWITCH, "switch");
|
||||||
|
kenter(FN, "fn");
|
||||||
|
}
|
||||||
|
tree *klook(char *name)
|
||||||
|
{
|
||||||
|
struct kw *p;
|
||||||
|
tree *t=token(name, WORD);
|
||||||
|
for(p=kw[hash(name, NKW)];p;p=p->next)
|
||||||
|
if(strcmp(p->name, name)==0){
|
||||||
|
t->type=p->type;
|
||||||
|
t->iskw=1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
var *gvlook(char *name)
|
||||||
|
{
|
||||||
|
int h=hash(name, NVAR);
|
||||||
|
var *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]);
|
||||||
|
}
|
||||||
|
var *vlook(char *name)
|
||||||
|
{
|
||||||
|
var *v;
|
||||||
|
if(runq)
|
||||||
|
for(v=runq->local;v;v=v->next)
|
||||||
|
if(strcmp(v->name, name)==0) return v;
|
||||||
|
return gvlook(name);
|
||||||
|
}
|
||||||
|
void setvar(char *name, word *val)
|
||||||
|
{
|
||||||
|
register struct var *v=vlook(name);
|
||||||
|
freewords(v->val);
|
||||||
|
v->val=val;
|
||||||
|
v->changed=1;
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user