aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNicholas Noll <nbnoll@eml.cc>2020-06-20 11:30:56 -0700
committerNicholas Noll <nbnoll@eml.cc>2020-06-20 11:30:56 -0700
commit955516759cfed29122439938632964fed4f8a347 (patch)
tree6cc0c6300e2b3d5b4e0c08103ecd9c9e939bc1c8
parent91c673b37782d4cd90e5cf9a8e4491723e6c04bf (diff)
feat: file globbing in shell. added dynamic.mk
-rw-r--r--include/libn.h2
-rw-r--r--share/dynamic.mk11
-rw-r--r--sys/cmd/rc/code.c165
-rw-r--r--sys/cmd/rc/exec.c120
-rw-r--r--sys/cmd/rc/glob.c198
-rw-r--r--sys/cmd/rc/io.c21
-rw-r--r--sys/cmd/rc/lex.c8
-rw-r--r--sys/cmd/rc/parse.c2
-rw-r--r--sys/cmd/rc/rc.h75
-rw-r--r--sys/cmd/rc/rules.mk15
-rw-r--r--sys/cmd/rc/var.c29
-rw-r--r--sys/cmd/rc/word.c6
-rw-r--r--sys/cmd/walk/walk.c4
-rw-r--r--sys/libn/fs.c12
14 files changed, 536 insertions, 132 deletions
diff --git a/include/libn.h b/include/libn.h
index 81ddc9f..19fb43c 100644
--- a/include/libn.h
+++ b/include/libn.h
@@ -321,7 +321,7 @@ struct fs·Walker
fs·History *hist;
struct {
void *data;
- void (*func)(void *data, char *relp, char *absp, io·Stat* info);
+ int (*func)(void *data, char *relp, char *absp, io·Stat* info);
};
char *base, *end, path[4096];
};
diff --git a/share/dynamic.mk b/share/dynamic.mk
new file mode 100644
index 0000000..3628cd4
--- /dev/null
+++ b/share/dynamic.mk
@@ -0,0 +1,11 @@
+$(BINS_$(d)): STATIC =
+$(BINS_$(d)): CINIT =
+$(BINS_$(d)): CFINI =
+$(BINS_$(d)): ELIBS =
+$(BINS_$(d)): INCS = -I $(INC_DIR)
+
+$(UNTS_$(d)): STATIC =
+$(UNTS_$(d)): CINIT =
+$(UNTS_$(d)): CFINI =
+$(UNTS_$(d)): ELIBS =
+$(UNTS_$(d)): INCS = -I $(INC_DIR)
diff --git a/sys/cmd/rc/code.c b/sys/cmd/rc/code.c
index 9aa1037..edf47cf 100644
--- a/sys/cmd/rc/code.c
+++ b/sys/cmd/rc/code.c
@@ -5,9 +5,9 @@
#define c1 t->child[1]
#define c2 t->child[2]
-#define emitf(x) ((code.ip!=code.end || morecode()), code.ip++->f = (x))
-#define emiti(x) ((code.ip!=code.end || morecode()), code.ip++->i = (x))
-#define emits(x) ((code.ip!=code.end || morecode()), code.ip++->s = (x))
+#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)
static struct
{
@@ -53,15 +53,15 @@ rcc(Tree *t, int eflag)
default:
pfmt(errio, "bad type %d in rc compiler\n", t->type);
break;
- case '$':
+ case Tdol:
emitf(Xmark);
rcc(c0, eflag);
emitf(Xdol);
break;
- case '"':
+ case Tquote:
emitf(Xmark);
rcc(c0, eflag);
- emitf(Xqdol);
+ emitf(Xflatten);
break;
case Tsub:
emitf(Xmark);
@@ -70,36 +70,30 @@ rcc(Tree *t, int eflag)
rcc(c1, eflag);
emitf(Xsub);
break;
- case '&':
+ case Tand:
emitf(Xasync);
- if(havefork){
- p = emiti(0);
- rcc(c0, eflag);
- emitf(Xexit);
- stuffdot(p);
- } else
- emits(fnstr(c0));
+ p = emiti(0);
+ rcc(c0, eflag);
+ emitf(Xexit);
+ stuffdot(p);
break;
- case ';':
+ case Tsemi:
rcc(c0, eflag);
rcc(c1, eflag);
break;
- case '^':
+ case Tcarot:
emitf(Xmark);
rcc(c1, eflag);
emitf(Xmark);
rcc(c0, eflag);
- emitf(Xconc);
+ emitf(Xcat);
break;
- case '`':
- emitf(Xbackq);
- if(havefork){
- p = emiti(0);
- rcc(c0, 0);
- emitf(Xexit);
- stuffdot(p);
- } else
- emits(fnstr(c0));
+ case Ttick:
+ emitf(Xcmdsub);
+ p = emiti(0);
+ rcc(c0, 0);
+ emitf(Xexit);
+ stuffdot(p);
break;
case Tandand:
rcc(c0, 0);
@@ -114,7 +108,7 @@ rcc(Tree *t, int eflag)
break;
case Tbang:
rcc(c0, eflag);
- emitf(Xbang);
+ emitf(Xnegate);
break;
case Tparen:
case Tbrace:
@@ -129,33 +123,32 @@ rcc(Tree *t, int eflag)
emitf(Xmark);
rcc(c0, eflag);
if(c1){
- emitf(Xfn);
+ emitf(Xfunc);
p = emiti(0);
emits(fnstr(c1));
rcc(c1, eflag);
emitf(Xunlocal); /* get rid of $* */
- emitf(Xreturn);
+ emitf(Xkill);
stuffdot(p);
- }
- else
- emitf(Xdelfn);
+ } else
+ emitf(Xunfunc);
break;
case Tif:
rcc(c0, 0);
emitf(Xif);
p = emiti(0);
rcc(c1, eflag);
- emitf(Xwastrue);
- stuffdot(p);
- break;
- case Telse:
- if(!runq->iflast)
- error("`else' does not follow `if(...)'");
- emitf(Xelse);
- p = emiti(0);
- rcc(c0, 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);
emitf(Xfalse);
@@ -163,7 +156,7 @@ rcc(Tree *t, int eflag)
rcc(c1, eflag);
stuffdot(p);
break;
- case Tparen:
+ case Tpcmd:
rcc(c0, eflag);
break;
case Tsimple:
@@ -175,13 +168,10 @@ rcc(Tree *t, int eflag)
break;
case Tsubshell:
emitf(Xsubshell);
- if(havefork){
- p = emiti(0);
- rcc(c0, eflag);
- emitf(Xexit);
- stuffdot(p);
- } else
- emits(fnstr(c0));
+ p = emiti(0);
+ rcc(c0, eflag);
+ emitf(Xexit);
+ stuffdot(p);
if(eflag)
emitf(Xeflag);
break;
@@ -197,7 +187,7 @@ rcc(Tree *t, int eflag)
if(eflag)
emitf(Xeflag);
break;
- case Kwhile:
+ case Twhile:
q = code.ip;
rcc(c0, 0);
if(q==code.ip)
@@ -206,7 +196,7 @@ rcc(Tree *t, int eflag)
p = emiti(0);
rcc(c1, eflag);
emitf(Xjump);
- emiti(q);
+ emiti(q-code.buf);
stuffdot(p);
break;
case Twords:
@@ -218,8 +208,7 @@ rcc(Tree *t, int eflag)
if(c1){
rcc(c1, eflag);
emitf(Xglob);
- }
- else{
+ } else{
emitf(Xmark);
emitf(Xword);
emits(strdup("*"));
@@ -242,35 +231,30 @@ rcc(Tree *t, int eflag)
emits(strdup(t->str));
break;
case Tdup:
- if(t->rtype==Tdupfd){
+ if(t->redir.type == Rdupfd){
emitf(Xdup);
- emiti(t->fd0);
- emiti(t->fd1);
- }
- else{
+ emiti(t->redir.fd[0]);
+ emiti(t->redir.fd[1]);
+ } else{
emitf(Xclose);
- emiti(t->fd0);
+ emiti(t->redir.fd[0]);
}
rcc(c1, eflag);
emitf(Xpopredir);
break;
case Tpipefd:
emitf(Xpipefd);
- emiti(t->rtype);
- if(havefork){
- p = emiti(0);
- rcc(c0, eflag);
- emitf(Xexit);
- stuffdot(p);
- } else {
- emits(fnstr(c0));
- }
+ emiti(t->redir.type);
+ p = emiti(0);
+ rcc(c0, eflag);
+ emitf(Xexit);
+ stuffdot(p);
break;
case Tredir:
emitf(Xmark);
rcc(c0, eflag);
emitf(Xglob);
- switch(t->rtype){
+ switch(t->redir.type){
case Rappend:
emitf(Xappend);
break;
@@ -285,15 +269,15 @@ rcc(Tree *t, int eflag)
emitf(Xrdwr);
break;
}
- emiti(t->fd0);
+ emiti(t->redir.fd[0]);
rcc(c1, eflag);
emitf(Xpopredir);
break;
- case '=':
+ case Teq:
tt = t;
- for(;t && t->type=='=';t = c2);
+ for(;t && t->type==Teq;t = c2);
if(t){
- for(t = tt;t->type=='=';t = c2){
+ for(t = tt;t->type==Teq;t = c2){
emitf(Xmark);
rcc(c1, eflag);
emitf(Xmark);
@@ -301,10 +285,9 @@ rcc(Tree *t, int eflag)
emitf(Xlocal);
}
rcc(t, eflag);
- for(t = tt; t->type=='='; t = c2)
+ for(t = tt; t->type==Teq; t = c2)
emitf(Xunlocal);
- }
- else{
+ } else{
for(t = tt;t;t = c2){
emitf(Xmark);
rcc(c1, eflag);
@@ -317,27 +300,23 @@ rcc(Tree *t, int eflag)
break;
case Tpipe:
emitf(Xpipe);
- emiti(t->fd0);
- emiti(t->fd1);
- if(havefork){
- p = emiti(0);
- q = emiti(0);
- rcc(c0, eflag);
- emitf(Xexit);
- stuffdot(p);
- } else {
- emits(fnstr(c0));
- q = emiti(0);
- }
+ 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(Xreturn);
+ emitf(Xkill);
stuffdot(q);
emitf(Xpipewait);
break;
}
- if(t->type!=Telse && t->type!=';')
- runq->iflast = t->type==IF;
- else if(c0) runq->iflast = c0->type==IF;
+ if(t->type!=Telse && t->type!=Tsemi)
+ shell->iflast = t->type==Tif;
+ else if (c0)
+ shell->iflast = c0->type==Tif;
}
Code*
@@ -349,7 +328,7 @@ compile(Tree *t)
emiti(0);
rcc(t, 0);
- emitf(Xreturn);
+ emitf(Xkill);
emitf(nil);
return code.buf;
diff --git a/sys/cmd/rc/exec.c b/sys/cmd/rc/exec.c
index 2879678..d4822a7 100644
--- a/sys/cmd/rc/exec.c
+++ b/sys/cmd/rc/exec.c
@@ -1,9 +1,93 @@
#include "rc.h"
+#define W0 shell->stack->words
+// -----------------------------------------------------------------------
+// helper functions
+
+static
+void
+setstatus(char *s)
+{
+ setvar("status", newword(s, nil));
+}
+
+static
+void
+pushredir(int type, int from, int to)
+{
+ Redir *r;
+
+ alloc(r);
+ r->type = type;
+ r->from = from;
+ r->to = to;
+ r->link = shell->redir, shell->redir = r;
+}
+
+// -----------------------------------------------------------------------
+// interpreter functions
+
void
Xerror(char *s)
{
+ 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);
+ setstatus("error");
+ while(!shell->interactive)
+ Xkill();
+}
+
+void
+Xappend(void)
+{
+ int fd;
+ char *path;
+
+ switch(count(W0)) {
+ default:
+ Xerror(">> requires a singleton list");
+ return;
+ case 0:
+ Xerror(">> requires one file");
+ return;
+ case 1:
+ ;
+ }
+
+ 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
+Xassign(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);
+
+ v->val = W0;
+ if(v->update)
+ v->update(v);
+ W0 = nil;
+ poplist();
}
void
@@ -17,3 +101,39 @@ 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);
diff --git a/sys/cmd/rc/glob.c b/sys/cmd/rc/glob.c
new file mode 100644
index 0000000..8a9c940
--- /dev/null
+++ b/sys/cmd/rc/glob.c
@@ -0,0 +1,198 @@
+#include "rc.h"
+#include <dirent.h>
+
+Io *errio;
+static Word *matches;
+static char buffer[6*1024];
+
+// -----------------------------------------------------------------------
+// main exports
+
+void
+unglob(char *s)
+{
+ 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)
+{
+ 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;
+}
+
+static
+void
+globdir(char *p, char *path, int fd)
+{
+ 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;
+ }
+ }
+
+ /* 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;
+ }
+
+ /* we have a non-trivial pattern to match */
+ /* partition on the next directory */
+ while(*g && *g!='/')
+ g++;
+
+ if(*g){
+ j = 1;
+ *g = 0;
+ } else
+ j = 0;
+
+ 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;
+
+ for(i=0;e->d_name[i];i++)
+ b[i]=e->d_name[i];
+ b[i]=0;
+
+ if(match(path, p))
+ globdir(g+j, b, fd);
+ }
+
+ printf("successful\n");
+cleanup:
+ printf("cleaning up\n");
+ /* NOTE: a successful closedir also closes the file descriptor */
+ closedir(d);
+ return;
+}
+
+void
+glob(char *p)
+{
+ char *path = buffer;
+
+ globdir(p, path, AT_FDCWD);
+}
+
+int
+main()
+{
+ errio = openfd(2);
+ glob("\x01*");
+ pval(errio, matches);
+ flush(&errio);
+}
diff --git a/sys/cmd/rc/io.c b/sys/cmd/rc/io.c
index 2fbe57f..e06bfcc 100644
--- a/sys/cmd/rc/io.c
+++ b/sys/cmd/rc/io.c
@@ -94,8 +94,8 @@ flush(Io **fp)
n = f->b - f->buf;
if (n && write(f->fd, f->buf, n) < 0) {
write(3, "write error\n", 12);
- if (ntrap)
- dotrap();
+ // if (ntrap)
+ // dotrap();
}
f->b = f->buf;
f->e = f->buf + bufsize;
@@ -153,10 +153,10 @@ void
pwrd(Io *f, char *s)
{
char *t;
- for (t = s; *t; t++)
- if (!wordchr(*t))
+ for(t = s; *t; t++)
+ if(!wordchr(*t))
break;
- if (t == s || *t)
+ if(t == s || *t)
pquo(f, s);
else
pstr(f, s);
@@ -186,10 +186,10 @@ pptr(Io *f, void *v)
void
pstr(Io *f, char *s)
{
- if (!s)
+ if(!s || !s[0])
s = "<null>";
- while (*s)
+ while(*s)
pchr(f, *s++);
}
@@ -228,8 +228,8 @@ poct(Io *f, uint n)
void
pval(Io *f, Word *a)
{
- if (a) {
- while (a->link && a->link->word) {
+ if(a) {
+ while(a->link && a->link->word) {
pwrd(f, a->word);
pchr(f, ' ');
a = a->link;
@@ -416,6 +416,9 @@ vpfmt(Io *f, char *fmt, va_list args)
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;
diff --git a/sys/cmd/rc/lex.c b/sys/cmd/rc/lex.c
index 8b4cdec..f6e2b4e 100644
--- a/sys/cmd/rc/lex.c
+++ b/sys/cmd/rc/lex.c
@@ -1,9 +1,9 @@
#include "rc.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)
+#define onebyte(c) ((c&0x80)==0x00)
+#define twobyte(c) ((c&0xe0)==0xc0)
+#define threebyte(c) ((c&0xf0)==0xe0)
+#define fourbyte(c) ((c&0xf8)==0xf0)
// -----------------------------------------------------------------------
// globals
diff --git a/sys/cmd/rc/parse.c b/sys/cmd/rc/parse.c
index c5c77d3..b61ac3c 100644
--- a/sys/cmd/rc/parse.c
+++ b/sys/cmd/rc/parse.c
@@ -1,5 +1,7 @@
#include "rc.h"
+/* TODO: better error messages */
+
// -----------------------------------------------------------------------
// global data
diff --git a/sys/cmd/rc/rc.h b/sys/cmd/rc/rc.h
index 7146aa0..f32a737 100644
--- a/sys/cmd/rc/rc.h
+++ b/sys/cmd/rc/rc.h
@@ -43,6 +43,13 @@ enum
Rrdwr = 7,
};
+enum
+{
+ Fopen = 1,
+ Fdup = 2,
+ Fclose = 3,
+};
+
// -----------------------------------------------------------------------
// main types
@@ -50,6 +57,7 @@ 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;
@@ -74,12 +82,26 @@ struct List
List *link;
};
+struct Redir
+{
+ uchar type;
+ short from, to;
+ Redir *link;
+};
+
struct Var
{
- string name;
+ string name;
Word *val;
- Code *func;
- Var *link;
+ struct {
+ Code *func, *ip;
+ uint funcnew : 1;
+ };
+ struct {
+ uint new : 1;
+ void (*update)(Var*);
+ };
+ Var *link;
};
struct Tree
@@ -107,7 +129,9 @@ struct Thread
{
Code *code, *ip;
List *stack;
+ Redir *redir, *root;
Var *local;
+ uchar interactive : 1;
struct {
uchar eof : 1;
int line;
@@ -145,16 +169,48 @@ extern Var *globals[1021]; /* for now must be prime */
* notation:
* (var1, var2, ...) : items from stack
* [var1, var2, ...] : items from code stream
- * -> moves value
+ * {var1, var2, ...} : jump block from code stream
+ * -> moves value (stack) [code stream]
*/
-extern void Xmark(void); /* Xmark: delimit stack with new list */
-extern void Xword(void); /* Xword[val] -> (val) */
+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 Xsimple(void); /* Xsimple(args): run command */
+extern void Xdup(void); /* Xdup[i, j]: duplicate file descriptor */
extern void Xexit(void); /* Xexit: exit with status */
-extern void Xerror(char *s); /* Xerror: report an error */
-extern void Xparse(void);
+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
@@ -228,6 +284,7 @@ Tree *wordnode(char *w);
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);
diff --git a/sys/cmd/rc/rules.mk b/sys/cmd/rc/rules.mk
index 33d6ba8..4f47886 100644
--- a/sys/cmd/rc/rules.mk
+++ b/sys/cmd/rc/rules.mk
@@ -2,14 +2,15 @@ include share/push.mk
# Local sources
SRCS_$(d) := \
- $(d)/io.c \
- $(d)/util.c \
- $(d)/var.c \
+ $(d)/glob.c \
$(d)/word.c \
- $(d)/tree.c \
- $(d)/lex.c \
- $(d)/parse.c \
- $(d)/main.c
+ $(d)/util.c \
+ $(d)/io.c
+ # $(d)/var.c \
+ # $(d)/tree.c \
+ # $(d)/lex.c \
+ # $(d)/parse.c \
+ # $(d)/main.c
BINS_$(d) := $(d)/rc
include share/paths.mk
diff --git a/sys/cmd/rc/var.c b/sys/cmd/rc/var.c
index ef339d7..d442369 100644
--- a/sys/cmd/rc/var.c
+++ b/sys/cmd/rc/var.c
@@ -73,10 +73,13 @@ newvar(char *name, Var *link)
Var *v;
alloc(v);
- v->name = name;
- v->val = 0;
- v->func = nil;
- v->link = link;
+ v->name = name;
+ v->val = 0;
+ v->func = nil;
+ v->funcnew = 0;
+ v->new = 0;
+ v->update = nil;
+ v->link = link;
return v;
}
@@ -106,3 +109,21 @@ vlookup(char *name)
return v;
return gvlookup(name);
}
+
+static
+void
+set(char *name, Word *val, int call)
+{
+ Var *v = vlookup(name);
+ freelist(v->val);
+ v->val = val;
+ v->new = 1;
+ if (call && v->update)
+ v->update(v);
+}
+
+void
+setvar(char *name, Word *val)
+{
+ set(name, val, 1);
+}
diff --git a/sys/cmd/rc/word.c b/sys/cmd/rc/word.c
index 84ff40c..56a6756 100644
--- a/sys/cmd/rc/word.c
+++ b/sys/cmd/rc/word.c
@@ -1,5 +1,6 @@
#include "rc.h"
+#if 0
void
pushlist(void)
{
@@ -9,6 +10,7 @@ pushlist(void)
ls->words = nil;
ls->link = shell->stack, shell->stack = ls;
}
+#endif
void
freelist(Word *w)
@@ -22,6 +24,7 @@ freelist(Word *w)
}
}
+#if 0
void
poplist(void)
{
@@ -33,6 +36,7 @@ poplist(void)
shell->stack = ls->link;
efree(ls);
}
+#endif
int
count(Word *w)
@@ -55,6 +59,7 @@ newword(char *w, Word *link)
return wd;
}
+#if 0
void
pushword(char *w)
{
@@ -62,3 +67,4 @@ pushword(char *w)
panicf("no active stack");
shell->stack->words = newword(w, shell->stack->words);
}
+#endif
diff --git a/sys/cmd/walk/walk.c b/sys/cmd/walk/walk.c
index 12f6c55..853369c 100644
--- a/sys/cmd/walk/walk.c
+++ b/sys/cmd/walk/walk.c
@@ -13,7 +13,7 @@ flush(void)
}
static
-void
+int
print(void *data, char *rel, char *abs, io·Stat *info)
{
copy:
@@ -25,6 +25,8 @@ copy:
goto copy;
}
*c++ = '\n';
+
+ return 0;
}
static
diff --git a/sys/libn/fs.c b/sys/libn/fs.c
index 5d06997..10cd93e 100644
--- a/sys/libn/fs.c
+++ b/sys/libn/fs.c
@@ -6,7 +6,6 @@
/*
* path history
*/
-
struct Key
{
ino_t ino;
@@ -151,9 +150,14 @@ fs·walk(fs·Walker *fs)
return;
}
- /* operate on directory if preorder traversal */
- if (fs->flags & fs·preorder)
- fs->func(fs->data, fs->base, fs->path, &cwd);
+ /*
+ * operate on directory first if preorder traversal
+ * truncate recursion if callback returns an error code
+ */
+ if (fs->flags & fs·preorder) {
+ if (fs->func(fs->data, fs->base, fs->path, &cwd))
+ return;
+ }
/* open directory */
if(!fs->max || fs->lev + 1 < fs->max) {