aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNicholas Noll <nbnoll@eml.cc>2021-10-13 08:27:37 -0700
committerNicholas Noll <nbnoll@eml.cc>2021-10-13 08:27:37 -0700
commitd1a19f0d477a6249d8af9322317b8434b86260ea (patch)
tree59e49fc95018bb9d09e4a76a012f6f06ae345c67
parent7d7af85919bbd352bb7dc0b5751b3684f8f0a8e4 (diff)
fix(email): bytes error. updated vendoring
-rw-r--r--.gitignore11
-rwxr-xr-xbin/email2
-rw-r--r--sys/cmd/rc/code.c520
-rw-r--r--sys/cmd/rc/code.dep166
-rw-r--r--sys/cmd/rc/exec.c1077
-rw-r--r--sys/cmd/rc/glob.c412
-rw-r--r--sys/cmd/rc/io.c573
-rw-r--r--sys/cmd/rc/lex.c688
-rw-r--r--sys/cmd/rc/main.c86
-rw-r--r--sys/cmd/rc/parse.c496
-rw-r--r--sys/cmd/rc/rc.h413
-rw-r--r--sys/cmd/rc/rules.mk37
-rw-r--r--sys/cmd/rc/simple.c507
-rw-r--r--sys/cmd/rc/tree.c214
-rw-r--r--sys/cmd/rc/util.c40
-rw-r--r--sys/cmd/rc/var.c230
-rw-r--r--sys/cmd/rc/word.c64
-rw-r--r--sys/cmd/rules.mk3
-rwxr-xr-xvendor/sync105
19 files changed, 3003 insertions, 2641 deletions
diff --git a/.gitignore b/.gitignore
index bb109a5..fd958fb 100644
--- a/.gitignore
+++ b/.gitignore
@@ -11,9 +11,20 @@ test/
include/libc
include/vendor
+include/libdraw.h
+include/libimage.h
sys/cc
sys/nixos
+sys/libdraw
+sys/libfont
+sys/libimage
+sys/libterm
+sys/libutf8
+
+sys/cmd/muc
+sys/cmd/wm
+sys/cmd/term2
bin/fasttree
bin/mafft
diff --git a/bin/email b/bin/email
index 231ab6c..efe3906 100755
--- a/bin/email
+++ b/bin/email
@@ -51,7 +51,7 @@ def mail(input):
if process(message):
return message.as_bytes()
- return input
+ return input.encode("utf-8")
def send(account, to):
input = sys.stdin.read()
diff --git a/sys/cmd/rc/code.c b/sys/cmd/rc/code.c
index edf47cf..fbb5435 100644
--- a/sys/cmd/rc/code.c
+++ b/sys/cmd/rc/code.c
@@ -1,214 +1,267 @@
#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]
-#define delcode 100
-#define c0 t->child[0]
-#define c1 t->child[1]
-#define c2 t->child[2]
+int codep, ncode;
-#define emitf(x) ((code.ip!=code.end || morecode()), code.ip++->f = (x), code.ip)
-#define emiti(x) ((code.ip!=code.end || morecode()), code.ip++->i = (x), code.ip)
-#define emits(x) ((code.ip!=code.end || morecode()), code.ip++->s = (x), code.ip)
+#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++)
-static struct
-{
- int cap;
- Code *buf, *ip, *end;
-} code;
+void stuffdot(int);
+char *fnstr(tree*);
+void outcode(tree*, int);
+void codeswitch(tree*, int);
+int iscase(tree*);
+code *codecopy(code*);
+void codefree(code*);
-static
int
morecode(void)
{
- code.cap += delcode;
- code.buf = erealloc(code.buf, code.cap*sizeof(*code.buf));
- code.end = code.ip + delcode;
- memset(code.ip, 0, delcode*sizeof(*code.buf));
-
- return 0;
+ 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]);
+ memset(codebuf+ncode-100, 0, 100*sizeof codebuf[0]);
+ return 0;
}
-static
void
-stuffdot(Code *p)
+stuffdot(int a)
{
- int a;
+ if(a<0 || codep<=a)
+ panic("Bad address %d in stuffdot", a);
+ codebuf[a].i = codep;
+}
- a = p - code.buf;
- if (code.ip <= p || p < code.buf)
- panic("bad address %d in stuffdot", a);
- code.buf[a].i = code.ip-code.buf;
+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;
}
-static
void
-rcc(Tree *t, int eflag)
+cleanhere(char *f)
{
- Code *p, *q;
- Tree *tt;
+ emitf(Xdelhere);
+ emits(strdup(f));
+}
- if (!t)
- return;
+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;
+}
- switch(t->type) {
- default:
- pfmt(errio, "bad type %d in rc compiler\n", t->type);
+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 Tdol:
+ case '$':
emitf(Xmark);
- rcc(c0, eflag);
+ outcode(c0, eflag);
emitf(Xdol);
break;
- case Tquote:
+ case '"':
emitf(Xmark);
- rcc(c0, eflag);
- emitf(Xflatten);
+ outcode(c0, eflag);
+ emitf(Xqdol);
break;
- case Tsub:
+ case SUB:
emitf(Xmark);
- rcc(c0, eflag);
+ outcode(c0, eflag);
emitf(Xmark);
- rcc(c1, eflag);
+ outcode(c1, eflag);
emitf(Xsub);
break;
- case Tand:
+ case '&':
emitf(Xasync);
- p = emiti(0);
- rcc(c0, eflag);
- emitf(Xexit);
- stuffdot(p);
+ if(havefork){
+ p = emiti(0);
+ outcode(c0, eflag);
+ emitf(Xexit);
+ stuffdot(p);
+ } else
+ emits(fnstr(c0));
break;
- case Tsemi:
- rcc(c0, eflag);
- rcc(c1, eflag);
+ case ';':
+ outcode(c0, eflag);
+ outcode(c1, eflag);
break;
- case Tcarot:
+ case '^':
emitf(Xmark);
- rcc(c1, eflag);
+ outcode(c1, eflag);
emitf(Xmark);
- rcc(c0, eflag);
- emitf(Xcat);
+ outcode(c0, eflag);
+ emitf(Xconc);
break;
- case Ttick:
- emitf(Xcmdsub);
- p = emiti(0);
- rcc(c0, 0);
- emitf(Xexit);
- stuffdot(p);
+ case '`':
+ emitf(Xbackq);
+ if(havefork){
+ p = emiti(0);
+ outcode(c0, 0);
+ emitf(Xexit);
+ stuffdot(p);
+ } else
+ emits(fnstr(c0));
break;
- case Tandand:
- rcc(c0, 0);
+ case ANDAND:
+ outcode(c0, 0);
emitf(Xtrue);
p = emiti(0);
- rcc(c1, eflag);
+ outcode(c1, eflag);
stuffdot(p);
break;
- case Targs:
- rcc(c1, eflag);
- rcc(c0, eflag);
+ case ARGLIST:
+ outcode(c1, eflag);
+ outcode(c0, eflag);
break;
- case Tbang:
- rcc(c0, eflag);
- emitf(Xnegate);
+ case BANG:
+ outcode(c0, eflag);
+ emitf(Xbang);
break;
- case Tparen:
- case Tbrace:
- rcc(c0, eflag);
+ case PCMD:
+ case BRACE:
+ outcode(c0, eflag);
break;
- case Tcount:
+ case COUNT:
emitf(Xmark);
- rcc(c0, eflag);
+ outcode(c0, eflag);
emitf(Xcount);
break;
- case Tfunc:
+ case FN:
emitf(Xmark);
- rcc(c0, eflag);
+ outcode(c0, eflag);
if(c1){
- emitf(Xfunc);
+ emitf(Xfn);
p = emiti(0);
emits(fnstr(c1));
- rcc(c1, eflag);
+ outcode(c1, eflag);
emitf(Xunlocal); /* get rid of $* */
- emitf(Xkill);
+ emitf(Xreturn);
stuffdot(p);
- } else
- emitf(Xunfunc);
+ }
+ else
+ emitf(Xdelfn);
break;
- case Tif:
- rcc(c0, 0);
+ case IF:
+ outcode(c0, 0);
emitf(Xif);
p = emiti(0);
- rcc(c1, eflag);
- // emitf(Xwastrue);
+ outcode(c1, eflag);
+ emitf(Xwastrue);
stuffdot(p);
break;
- // case Telse:
- // if(!runq->iflast)
- // rcerror("`else' does not follow `if(...)'");
- // emitf(Xelse);
- // p = emiti(0);
- // rcc(c0, eflag);
- // stuffdot(p);
- // break;
- case Toror:
- rcc(c0, 0);
+ 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);
- rcc(c1, eflag);
+ outcode(c1, eflag);
stuffdot(p);
break;
- case Tpcmd:
- rcc(c0, eflag);
+ case PAREN:
+ outcode(c0, eflag);
break;
- case Tsimple:
+ case SIMPLE:
emitf(Xmark);
- rcc(c0, eflag);
+ outcode(c0, eflag);
emitf(Xsimple);
if(eflag)
emitf(Xeflag);
break;
- case Tsubshell:
+ case SUBSHELL:
emitf(Xsubshell);
- p = emiti(0);
- rcc(c0, eflag);
- emitf(Xexit);
- stuffdot(p);
+ if(havefork){
+ p = emiti(0);
+ outcode(c0, eflag);
+ emitf(Xexit);
+ stuffdot(p);
+ } else
+ emits(fnstr(c0));
if(eflag)
emitf(Xeflag);
break;
- case Tswitch:
+ case SWITCH:
codeswitch(t, eflag);
break;
- case Ttwiddle:
+ case TWIDDLE:
emitf(Xmark);
- rcc(c1, eflag);
+ outcode(c1, eflag);
emitf(Xmark);
- rcc(c0, eflag);
+ outcode(c0, eflag);
emitf(Xmatch);
if(eflag)
emitf(Xeflag);
break;
- case Twhile:
- q = code.ip;
- rcc(c0, 0);
- if(q==code.ip)
+ case WHILE:
+ q = codep;
+ outcode(c0, 0);
+ if(q==codep)
emitf(Xsettrue); /* empty condition == while(true) */
emitf(Xtrue);
p = emiti(0);
- rcc(c1, eflag);
+ outcode(c1, eflag);
emitf(Xjump);
- emiti(q-code.buf);
+ emiti(q);
stuffdot(p);
break;
- case Twords:
- rcc(c1, eflag);
- rcc(c0, eflag);
+ case WORDS:
+ outcode(c1, eflag);
+ outcode(c0, eflag);
break;
- case Tfor:
+ case FOR:
emitf(Xmark);
if(c1){
- rcc(c1, eflag);
+ outcode(c1, eflag);
emitf(Xglob);
- } else{
+ }
+ else{
emitf(Xmark);
emitf(Xword);
emits(strdup("*"));
@@ -216,120 +269,221 @@ rcc(Tree *t, int eflag)
}
emitf(Xmark); /* dummy value for Xlocal */
emitf(Xmark);
- rcc(c0, eflag);
+ outcode(c0, eflag);
emitf(Xlocal);
p = emitf(Xfor);
q = emiti(0);
- rcc(c2, eflag);
+ outcode(c2, eflag);
emitf(Xjump);
- emiti(p-code.buf);
+ emiti(p);
stuffdot(q);
emitf(Xunlocal);
break;
- case Tword:
+ case WORD:
emitf(Xword);
emits(strdup(t->str));
break;
- case Tdup:
- if(t->redir.type == Rdupfd){
+ case DUP:
+ if(t->rtype==DUPFD){
emitf(Xdup);
- emiti(t->redir.fd[0]);
- emiti(t->redir.fd[1]);
- } else{
+ emiti(t->fd0);
+ emiti(t->fd1);
+ }
+ else{
emitf(Xclose);
- emiti(t->redir.fd[0]);
+ emiti(t->fd0);
}
- rcc(c1, eflag);
+ outcode(c1, eflag);
emitf(Xpopredir);
break;
- case Tpipefd:
+ case PIPEFD:
emitf(Xpipefd);
- emiti(t->redir.type);
- p = emiti(0);
- rcc(c0, eflag);
- emitf(Xexit);
- stuffdot(p);
+ emiti(t->rtype);
+ if(havefork){
+ p = emiti(0);
+ outcode(c0, eflag);
+ emitf(Xexit);
+ stuffdot(p);
+ } else {
+ emits(fnstr(c0));
+ }
break;
- case Tredir:
+ case REDIR:
emitf(Xmark);
- rcc(c0, eflag);
+ outcode(c0, eflag);
emitf(Xglob);
- switch(t->redir.type){
- case Rappend:
+ switch(t->rtype){
+ case APPEND:
emitf(Xappend);
break;
- case Rwrite:
+ case WRITE:
emitf(Xwrite);
break;
- case Rread:
- case Rhere:
+ case READ:
+ case HERE:
emitf(Xread);
break;
- case Rrdwr:
+ case RDWR:
emitf(Xrdwr);
break;
}
- emiti(t->redir.fd[0]);
- rcc(c1, eflag);
+ emiti(t->fd0);
+ outcode(c1, eflag);
emitf(Xpopredir);
break;
- case Teq:
+ case '=':
tt = t;
- for(;t && t->type==Teq;t = c2);
+ for(;t && t->type=='=';t = c2);
if(t){
- for(t = tt;t->type==Teq;t = c2){
+ for(t = tt;t->type=='=';t = c2){
emitf(Xmark);
- rcc(c1, eflag);
+ outcode(c1, eflag);
emitf(Xmark);
- rcc(c0, eflag);
+ outcode(c0, eflag);
emitf(Xlocal);
}
- rcc(t, eflag);
- for(t = tt; t->type==Teq; t = c2)
+ outcode(t, eflag);
+ for(t = tt; t->type=='='; t = c2)
emitf(Xunlocal);
- } else{
+ }
+ else{
for(t = tt;t;t = c2){
emitf(Xmark);
- rcc(c1, eflag);
+ outcode(c1, eflag);
emitf(Xmark);
- rcc(c0, eflag);
+ outcode(c0, eflag);
emitf(Xassign);
}
}
t = tt; /* so tests below will work */
break;
- case Tpipe:
+ case PIPE:
emitf(Xpipe);
- emiti(t->redir.fd[0]);
- emiti(t->redir.fd[1]);
- p = emiti(0);
- q = emiti(0);
- rcc(c0, eflag);
- emitf(Xexit);
- stuffdot(p);
- rcc(c1, eflag);
- emitf(Xkill);
+ emiti(t->fd0);
+ emiti(t->fd1);
+ if(havefork){
+ p = emiti(0);
+ q = emiti(0);
+ outcode(c0, eflag);
+ emitf(Xexit);
+ stuffdot(p);
+ } else {
+ emits(fnstr(c0));
+ q = emiti(0);
+ }
+ outcode(c1, eflag);
+ emitf(Xreturn);
stuffdot(q);
emitf(Xpipewait);
break;
}
- if(t->type!=Telse && t->type!=Tsemi)
- shell->iflast = t->type==Tif;
- else if (c0)
- shell->iflast = c0->type==Tif;
+ 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);
}
-Code*
-compile(Tree *t)
+int
+iscase(tree *t)
{
- code.cap = delcode;
- code.buf = code.ip = emalloc(code.cap*sizeof *code.buf);
- code.end = code.ip + code.cap;
+ if(t->type!=SIMPLE)
+ return 0;
+ do t = c0; while(t->type==ARGLIST);
+ return t->type==WORD && !t->quoted && strcmp(t->str, "case")==0;
+}
- emiti(0);
- rcc(t, 0);
- emitf(Xkill);
- emitf(nil);
+code*
+codecopy(code *cp)
+{
+ cp[0].i++;
+ return cp;
+}
- return code.buf;
+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==Xrdwr
+ || 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);
}
diff --git a/sys/cmd/rc/code.dep b/sys/cmd/rc/code.dep
deleted file mode 100644
index 7fdd4bc..0000000
--- a/sys/cmd/rc/code.dep
+++ /dev/null
@@ -1,166 +0,0 @@
-#if 0
-// simple example code
-error
-cd(Args args)
-{
- switch (args.len) {
- case 0:
- errorf("reached cd with no arguments!");
- return 1;
- case 1:
- one:
- errorf("sh: expected argument to command 'cd'");
- return 1;
- case 2:
- if (args.a[1] == nil)
- goto one;
- break;
- default:
- errorf("sh: too many arguments to command 'cd'");
- return 1;
- }
- if (chdir(args.a[1]))
- errorf("cd fail: %s", strerror(errno));
-
- return 0;
-}
-
-error
-quit(Args args)
-{
- exit(0);
-}
-
-Builtin builtins[] = {
- { "cd", cd },
- { "exit", quit },
-};
-
-void
-clear(Header *arr)
-{
- arr->len = 0;
-}
-
-int
-readline(Code *code)
-{
- int n, b;
-
- n = code->len;
-getchar:
- if (code->len >= code->cap) {
- code->cap += 100;
- code->s = realloc(code->s, code->cap);
- }
- /* TODO: unicode? */
- switch ((b = getchar())) {
- case EOF:
- n = -1;
- goto null;
- case '\n':
- n = code->len - n;
- null:
- code->s[code->len] = '\0';
- break;
- default:
- code->s[code->len++] = b;
- goto getchar;
- }
-
- return n;
-}
-
-/* TODO: unicode */
-int
-readargs(Code code, Args *args)
-{
- if (args->a)
- clear(&args->hdr);
- else {
- args->cap += 20;
- args->a = realloc(args->a, args->cap);
- }
-
- args->a[args->len++] = code.s;
- while (*code.s) {
- if (!isspace(*code.s++))
- continue;
-
- code.s[-1] = '\0';
- /* consume all remaining space */
- while (isspace(*code.s))
- code.s++;
-
- if (args->len >= args->cap-1) {
- args->cap += 20;
- args->a = realloc(args->a, args->cap);
- }
- args->a[args->len++] = code.s;
- }
- /* nil acts as a sentinel value */
- args->a[args->len] = nil;
-
- return args->len;
-}
-
-error
-execute(Args args)
-{
- int i, status;
- pid_t cid, wid;
-
- for (i = 0; i < arrlen(builtins); i++) {
- if (strcmp(args.a[0], builtins[i].cmd) == 0)
- return builtins[i].func(args);
- }
-
- if ((cid = fork()) == 0) {
- if (execvp(args.a[0], args.a) == -1)
- errorf("exec failed: %s", strerror(errno));
- exit(1);
- } else if (cid > 0)
- do
- wid = waitpid(cid, &status, WUNTRACED);
- while (!WIFEXITED(status) && !WIFSIGNALED(status));
- else
- errorf("fork failed: %s", strerror(errno));
-
- return status;
-}
-
-static
-void
-flush(void)
-{
- io·flush(stdout);
-}
-
-static
-void
-prompt(void)
-{
- printf(";");
- flush();
-}
-
-int
-main(int argc, char *argv[])
-{
- int i, err, n;
- Code code = {0};
- Args args = {0};
-
- ARGBEGIN {
- } ARGEND;
-
- do {
- clear(&code.hdr);
- prompt();
-
- n = readline(&code);
- readargs(code, &args);
- err = execute(args);
- } while (!err && n > 0);
-}
-#endif
diff --git a/sys/cmd/rc/exec.c b/sys/cmd/rc/exec.c
index 0155b22..15d1cdf 100644
--- a/sys/cmd/rc/exec.c
+++ b/sys/cmd/rc/exec.c
@@ -1,139 +1,1014 @@
#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";
+int ndot;
+int lastc;
+int kidpid;
+int mypid;
-#define W0 shell->stack->words
-// -----------------------------------------------------------------------
-// helper functions
+thread *runq;
+code *codebuf; /* compiler output */
+int ntrap; /* number of outstanding traps */
+int trap[NSIG]; /* number of outstanding traps per type */
+
+int eflagok; /* kludge flag so that -e doesn't exit in startup */
+
+char **argp;
+char **args;
+int nerror; /* number of errors encountered during compilation */
-static
void
-setstatus(char *s)
+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)
{
- setvar("status", newword(s, nil));
+ word *p = new(word);
+ p->word = strdup(wd);
+ p->next = next;
+ return p;
}
-static
void
-pushredir(int type, int from, int to)
+pushword(char *wd)
{
- Redir *r;
+ if(runq->argv==0)
+ panic("pushword but no argv!", 0);
+ runq->argv->words = newword(wd, runq->argv->words);
+}
- alloc(r);
- r->type = type;
- r->from = from;
- r->to = to;
- r->link = shell->redir, shell->redir = r;
+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);
}
-// -----------------------------------------------------------------------
-// interpreter functions
+void
+freelist(word *w)
+{
+ word *nw;
+ while(w){
+ nw = w->next;
+ efree(w->word);
+ efree((char *)w);
+ w = nw;
+ }
+}
void
-Xerror(char *s)
+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)
{
- if(!strcmp(argv0, "rc")||!strcmp(argv0, "/bin/rc"))
- pfmt(errio, "rc: %s: %r\n", s);
- else
- pfmt(errio, "rc (%s): %s: %r\n", argv0, s);
- flush(&errio);
+ redir * rp = new(redir);
+ rp->type = type;
+ rp->from = from;
+ rp->to = to;
+ rp->next = runq->redir;
+ runq->redir = rp;
+}
- setstatus("error");
- while(!shell->interactive)
- Xkill();
+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, "SsrdiIlxepvVc: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();
+ inttoascii(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;
+ memset(bootstrap, 0, sizeof bootstrap);
+ 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; /* not reached; silence OS X Lion gcc */
+}
+/*
+ * 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
+ * Xrdwr(file)[fd] open file for reading and writing
+ * 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)
{
- int fd;
- char *path;
+ 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();
+}
- switch(count(W0)) {
- default:
- Xerror(">> requires a singleton list");
- return;
- case 0:
- Xerror(">> requires one file");
- return;
- case 1:
- ;
- }
+void
+Xsettrue(void)
+{
+ setstatus("");
+}
- path = shell->stack->words->word;
- if ((fd=open(path, 1))< 0 && (fd=creat(path, 0666L))<0) {
- pfmt(errio, "%s: ", path);
- Xerror("can't open");
- return;
- }
- lseek(fd, 0L, 2);
- pushredir(Fopen, fd, shell->ip++->i);
- poplist();
+void
+Xbang(void)
+{
+ setstatus(truestatus()?"false":"");
}
void
-Xassign(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)
{
- Var *v;
- if(count(W0)!=1) {
- Xerror("variable name not singleton");
- return;
- }
- unglob(W0->word);
- v = vlookup(W0->word);
- poplist();
- globlist();
- freelist(v->val);
+ if(truestatus()) runq->pc = runq->code[runq->pc].i;
+ else runq->pc++;
+}
+int ifnot; /* dynamic if not flag */
- v->val = W0;
- if(v->update)
- v->update(v);
- W0 = nil;
- poplist();
+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();
+ 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
+Xrdwr(void)
+{
+ char *file;
+ int f;
+
+ switch(count(runq->argv->words)){
+ default:
+ Xerror1("<> requires singleton\n");
+ return;
+ case 0:
+ Xerror1("<> requires file\n");
+ return;
+ case 1:
+ break;
+ }
+ file = runq->argv->words->word;
+ if((f = open(file, ORDWR))<0){
+ pfmt(err, "%s: ", file);
+ Xerror("can't open");
+ return;
+ }
+ pushredir(ROPEN, f, runq->code[runq->pc].i);
+ runq->pc++;
+ poplist();
+}
+
+void
+turfredir(void)
+{
+ while(runq->redir!=runq->startredir)
+ 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(shell->ip++->s);
-}
-
-void Xasync(void);
-void Xcat(void);
-void Xclose(void);
-void Xcmdsub(void);
-void Xcount(void);
-void Xdol(void);
-void Xdup(void);
-void Xexit(void);
-void Xfalse(void);
-void Xflatten(void);
-void Xfor(void);
-void Xfunc(void);
-void Xglob(void);
-void Xif(void);
-void Xjump(void);
-void Xkill(void);
-void Xlocal(void);
-void Xmark(void);
-void Xmatch(void);
-void Xnegate(void);
-void Xpipe(void);
-void Xpipefd(void);
-void Xpipewait(void);
-void Xpop(void);
-void Xpopredir(void);
-void Xrdwr(void);
-void Xread(void);
-void Xsub(void);
-void Xsimple(void);
-void Xsubshell(void);
-void Xtrue(void);
-void Xunfunc(void);
-void Xunlocal(void);
-void Xword(void);
-void Xwrite(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;
+ 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*
+copynwords(word *a, word *tail, int n)
+{
+ word *v, **end;
+
+ v = 0;
+ end = &v;
+ while(n-- > 0){
+ *end = newword(a->word, 0);
+ end = &(*end)->next;
+ a = a->next;
+ }
+ *end = tail;
+ return v;
+}
+
+word*
+subwords(word *val, int len, word *sub, word *a)
+{
+ int n, m;
+ char *s;
+ if(!sub)
+ return a;
+ a = subwords(val, len, sub->next, a);
+ s = sub->word;
+ deglob(s);
+ m = 0;
+ n = 0;
+ while('0'<=*s && *s<='9')
+ n = n*10+ *s++ -'0';
+ if(*s == '-'){
+ if(*++s == 0)
+ m = len - n;
+ else{
+ while('0'<=*s && *s<='9')
+ m = m*10+ *s++ -'0';
+ m -= n;
+ }
+ }
+ if(n<1 || n>len || m<0)
+ return a;
+ if(n+m>len)
+ m = len-n;
+ while(--n > 0)
+ val = val->next;
+ return copynwords(val, a, m+1);
+}
+
+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;
+ inttoascii(num, count(a));
+ }
+ else{
+ a = vlook("*")->val;
+ inttoascii(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();
+}
+
+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
+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();
+}
diff --git a/sys/cmd/rc/glob.c b/sys/cmd/rc/glob.c
index 95b2ef3..baea44d 100644
--- a/sys/cmd/rc/glob.c
+++ b/sys/cmd/rc/glob.c
@@ -1,199 +1,267 @@
#include "rc.h"
-#include <dirent.h>
-
-static Word *matches;
-static char buffer[6*1024];
-
-// -----------------------------------------------------------------------
-// main exports
+#include "exec.h"
+#include "fns.h"
+char *globname;
+struct word *globv;
+/*
+ * delete all the GLOB marks from s, in place
+ */
void
-unglob(char *s)
+deglob(char *s)
{
- char *t = s;
- do {
- if(*t==GLOB)
- t++;
- *s++ = *t;
- } while(*t++);
+ char *t = s;
+ do{
+ if(*t==GLOB)
+ t++;
+ *s++=*t;
+ }while(*t++);
}
-/*
- * inspiration from rsc's blog post
- * modified for utf8 sequences and character classes
- * returns 1 if string matches pattern is found, 0 otherwise
- */
-static
int
-match(char *s, char *p)
+globcmp(const void *s, const void *t)
{
- int c, ns, np;
- rune sr, pr, lo, tr, hi;
- char *sb = s, *ss = s, *pp = p;
- while(*s || *p){
- if(*p){
- ns = utf8·bytetorune(&sr, s);
- np = utf8·bytetorune(&pr, p);
-
- if(pr==GLOB){
- np = utf8·bytetorune(&pr, ++p);
- switch(pr){
- case '?': /* single match */
- if(*s){
- p+=np, s+=ns;
- continue;
- }
- case '[': /* class match */
- np = utf8·bytetorune(&pr, ++p);
- if((c = (pr == '~')))
- np = utf8·bytetorune(&pr, ++p);
-
- lo = pr;
- while(lo != ']' && *p){
- utf8·bytetorune(&tr, p+np); /* peek ahead */
- if(tr != '-')
- hi = lo;
- else {
- p += np + 1, np = utf8·bytetorune(&hi, p);
- if(!hi) /* we hit a syntax error */
- return 0;
- if(hi < lo)
- tr = hi, hi = lo, lo = tr;
- }
- if(c ^ (lo<=sr && sr<= hi))
- goto match;
- p += np, np = utf8·bytetorune(&lo, p);
- }
- return 0;
- match:
- while (*p++ != ']' && *p); /* just iterate byte-wise */
- s += ns;
- continue;
- case '*': /* zero-or-more match */
- pp = p-1, ss = s+ns;
- p++;
- continue;
- case GLOB:
- if (sr != GLOB)
- return 0;
- s++, p++;
- continue;
- default:
- panic("unrecognized glob operation", pr);
- }
- }
-
- if (sr==pr){
- s+=ns, p+=np;
- continue;
- }
- }
- /* hit end of pattern with no match, restart at last star */
- if (ss > sb) {
- if (!*ss) /* hit end of string while matching a star */
- return 1;
-
- s = ss, p = pp;
- continue;
- }
- /* mismatch */
- return 0;
- }
- return 1;
+ return strcmp(*(char**)s, *(char**)t);
}
-static
void
-globdir(char *p, char *path, int fd)
+globsort(word *left, word *right)
{
- DIR *d = nil;
- char *g; /* pattern offset (base of new GLOB) */
- char *b; /* pointer into path */
- int i, j;
- struct dirent *e;
-
- if(!*p) {
- printf("making path %s\n", path);
- matches = newword(buffer, matches);
- return;
- }
-
- if((fd = openat(fd, path[0]?path:".", O_RDONLY|O_CLOEXEC|O_DIRECTORY)) < 0)
- return;
- d = fdopendir(fd);
-
- for(g = p, b = path; *g; b++) {
- if(*g==GLOB)
- break;
- *b=*g++;
- if(*b == '/') {
- *b = 0;
- /* open new directory (close if we have opened another already */
- if ((fd = openat(fd, path, O_RDONLY|O_CLOEXEC|O_DIRECTORY)) < 0)
- goto cleanup;
- closedir(d);
- d = fdopendir(fd);
- *b = '/';
- path = b, p = g;
- }
- }
+ 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((void *)list, n, sizeof(void *), 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.
+ */
- /* if we are at the end of the pattern, check if name exists */
- if(!*g) {
- *b = 0;
- if(faccessat(fd, path, F_OK, AT_SYMLINK_NOFOLLOW) == 0)
- matches = newword(buffer, matches);
- goto cleanup;
- }
+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, *newp=='/')){
+ 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.
+ */
- /* we have a non-trivial pattern to match */
- /* partition on the next directory */
- while(*g && *g!='/')
- g++;
+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
+ */
- if(*g){
- j = 1;
- *g = 0;
- } else
- j = 0;
+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];
+ }
+ if(fourbyte(*p)){
+ if(p[1]!=q[1])
+ return 0;
+ if(p[1]=='\0')
+ return 1;
+ if(p[2]!=q[2])
+ return 0;
+ if(p[2]=='\0')
+ return 1;
+ return p[3]==q[3];
+ }
+ return 1;
+}
+/*
+ * Return a pointer to the next utf code in the string,
+ * not jumping past nuls in broken utf codes!
+ */
- while((e = readdir(d))) {
- if (e->d_name[0] == '.')
- if (e->d_name[1] == 0 || /* . */
- (e->d_name[1] == '.' && e->d_name[2] == 0)) /* .. */
- continue;
+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;
+ if(fourbyte(*p)) return p[1]=='\0'?p+1:p[2]=='\0'?p+2:p[3]=='\0'?p+3:p+4;
+ return p+1;
+}
+/*
+ * Convert the utf code at *p to a unicode value
+ */
- for(i=0;e->d_name[i];i++)
- b[i]=e->d_name[i];
- b[i]=0;
+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);
+ if(fourbyte(u)) return (u<<18)|((p[1]&0x3f)<<12)|((p[2]&0x3f)<<6)|(p[3]&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
+ */
- if(match(path, p))
- globdir(g+j, b, fd);
- }
+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, '/');
+}
- printf("successful\n");
-cleanup:
- printf("cleaning up\n");
- /* NOTE: a successful closedir also closes the file descriptor */
- closedir(d);
- return;
+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
-glob(char *p)
+globlist1(word *gl)
{
- char *path = buffer;
-
- globdir(p, path, AT_FDCWD);
+ if(gl){
+ globlist1(gl->next);
+ glob(gl->word);
+ }
}
-#if 0
-int
-main()
+void
+globlist(void)
{
- errio = openfd(2);
- glob("\x01*");
- pval(errio, matches);
- flush(&errio);
+ 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;
+ }
}
-#endif
diff --git a/sys/cmd/rc/io.c b/sys/cmd/rc/io.c
index e06bfcc..3e17369 100644
--- a/sys/cmd/rc/io.c
+++ b/sys/cmd/rc/io.c
@@ -1,446 +1,263 @@
+#include <limits.h>
#include "rc.h"
+#include "exec.h"
+#include "io.h"
+#include "fns.h"
-#define c0 t->child[0]
-#define c1 t->child[1]
-#define c2 t->child[2]
+io *err;
+int pfmtnest = 0;
-#undef bufsize
-#define bufsize 512
-#define strsize 100
-
-//------------------------------------------------------------------------
-// buffer operations
-
-/* open file */
-Io*
-openfd(int fd)
+void
+pfmt(io *f, char *fmt, ...)
{
- Io *f;
-
- f = emalloc(sizeof *f + bufsize);
- f->fd = fd;
- f->b = f->e = f->buf;
- return f;
+ 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':
+ pptr(f, va_arg(ap, void*));
+ break;
+ case 'Q':
+ pquo(f, va_arg(ap, char *));
+ break;
+ case 'q':
+ pwrd(f, va_arg(ap, char *));
+ break;
+ case 'r':
+ rerrstr(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);
}
-/* open string */
-Io*
-openstr(void)
+void
+pchr(io *b, int c)
{
- Io *f;
-
- f = emalloc(sizeof *f + strsize + 1);
- f->fd = -1;
- f->b = f->buf;
- f->e = f->buf+strsize;
- memset(f->b, 0, strsize+1);
-
- return f;
+ if(b->bufp==b->ebuf)
+ fullbuf(b, c);
+ else *b->bufp++=c;
}
-/* open core (not nil terminated) */
-Io*
-opencore(int len, char *s)
+int
+rchr(io *b)
{
- Io *f;
-
- f = emalloc(sizeof *f + len);
- f->fd = -1;
- f->b = f->buf;
- f->e = f->buf+len;
- memcpy(f->b, s, len);
-
- return f;
+ if(b->bufp==b->ebuf)
+ return emptybuf(b);
+ return *b->bufp++ & 0xFF;
}
void
-rewindio(Io *f)
+pquo(io *f, char *s)
{
- if (f->fd < 0)
- f->b = f->buf;
- else {
- f->b = f->e = f->buf;
- lseek(f->fd, 0, 0);
- }
+ pchr(f, '\'');
+ for(;*s;s++)
+ if(*s=='\'')
+ pfmt(f, "''");
+ else pchr(f, *s);
+ pchr(f, '\'');
}
void
-closeio(Io *f)
+pwrd(io *f, char *s)
{
- if (f->fd >= 0)
- close(f->fd);
-
- efree(f);
+ char *t;
+ for(t = s;*t;t++) if(!wordchr(*t)) break;
+ if(t==s || *t)
+ pquo(f, s);
+ else pstr(f, s);
}
-/* has the chance to realloc */
void
-flush(Io **fp)
+pptr(io *f, void *v)
{
- int n;
- char *s;
- Io *f;
+ int n;
+ uintptr p;
- f = *fp;
- if (f->fd < 0) {
- n = f->e - f->b;
- f = erealloc(f, sizeof *f + n + strsize + 1);
- if (!f)
- panic("can't realloc %d bytes in flush", n+strsize+1);
- f->b = f->buf+n;
- f->e = f->buf+n+strsize;
- memset(f->b, 0, strsize+1);
- } else {
- n = f->b - f->buf;
- if (n && write(f->fd, f->buf, n) < 0) {
- write(3, "write error\n", 12);
- // if (ntrap)
- // dotrap();
- }
- f->b = f->buf;
- f->e = f->buf + bufsize;
- }
+ p = (uintptr)v;
+ if(sizeof(uintptr) == sizeof(uvlong) && p>>32)
+ for(n = 60;n>=32;n-=4) pchr(f, "0123456789ABCDEF"[(p>>n)&0xF]);
- *fp = f;
+ for(n = 28;n>=0;n-=4) pchr(f, "0123456789ABCDEF"[(p>>n)&0xF]);
}
-//------------------------------------------------------------------------
-// read from io
-
-int
-rchr(Io *f)
-{
- int n;
- if (f->b == f->e) {
- if (f->fd < 0 || (n = read(f->fd, f->buf, bufsize)) <= 0)
- return EOF;
-
- f->b = f->buf;
- f->e = f->b + n;
- }
-
- return *f->b++&0xFF;
-}
-
-//------------------------------------------------------------------------
-// printf functionality
-
-/* character literal */
-int
-pchr(Io *f, int c)
+void
+pstr(io *f, char *s)
{
- if (f->b == f->e)
- flush(&f);
-
- return *f->b++=c;
+ if(s==0)
+ s="(null)";
+ while(*s) pchr(f, *s++);
}
-/* quote */
void
-pquo(Io *f, char *s)
+pdec(io *f, int n)
{
- pchr(f, '\'');
- for (; *s; s++)
- if (*s == '\'')
- pfmt(f, "''");
- else
- pchr(f, *s);
- pchr(f, '\'');
+ if(n<0){
+ if(n!=INT_MIN){
+ pchr(f, '-');
+ pdec(f, -n);
+ return;
+ }
+ /* n is two's complement minimum integer */
+ n = -(INT_MIN+1);
+ pchr(f, '-');
+ pdec(f, n/10);
+ pchr(f, n%10+'1');
+ return;
+ }
+ if(n>9)
+ pdec(f, n/10);
+ pchr(f, n%10+'0');
}
-/* word */
void
-pwrd(Io *f, char *s)
+poct(io *f, unsigned n)
{
- char *t;
- for(t = s; *t; t++)
- if(!wordchr(*t))
- break;
- if(t == s || *t)
- pquo(f, s);
- else
- pstr(f, s);
+ if(n>7)
+ poct(f, n>>3);
+ pchr(f, (n&7)+'0');
}
-/* pointer */
void
-pptr(Io *f, void *v)
+pval(io *f, word *a)
{
- int n;
- uintptr p;
-
- if (!v) {
- pstr(f, "<nil>");
- return;
- }
-
- 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]);
+ if(a){
+ while(a->next && a->next->word){
+ pwrd(f, a->word);
+ pchr(f, ' ');
+ a = a->next;
+ }
+ pwrd(f, a->word);
+ }
}
-/* string */
-void
-pstr(Io *f, char *s)
+int
+fullbuf(io *f, int c)
{
- if(!s || !s[0])
- s = "<null>";
-
- while(*s)
- pchr(f, *s++);
+ flush(f);
+ return *f->bufp++=c;
}
-/* decimal */
void
-pdec(Io *f, int n)
+flush(io *f)
{
- if (n < 0) {
- n = -n;
- pchr(f, '-');
- if (n >= 0) {
- pdec(f, n);
- return;
- }
- n = 1 - n;
- pdec(f, n/10);
- pchr(f, n%10+'1');
- return;
- }
-
- if (n > 9)
- pdec(f, n/10);
- pchr(f, n%10+'0');
+ 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;
+ }
}
-/* octal */
-void
-poct(Io *f, uint n)
+io*
+openfd(int fd)
{
- if (n > 7)
- poct(f, n>>3);
- pchr(f, (n&7)+'0');
+ io *f = new(struct io);
+ f->fd = fd;
+ f->bufp = f->ebuf = f->buf;
+ f->strp = 0;
+ return f;
}
-/* value */
-void
-pval(Io *f, Word *a)
+io*
+openstr(void)
{
- if(a) {
- while(a->link && a->link->word) {
- pwrd(f, a->word);
- pchr(f, ' ');
- a = a->link;
- }
- pwrd(f, a->word);
- }
+ 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.
+ */
-/* tree */
-static
-void
-pdeglob(Io *f, char *s)
+io*
+opencore(char *s, int len)
{
- while(*s){
- if(*s==GLOB)
- s++;
- pchr(f, *s++);
- }
+ 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
-pcmd(Io *f, Tree *t)
+iorewind(io *io)
{
- if(!t)
- return;
-
- switch(t->type){
- default: pfmt(f, "bad<%d> %p %p %p", t->type, c0, c1, c2);
- break;
- case Tdol: pfmt(f, "$%t", c0);
- break;
- case Tquote: pfmt(f, "$\"%t", c0);
- break;
- case Tand: pfmt(f, "%t&", c0);
- break;
- case Tcarot: pfmt(f, "%t^%t", c0, c1);
- break;
- case Ttick: pfmt(f, "`%t", c0);
- break;
- case Tandand: pfmt(f, "%t && %t", c0, c1);
- break;
- case Tbang: pfmt(f, "! %t", c0);
- break;
- case Tbrace: pfmt(f, "{%t}", c0);
- break;
- case Tcount: pfmt(f, "$#%t", c0);
- break;
- case Tfunc: pfmt(f, "func %t %t", c0, c1);
- break;
- case Tif: (c2) ? pfmt(f, "if%t%t else %t", c0, c1, c2): pfmt(f, "if%t%t", c0, c1);
- break;
- case Toror: pfmt(f, "%t || %t", c0, c1);
- break;
- case Tpcmd: /* fallthrough */
- case Tparen: pfmt(f, "(%t)", c0);
- break;
- case Tsub: pfmt(f, "$%t(%t)", c0, c1);
- break;
- case Tsimple: pfmt(f, "%t", c0);
- break;
- case Tsubshell: pfmt(f, "@ %t", c0);
- break;
- case Tswitch: pfmt(f, "switch %t %t", c0, c1);
- break;
- case Tcase: pfmt(f, "case %t:\n%t", c0, c1);
- break;
- case Ttwiddle: pfmt(f, "~ %t %t", c0, c1);
- break;
- case Twhile: pfmt(f, "while %t%t", c0, c1);
- break;
- case Targs:
- if(c0==0)
- pfmt(f, "%t", c1);
- else if(c1==0)
- pfmt(f, "%t", c0);
- else
- pfmt(f, "%t %t", c0, c1);
- break;
- case Tsemi:
- if(c0) {
- if(c1)
- pfmt(f, "%t%c%t", c0, '\n', c1);
- else
- pfmt(f, "%t", c0);
- } else
- pfmt(f, "%t", c1);
- break;
- case Twords:
- if(c0)
- pfmt(f, "%t ", c0);
- pfmt(f, "%t", c1);
- break;
- case Tfor:
- pfmt(f, "for(%t", c0);
- if(c1)
- pfmt(f, " in %t", c1);
- pfmt(f, ")%t", c2);
- break;
- case Tword:
- if(t->quoted)
- pfmt(f, "%Q", t->str);
- else
- pdeglob(f, t->str);
- break;
- case Tdup:
- if(t->redir.type==Rdupfd)
- pfmt(f, ">[%d=%d]", t->redir.fd[1], t->redir.fd[0]); /* yes, fd1, then fd0; read lex.c */
- else
- pfmt(f, ">[%d=]", t->redir.fd[0]);
- pfmt(f, "%t", c1);
- break;
- case Tpipefd:
- case Tredir:
- switch(t->redir.type){
- case Rhere:
- pchr(f, '<');
- case Rread:
- case Rrdwr:
- pchr(f, '<');
- if(t->redir.type==Rrdwr)
- pchr(f, '>');
- if(t->redir.fd[0]!=0)
- pfmt(f, "[%d]", t->redir.fd[0]);
- break;
- case Rappend:
- pchr(f, '>');
- case Rwrite:
- pchr(f, '>');
- if(t->redir.fd[0]!=1)
- pfmt(f, "[%d]", t->redir.fd[0]);
- break;
- }
- pfmt(f, "%t", c0);
- if(c1)
- pfmt(f, " %t", c1);
- break;
- case Teq:
- pfmt(f, "%t=%t", c0, c1);
- if(c2)
- pfmt(f, " %t", c2);
- break;
- case Tpipe:
- pfmt(f, "%t|", c0);
- if(t->redir.fd[1]==0){
- if(t->redir.fd[0]!=1)
- pfmt(f, "[%d]", t->redir.fd[0]);
- }
- else pfmt(f, "[%d=%d]", t->redir.fd[0], t->redir.fd[1]);
- pfmt(f, "%t", c1);
- break;
+ if(io->fd==-1)
+ io->bufp = io->strp;
+ else{
+ io->bufp = io->ebuf = io->buf;
+ Seek(io->fd, 0L, 0);
}
}
-/* rc specific printf */
-static int pfmtlev;
-
void
-vpfmt(Io *f, char *fmt, va_list args)
+closeio(io *io)
{
- char err[124];
-
- pfmtlev++;
- for (; *fmt; fmt++)
- if (*fmt!='%')
- pchr(f, *fmt);
- else switch(*++fmt) {
- case '\0':
- break;
- case 'c':
- pchr(f, va_arg(args, int));
- break;
- case 'd':
- pdec(f, va_arg(args, int));
- break;
- case 'o':
- poct(f, va_arg(args, uint));
- break;
- case 'p':
- pptr(f, va_arg(args, void*));
- break;
- case 'Q':
- pquo(f, va_arg(args, char*));
- break;
- case 'q':
- pwrd(f, va_arg(args, char*));
- break;
- case 'r':
- pstr(f, strerror(errno));
- break;
- case 's':
- pstr(f, va_arg(args, char*));
- break;
- case 't':
- pcmd(f, va_arg(args, Tree*));
- break;
- case 'v':
- pval(f, va_arg(args, Word*));
- break;
- }
-
- if (--pfmtlev==0)
- flush(&f);
+ if(io->fd>=0)
+ close(io->fd);
+ if(io->strp)
+ efree(io->strp);
+ efree((char *)io);
}
-void
-pfmt(Io *f, char *fmt, ...)
+int
+emptybuf(io *f)
{
- va_list args;
- char err[124];
-
- va_start(args, fmt);
- vpfmt(f, fmt, args);
- va_end(args);
+ 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;
}
diff --git a/sys/cmd/rc/lex.c b/sys/cmd/rc/lex.c
index f6e2b4e..253d05a 100644
--- a/sys/cmd/rc/lex.c
+++ b/sys/cmd/rc/lex.c
@@ -1,417 +1,371 @@
#include "rc.h"
+#include "exec.h"
+#include "io.h"
+#include "getflags.h"
+#include "fns.h"
-#define onebyte(c) ((c&0x80)==0x00)
-#define twobyte(c) ((c&0xe0)==0xc0)
-#define threebyte(c) ((c&0xf0)==0xe0)
-#define fourbyte(c) ((c&0xf8)==0xf0)
+char *promptstr;
+int doprompt;
+char tok[NTOK];
-// -----------------------------------------------------------------------
-// globals
-
-static int lastc, nextc=EOF, lastdol, lastword, doprompt = 1;
-static char buf[8*1024];
-
-// -----------------------------------------------------------------------
-// utilities
-
-static uchar nwordc[256] =
-{
- 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 1, 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0,
- 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
-};
+int getnext(void);
int
wordchr(int c)
{
- return !nwordc[c] && c!=EOF;
+ return !strchr("\n \t#;&|^$=`'{}()<>", c) && c!=EOF;
}
-
-static uchar nquotec[256] =
-{
- 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
-};
-
int
-quotechr(char c)
+idchr(int c)
{
- return !nquotec[c] && c!=EOF;
+ /*
+ * Formerly:
+ * return 'a'<=c && c<='z' || 'A'<=c && c<='Z' || '0'<=c && c<='9'
+ * || c=='_' || c=='*';
+ */
+ return c>' ' && !strchr("!\"#$%&'()+,-./:;<=>?@[\\]^`{|}~", c);
}
-
-static uchar nvarc[256] =
-{
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1,
- 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0,
- 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
-};
-
+int future = EOF;
+int doprompt = 1;
+int inquote;
+int incomm;
+/*
+ * Look ahead in the input stream
+ */
int
-varchr(char c)
+nextc(void)
{
- return !nvarc[c] && c!=EOF;
+ if(future==EOF)
+ future = getnext();
+ return future;
}
+/*
+ * Consume the lookahead character.
+ */
-static
-void
-prompt(void)
-{
- shell->cmd.line++;
- doprompt = 0;
-}
-
-/* lookahead one byte */
-static
int
-lookahead(void)
+advance(void)
{
- int c;
-
- if(nextc != EOF)
- return nextc;
- if(shell->cmd.eof)
- return EOF;
-
- if(doprompt)
- prompt();
-
- c = rchr(shell->cmd.io);
- doprompt = c == '\n' || c == EOF;
-
- if(c == EOF)
- shell->cmd.eof++;
-
- return nextc = c;
+ int c = nextc();
+ lastc = future;
+ future = EOF;
+ return c;
}
+/*
+ * read a character from the input stream
+ */
-/* consumes the lookahead */
-static
int
-advance(void)
+getnext(void)
{
- int c = lookahead();
- lastc = nextc, nextc = EOF;
-
- return c;
+ 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' && !incomm){ /* don't continue a comment */
+ 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;
}
-/*
- * advance until we no longer hit horizontal space
- * consumes all comments
- */
-static
void
-skipws(void)
+skipwhite(void)
{
- int c;
- for(;;) {
- c = lookahead();
- if(c=='#'){
- for(;;){
- c = lookahead();
- if(c=='\n' || c==EOF)
- break;
- advance();
- }
- }
- if(c==' ' || c=='\t')
- advance();
- else
- return;
- }
+ int c;
+ for(;;){
+ c = nextc();
+ /* Why did this used to be if(!inquote && c=='#') ?? */
+ if(c=='#'){
+ incomm = 1;
+ for(;;){
+ c = nextc();
+ if(c=='\n' || c==EOF) {
+ incomm = 0;
+ break;
+ }
+ advance();
+ }
+ }
+ if(c==' ' || c=='\t')
+ advance();
+ else return;
+ }
}
-/* advance until we no longer hit any space */
void
skipnl(void)
{
- int c;
- for(;;) {
- skipws();
- if ((c = lookahead()) != '\n')
- return;
- advance();
- }
+ int c;
+ for(;;){
+ skipwhite();
+ c = nextc();
+ if(c!='\n')
+ return;
+ advance();
+ }
}
-/* advance if next char is equal to c */
-static
int
nextis(int c)
{
- if(lookahead()==c) {
- advance();
- return 1;
- }
- return 0;
+ if(nextc()==c){
+ advance();
+ return 1;
+ }
+ return 0;
}
-/* functions to append to our write buffer */
-static
char*
-putbyte(char *s, int c)
+addtok(char *p, int val)
{
- if(!s)
- return s;
- if(s == arrend(buf)){
- *s = 0;
- rcerror("out of buffer space");
- return nil;
- }
- *s++ = c;
- return s;
+ if(p==0)
+ return 0;
+ if(p==&tok[NTOK-1]){
+ *p = 0;
+ yyerror("token buffer too short");
+ return 0;
+ }
+ *p++=val;
+ return p;
}
-static
char*
-putrune(char *s, int c)
+addutf(char *p, int c)
{
- s = putbyte(s, c);
- if (onebyte(c))
- return s;
- if (twobyte(c))
- return putbyte(s, advance());
- if (threebyte(c)) {
- putbyte(s, advance());
- return putbyte(s, advance());
- }
- if (fourbyte(c)) {
- putbyte(s, advance());
- putbyte(s, advance());
- return putbyte(s, advance());
- }
- rcerror("malformed utf8 stream");
- return nil;
+ 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());
+ }
+ if(fourbyte(c)){ /* 4-byte escape */
+ p = addtok(p, advance());
+ 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? */
-// -----------------------------------------------------------------------
-// main exports
-
-void
-rcerror(char *fmt, ...)
-{
- va_list args;
-
- pfmt(errio, "rc:");
- if (shell->cmd.io)
- pfmt(errio, "%s:%d ", shell->cmd.name, shell->cmd.line);
-
- va_start(args, fmt);
- vpfmt(errio, fmt, args);
- va_end(args);
-
- pfmt(errio, "\n");
-
- flush(&errio);
- lastword = lastdol = 0;
- while (lastc != '\n' && lastc != EOF)
- advance();
- /* for debugging only */
- abort();
-}
-
-/* word is only modified in the event of a lexed word */
int
-lex(Tree **node)
+yylex(void)
{
- int c;
- char *w = buf;
- /*
- * NOTE:
- * we inject tokens into the lexer based on context if last token = word:
- * if we see a (, then we interpret that as a subscript
- * otherwise, if the next character is the first char of a word, we return a ^ operator.
- */
- if(lastword){
- lastword=0;
- c = lookahead();
- if(c=='('){
- advance();
- return Tlparen;
- }
- if(quotechr(c))
- return Tcarot;
- }
-
- skipws();
- switch(c=advance()) {
- case EOF:
- lastdol = 0;
- return EOF;
- case '$':
- lastdol = 1;
- if(nextis('#'))
- return Tcount;
- if (nextis('"'))
- return Tquote;
- return Tdol;
- case '&':
- lastdol = 0;
- if(nextis('&'))
- return Tandand;
- return Tand;
-
- case '!':
- return Tbang;
- case '@':
- return Tsubshell;
- case '~':
- return Ttwiddle;
-
- case '|':
- lastdol = 0;
- if(nextis('|')){
- skipnl();
- return Toror;
- }
- (*node) = newtree();
- (*node)->type = Tpipe;
- (*node)->redir.fd[0] = 0;
- (*node)->redir.fd[1] = 1;
- goto redir;
- case '>':
- (*node) = newtree();
- (*node)->type = Tredir;
- if (nextis(c))
- (*node)->redir.type = Rappend;
- else
- (*node)->redir.type = Rwrite;
- (*node)->redir.fd[0] = 1;
- goto redir;
- case '<':
- (*node) = newtree();
- (*node)->type = Tredir;
- if(nextis(c))
- (*node)->redir.type = Rhere;
- else if(nextis('>'))
- (*node)->redir.type = Rrdwr;
- else
- (*node)->redir.type = Rread;
- (*node)->redir.fd[0] = 0;
- /* fallthrough */
- redir:
- if(nextis('[')) {
- c = advance();
- if(c < '0' || '9' < c) {
- redirerr:
- rcerror("incorrect redirection syntax");
- return EOF;
- }
- (*node)->redir.fd[0] = 0;
- do {
- (*node)->redir.fd[0] = 10*(*node)->redir.fd[0]+(c-'0');
- c = advance();
- } while('0'<=c && c<='9');
-
- if(c == '=') {
- if((*node)->type == Tredir)
- (*node)->type = Tdup;
- c = advance();
- if('0'<=c && c<='9') {
- (*node)->redir.type = Rdupfd;
- (*node)->redir.fd[1] = (*node)->redir.fd[0];
- (*node)->redir.fd[0] = 0;
- do {
- (*node)->redir.fd[0] = 10*(*node)->redir.fd[0]+(c-'0');
- c = advance();
- } while('0'<=c && c<='9');
- } else {
- if((*node)->type == Tpipe)
- goto redirerr;
- (*node)->redir.type = Rclose;
- }
- }
- if (c != ']'
- ||(*node)->type==Tdup && ((*node)->redir.type==Rhere || (*node)->redir.type==Rappend))
- goto redirerr;
- }
- if ((c = ((*node)->type)) == Tpipe)
- skipnl();
- return c;
-
- case '\'':
- lastdol = 0;
- lastword = 1;
- for(;;){
- c = advance();
- if(c==EOF)
- break;
- if(c=='\''){
- if(lookahead()!='\'')
- break;
- advance();
- }
- w = putrune(w, c);
- }
- *w = 0;
- *node = wordnode(buf);
- (*node)->quoted = 1;
- return Tword;
- }
- if (!wordchr(c)) {
- lastdol = 0;
- return c;
- }
- for(;;){
- if(c=='*'||c=='['||c=='?'||c==GLOB)
- w = putbyte(w, GLOB);
- w = putrune(w, c);
- c = lookahead();
- if(lastdol?!varchr(c):!wordchr(c))
- break;
- advance();
- }
- *w = 0;
-
- if ((c = kwlookup(buf)) == -1) {
- (*node) = wordnode(buf);
- (*node)->type = c = Tword;
- (*node)->quoted = 0;
- lastword = 1;
- }
-
- lastdol = 0;
- return c;
+ int c, d = nextc();
+ char *w = tok;
+ 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 if (nextis('>')){
+ t->rtype = RDWR;
+ *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;
}
diff --git a/sys/cmd/rc/main.c b/sys/cmd/rc/main.c
deleted file mode 100644
index b4a355e..0000000
--- a/sys/cmd/rc/main.c
+++ /dev/null
@@ -1,86 +0,0 @@
-#include "rc.h"
-
-/* globals */
-Thread *shell = nil;
-int ntrap = 0;
-Io *errio;
-
-/* main execution */
-
-void
-dotrap(void)
-{
- exit(1);
-}
-
-void
-bootup(Code *c, int off, Var *vars)
-{
- Thread *sh;
-
- alloc(sh);
- sh->code = c, c->i++;
- sh->ip = sh->code + off;
- sh->local = vars;
- sh->stack = nil;
-
- sh->link = shell, shell = sh;
-}
-
-int
-main(int argc, char *argv[])
-{
- int i;
- Code *ip, sh[32];
-
- ARGBEGIN {
- } ARGEND;
-
- errio = openfd(2);
-
- initkw();
-
- ip = sh;
- memset(sh, 0, sizeof(sh));
- /*
- * NOTE: first element of code is a reference count
- * bootup runs:
- * 1. *=argv[1:]
- * 2. . rcmain $*
- */
-#if 0
- ip++->i = 1;
- ip++->f = Xmark;
- ip++->f = Xword;
- ip++->s = "*";
- ip++->f = Xassign;
- ip++->f = Xmark;
- ip++->f = Xmark;
- ip++->s = "*";
- ip++->f = Xdol;
- ip++->s = "rcmain";
- ip++->f = Xword;
- ip++->s = ".";
- ip++->f = Xsimple;
- ip++->f = Xexit;
- ip++->i = 0;
-
- bootup(sh, 1, nil);
- pushlist();
- for (i = argc-1; i != 0; i--)
- pushword(argv[i]);
-
- for (;;) {
- shell->ip++->f();
- if (ntrap)
- dotrap();
- }
-#else
- bootup(sh, 1, nil);
- shell->cmd.io = openfd(0);
- while (parse())
- ;
-
-#endif
- exit(0);
-}
diff --git a/sys/cmd/rc/parse.c b/sys/cmd/rc/parse.c
deleted file mode 100644
index b61ac3c..0000000
--- a/sys/cmd/rc/parse.c
+++ /dev/null
@@ -1,496 +0,0 @@
-#include "rc.h"
-
-/* TODO: better error messages */
-
-// -----------------------------------------------------------------------
-// global data
-
-static int lastt, nextt=EOF;
-static Tree *node; /* if token was lexed as a tree node (redirs and words), its here */
-
-/* anything that is not listed will automatically terminate parsing the given command */
-static uchar prectab[256] = {
- [Tif] = 1, [Tfor] = 1, [Tswitch] = 1, /* NOTE: we give else lower precedence than if [Telse] = 1, */
- [Tandand] = 2, [Toror] = 2,
- [Tbang] = 3, [Tsubshell] = 3,
- [Tpipe] = 4,
- [Tcarot] = 5,
- [Tdol] = 6, [Tcount] = 6, [Tquote] = 6,
- [Tsub] = 7,
-};
-
-// -----------------------------------------------------------------------
-// helpers
-
-static
-int
-lookahead(void)
-{
- int tok;
-
- if (nextt != EOF)
- return nextt;
-
- tok = lex(&node);
- return nextt = tok;
-}
-
-static
-int
-advance(void)
-{
- int tok = lookahead();
- lastt = nextt, nextt = EOF;
- node = nil;
-
- return tok;
-}
-
-static
-int
-nextis(int tok)
-{
- if (lookahead() == tok) {
- advance();
- return 1;
- }
- return 0;
-}
-
-// -----------------------------------------------------------------------
-// subparsers
-
-/* forward declarations */
-static Tree *word(void);
-static Tree *words(void);
-static Tree* body(int c);
-static Tree *comword(void);
-static Tree *cmd(int prec);
-
-/* implementations */
-
-/*
- * TODO:
- * i don't like all this branching.
- * think of a better way
- */
-
-static
-Tree*
-case_or_cmd(int c)
-{
- Tree *t;
- if (!c || !nextis(Tcase))
- return cmd(1);
-
- t = words();
- if (!nextis(';') && !nextis('\n'))
- rcerror("case: missing terminator: recieved %d", nextt);
-
- t = tree2(Tcase, t, body(0));
- pfmt(errio, "%t\n", t);
-
- return t;
-}
-
-static
-Tree*
-body(int c)
-{
- int tok;
- Tree *l, *r;
-
- skipnl();
- l = case_or_cmd(c);
-loop:
- switch((tok=lookahead())){
- case '&':
- l = tree1('&', l);
- /* fallthrough */
- case ';': case '\n':
- advance();
- /* fallthrough */
- case Tcase:
- if ((r = case_or_cmd(c))) {
- l = tree2(';', l, r);
- goto loop;
- }
- /* fallthrough */
- default:
- ;
- }
-
- return l;
-}
-
-static
-Tree*
-brace(int c)
-{
- Tree *t;
-
- if (!nextis('{'))
- rcerror("brace: expected { found: %c", nextt);
- t = tree1(Tbrace, body(c));
- if (!nextis('}'))
- rcerror("brace: expected } found: %c", nextt);
-
- return t;
-}
-
-static
-Tree*
-paren(void)
-{
- Tree *t;
-
- if (!nextis('('))
- rcerror("not a paren");
- t = tree1(Tparen, body(0));
- if (!nextis(')'))
- rcerror("unmatched paren");
-
- return t;
-}
-
-/* TODO: fill in */
-static
-Tree*
-heredoc(Tree* t)
-{
- return t;
-}
-
-static
-Tree*
-redir(void)
-{
- int tok;
- Tree *t;
-
- switch (tok = lookahead()) {
- case Tdup:
- t = node;
- advance();
- break;
- case Tredir:
- t = node;
- advance();
- t = hang1(t, (t->redir.type == Rhere) ? heredoc(word()) : word());
- break;
- default:
- t = nil;
- }
-
- return t;
-}
-
-static
-Tree*
-epilog(void)
-{
- Tree *t, *tt;
-
- t = redir();
- while((tt = redir()))
- t = hang2(t, t->child[0], tt);
-
- return t;
-}
-
-static
-Tree*
-sword(void)
-{
- int tok;
- if (Kstart < (tok=lookahead()) && tok < Kend)
- return node;
-
- return comword();
-}
-
-static
-Tree*
-word(void)
-{
- int tok;
- Tree *t;
-
- t = sword();
- while(nextis('^'))
- t = tree2('^', t, sword());
-
- return t;
-}
-
-
-static
-Tree*
-words(void)
-{
- Tree *t, *tt;
- t = word();
- while((tt=word()))
- t = tree2(Twords, t, tt);
-
- return t;
-}
-
-/*
- * NOTE: we divergence from Duff's yacc grammar here.
- * he has [dol|count|"]->word, we have [dol|count]->sword
- * calling sword ensures we don't cat strings
- * this was done in Tom's version by setting precedence
- */
-static
-Tree*
-comword(void)
-{
- int tok;
- Tree *t, *tt;
-
- switch(tok=lookahead()){
- case Tdol:
- advance();
- t = sword();
- if(nextis('(')) {
- t = tree2(Tsub, t, words());
- if (!nextis(')'))
- rcerror("malformed index expression");
- }
- return tree1(Tdol, t);
- case Tquote:
- return tree1(Tquote, sword());
- case Tcount:
- advance();
- return tree1(Tcount, sword());
- case Ttick:
- advance();
- return tree1(Ttick, brace(0));
- case Tlparen:
- return paren();
- case Tredir:
- advance();
- t = hang1(node, brace(0));
- t->type = Tpipefd;
- return t;
- case Tword:
- t = node;
- advance();
- return t;
- }
- return nil;
-}
-
-static
-Tree*
-first(void)
-{
- int tok;
- Tree *t;
-
- t = comword();
- while(nextis('^')) {
- t = tree2('^', t, word());
- }
-
- return t;
-}
-
-/* simple _or_ assignment */
-static
-Tree*
-simple_or_assign(void)
-{
- int tok;
- Tree *t, *tt;
-
- /* can't continue */
- if (!(t = first()))
- return nil;
-
- /* is an assignment */
-assign:
- if(nextis('=')) {
- tt = word();
- return tree3(Teq, t, tt, cmd(prectab[Tbang]));
- }
-
- /* is a 'simple' */
-simple:
- switch ((tok=lookahead())) {
- case Tredir:
- case Tdup:
- t = tree2(Targs, t, redir());
- goto simple;
- default:
- if ((tt = word())) {
- t = tree2(Targs, t, tt);
- goto simple;
- }
- /* fallthrough */
- }
-
- return simplehang(t);
-}
-
-static
-Tree*
-opand(void)
-{
- int tok;
- Tree *t, *tt;
-
- switch(tok=lookahead()) {
- case Tif:
- advance();
- t = paren();
- skipnl();
- tt = cmd(prectab[Tif]);
- if (nextis(Telse)) {
- skipnl();
- t = tree3(Tif, t, tt, cmd(prectab[Tif]));
- } else
- t = tree3(Tif, t, tt, nil);
- return t;
- case Telse:
- rcerror("invalid hanging else");
- break;
-
- case Tswitch:
- advance();
- t = word();
- skipnl();
- tt = brace(1);
- t = tree2(Tswitch, t, tt);
- return t;
-
- case Tfor:
- advance();
-
- if (!nextis('('))
- rcerror("for: missing opening paren");
- t = word();
- if (nextis(Tin)) {
- advance();
- tt = words();
- t = tree3(Tfor, t, tt, nil);
- } else
- t = tree3(Tfor, t, nil, nil);
- if (!nextis(')'))
- rcerror("for: missing closing paren");
-
- skipnl();
- tt = cmd(prectab[Tfor]);
- t->child[2] = tt;
- return t;
-
- case Twhile:
- advance();
- t = paren();
- skipnl();
- tt = cmd(1);
- return tree2(Twhile, t, tt);
-
- case Tfunc:
- advance();
- t = words();
- if ((tok=lookahead()) == '{') {
- tt = brace(0);
- t = tree2(Tfunc, t, tt);
- } else
- t = tree1(Tfunc, t);
- return t;
-
- case Tsubshell:
- advance();
- t = tree1(Tsubshell, cmd(prectab[Tsubshell]));
- return t;
-
- case Tbang:
- advance();
- t = tree1(Tbang, cmd(prectab[Tbang]));
- return t;
-
- case Ttwiddle:
- advance();
- tt = word();
- t = tree2(Ttwiddle, tt, words());
- return t;
-
- case Tlbrace:
- t = brace(0);
- tt = epilog();
- return epihang(t, tt);
-
- case Tredir: /* fallthrough */
- case Tdup:
- t = redir();
- tt = cmd(prectab[Tbang]);
- t = hang2(t, t->child[0], tt);
- return t;
- }
-
- return simple_or_assign();
-}
-
-static
-Tree *
-cmd(int prec)
-{
- int np, tok;
- Tree *l, *r, *p;
-
- if (!(l = opand()))
- return nil;
-
- for(;;) {
- tok = lookahead();
- np = prectab[tok];
- if (np < prec)
- break;
- p = node;
- advance();
- r = cmd(np+1);
- if (tok == Tpipe)
- l = hang2(p, l, r);
- else
- l = tree2(tok, l, r);
- }
-
- return l;
-}
-
-// -----------------------------------------------------------------------
-// main function
-
-int
-parse(void)
-{
- int tok;
- Tree *t, *tt;
-
- t = cmd(1);
-loop:
- switch(tok=lookahead()) {
- case '&':
- t = tree1('&', t);
- /* fallthrough */
- case ';':
- advance();
- tt = cmd(1);
- t = tree2(';', t, tt);
- goto loop;
- case '\n':
- advance();
- case EOF:
- pfmt(errio, "%t\n", t);
- break;
- default:
- if (tok > 0x20)
- rcerror("unrecognized token: %c[%d]", tok, tok);
- else
- rcerror("unrecognized token: %d", tok, tok);
- }
- return tok != EOF;
-}
diff --git a/sys/cmd/rc/rc.h b/sys/cmd/rc/rc.h
index f32a737..1f73f11 100644
--- a/sys/cmd/rc/rc.h
+++ b/sys/cmd/rc/rc.h
@@ -1,312 +1,133 @@
-#pragma once
-
-#include <u.h>
-#include <libn.h>
-
-#include <errno.h>
-#include <sys/wait.h>
-
-#define alloc(ptr) ptr = emalloc(sizeof(*ptr))
-
-// -----------------------------------------------------------------------
-// main enums
-
-#define GLOB 0x01
-
-enum
-{
- /* keywords */
- Kstart = 11,
- Tfor, Tin, Twhile, Tif, Telse,
- Tswitch, Tcase, Tfunc, Ttwiddle,
- Tbang, Tsubshell,
- Kend,
-
- /* tokens */
- Tword='w', Tredir='r', Tdup='d', Tsimple='s',
- Targs='A', Twords='W', Tbrace='b', Tparen='p', Tsub='S',
- Tpcmd='c', Tpipefd='-', Tandand='%', Toror='@', Tcount='#',
-
- Ttick='`', Tpipe = '|', Tdol='$', Tquote='"', Tand='&',
- Tlparen = '(', Trparen = ')', Tlbrace='{', Trbrace='}',
- Tsemi=';', Tcarot='^', Teq='=',
+#include "unix.h"
+
+#define YYMAXDEPTH 500
+#ifndef PAREN
+#ifndef YYMAJOR
+#include "x.tab.h"
+#endif
+#endif
+
+#undef pipe /* so that /dev/fd works */
+#define searchpath rcsearchpath /* avoid new libc function */
+
+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*);
-enum
-{
- Rappend = 1,
- Rwrite = 2,
- Rread = 3,
- Rhere = 4,
- Rdupfd = 5,
- Rclose = 6,
- Rrdwr = 7,
-};
-
-enum
-{
- Fopen = 1,
- Fdup = 2,
- Fclose = 3,
-};
-
-// -----------------------------------------------------------------------
-// main types
+extern tree *cmdtree;
-typedef union Code Code;
-typedef struct Word Word;
-typedef struct List List;
-typedef struct Var Var;
-typedef struct Redir Redir;
-typedef struct Tree Tree;
-typedef struct Builtin Builtin;
-typedef struct Thread Thread;
-typedef struct Io Io;
-
-union Code
-{
- int i;
- char *s;
- void (*f)(void);
-};
-
-struct Word
-{
- char *word;
- Word *link;
-};
-
-struct List
-{
- Word *words;
- List *link;
-};
-
-struct Redir
-{
- uchar type;
- short from, to;
- Redir *link;
-};
-
-struct Var
-{
- string name;
- Word *val;
- struct {
- Code *func, *ip;
- uint funcnew : 1;
- };
- struct {
- uint new : 1;
- void (*update)(Var*);
- };
- Var *link;
-};
-
-struct Tree
-{
- ushort type;
- uchar quoted : 1;
- union {
- char *str;
- struct {
- ushort type;
- int fd[2];
- } redir;
- };
-
- Tree *child[3], *link;
+/*
+ * 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;
};
-struct Builtin
-{
- char *cmd;
- void (*func)(void);
+extern char *promptstr;
+extern int doprompt;
+
+#define NTOK 8192
+extern char tok[NTOK];
+
+#define APPEND 1
+#define WRITE 2
+#define READ 3
+#define HERE 4
+#define DUPFD 5
+#define CLOSE 6
+#define RDWR 7
+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 */
+ void (*changefn)(var*);
};
-
-struct Thread
-{
- Code *code, *ip;
- List *stack;
- Redir *redir, *root;
- Var *local;
- uchar interactive : 1;
- struct {
- uchar eof : 1;
- int line;
- char *name;
- Io *io;
- } cmd;
-
- int pid;
- Tree *nodes;
- Thread *link; /* continuation */
+var *vlook(char*), *gvlook(char*), *newvar(char*, var*);
+
+#define NVAR 521
+extern var *gvar[NVAR]; /* hash for globals */
+
+#define new(type) ((type *)emalloc(sizeof(type)))
+void *emalloc(long);
+void *Malloc(ulong);
+void efree(void*);
+#define NOFILE 128 /* should come from <param.h> */
+struct here{
+ tree *tag;
+ char *name;
+ struct here *next;
};
-
-struct Io
-{
- int fd;
- uchar *b, *e, buf[];
-};
-
-// -----------------------------------------------------------------------
-// global interpreter variables
-
-extern Thread *shell;
-extern int ntrap;
-extern int status;
-
-extern Io *errio;
-
-extern Builtin builtins[];
-extern Var *globals[1021]; /* for now must be prime */
-
-// -----------------------------------------------------------------------
-// interpreter functions (defined in exec.c)
-
-/*
- * notation:
- * (var1, var2, ...) : items from stack
- * [var1, var2, ...] : items from code stream
- * {var1, var2, ...} : jump block from code stream
- * -> moves value (stack) [code stream]
- */
-extern void Xappend(void); /* Xappend(file)[fd]: open file to append */
-extern void Xassign(void); /* Xassign(name, val): assign name to val */
-extern void Xasync(void); /* Xasync(cmd): run command asynchronously */
-extern void Xcat(void); /* Xcat(list1, list2): concatenate strings */
-extern void Xclose(void); /* Xclose[fd]: close file descriptor */
-extern void Xcmdsub(void); /* Xcmdsub(cmd): use output of command as input to other */
-extern void Xcount(void); /* Xcount(name) -> (number): count items in list*/
-extern void Xdol(void); /* Xdol(name): get variable value */
-extern void Xdup(void); /* Xdup[i, j]: duplicate file descriptor */
-extern void Xexit(void); /* Xexit: exit with status */
-extern void Xfalse(void); /* Xfalse{...}: run only if $status=1 */
-extern void Xflatten(void); /* Xflatten(list) -> (string): flatten list */
-extern void Xfor(void); /* Xfor(list): flatten list */
-extern void Xfunc(void); /* Xfunc(name){... Xreturn}: define function */
-extern void Xglob(void); /* Xglob(list): globs value */
-extern void Xif(void); /* Xif: execute if $status */
-extern void Xjump(void); /* Xjump[addr]: jump to address */
-extern void Xkill(void); /* Xkill kill thread */
-extern void Xlocal(void); /* Xlocal(name, val): define local variable */
-extern void Xmark(void); /* Xmark: delimit stack with new list */
-extern void Xmatch(void); /* Xmatch(pat, str): sets status with result */
-extern void Xnegate(void); /* Xnegate: negate condition */
-extern void Xpipe(void); /* Xpipe[i j]{... Xkill}{... Xkill}: construct a pipe between 2 threads*/
-extern void Xpipefd(void); /* Xpipe[type]{... Xkill}: connect {} to a pipe */
-extern void Xpipewait(void); /* Xpipewait: wait on a pipe */
-extern void Xpop(void); /* Xpop(value): pops value from stack */
-extern void Xpopredir(void); /* Xpopredir(value): pops redir from redir stack */
-extern void Xrdwr(void); /* Xrdwr(file)[fd]: open file for reads/writes */
-extern void Xread(void); /* Xread(file)[fd]: open file for reads */
-extern void Xsub(void); /* Xsub(list, index): subscript list */
-extern void Xsimple(void); /* Xsimple(args): run command */
-extern void Xsubshell(void); /* Xsubshell(args): run command in a subshell */
-extern void Xtrue(void); /* Xtrue{...}: run only if $status=0 */
-extern void Xunfunc(void); /* Xunfunc(name) undefine function */
-extern void Xunlocal(void); /* Xunlocal(name) undefine local */
-extern void Xword(void); /* Xword[val] -> (val) */
-extern void Xwrite(void); /* Xwrite(file)[fd]: open file to write */
-
-extern void Xerror(char *s); /* Xerror report an error */
-
-// -----------------------------------------------------------------------
-// shell functions
-
-/*
- * util.c
- */
-void *emalloc(uintptr size);
-void *erealloc(void *ptr, uintptr size);
-void efree(void *);
-void panic(char *msg, int n);
-
-/*
- * io.c
- */
-Io *openfd(int fd);
-Io *openstr(void);
-Io *opencore(int len, char *s);
-void rewindio(Io *f);
-void closeio(Io *f);
-void flush(Io **fp);
-
-/* reads */
-int rchr(Io *f);
-
-/* writes */
-int pchr(Io *f, int c);
-void pquo(Io *f, char *s);
-void pwrd(Io *f, char *s);
-void pptr(Io *f, void *v);
-void pstr(Io *f, char *s);
-void pdec(Io *f, int n);
-void poct(Io *f, uint n);
-void pval(Io *f, Word *a);
-void pcmd(Io *f, Tree *t);
-void pfmt(Io *f, char *fmt, ...);
-void vpfmt(Io *f, char *fmt, va_list args);
-
-/*
- * word.c
- */
-void pushlist(void);
-void freelist(Word *w);
-void poplist(void);
-
-int count(Word *w);
-Word *newword(char *w, Word *link);
-void pushword(char *w);
-
-/*
- * tree.c
- */
-
-Tree *newtree(void);
-void freetree(Tree *t);
-Tree *tree3(int type, Tree *c0, Tree *c1, Tree *c2);
-Tree *tree2(int type, Tree *c0, Tree *c1);
-Tree *tree1(int type, Tree *c0);
-
-Tree *hang1(Tree *p, Tree *c0);
-Tree *hang2(Tree *p, Tree *c0, Tree *c1);
-Tree *hang3(Tree *p, Tree *c0, Tree *c1, Tree *c2);
-Tree *epihang(Tree *c, Tree *epi);
-Tree *simplehang(Tree *t);
-Tree *wordnode(char *w);
-
/*
- * var.c
+ * 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
*/
-
-Var *newvar(char *name, Var *link);
-Var *gvlookup(char *name);
-Var *vlookup(char *name);
-void setvar(char *name, Word *val);
-
-int kwlookup(char *name);
-void initkw(void);
-
-/*
- * lex.c
+#define GLOB ((char)0x01)
+/*
+ * onebyte(c), twobyte(c), threebyte(c)
+ * Is c the first character of a one- two- or three-byte utf sequence?
*/
-
-void skipnl(void);
-int wordchr(int c);
-
-void rcerror(char *msg, ...);
-int lex(Tree **node);
-
+#define onebyte(c) ((c&0x80)==0x00)
+#define twobyte(c) ((c&0xe0)==0xc0)
+#define threebyte(c) ((c&0xf0)==0xe0)
+#define fourbyte(c) ((c&0xf8)==0xf0)
+
+extern char **argp;
+extern char **args;
+extern int nerror; /* number of errors encountered during compilation */
/*
- * parse.c
+ * 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
-int parse(void);
+char *getstatus(void);
/*
- * main.c
+ * How many dot commands have we executed?
+ * Used to ensure that -v flag doesn't print rcmain.
*/
-
-void dotrap(void);
+extern int ndot;
+extern int lastc;
+extern int lastword;
+extern int kidpid;
+extern int mypid;
diff --git a/sys/cmd/rc/rules.mk b/sys/cmd/rc/rules.mk
index 654a44e..0a5af08 100644
--- a/sys/cmd/rc/rules.mk
+++ b/sys/cmd/rc/rules.mk
@@ -1,22 +1,39 @@
include share/push.mk
+# Iterate through subdirectory tree
# Local sources
SRCS_$(d) := \
- $(d)/glob.c \
- $(d)/word.c \
- $(d)/util.c \
- $(d)/io.c \
- $(d)/var.c \
- $(d)/tree.c \
- $(d)/lex.c \
- $(d)/parse.c \
- $(d)/main.c
+ $(d)/code.c\
+ $(d)/exec.c\
+ $(d)/getflags.c\
+ $(d)/glob.c\
+ $(d)/here.c\
+ $(d)/io.c\
+ $(d)/lex.c\
+ $(d)/pcmd.c\
+ $(d)/pfnc.c\
+ $(d)/simple.c\
+ $(d)/subr.c\
+ $(d)/trap.c\
+ $(d)/tree.c\
+ $(d)/var.c\
+ $(d)/y.tab.c\
+ $(d)/unix.c\
+ $(d)/havefork.c\
+ $(d)/prompt.c
+
BINS_$(d) := $(d)/rc
include share/paths.mk
# Local rules
-$(BINS_$(d)): $(OBJS_$(d)) $(OBJ_DIR)/libn/libn.a
+$(d)/y.tab.h $(d)/y.tab.c: $(d)/syn.y
+ yacc -d $^
+
+$(BINS_$(d)): TCFLAGS = \
+ -D_XOPEN_SOURCE=500
+
+$(BINS_$(d)): $(OBJS_$(d)) $(OBJ_DIR)/sys/libn/libn.a /home/nolln/root/lib/libreadline.a /home/nolln/root/lib/libhistory.a /home/nolln/root/lib/libncursesw.a
$(COMPLINK)
include share/pop.mk
diff --git a/sys/cmd/rc/simple.c b/sys/cmd/rc/simple.c
index f934aa1..d587227 100644
--- a/sys/cmd/rc/simple.c
+++ b/sys/cmd/rc/simple.c
@@ -1,13 +1,504 @@
+/*
+ * 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;
- Var *v;
+ word *a;
+ thread *p = runq;
+ var *v;
+ struct builtin *bp;
+ int pid;
+ 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 */
+ if((pid = execforkexec()) < 0){
+ Xerror("try again");
+ return;
+ }
+
+ /* interrupts don't get us out */
+ poplist();
+ 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();
+}
- a = shell->stack->words;
- if (!a) {
- Xerror("empty argument list");
- return;
- }
- v = vlookup(a->word);
+void
+execfunc(var *func)
+{
+ word *starval;
+ popword();
+ starval = runq->argv->words;
+ runq->argv->words = 0;
+ poplist();
+ start(func->fn, func->pc, runq->local);
+ 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();
}
diff --git a/sys/cmd/rc/tree.c b/sys/cmd/rc/tree.c
index 14049e5..897597e 100644
--- a/sys/cmd/rc/tree.c
+++ b/sys/cmd/rc/tree.c
@@ -1,144 +1,146 @@
#include "rc.h"
-
-// -----------------------------------------------------------------------
-// globals
-
-static Tree *nodes;
-
-// -----------------------------------------------------------------------
-// exported funcs
-
-Tree*
+#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;
-
- alloc(t);
- t->str = nil;
- t->child[0] = t->child[1] = t->child[2] = nil;
- t->redir.fd[0] = t->redir.fd[1] = t->redir.type = 0;
-
- t->link = nodes, nodes = t;
- return t;
+ 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
-freetree(Tree *t)
+freenodes(void)
{
- if (!t)
- return;
-
- freetree(t->child[0]);
- freetree(t->child[1]);
- freetree(t->child[2]);
-
- if (t->str)
- efree(t->str);
- efree(t);
+ tree *t, *u;
+ for(t = treenodes;t;t = u){
+ u = t->next;
+ if(t->str)
+ efree(t->str);
+ efree((char *)t);
+ }
+ treenodes = 0;
}
-void
-freenodes(void)
+tree*
+tree1(int type, tree *c0)
{
- Tree *t, *u;
-
- for (t = nodes;t;t = u) {
- u = t->link;
- if (t->str)
- efree(t->str);
- efree(t);
- }
- nodes = nil;
+ return tree3(type, c0, (tree *)0, (tree *)0);
}
-/* tree creation */
-Tree*
-tree3(int type, Tree *c0, Tree *c1, Tree *c2)
+tree*
+tree2(int type, tree *c0, tree *c1)
{
- Tree *t;
-
- t = newtree();
- t->type = type;
- t->child[0] = c0;
- t->child[1] = c1;
- t->child[2] = c2;
-
- return t;
+ return tree3(type, c0, c1, (tree *)0);
}
-Tree*
-tree2(int type, Tree *c0, Tree *c1)
+tree*
+tree3(int type, tree *c0, tree *c1, tree *c2)
{
- return tree3(type, c0, c1, nil);
+ 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*
-tree1(int type, Tree *c0)
+tree*
+mung1(tree *t, tree *c0)
{
- return tree3(type, c0, nil, nil);
+ t->child[0] = c0;
+ return t;
}
-/* tree hang */
-Tree*
-hang1(Tree *p, Tree *c0)
+tree*
+mung2(tree *t, tree *c0, tree *c1)
{
- p->child[0] = c0;
- return p;
+ t->child[0] = c0;
+ t->child[1] = c1;
+ return t;
}
-Tree*
-hang2(Tree *p, Tree *c0, Tree *c1)
+tree*
+mung3(tree *t, tree *c0, tree *c1, tree *c2)
{
- p->child[0] = c0;
- p->child[1] = c1;
- return p;
+ t->child[0] = c0;
+ t->child[1] = c1;
+ t->child[2] = c2;
+ return t;
}
-Tree*
-hang3(Tree *p, Tree *c0, Tree *c1, Tree *c2)
+tree*
+epimung(tree *comp, tree *epi)
{
- p->child[0] = c0;
- p->child[1] = c1;
- p->child[2] = c2;
- return p;
+ 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.
+ */
-/* hangs the cmd underneath the epilogue */
-Tree*
-epihang(Tree *c, Tree *epi)
+tree*
+simplemung(tree *t)
{
- Tree *p;
- if(!epi)
- return c;
- for(p=epi;p->child[1];p = p->child[1])
- ;
- p->child[1] = c;
- return epi;
+ 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;
}
-/* hangs tree t from a new simple node. percolates redirections to root */
-Tree*
-simplehang(Tree *t)
+tree*
+token(char *str, int type)
{
- Tree *u;
- t = tree1(Tsimple, t);
- for(u = t->child[0];u->type==Targs;u=u->child[0]) {
- if (u->child[1]->type==Tdup
- || u->child[1]->type==Tredir){
- u->child[1]->child[1] = t;
- t = u->child[1];
- u->child[1] = nil;
- }
- }
- return t;
+ tree *t = newtree();
+ t->type = type;
+ t->str = strdup(str);
+ return t;
}
-Tree*
-wordnode(char *w)
+void
+freetree(tree *p)
{
- Tree *t = newtree();
- t->type = Tword;
- t->str = strdup(w);
-
- return t;
+ 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);
}
diff --git a/sys/cmd/rc/util.c b/sys/cmd/rc/util.c
deleted file mode 100644
index 02b3611..0000000
--- a/sys/cmd/rc/util.c
+++ /dev/null
@@ -1,40 +0,0 @@
-#include "rc.h"
-
-void *
-emalloc(uintptr n)
-{
- void *p = malloc(n);
- if (!p)
- panic("can't malloc %d bytes", n);
-
- return p;
-}
-
-void *
-erealloc(void *p, uintptr n)
-{
- void *new = realloc(p, n);
- if (!new)
- panic("can't realloc %d bytes", n);
-
- return new;
-}
-
-void
-efree(void *p)
-{
- if (p)
- free(p);
- else
- pfmt(errio, "free <nil>\n");
-}
-
-void
-panic(char *s, int n)
-{
- pfmt(errio, "rc: ");
- pfmt(errio, s, n);
- pchr(errio, '\n');
- flush(&errio);
- abort();
-}
diff --git a/sys/cmd/rc/var.c b/sys/cmd/rc/var.c
index d442369..d48dc66 100644
--- a/sys/cmd/rc/var.c
+++ b/sys/cmd/rc/var.c
@@ -1,129 +1,175 @@
#include "rc.h"
+#include "exec.h"
+#include "fns.h"
-Var *globals[1021] = { 0 };
+var *gvar[NVAR] = { 0 }; /* hash for globals */
-struct Keyword {
- ushort type;
- char *name;
- struct Keyword *link;
-} *keywords[41];
-
-// -----------------------------------------------------------------------
-// utility
-
-static
int
hash(char *s, int n)
{
- int i = 1, h = 0;
- while (*s)
- h += *s++*i++;
- h %= n;
- return (h<0)?h+n:h;
+ 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];
-// -----------------------------------------------------------------------
-// keywords
-
-static
void
-putkw(int type, char *name)
+kenter(int type, char *name)
{
- struct Keyword *kw;
- int h = hash(name, arrlen(keywords));
-
- alloc(kw);
- kw->type = type;
- kw->name = name;
- kw->link = keywords[h];
-
- keywords[h] = kw;
+ int h = hash(name, NKW);
+ struct kw *p = new(struct kw);
+ p->type = type;
+ p->name = name;
+ p->next = kw[h];
+ kw[h] = p;
}
void
-initkw(void)
+kinit(void)
{
- putkw(Tfor, "for");
- putkw(Tin, "in");
- putkw(Twhile, "while");
- putkw(Tif, "if");
- putkw(Telse, "else");
- putkw(Tswitch, "switch");
- putkw(Tcase, "case");
- putkw(Tfunc, "func");
+ 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");
}
-int
-kwlookup(char *name)
+tree*
+klook(char *name)
{
- int t;
- struct Keyword *it;
- for(t=-1,it = keywords[hash(name, arrlen(keywords))];it;it = it->link)
- if(!strcmp(it->name, name))
- t = it->type;
- return t;
+ 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;
}
-// -----------------------------------------------------------------------
-// variables
-
-Var *
-newvar(char *name, Var *link)
+var*
+gvlook(char *name)
{
- Var *v;
-
- alloc(v);
- v->name = name;
- v->val = 0;
- v->func = nil;
- v->funcnew = 0;
- v->new = 0;
- v->update = nil;
- v->link = link;
-
- return v;
+ 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]);
}
-/* only global lookup */
+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);
+}
-Var *
-gvlookup(char *name)
+void
+_setvar(char *name, word *val, int callfn)
{
- Var *v;
- int h = hash(name, arrlen(globals));
- for (v = globals[h]; v; v = v->link)
- if (!strcmp(v->name, name))
- return v;
+ struct var *v = vlook(name);
+ freewords(v->val);
+ v->val=val;
+ v->changed=1;
+ if(callfn && v->changefn)
+ v->changefn(v);
+}
- return globals[h] = newvar(strdup(name), globals[h]);
+void
+setvar(char *name, word *val)
+{
+ _setvar(name, val, 1);
}
-/* local + global lookup */
-Var *
-vlookup(char *name)
+void
+bigpath(var *v)
{
- Var *v;
- if (shell)
- for (v = shell->local; v; v = v->link)
- if (!strcmp(v->name, name))
- return v;
- return gvlookup(name);
+ /* convert $PATH to $path */
+ char *p, *q;
+ word **l, *w;
+
+ if(v->val == nil){
+ _setvar("path", nil, 0);
+ return;
+ }
+ p = v->val->word;
+ w = nil;
+ l = &w;
+ /*
+ * Doesn't handle escaped colon nonsense.
+ */
+ if(p[0] == 0)
+ p = nil;
+ while(p){
+ q = strchr(p, ':');
+ if(q)
+ *q = 0;
+ *l = newword(p[0] ? p : ".", nil);
+ l = &(*l)->next;
+ if(q){
+ *q = ':';
+ p = q+1;
+ }else
+ p = nil;
+ }
+ _setvar("path", w, 0);
}
-static
+char*
+list2strcolon(word *words)
+{
+ char *value, *s, *t;
+ int len = 0;
+ word *ap;
+ for(ap = words;ap;ap = ap->next)
+ len+=1+strlen(ap->word);
+ value = emalloc(len+1);
+ s = value;
+ for(ap = words;ap;ap = ap->next){
+ for(t = ap->word;*t;) *s++=*t++;
+ *s++=':';
+ }
+ if(s==value)
+ *s='\0';
+ else s[-1]='\0';
+ return value;
+}
void
-set(char *name, Word *val, int call)
+littlepath(var *v)
{
- Var *v = vlookup(name);
- freelist(v->val);
- v->val = val;
- v->new = 1;
- if (call && v->update)
- v->update(v);
+ /* convert $path to $PATH */
+ char *p;
+ word *w;
+
+ p = list2strcolon(v->val);
+ w = new(word);
+ w->word = p;
+ w->next = nil;
+ _setvar("PATH", w, 1); /* 1: recompute $path to expose colon problems */
}
void
-setvar(char *name, Word *val)
+pathinit(void)
{
- set(name, val, 1);
+ var *v;
+
+ v = gvlook("path");
+ v->changefn = littlepath;
+ v = gvlook("PATH");
+ v->changefn = bigpath;
+ bigpath(v);
}
diff --git a/sys/cmd/rc/word.c b/sys/cmd/rc/word.c
deleted file mode 100644
index 84ff40c..0000000
--- a/sys/cmd/rc/word.c
+++ /dev/null
@@ -1,64 +0,0 @@
-#include "rc.h"
-
-void
-pushlist(void)
-{
- List *ls;
-
- alloc(ls);
- ls->words = nil;
- ls->link = shell->stack, shell->stack = ls;
-}
-
-void
-freelist(Word *w)
-{
- Word *it;
- while (w) {
- it = w->link;
- efree(w->word);
- efree(w);
- w = it;
- }
-}
-
-void
-poplist(void)
-{
- List *ls = shell->stack;
- if (!ls)
- panicf("shell stack underflow");
-
- freelist(ls->words);
- shell->stack = ls->link;
- efree(ls);
-}
-
-int
-count(Word *w)
-{
- int n;
- for (n=0; w; n++)
- w = w->link;
- return n;
-}
-
-Word*
-newword(char *w, Word *link)
-{
- Word *wd;
-
- alloc(wd);
- wd->word = strdup(w);
- wd->link = link;
-
- return wd;
-}
-
-void
-pushword(char *w)
-{
- if (shell->stack == nil)
- panicf("no active stack");
- shell->stack->words = newword(w, shell->stack->words);
-}
diff --git a/sys/cmd/rules.mk b/sys/cmd/rules.mk
index 250b1ac..2302c49 100644
--- a/sys/cmd/rules.mk
+++ b/sys/cmd/rules.mk
@@ -2,6 +2,9 @@ include share/push.mk
# Iterate through subdirectory tree
+DIR := $(d)/rc
+include $(DIR)/rules.mk
+
# DIR := $(d)/cc
# include $(DIR)/rules.mk
diff --git a/vendor/sync b/vendor/sync
index 2a49a2b..6797185 100755
--- a/vendor/sync
+++ b/vendor/sync
@@ -183,93 +183,48 @@ build_wlroots()
}
# ------------------------------------------------------------------------
-# harfbuzz
+# readline
-HARFBUZZ_URL="https://github.com/harfbuzz/harfbuzz.git"
-HARFBUZZ_TAG="3.0.0"
+READLINE_URL="https://git.savannah.gnu.org/git/readline.git"
+READLINE_TAG="readline-8.1-rc3"
-build_harfbuzz()
+build_readline()
{
- git clone $HARFBUZZ_URL
- cd harfbuzz && git checkout $HARFBUZZ_TAG
- meson \
- --prefix=$ROOT \
- --includedir=include/vendor \
- --libdir=lib/vendor \
- --buildtype=minsize \
- -Ddefault_library=static\
- -Dglib=disabled \
- -Dgobject=disabled \
- -Ddocs=disabled \
- -Db_lto="true"\
- build/ \
- && ninja -C build/ \
- && meson install -C build
-
- mv $ROOT/lib/vendor/pkgconfig/* $ROOT/lib/pkgconfig
- rm -rf $ROOT/lib/vendor/pkgconfig
-
- cd $VENDOR
- echo $HARFBUZZ_TAG > harfbuzz/build.tag
-}
-
-# ------------------------------------------------------------------------
-# freetype2
-
-FREETYPE_URL="git clone https://gitlab.freedesktop.org/freetype/freetype.git"
-FREETYPE_TAG="3.0.0"
-
-build_harfbuzz()
-{
- git clone $HARFBUZZ_URL
- cd harfbuzz && git checkout $HARFBUZZ_TAG
- meson \
+ git clone $READLINE_URL readline
+ cd readline && git checkout $READLINE_TAG
+ ./configure \
--prefix=$ROOT \
- --includedir=include/vendor \
- --libdir=lib/vendor \
- --buildtype=minsize \
- -Ddefault_library=static\
- -Dglib=disabled \
- -Dgobject=disabled \
- -Ddocs=disabled \
- -Db_lto="true"\
- build/ \
- && ninja -C build/ \
- && meson install -C build
-
- mv $ROOT/lib/vendor/pkgconfig/* $ROOT/lib/pkgconfig
- rm -rf $ROOT/lib/vendor/pkgconfig
+ --includedir=$ROOT/include/vendor \
+ --disable-shared
+ make && make install
cd $VENDOR
- echo $HARFBUZZ_TAG > harfbuzz/build.tag
+ echo $READLINE_TAG > readline/build.tag
}
# ------------------------------------------------------------------------
-# fontconfig
+# ncurses
-FONTCONFIG_URL="https://github.com/freedesktop/fontconfig.git"
-FONTCONFIG_TAG="2.3.94"
+NCURSES_URL="https://github.com/mirror/ncurses.git"
+NCURSES_TAG="v6.2"
-build_fontconfig()
+build_ncurses()
{
- git clone $FONTCONFIG_URL
- cd fontconfig && git checkout $FONTCONFIG_TAG
- meson \
+ git clone $NCURSES_URL ncurses
+ cd ncurses && git checkout $NCURSES_TAG
+ ./configure \
--prefix=$ROOT \
- --includedir=include/vendor \
- --libdir=lib/vendor \
- -Ddefault_library=static \
- -Dtools=disabled \
- -Dtests=disabled \
- build/ \
- && ninja -C build/ \
- && meson install -C build
-
- mv $ROOT/lib/vendor/pkgconfig/* $ROOT/lib/pkgconfig
- rm -rf $ROOT/lib/vendor/pkgconfig
+ --includedir=$ROOT/include/vendor \
+ --with-normal \
+ --disable-shared \
+ --without-cxx \
+ --without-cxx-binding \
+ --without-manpages \
+ --enable-widec
+ make && make install.libs && make install.includes
cd $VENDOR
- echo $FONTCONFIG_TAG > fontconfig/build.tag
+ echo $NCURSES_TAG > ncurses/build.tag
}
# ------------------------------------------------------------------------
@@ -294,7 +249,7 @@ update nlopt $NLOPT_TAG
update musl $MUSL_TAG
update blas $BLAS_TAG
update zlib $ZLIB_TAG
+
update wlroots $WLROOTS_TAG
-update fontconfig $FONTCONFIG_TAG
-# update harfbuzz $HARFBUZZ_TAG
-# update glfw $GLFW_TAG
+update ncurses $NCURSES_TAG
+update readline $READLINE_TAG