mirror of
https://git.suckless.org/9base
synced 2025-08-28 10:53:47 -07:00
initial import
This commit is contained in:
946
rc/exec.c
Normal file
946
rc/exec.c
Normal file
@@ -0,0 +1,946 @@
|
||||
#include <u.h>
|
||||
#include <signal.h>
|
||||
#if defined(PLAN9PORT) && defined(__sun__)
|
||||
# define BSD_COMP /* sigh. for TIOCNOTTY */
|
||||
#endif
|
||||
#include <sys/ioctl.h>
|
||||
#include "rc.h"
|
||||
#include "getflags.h"
|
||||
#include "exec.h"
|
||||
#include "io.h"
|
||||
#include "fns.h"
|
||||
/*
|
||||
* 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->pid=-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;
|
||||
v->changefn = 0;
|
||||
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());
|
||||
pathinit();
|
||||
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();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
/*
|
||||
* 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 tty;
|
||||
int pid;
|
||||
char npid[10];
|
||||
if(null<0){
|
||||
Xerror("Can't open /dev/null\n");
|
||||
return;
|
||||
}
|
||||
switch(pid=rfork(RFFDG|RFPROC|RFNOTEG)){
|
||||
case -1:
|
||||
close(null);
|
||||
Xerror("try again");
|
||||
break;
|
||||
case 0:
|
||||
/*
|
||||
* I don't know what the right thing to do here is,
|
||||
* so this is all experimentally determined.
|
||||
* If we just dup /dev/null onto 0, then running
|
||||
* ssh foo & will reopen /dev/tty, try to read a password,
|
||||
* get a signal, and repeat, in a tight loop, forever.
|
||||
* Arguably this is a bug in ssh (it behaves the same
|
||||
* way under bash as under rc) but I'm fixing it here
|
||||
* anyway. If we dissociate the process from the tty,
|
||||
* then it won't be able to open /dev/tty ever again.
|
||||
* The SIG_IGN on SIGTTOU makes writing the tty
|
||||
* (via fd 1 or 2, for example) succeed even though
|
||||
* our pgrp is not the terminal's controlling pgrp.
|
||||
*/
|
||||
if((tty=open("/dev/tty", OREAD)) >= 0){
|
||||
/*
|
||||
* Should make reads of tty fail, writes succeed.
|
||||
*/
|
||||
signal(SIGTTIN, SIG_IGN);
|
||||
signal(SIGTTOU, SIG_IGN);
|
||||
ioctl(tty, TIOCNOTTY);
|
||||
close(tty);
|
||||
}
|
||||
if(isatty(0))
|
||||
pushredir(ROPEN, null, 0);
|
||||
else
|
||||
close(null);
|
||||
start(runq->code, runq->pc+1, runq->local);
|
||||
runq->ret=0;
|
||||
break;
|
||||
default:
|
||||
close(null);
|
||||
runq->pc=runq->code[runq->pc].i;
|
||||
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, int c){
|
||||
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++=c;
|
||||
}
|
||||
if(s==value) *s='\0';
|
||||
else s[-1]='\0';
|
||||
return value;
|
||||
}
|
||||
char *list2str(word *words){
|
||||
return _list2str(words, ' ');
|
||||
}
|
||||
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;
|
||||
if(v->changefn)
|
||||
v->changefn(v);
|
||||
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);
|
||||
setstatus("error");
|
||||
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);
|
||||
setstatus("error");
|
||||
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();
|
||||
}
|
Reference in New Issue
Block a user