rc: make it portable (for UNIX)

Fixup remaining Plan9 dependencies (chartorune()).
Add Makefile for UNIX-like systems (tested with Linux and APE).
Make error printing consistent, use Errstr() explicitely.
Get rid of NSTATUS buffer limit, just malloc it.
This commit is contained in:
cinap_lenrek 2022-01-03 18:41:48 +00:00
parent c51a5cfa06
commit 189731aad0
21 changed files with 803 additions and 159 deletions

51
sys/src/cmd/rc/Makefile Normal file
View file

@ -0,0 +1,51 @@
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\
havefork.o\
unix.o\
y.tab.o\
HFILES=rc.h\
y.tab.h\
io.h\
exec.h\
fns.h\
getflags.h\
YFILES=syn.y
PREFIX=/usr/local
all: $(TARG)
install: $(TARG) rcmain.unix
cp $(TARG) $(PREFIX)/bin/
cp rcmain.unix $(PREFIX)/lib/rcmain
$(TARG): $(OFILES)
$(CC) $(CFLAGS) $(LDFLAGS) -o $(TARG) $(OFILES)
y.tab.h y.tab.c: $(YFILES)
$(YACC) -d $(YFILES)
unix.o: unix.c
$(CC) $(CFLAGS) '-DPREFIX="$(PREFIX)"' -c unix.c
$(OFILES): $(HFILES)
clean:
rm -f $(OFILES) $(TARG) y.tab.? y.debug

View file

@ -460,7 +460,7 @@ codeswitch(tree *t, int eflag)
int out; /* jump here to leave switch */
int nextcase; /* patch jump address to next case */
tree *tt;
if(c1->child[0]==nil
if(c1->child[0]==0
|| c1->child[0]->type!=';'
|| !iscase(c1->child[0]->child[0])){
yyerror("case missing in switch");

View file

@ -19,6 +19,8 @@ start(code *c, int pc, var *local, redir *redir)
p->lex = 0;
p->local = local;
p->iflag = 0;
p->pid = 0;
p->status = 0;
p->ret = runq;
runq = p;
}
@ -42,6 +44,7 @@ popthread(void)
runq = p->ret;
if(p->lex) freelexer(p->lex);
codefree(p->code);
free(p->status);
free(p);
}
@ -341,7 +344,7 @@ Xappend(void)
}
file = runq->argv->words->word;
if((fd = Open(file, 1))<0 && (fd = Creat(file))<0){
Xerror("can't open");
Xerror3(">> can't open", file, Errstr());
return;
}
Seek(fd, 0L, 2);
@ -395,7 +398,7 @@ Xexit(void)
return;
}
}
Exit(getstatus());
Exit();
}
void
@ -443,25 +446,51 @@ Xpush(void)
runq->argv->words = h;
}
static int
herefile(char *tmp)
{
char *s = tmp+strlen(tmp)-1;
static int ser;
int fd, i;
i = ser++;
while(*s == 'Y'){
*s-- = (i%26) + 'A';
i = i/26;
}
i = getpid();
while(*s == 'X'){
*s-- = (i%10) + '0';
i = i/10;
}
s++;
for(i='a'; i<'z'; i++){
if(access(tmp, 0)!=0 && (fd = Creat(tmp))>=0)
return fd;
*s = i;
}
return -1;
}
void
Xhere(void)
{
char file[] = "/tmp/here.XXXXXXXXXXX";
char file[]="/tmp/hereXXXXXXXXXXYY";
int fd;
io *io;
if((fd = Creat(mktemp(file)))<0){
Xerror("can't open");
if((fd = herefile(file))<0){
Xerror3("<< can't get temp file", file, Errstr());
return;
}
io = openiofd(fd);
psubst(io, (uchar*)runq->code[runq->pc++].s);
psubst(io, (unsigned char*)runq->code[runq->pc++].s);
flushio(io);
closeio(io);
/* open for reading and unlink */
if((fd = Open(file, 3))<0){
Xerror("can't open");
Xerror3("<< can't open", file, Errstr());
return;
}
pushredir(ROPEN, fd, runq->code[runq->pc++].i);
@ -470,11 +499,11 @@ Xhere(void)
void
Xhereq(void)
{
char file[] = "/tmp/here.XXXXXXXXXXX", *body;
char file[]="/tmp/hereXXXXXXXXXXYY", *body;
int fd;
if((fd = Creat(mktemp(file)))<0){
Xerror("can't open");
if((fd = herefile(file))<0){
Xerror3("<< can't get temp file", file, Errstr());
return;
}
body = runq->code[runq->pc++].s;
@ -483,7 +512,7 @@ Xhereq(void)
/* open for reading and unlink */
if((fd = Open(file, 3))<0){
Xerror("can't open");
Xerror3("<< can't open", file, Errstr());
return;
}
pushredir(ROPEN, fd, runq->code[runq->pc++].i);
@ -492,6 +521,7 @@ Xhereq(void)
void
Xread(void)
{
char *file;
int fd;
switch(count(runq->argv->words)){
@ -504,8 +534,9 @@ Xread(void)
case 1:
break;
}
if((fd = Open(runq->argv->words->word, 0))<0){
Xerror("can't open");
file = runq->argv->words->word;
if((fd = Open(file, 0))<0){
Xerror3("< can't open", file, Errstr());
return;
}
pushredir(ROPEN, fd, runq->code[runq->pc++].i);
@ -515,6 +546,7 @@ Xread(void)
void
Xrdwr(void)
{
char *file;
int fd;
switch(count(runq->argv->words)){
@ -527,8 +559,9 @@ Xrdwr(void)
case 1:
break;
}
if((fd = Open(runq->argv->words->word, 2))<0){
Xerror("can't open");
file = runq->argv->words->word;
if((fd = Open(file, 2))<0){
Xerror3("<> can't open", file, Errstr());
return;
}
pushredir(ROPEN, fd, runq->code[runq->pc++].i);
@ -555,7 +588,7 @@ Xreturn(void)
Xpopredir();
popthread();
if(runq==0)
Exit(getstatus());
Exit();
}
void
@ -588,6 +621,7 @@ Xword(void)
void
Xwrite(void)
{
char *file;
int fd;
switch(count(runq->argv->words)){
@ -600,8 +634,9 @@ Xwrite(void)
case 1:
break;
}
if((fd = Creat(runq->argv->words->word))<0){
Xerror("can't open");
file = runq->argv->words->word;
if((fd = Creat(file))<0){
Xerror3("> can't create", file, Errstr());
return;
}
pushredir(ROPEN, fd, runq->code[runq->pc++].i);
@ -696,7 +731,7 @@ Xassign(void)
var *v;
if(count(runq->argv->words)!=1){
Xerror1("variable name not singleton!");
Xerror1("= variable name not singleton!");
return;
}
v = vlook(runq->argv->words->word);
@ -728,7 +763,7 @@ Xdol(void)
int n;
if(count(runq->argv->words)!=1){
Xerror1("variable name not singleton!");
Xerror1("$ variable name not singleton!");
return;
}
n = 0;
@ -833,7 +868,7 @@ Xsub(void)
char *s;
if(count(runq->argv->next->words)!=1){
Xerror1("variable name not singleton!");
Xerror1("$() variable name not singleton!");
return;
}
s = runq->argv->next->words->word;
@ -853,7 +888,7 @@ Xcount(void)
int n;
if(count(runq->argv->words)!=1){
Xerror1("variable name not singleton!");
Xerror1("$# variable name not singleton!");
return;
}
n = 0;
@ -875,7 +910,7 @@ void
Xlocal(void)
{
if(count(runq->argv->words)!=1){
Xerror1("variable name must be singleton");
Xerror1("local variable name must be singleton");
return;
}
runq->local = newvar(runq->argv->words->word, runq->local);
@ -932,29 +967,31 @@ Xdelfn(void)
static 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;
int n, m;
if(t==0) return s;
if(s==0) return t;
n = strlen(s);
m = strlen(t);
s = erealloc(s, n+m+2);
if(n > 0) s[n++]='|';
memmove(s+n, t, m+1);
free(t);
return s;
}
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);
char *old = Getstatus();
if(runq->pid==-1){
Setstatus(concstatus(runq->status, old));
runq->status=0;
}else{
while(Waitfor(runq->pid) < 0)
;
runq->pid=-1;
setstatus(concstatus(getstatus(), status));
Setstatus(concstatus(Getstatus(), old));
}
}
@ -995,7 +1032,6 @@ Xrdcmds(void)
p->lex = 0;
} else
--p->pc; /* re-execute Xrdcmds after codebuf runs */
ntrap = 0; /* avoid double-interrupts during blocked writes */
start(codebuf, 2, p->local, p->redir);
}
lex = 0;
@ -1026,32 +1062,55 @@ srcfile(thread *p)
return p->code[1].s;
}
void
Xerror(char *s)
{
pfln(err, srcfile(runq), runq->line);
pfmt(err, ": %s: %r\n", s);
flushio(err);
setstatus("error");
while(!runq->iflag) Xreturn();
}
void
Xerror1(char *s)
{
setstatus("error");
pfln(err, srcfile(runq), runq->line);
pfmt(err, ": %s\n", s);
flushio(err);
setstatus("error");
while(!runq->iflag) Xreturn();
}
void
Xerror2(char *s, char *e)
{
setstatus(e);
pfln(err, srcfile(runq), runq->line);
pfmt(err, ": %s: %s\n", s, e);
flushio(err);
while(!runq->iflag) Xreturn();
}
void
Xerror3(char *s, char *m, char *e)
{
setstatus(e);
pfln(err, srcfile(runq), runq->line);
pfmt(err, ": %s: %s: %s\n", s, m, e);
flushio(err);
while(!runq->iflag) Xreturn();
}
void
Setstatus(char *s)
{
setvar("status", Newword(s?s:estrdup(""), (word *)0));
}
void
setstatus(char *s)
{
setvar("status", newword(s, (word *)0));
Setstatus(estrdup(s));
}
char*
Getstatus(void)
{
var *status = vlook("status");
word *val = status->val;
if(val==0) return 0;
status->val=0;
status->changed=1;
freewords(val->next);
return Freeword(val);
}
char*
getstatus(void)
{

View file

@ -11,8 +11,9 @@ extern void Xtrue(void), Xword(void), Xwrite(void), Xpipefd(void), Xcase(void);
extern void Xlocal(void), Xunlocal(void), Xassign(void), Xsimple(void), Xpopm(void), Xpush(void);
extern void Xrdcmds(void), Xwastrue(void), Xif(void), Xifnot(void), Xpipewait(void);
extern void Xpopredir(void), Xsub(void), Xeflag(void), Xsettrue(void);
extern void Xerror(char*);
extern void Xerror1(char*);
extern void Xerror2(char*,char*);
extern void Xerror3(char*,char*,char*);
/*
* word lists are in correct order,
@ -33,7 +34,6 @@ struct redir{
int from, to; /* what to do it to */
redir *next; /* what else to do (reverse order) */
};
#define NSTATUS 128 /* length of status */
/*
* redir types
@ -54,7 +54,7 @@ struct thread{
lexer *lex; /* lexer for Xrdcmds */
int iflag; /* interactive? */
int pid; /* process for Xpipewait to wait for */
char status[NSTATUS]; /* status for Xpipewait */
char *status; /* status for Xpipewait */
thread *ret; /* who continues when this finishes */
};
@ -82,3 +82,5 @@ void startfunc(var*, word*, var*, redir*);
char *srcfile(thread*);
char *getstatus(void);
extern char *argv0;

View file

@ -8,10 +8,11 @@ int Dup1(int);
int Eintr(void);
int Executable(char*);
void Exec(char**);
void Exit(char*);
void Exit(void);
char* Errstr(void);
char* Freeword(word*);
int Fork(void);
char* Getstatus(void);
int Isatty(int);
word* Newword(char*,word*);
void Noerror(void);
@ -23,10 +24,11 @@ word* Pushword(char*);
long Read(int, void*, long);
char* Readdir(void*, int);
long Seek(int, long, long);
void Setstatus(char*);
void Trapinit(void);
void Updenv(void);
void Vinit(void);
int Waitfor(int, int);
int Waitfor(int);
long Write(int, void*, long);
void addwaitpid(int);
void clearwaitpids(void);
@ -52,7 +54,7 @@ void poplist(void);
void popword(void);
void pprompt(void);
void Prompt(char*);
void psubst(io *f, uchar *s);
void psubst(io*, unsigned char*);
void pushlist(void);
void pushredir(int, int, int);
word* pushword(char*);

View file

@ -205,7 +205,8 @@ usage(char *tail)
errs(tail);
}
errs("\n");
Exit("bad flags");
setstatus("bad flags");
Exit();
}
static void

View file

@ -21,7 +21,7 @@ deglob(char *s)
}
static int
globcmp(void *s, void *t)
globcmp(const void *s, const void *t)
{
return strcmp(*(char**)s, *(char**)t);
}
@ -70,11 +70,13 @@ globdir(word *list, char *pattern, char *name)
char *slash, *glob, *entry;
void *dir;
#ifdef Plan9
/* append slashes, Readdir() already filtered directories */
while(*pattern=='/'){
pappend(&name, "/");
pattern++;
}
#endif
if(*pattern=='\0')
return Newword(name, list);
@ -140,32 +142,51 @@ globword(word *w)
* Return a pointer to the next utf code in the string,
* not jumping past nuls in broken utf codes!
*/
static char*
nextutf(char *p)
{
Rune dummy;
int i, n, c = *p;
return p + chartorune(&dummy, p);
if(onebyte(c))
return p+1;
if(twobyte(c))
n = 2;
else if(threebyte(c))
n = 3;
else
n = 4;
for(i = 1; i < n; i++)
if(!xbyte(p[i]))
break;
return p+i;
}
/*
* Convert the utf code at *p to a unicode value
*/
static int
unicode(char *p)
{
Rune r;
int c = *p;
chartorune(&r, p);
return r;
if(onebyte(c))
return c&0xFF;
if(twobyte(c)){
if(xbyte(p[1]))
return ((c&0x1F)<<6) | (p[1]&0x3F);
} else if(threebyte(c)){
if(xbyte(p[1]) && xbyte(p[2]))
return ((c&0x0F)<<12) | ((p[1]&0x3F)<<6) | (p[2]&0x3F);
} else if(fourbyte(c)){
if(xbyte(p[1]) && xbyte(p[2]) && xbyte(p[3]))
return ((c&0x07)<<18) | ((p[1]&0x3F)<<12) | ((p[2]&0x3F)<<6) | (p[3]&0x3F);
}
return -1;
}
/*
* Do p and q point at equal utf codes
*/
static int
equtf(char *p, char *q)
{

View file

@ -50,7 +50,7 @@ Xasync(void)
switch(pid = Fork()){
case -1:
Xerror("try again");
Xerror2("try again", Errstr());
break;
case 0:
clearwaitpids();
@ -76,12 +76,12 @@ Xpipe(void)
int pfd[2];
if(pipe(pfd)<0){
Xerror("can't get pipe");
Xerror2("can't get pipe", Errstr());
return;
}
switch(pid = Fork()){
case -1:
Xerror("try again");
Xerror2("try again", Errstr());
break;
case 0:
clearwaitpids();
@ -114,12 +114,12 @@ Xbackq(void)
io *f;
if(pipe(pfd)<0){
Xerror("can't make pipe");
Xerror2("can't make pipe", Errstr());
return;
}
switch(pid = Fork()){
case -1:
Xerror("try again");
Xerror2("try again", Errstr());
Close(pfd[PRD]);
Close(pfd[PWR]);
return;
@ -146,7 +146,7 @@ Xbackq(void)
closeio(f);
free(split);
Waitfor(pid, 0);
Waitfor(pid);
runq->pc = runq->code[runq->pc].i;
return;
@ -163,7 +163,7 @@ Xpipefd(void)
int sidefd, mainfd;
if(pipe(pfd)<0){
Xerror("can't get pipe");
Xerror2("can't get pipe", Errstr());
return;
}
if(p->code[pc].i==READ){
@ -176,7 +176,7 @@ Xpipefd(void)
}
switch(pid = Fork()){
case -1:
Xerror("try again");
Xerror2("try again", Errstr());
break;
case 0:
clearwaitpids();
@ -205,7 +205,7 @@ Xsubshell(void)
switch(pid = Fork()){
case -1:
Xerror("try again");
Xerror2("try again", Errstr());
break;
case 0:
clearwaitpids();
@ -214,7 +214,8 @@ Xsubshell(void)
break;
default:
addwaitpid(pid);
Waitfor(pid, 1);
while(Waitfor(pid) < 0)
;
runq->pc = runq->code[runq->pc].i;
break;
}

View file

@ -3,7 +3,7 @@
#include "io.h"
#include "fns.h"
void psubst(io*, uchar*);
void psubst(io*, unsigned char*);
void pstrs(io*, word*);
char*
@ -48,11 +48,12 @@ readhere(tree *tag, io *in)
}
void
psubst(io *f, uchar *s)
psubst(io *f, unsigned char *s)
{
int savec, n;
uchar *t, *u;
unsigned char *t, *u;
word *star;
int savec, n;
while(*s){
if(*s!='$'){
if(0xa0 <= *s && *s <= 0xf5){

View file

@ -36,9 +36,6 @@ vpfmt(io *f, char *fmt, va_list ap)
case 'q':
pwrd(f, va_arg(ap, char *));
break;
case 'r':
pstr(f, Errstr());
break;
case 's':
pstr(f, va_arg(ap, char *));
break;
@ -141,23 +138,23 @@ void
pwrd(io *f, char *s)
{
char *t;
for(t = s;*t;t++) if(*t >= 0 && needsrcquote(*t)) break;
for(t = s;*t;t++) if(*t >= 0 && strchr("`^#*[]=|\\?${}()'<>&;", *t)) break;
if(t==s || *t)
pquo(f, s);
else pstr(f, s);
}
void
pptr(io *f, void *v)
pptr(io *f, void *p)
{
static char hex[] = "0123456789ABCDEF";
unsigned long long v;
int n;
uintptr p;
p = (uintptr)v;
if(sizeof(uintptr) == sizeof(uvlong) && p>>32)
for(n = 60;n>=32;n-=4) pchr(f, "0123456789ABCDEF"[(p>>n)&0xF]);
for(n = 28;n>=0;n-=4) pchr(f, "0123456789ABCDEF"[(p>>n)&0xF]);
v = (unsigned long long)p;
if(sizeof(v) == sizeof(p) && v>>32)
for(n = 60;n>=32;n-=4) pchr(f, hex[(v>>n)&0xF]);
for(n = 28;n>=0;n-=4) pchr(f, hex[(v>>n)&0xF]);
}
void
@ -212,7 +209,7 @@ pval(io *f, word *a)
}
io*
newio(uchar *buf, int len, int fd)
newio(unsigned char *buf, int len, int fd)
{
io *f = new(io);
f->buf = buf;
@ -228,7 +225,7 @@ newio(uchar *buf, int len, int fd)
io*
openiostr(void)
{
uchar *buf = emalloc(100+1);
unsigned char *buf = emalloc(100+1);
memset(buf, '\0', 100+1);
return newio(buf, 100, -1);
}
@ -258,7 +255,7 @@ openiofd(int fd)
* characters from buf.
*/
io*
openiocore(uchar *buf, int len)
openiocore(void *buf, int len)
{
return newio(buf, len, -1);
}

View file

@ -2,12 +2,12 @@
struct io{
int fd;
uchar *buf, *bufp, *ebuf;
unsigned char *buf, *bufp, *ebuf;
io *next;
};
io *err;
io *openiofd(int), *openiostr(void), *openiocore(uchar*, int);
io *openiofd(int), *openiostr(void), *openiocore(void*, int);
void pchr(io*, int);
int rchr(io*);
char *rstr(io*, char*);

View file

@ -190,21 +190,22 @@ addtok(char *p, int val)
static char*
addutf(char *p, int c)
{
uchar b, m;
int i;
int i, n;
p = addtok(p, c); /* 1-byte UTF runes are special */
if(onebyte(c))
return p;
m = 0xc0;
b = 0x80;
for(i=1; i < UTFmax; i++){
if((c&m) == b)
if(twobyte(c))
n = 2;
else if(threebyte(c))
n = 3;
else
n = 4;
for(i = 1; i < n; i++) {
c = nextc();
if(c == EOF || !xbyte(c))
break;
p = addtok(p, advance());
b = m;
m = (m >> 1)|0x80;
}
return p;
}

View file

@ -21,7 +21,7 @@ OFILES=\
y.tab.$O\
HFILES=rc.h\
x.tab.h\
y.tab.h\
io.h\
exec.h\
fns.h\
@ -38,10 +38,9 @@ UPDATE=\
$YFILES\
${TARG:%=/386/bin/%}\
CFLAGS=$CFLAGS -DPlan9
</sys/src/cmd/mkone
x.tab.h: y.tab.h
cmp -s x.tab.h y.tab.h || cp y.tab.h x.tab.h
clean:V:
rm -f [$OS].out *.[$OS] [xy].tab.? y.debug $TARG
rm -f [$OS].out *.[$OS] y.tab.? y.debug $TARG

View file

@ -47,13 +47,17 @@ static char *syssigname[] = {
0
};
/*
* finit could be removed but is kept for
* backwards compatibility, see: rcmain.plan9
*/
static void
execfinit(void)
{
char *cmds = estrdup("for(i in '/env/fn#'*){. -bq $i}\n");
int line = runq->line;
poplist();
execcmds(openiocore((uchar*)cmds, strlen(cmds)), estrdup(srcfile(runq)), runq->local, runq->redir);
execcmds(openiocore(cmds, strlen(cmds)), estrdup(srcfile(runq)), runq->local, runq->redir);
runq->lex->line = line;
runq->lex->qflag = 1;
}
@ -131,7 +135,7 @@ Vinit(void)
dir = Open(Env("", 0), 0);
if(dir<0){
pfmt(err, "%s: can't open: %r\n", argv0);
pfmt(err, "%s: can't open: %s\n", argv0, Errstr());
return;
}
for(;;){
@ -169,7 +173,7 @@ Errstr(void)
}
int
Waitfor(int pid, int)
Waitfor(int pid)
{
thread *p;
Waitmsg *w;
@ -187,7 +191,8 @@ Waitfor(int pid, int)
for(p = runq->ret;p;p = p->ret)
if(p->pid==w->pid){
p->pid=-1;
strcpy(p->status, w->msg);
p->status = estrdup(w->msg);
break;
}
free(w);
}
@ -206,7 +211,7 @@ addenv(var *v)
if(v->changed){
v->changed = 0;
if((fd = Creat(Env(v->name, 0)))<0)
pfmt(err, "%s: can't open: %r\n", argv0);
pfmt(err, "%s: can't open: %s\n", argv0, Errstr());
else{
f = openiofd(fd);
for(w = v->val;w;w = w->next){
@ -220,7 +225,7 @@ addenv(var *v)
if(v->fnchanged){
v->fnchanged = 0;
if((fd = Creat(Env(v->name, 1)))<0)
pfmt(err, "%s: can't open: %r\n", argv0);
pfmt(err, "%s: can't open: %s\n", argv0, Errstr());
else{
f = openiofd(fd);
if(v->fn)
@ -420,16 +425,15 @@ Dup(int a, int b)
}
int
Dup1(int)
Dup1(int a)
{
return -1;
return dup(a, -1);
}
void
Exit(char *stat)
Exit(void)
{
Updenv();
setstatus(stat);
exits(truestatus()?"":getstatus());
}
@ -459,8 +463,7 @@ Isatty(int fd)
void
Abort(void)
{
pfmt(err, "aborting\n");
Exit("aborting");
abort();
}
static int newwdir;

View file

@ -1,28 +1,29 @@
/*
* Plan9 is defined for plan 9
* V9 is defined for 9th edition
* Sun is defined for sun-os
* otherwise its UNIX.
* Please don't litter the code with ifdefs. The three below (and one in
* getflags) should be enough.
*/
#define Plan9
#ifdef Plan9
#ifdef Plan9
#include <u.h>
#include <libc.h>
#define NSIG 32
#define NSIG 32
#define SIGINT 2
#define SIGQUIT 3
#endif
#ifdef V9
#else
#include <stdlib.h>
#include <stdarg.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
#include <libc.h>
#ifndef NSIG
#define NSIG 32
#endif
#ifdef Sun
#include <signal.h>
#endif
#define YYMAXDEPTH 500
#ifndef PAREN
#include "x.tab.h"
#include "y.tab.h"
#endif
typedef struct tree tree;
typedef struct word word;
@ -143,10 +144,13 @@ int mypid;
*/
#define GLOB ((char)0x01)
/*
* onebyte(c)
* Is c the first character of a one-byte utf sequence?
* Is c the first character of a utf sequence?
*/
#define onebyte(c) ((c&0x80)==0x00)
#define onebyte(c) (((c)&0x80)==0x00)
#define twobyte(c) (((c)&0xe0)==0xc0)
#define threebyte(c) (((c)&0xf0)==0xe0)
#define fourbyte(c) (((c)&0xf8)==0xf0)
#define xbyte(c) (((c)&0xc0)==0x80)
extern char **argp;
extern char **args;

View file

@ -0,0 +1,41 @@
# rcmain: Plan 9 version
if(~ $#home 0) home=/
if(~ $#ifs 0) ifs='
'
switch($#prompt){
case 0
prompt=('% ' ' ')
case 1
prompt=($prompt ' ')
}
if(~ $rcname ?.out) prompt=('broken! ' ' ')
if(flag p) path=/bin
if not{
for(i in '/env/fn#'*){
. -bq $i
}
if(~ $#path 0) path=(/bin .)
}
fn sigexit
if(! ~ $#cflag 0){
if(flag l){
. -q /rc/lib/rcmain.local
. -q $home/lib/profile
}
status=''
eval $cflag
}
if not if(flag i){
if(flag l){
. -q /rc/lib/rcmain.local
. -q $home/lib/profile
}
status=''
if(! ~ $#* 0) . $*
. -i '#d/0'
}
if not if(~ $#* 0) . '#d/0'
if not{
status=''
. $*
}

View file

@ -0,0 +1,38 @@
# rcmain: unix version
if(~ $#home 0) home=$HOME
if(~ $#ifs 0) ifs='
'
profile=$home/.rcrc
switch($#prompt){
case 0
prompt=('% ' ' ')
case 1
prompt=($prompt ' ')
}
if(~ $rcname ?.out) prompt=('broken! ' ' ')
if(flag p) path=/bin
if not {
finit
if(~ $#path 0) path=(. /bin /usr/bin /usr/local/bin)
}
fn sigexit
if(! ~ $#cflag 0){
if(flag l) {
. -q $profile
}
status=''
eval $cflag
}
if not if(flag i){
if(flag l) {
. -q $profile
}
status=''
if(! ~ $#* 0) . $*
. -i /dev/fd/0
}
if not if(~ $#* 0) . /dev/fd/0
if not{
status=''
. $*
}

View file

@ -94,13 +94,13 @@ Xsimple(void)
}
else{
if((pid = execforkexec()) < 0){
Xerror("try again");
Xerror2("try again", Errstr());
return;
}
poplist();
/* interrupts don't get us out */
poplist();
while(Waitfor(pid, 1) < 0)
while(Waitfor(pid) < 0)
;
}
}
@ -177,7 +177,7 @@ execexec(void)
popword(); /* "exec" */
if(runq->argv->words==0){
Xerror1("empty argument list");
Xerror1("exec: empty argument list");
return;
}
argv = mkargv(runq->argv->words);
@ -189,7 +189,7 @@ execexec(void)
}
setstatus(Errstr());
pfln(err, srcfile(runq), runq->line);
pfmt(err, ": %s: %r\n", argv[1]);
pfmt(err, ": %s: %s\n", argv[1], getstatus());
Xexit();
}
@ -226,7 +226,7 @@ execcd(void)
free(dir);
}
if(cdpath==0)
pfmt(err, "Can't cd %s: %r\n", a->word);
pfmt(err, "Can't cd %s: %s\n", a->word, Errstr());
break;
case 1:
a = vlook("home")->val;
@ -234,7 +234,7 @@ execcd(void)
if(Chdir(a->word)>=0)
setstatus("");
else
pfmt(err, "Can't cd %s: %r\n", a->word);
pfmt(err, "Can't cd %s: %s\n", a->word, Errstr());
}
else
pfmt(err, "Can't cd -- $home empty\n");
@ -347,7 +347,7 @@ execeval(void)
pfln(f, srcfile(runq), runq->line);
pstr(f, " *eval*");
execcmds(openiocore((uchar*)cmds, len), closeiostr(f), runq->local, runq->redir);
execcmds(openiocore(cmds, len), closeiostr(f), runq->local, runq->redir);
}
void
@ -406,7 +406,8 @@ Usage:
free(file);
}
if(fd<0){
if(!qflag) Xerror(".: can't open");
if(!qflag)
Xerror3(". can't open", argv->word, Errstr());
freewords(argv);
return;
}
@ -436,18 +437,18 @@ execflag(void)
char *letter, *val;
switch(count(runq->argv->words)){
case 2:
setstatus(flag[(uchar)runq->argv->words->next->word[0]]?"":"flag not set");
setstatus(flag[(unsigned char)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;
flag[(unsigned char)letter[0]] = flagset;
break;
}
if(strcmp(val, "-")==0){
flag[(uchar)letter[0]] = 0;
flag[(unsigned char)letter[0]] = 0;
break;
}
}
@ -526,10 +527,10 @@ execwait(void)
Xerror1("Usage: wait [pid]");
return;
case 2:
Waitfor(atoi(runq->argv->words->next->word), 0);
Waitfor(atoi(runq->argv->words->next->word));
break;
case 1:
Waitfor(-1, 0);
Waitfor(-1);
break;
}
poplist();

View file

@ -41,7 +41,7 @@ pfln(io *fd, char *file, int line)
pstr(fd, argv0);
}
char *bp;
static char *bp;
static void
iacvt(int n)
@ -69,5 +69,7 @@ panic(char *s, int n)
pfmt(err, "%s: ", argv0);
pfmt(err, s, n);
pchr(err, '\n');
flushio(err);
Abort();
}

View file

@ -11,10 +11,10 @@ dotrap(void)
var *trapreq;
word *starval;
starval = vlook("*")->val;
while(ntrap) for(i = 0;i!=NSIG;i++) while(trap[i]){
while(ntrap) for(i = 0;i<NSIG;i++) while(trap[i]){
--trap[i];
--ntrap;
if(getpid()!=mypid) Exit(getstatus());
if(getpid()!=mypid) Exit();
trapreq = vlook(Signame[i]);
if(trapreq->fn)
startfunc(trapreq, copywords(starval, (word*)0), (var*)0, (redir*)0);
@ -27,6 +27,6 @@ dotrap(void)
*/
while(!runq->iflag) Xreturn();
}
else Exit(getstatus());
else Exit();
}
}

420
sys/src/cmd/rc/unix.c Normal file
View file

@ -0,0 +1,420 @@
/*
* Unix 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"
#include <errno.h>
#include <fcntl.h>
#include <dirent.h>
#include <sys/wait.h>
static void execfinit(void);
builtin Builtin[] = {
"cd", execcd,
"whatis", execwhatis,
"eval", execeval,
"exec", execexec, /* but with popword first */
"exit", execexit,
"shift", execshift,
"wait", execwait,
".", execdot,
"flag", execflag,
"finit", execfinit,
0
};
char Rcmain[] = PREFIX "/lib/rcmain";
char Fdprefix[] = "/dev/fd/";
char *Signame[NSIG];
#define SEP '\1'
extern char **environ;
static char **envp;
static void
Xrdfn(void)
{
char *s;
int len;
for(;*envp;envp++){
for(s=*envp;*s && *s!='(' && *s!='=';s++);
switch(*s){
case '(': /* Bourne again */
if(strncmp(s, "()fn ", 5)!=0)
continue;
s=estrdup(s+2);
len=strlen(s);
s[len++]='\n';
envp++;
runq->pc--; /* re-execute */
execcmds(openiocore(s, len), estrdup("*environ*"), runq->local, runq->redir);
runq->lex->qflag = 1;
return;
default:
continue;
}
}
}
static void
execfinit(void)
{
static union code rdfns[5];
if(rdfns[0].i==0){
rdfns[0].i = 1;
rdfns[1].s = "*rdfns*";
rdfns[2].f = Xrdfn;
rdfns[3].f = Xreturn;
rdfns[4].f = 0;
}
poplist();
envp=environ;
start(rdfns, 2, runq->local, runq->redir);
}
static int
cmpenv(const void *aa, const void *ab)
{
return strcmp(*(char**)aa, *(char**)ab);
}
static char**
mkenv(void)
{
char **env, **ep, *p, *q;
struct var **h, *v;
struct word *a;
int nvar = 0, nchr = 0, sep;
/*
* Slightly kludgy loops look at locals then globals.
* locals no longer exist - geoff
*/
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;
*p++='#'; *p++='('; *p++=')'; /* to fool Bourne */
*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++='\0';
}
}
*ep = 0;
qsort((void *)env, nvar, sizeof ep[0], cmpenv);
return env;
}
static word*
envval(char *s)
{
char *t, c;
word *v;
for(t=s;*t&&*t!=SEP;t++);
c=*t;
*t='\0';
v=newword(s, c=='\0'?(word*)0:envval(t+1));
*t=c;
return v;
}
void
Vinit(void)
{
char *s;
for(envp=environ;*envp;envp++){
for(s=*envp;*s && *s!='(' && *s!='=';s++);
switch(*s){
case '=':
*s='\0';
setvar(*envp, envval(s+1));
*s='=';
break;
default: continue;
}
}
}
static void
sighandler(int sig)
{
trap[sig]++;
ntrap++;
}
void
Trapinit(void)
{
int i;
Signame[0] = "sigexit";
#ifdef SIGINT
Signame[SIGINT] = "sigint";
#endif
#ifdef SIGTERM
Signame[SIGTERM] = "sigterm";
#endif
#ifdef SIGHUP
Signame[SIGHUP] = "sighup";
#endif
#ifdef SIGQUIT
Signame[SIGQUIT] = "sigquit";
#endif
#ifdef SIGPIPE
Signame[SIGPIPE] = "sigpipe";
#endif
#ifdef SIGUSR1
Signame[SIGUSR1] = "sigusr1";
#endif
#ifdef SIGUSR2
Signame[SIGUSR2] = "sigusr2";
#endif
#ifdef SIGBUS
Signame[SIGBUS] = "sigbus";
#endif
#ifdef SIGWINCH
Signame[SIGWINCH] = "sigwinch";
#endif
for(i=1; i<NSIG; i++) if(Signame[i]){
#ifdef SA_RESTART
struct sigaction a;
sigaction(i, NULL, &a);
a.sa_flags &= ~SA_RESTART;
a.sa_handler = sighandler;
sigaction(i, &a, NULL);
#else
signal(i, sighandler);
#endif
}
}
char*
Errstr(void)
{
return strerror(errno);
}
int
Waitfor(int pid)
{
thread *p;
char num[12];
int wpid, status;
if(pid >= 0 && !havewaitpid(pid))
return 0;
while((wpid = wait(&status))!=-1){
delwaitpid(wpid);
inttoascii(num, WIFSIGNALED(status)?WTERMSIG(status)+1000:WEXITSTATUS(status));
if(wpid==pid){
setstatus(num);
return 0;
}
for(p = runq->ret;p;p = p->ret)
if(p->pid==wpid){
p->pid=-1;
p->status = estrdup(num);
break;
}
}
if(Eintr()) return -1;
return 0;
}
static char **nextenv;
void
Updenv(void)
{
if(nextenv){
free(nextenv);
nextenv = NULL;
}
if(err)
flushio(err);
}
void
Exec(char **argv)
{
if(nextenv==NULL) nextenv=mkenv();
execve(argv[0], argv+1, nextenv);
}
int
Fork(void)
{
Updenv();
return fork();
}
void*
Opendir(char *name)
{
return opendir(name);
}
char*
Readdir(void *arg, int onlydirs)
{
DIR *rd = arg;
struct dirent *ent = readdir(rd);
if(ent == NULL)
return 0;
return ent->d_name;
}
void
Closedir(void *arg)
{
DIR *rd = arg;
closedir(rd);
}
long
Write(int fd, void *buf, long cnt)
{
return write(fd, buf, cnt);
}
long
Read(int fd, void *buf, long cnt)
{
return read(fd, buf, cnt);
}
long
Seek(int fd, long cnt, long whence)
{
return lseek(fd, cnt, whence);
}
int
Executable(char *file)
{
return access(file, 01)==0;
}
int
Open(char *file, int mode)
{
static int tab[] = {O_RDONLY,O_WRONLY,O_RDWR,O_RDONLY};
int fd = open(file, tab[mode&3]);
if(fd >= 0 && mode == 3)
unlink(file);
return fd;
}
void
Close(int fd)
{
close(fd);
}
int
Creat(char *file)
{
return creat(file, 0666L);
}
int
Dup(int a, int b)
{
return dup2(a, b);
}
int
Dup1(int a)
{
return dup(a);
}
void
Exit(void)
{
Updenv();
exit(truestatus()?0:1);
}
int
Eintr(void)
{
return errno==EINTR;
}
void
Noerror(void)
{
errno=0;
}
int
Isatty(int fd)
{
return isatty(fd);
}
void
Abort(void)
{
abort();
}
int
Chdir(char *dir)
{
return chdir(dir);
}
void
Prompt(char *s)
{
pstr(err, s);
flushio(err);
}