#include "rc.h"
int ifnot;
int eflagok;
/*
* 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
*/
static char **
rcargv(char *s)
{
char *flags;
if(flag['e'])
flags = "-Se";
else
flags = "-S";
return procargv(argv0, flags, "-c", s, vlook("*")->val);
}
void
Xappend(void)
{
char *file;
int f;
switch(count(runq->argv->words)){
default: Xerror(">> requires singleton"); return;
case 0: Xerror(">> requires file"); return;
case 1: break;
}
file=runq->argv->words->word;
if((f=open(file, 1))<0 && (f=create(file, 1, 0666))<0){
Xperror(file);
return;
}
seek(f, 0L, 2);
pushredir(ROPEN, f, runq->code[runq->pc].i);
runq->pc++;
poplist();
}
void
Xassign(void)
{
Var *v;
if(count(runq->argv->words)!=1){
Xerror("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();
}
static void
procproc(void *a)
{
int i;
struct { Channel *pidc; char *cmd; char **argv; int *fd; } *arg;
arg = a;
rfork(RFFDG);
for(i=0; i<3; i++){
if(arg->fd[i]==-1)
close(i);
else if(arg->fd[i] != i)
dup(arg->fd[i], i);
}
procexec(arg->pidc, arg->cmd, arg->argv);
threadexits(nil);
}
int
proc(char *cmd, char **argv, int fd[3])
{
int pid;
struct { Channel *pidc; char *cmd; char **argv; int *fd; } s;
s.pidc = chancreate(sizeof(ulong), 0);
s.cmd = cmd;
s.argv = argv;
s.fd = fd;
proccreate(procproc, &s, 8192);
pid = recvul(s.pidc);
chanfree(s.pidc);
return pid;
}
void
Xasync(void)
{
int fd[3], pid;
char buf[20], **argv;
updenv();
argv = rcargv(runq->code[runq->pc].s);
fd[0] = -1;
fd[1] = 1;
fd[2] = 2;
pid = proc(argv[0], argv, fd);
free(argv);
if(pid < 0) {
Xperror("proc failed");
return;
}
runq->pc++;
sprint(buf, "%d", pid);
setvar("apid", newword(buf, (Word *)0));
}
void
Xbackq(void)
{
char wd[8193], **argv;
int c, fd[3];
char *s, *ewd=&wd[8192], *stop;
Io *f;
Var *ifs=vlook("ifs");
Word *v, *nextv;
int pfd[2];
int pid;
stop = ifs->val?ifs->val->word:"";
if(pipe(pfd)<0){
snprint(wd, sizeof wd, "can't make pipe: %r");
Xerror(wd);
return;
}
updenv();
argv = rcargv(runq->code[runq->pc].s);
fd[0] = -1;
fd[1] = pfd[1];
fd[2] = 2;
pid = proc(argv[0], argv, fd);
//fprint(2, "procexec %d\n", pid);
close(pfd[1]);
if(pid < 0) {
snprint(wd, sizeof wd, "procexec %s failed: %r", argv[0]);
free(argv);
Xerror(wd);
close(pfd[0]);
return;
}
free(argv);
//fprint(2, "open %d\n", pfd[0]);
f = openfd(pfd[0]);
s = wd;
v = 0;
while((c=rchr(f))!=EOF){
//fprint(2, "rchr %d...", c);
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);
//fprint(2, "waitfor %d\n", pid);
waitfor(pid);
//fprint(2, "done\n");
/* 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
Xbang(void)
{
setstatus(truestatus()?"false":"");
}
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;
}
}
free(s);
if(ok)
runq->pc++;
else
runq->pc=runq->code[runq->pc].i;
poplist();
}
void
Xclose(void)
{
pushredir(RCLOSE, runq->code[runq->pc].i, 0);
runq->pc++;
}
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){
Xerror("null list in concatenation");
return;
}
if(lc!=1 && rc!=1 && lc!=rc){
Xerror("mismatched list lengths in concatenation");
return;
}
vp=conclist(lp, rp, vp);
}
poplist();
poplist();
runq->argv->words=vp;
}
void
Xcount(void)
{
Word *a;
char *s, *t;
int n;
char num[12];
if(count(runq->argv->words)!=1){
Xerror("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;
sprint(num, "%d", count(a));
}
else{
a=vlook("*")->val;
sprint(num, "%d", a && 1<=n && n<=count(a)?1:0);
}
poplist();
pushword(num);
}
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
Xdelhere(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
Xdol(void)
{
Word *a, *star;
char *s, *t;
int n;
if(count(runq->argv->words)!=1){
Xerror("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
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)
{
Var *trapreq;
Word *starval;
char *c;
static int beenhere=0;
if(truestatus())
c = "";
else
c = getstatus();
if(flag['S'] || beenhere)
threadexitsall(c);
trapreq=vlook("sigexit");
if(trapreq->fn){
beenhere=1;
--runq->pc;
starval=vlook("*")->val;
start(trapreq->fn, trapreq->pc, (Var*)0);
runq->local=newvar(strdup("*"), runq->local);
runq->local->val=copywords(starval, (Word*)0);
runq->local->changed=1;
runq->redir=runq->startredir=0;
}
threadexitsall(c);
}
void
Xfalse(void)
{
if(truestatus())
runq->pc=runq->code[runq->pc].i;
else
runq->pc++;
}
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
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
Xglob(void)
{
globlist();
}
void
Xif(void)
{
ifnot=1;
if(truestatus()) runq->pc++;
else runq->pc=runq->code[runq->pc].i;
}
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
Xlocal(void)
{
if(count(runq->argv->words)!=1){
Xerror("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, 0);
runq->local->changed=1;
poplist();
poplist();
}
void
Xmark(void)
{
pushlist();
}
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;
}
}
free(subject);
poplist();
poplist();
}
void
Xpipe(void)
{
Thread *p=runq;
int pc=p->pc, pid;
int lfd=p->code[pc].i;
int rfd=p->code[pc+1].i;
int fd[3], pfd[2];
char **argv;
if(pipe(pfd)<0){
Xperror("can't get pipe");
return;
}
updenv();
argv = rcargv(runq->code[pc+2].s);
fd[0] = 0;
fd[1] = pfd[1];
fd[2] = 2;
pid = proc(argv[0], argv, fd);
free(argv);
close(pfd[1]);
if(pid < 0) {
Xperror("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)
{
sysfatal("Xpipefd");
}
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);
runq->pid=-1;
setstatus(concstatus(getstatus(), status));
}
}
void
Xpopm(void)
{
poplist();
}
void
Xpopredir(void)
{
Redir *rp=runq->redir;
if(rp==0)
panic("turfredir null!", 0);
runq->redir=rp->next;
if(rp->type==ROPEN)
close(rp->from);
free((char *)rp);
}
void
Xqdol(void)
{
Word *a, *p;
char *s;
int n;
if(count(runq->argv->words)!=1){
Xerror("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=malloc(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);
free(s);
}
void
Xrdcmds(void)
{
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="% ";
}
if(yyparse()) {
if(!p->iflag || p->eof && !interrupted) {
if(p->cmdfile)
free(p->cmdfile);
closeio(p->cmdfd);
Xreturn(); /* should this be omitted? */
} else {
if(interrupted){
interrupted=0;
pchr(err, '\n');
p->eof=0;
}
--p->pc; /* go back for next command */
}
} else {
ntrap.ref = 0; /* avoid race with intr */
--p->pc; /* re-execute Xrdcmds after codebuf runs */
start(codebuf, 1, runq->local);
}
freenodes();
}
void
Xread(void)
{
char *file;
int f;
switch(count(runq->argv->words)){
default: Xerror("< requires singleton\n"); return;
case 0: Xerror("< requires file\n"); return;
case 1: break;
}
file=runq->argv->words->word;
if((f=open(file, 0))<0){
Xperror(file);
return;
}
pushredir(ROPEN, f, runq->code[runq->pc].i);
runq->pc++;
poplist();
}
void
Xreturn(void)
{
Thread *p=runq;
turfredir();
while(p->argv)
poplist();
codefree(p->code);
runq=p->ret;
//fprint(2, "return runq=%p\n", runq);
free(p);
if(runq==0)
exits(truestatus()?"":getstatus());
}
void
Xsettrue(void)
{
setstatus("");
}
void
Xsub(void)
{
Word *a, *v;
char *s;
if(count(runq->argv->next->words)!=1){
Xerror("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
Xsubshell(void)
{
char **argv;
int fd[3], pid;
updenv();
argv = rcargv(runq->code[runq->pc].s);
fd[0] = -1;
fd[1] = 1;
fd[2] = 2;
pid = proc(argv[0], argv, fd);
free(argv);
if(pid < 0) {
Xperror("proc failed");
return;
}
waitfor(pid);
runq->pc++;
}
void
Xtrue(void)
{
if(truestatus())
runq->pc++;
else
runq->pc=runq->code[runq->pc].i;
}
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;
free(v->name);
freewords(v->val);
free(v);
}
void
Xwastrue(void)
{
ifnot=0;
}
void
Xwrite(void)
{
char *file;
int f;
switch(count(runq->argv->words)){
default: Xerror("> requires singleton\n"); return;
case 0: Xerror("> requires file\n"); return;
case 1: break;
}
file=runq->argv->words->word;
if((f = create(file, 1, 0666))<0){
Xperror(file);
return;
}
pushredir(ROPEN, f, runq->code[runq->pc].i);
runq->pc++;
poplist();
}
void
Xword(void)
{
pushword(runq->code[runq->pc++].s);
}
void
Xerror(char *s)
{
pfmt(err, "rcsh: %s\n", s);
flush(err);
while(!runq->iflag)
Xreturn();
}
void
Xperror(char *s)
{
pfmt(err, "rcsh: %s: %r\n", s);
flush(err);
while(!runq->iflag)
Xreturn();
}
syntax highlighted by Code2HTML, v. 0.9.1