summaryrefslogtreecommitdiff
path: root/appl/alphabet/main
diff options
context:
space:
mode:
authorCharles.Forsyth <devnull@localhost>2006-12-22 17:07:39 +0000
committerCharles.Forsyth <devnull@localhost>2006-12-22 17:07:39 +0000
commit37da2899f40661e3e9631e497da8dc59b971cbd0 (patch)
treecbc6d4680e347d906f5fa7fca73214418741df72 /appl/alphabet/main
parent54bc8ff236ac10b3eaa928fd6bcfc0cdb2ba46ae (diff)
20060303a
Diffstat (limited to 'appl/alphabet/main')
-rw-r--r--appl/alphabet/main/auth.b157
-rw-r--r--appl/alphabet/main/cat.b78
-rw-r--r--appl/alphabet/main/create.b55
-rw-r--r--appl/alphabet/main/dial.b85
-rw-r--r--appl/alphabet/main/echo.b51
-rw-r--r--appl/alphabet/main/export.b52
-rw-r--r--appl/alphabet/main/fd.b83
-rw-r--r--appl/alphabet/main/filter.b114
-rw-r--r--appl/alphabet/main/genfilter.b79
-rw-r--r--appl/alphabet/main/mkfile36
-rw-r--r--appl/alphabet/main/mount.b80
-rw-r--r--appl/alphabet/main/par.b50
-rw-r--r--appl/alphabet/main/parse.b43
-rw-r--r--appl/alphabet/main/pretty.b116
-rw-r--r--appl/alphabet/main/print.b55
-rw-r--r--appl/alphabet/main/read.b56
-rw-r--r--appl/alphabet/main/readall.b46
-rw-r--r--appl/alphabet/main/rewrite.b97
-rw-r--r--appl/alphabet/main/rw.b50
-rw-r--r--appl/alphabet/main/seq.b66
-rw-r--r--appl/alphabet/main/unparse.b38
-rw-r--r--appl/alphabet/main/w2fd.b61
-rw-r--r--appl/alphabet/main/wait.b35
23 files changed, 1583 insertions, 0 deletions
diff --git a/appl/alphabet/main/auth.b b/appl/alphabet/main/auth.b
new file mode 100644
index 00000000..d05ecb46
--- /dev/null
+++ b/appl/alphabet/main/auth.b
@@ -0,0 +1,157 @@
+implement Authenticate, Mainmodule;
+include "sys.m";
+ sys: Sys;
+include "draw.m";
+include "sh.m";
+include "keyring.m";
+ keyring: Keyring;
+include "security.m";
+ auth: Auth;
+include "alphabet/reports.m";
+ reports: Reports;
+ Report, report: import reports;
+include "alphabet.m";
+ alphabet: Alphabet;
+ Value: import alphabet;
+
+Authenticate: module {};
+
+typesig(): string
+{
+ return "ww-ks-Cs-v";
+}
+
+init()
+{
+ sys = load Sys Sys->PATH;
+ alphabet = load Alphabet Alphabet->PATH;
+ reports = load Reports Reports->PATH;
+ keyring = load Keyring Keyring->PATH;
+ auth = load Auth Auth->PATH;
+ auth->init();
+}
+
+quit()
+{
+}
+
+After, Before, Create: con 1<<iota;
+
+run(nil: ref Draw->Context, r: ref Reports->Report, errorc: chan of string,
+ opts: list of (int, list of ref Alphabet->Value),
+ args: list of ref Alphabet->Value): ref Alphabet->Value
+{
+ keyfile: string;
+ alg: string;
+ verbose: int;
+ for(; opts != nil; opts = tl opts){
+ case (hd opts).t0 {
+ 'k' =>
+ keyfile = (hd (hd opts).t1).s().i;
+ if (keyfile != nil && ! (keyfile[0] == '/' || (len keyfile > 2 && keyfile[0:2] == "./")))
+ keyfile = "/usr/" + user() + "/keyring/" + keyfile;
+ 'C' =>
+ alg = (hd (hd opts).t1).s().i;
+ 'v' =>
+ verbose = 1;
+ }
+ }
+ if(keyfile == nil)
+ keyfile = "/usr/" + user() + "/keyring/default";
+ cert := keyring->readauthinfo(keyfile);
+ if (cert == nil) {
+ report(errorc, sys->sprint("auth: cannot read %q: %r", keyfile));
+ return nil;
+ }
+ w := chan of ref Sys->FD;
+ spawn authproc((hd args).w().i, w, cert, verbose, alg, r.start("auth"));
+ return ref Value.Vw(w);
+}
+
+authproc(f0, f1: chan of ref Sys->FD, cert: ref Keyring->Authinfo,
+ verbose: int, alg: string, errorc: chan of string)
+{
+ fd0 := <-f0;
+ if(fd0 == nil){
+ sys->pipe(p := array[2] of ref Sys->FD);
+ f0 <-= p[1];
+ fd0 = p[0];
+ }else
+ f0 <-= nil;
+
+ eu: string;
+ (fd0, eu) = auth->client(alg, cert, fd0);
+ if(fd0 == nil){
+ report(errorc, "authentication failed: "+eu);
+ f1 <-= nil;
+ <-f1;
+ reports->quit(errorc);
+ }
+ if(verbose)
+ report(errorc, sys->sprint("remote user %q", eu));
+ f1 <-= fd0;
+ fd1 := <-f1;
+ if(fd1 == nil)
+ reports->quit(errorc);
+ wstream(fd0, fd1, errorc);
+ reports->quit(errorc);
+}
+
+wstream(fd0, fd1: ref Sys->FD, errorc: chan of string)
+{
+ sync := chan[2] of int;
+ qc := chan of int;
+ spawn stream(fd0, fd1, sync, qc, errorc);
+ spawn stream(fd1, fd0, sync, qc, errorc);
+ <-qc;
+ kill(<-sync);
+ kill(<-sync);
+}
+
+stream(fd0, fd1: ref Sys->FD, sync, qc: chan of int, errorc: chan of string)
+{
+ sync <-= sys->pctl(0, nil);
+ buf := array[Sys->ATOMICIO] of byte;
+ while((n := sys->read(fd0, buf, len buf)) > 0){
+ if(sys->write(fd1, buf, n) == -1){
+ report(errorc, sys->sprint("write error: %r"));
+ break;
+ }
+ }
+ qc <-= 1;
+ exit;
+}
+
+kill(pid: int)
+{
+ sys->fprint(sys->open("#p/"+string pid+"/ctl", Sys->OWRITE), "kill");
+}
+
+
+exists(f: string): int
+{
+ (ok, nil) := sys->stat(f);
+ return ok != -1;
+}
+
+user(): string
+{
+ u := readfile("/dev/user");
+ if (u == nil)
+ return "nobody";
+ return u;
+}
+
+readfile(f: string): string
+{
+ fd := sys->open(f, sys->OREAD);
+ if(fd == nil)
+ return nil;
+
+ buf := array[128] of byte;
+ n := sys->read(fd, buf, len buf);
+ if(n < 0)
+ return nil;
+
+ return string buf[0:n];
+}
diff --git a/appl/alphabet/main/cat.b b/appl/alphabet/main/cat.b
new file mode 100644
index 00000000..b19b1fd9
--- /dev/null
+++ b/appl/alphabet/main/cat.b
@@ -0,0 +1,78 @@
+implement Mainmodule;
+include "sys.m";
+ sys: Sys;
+include "draw.m";
+include "sh.m";
+include "alphabet/reports.m";
+ reports: Reports;
+ Report, report: import reports;
+include "alphabet.m";
+ alphabet: Alphabet;
+ Value: import alphabet;
+
+typesig(): string
+{
+ return "ff*";
+}
+
+init()
+{
+ sys = load Sys Sys->PATH;
+ alphabet = load Alphabet Alphabet->PATH;
+ reports = load Reports Reports->PATH;
+}
+
+quit()
+{
+}
+
+run(nil: ref Draw->Context, r: ref Reports->Report, nil: chan of string,
+ nil: list of (int, list of ref Alphabet->Value),
+ args: list of ref Alphabet->Value): ref Alphabet->Value
+{
+ fds: list of chan of ref Sys->FD;
+ for(; args != nil; args = tl args)
+ fds = (hd args).f().i :: fds;
+ f := chan of ref Sys->FD;
+ spawn catproc(f, rev(fds), r.start("print"));
+ return ref Value.Vf(f);
+}
+
+catproc(f: chan of ref Sys->FD, fds: list of chan of ref Sys->FD, reportc: chan of string)
+{
+ f <-= nil;
+ if((fd1 := <-f) == nil){
+ for(; fds != nil; fds = tl fds){
+ <-hd fds;
+ hd fds <-= nil;
+ }
+ reports->quit(reportc);
+ }
+ buf := array[8192] of byte;
+ for(; fds != nil; fds = tl fds){
+ fd0 := <-hd fds;
+ if(fd0 == nil){
+ p := array[2] of ref Sys->FD;
+ sys->pipe(p);
+ fd0 = p[0];
+ hd fds <-= p[1];
+ }else
+ hd fds <-= nil;
+ while((n := sys->read(fd0, buf, len buf)) > 0){
+ sys->write(fd1, buf, n);
+ }exception{
+ "write on closed pipe" =>
+ ;
+ }
+ }
+ sys->write(fd1, array[0] of byte, 0);
+ reports->quit(reportc);
+}
+
+rev[T](l: list of T): list of T
+{
+ r: list of T;
+ for(; l != nil; l = tl l)
+ r = hd l :: r;
+ return r;
+} \ No newline at end of file
diff --git a/appl/alphabet/main/create.b b/appl/alphabet/main/create.b
new file mode 100644
index 00000000..bb1601dc
--- /dev/null
+++ b/appl/alphabet/main/create.b
@@ -0,0 +1,55 @@
+implement Create,Mainmodule;
+include "sys.m";
+ sys: Sys;
+include "draw.m";
+include "sh.m";
+include "alphabet/reports.m";
+ reports: Reports;
+ Report, report: import reports;
+include "alphabet.m";
+ alphabet: Alphabet;
+ Value: import alphabet;
+
+Create: module {};
+
+typesig(): string
+{
+ return "rfs";
+}
+
+init()
+{
+ sys = load Sys Sys->PATH;
+ alphabet = load Alphabet Alphabet->PATH;
+ reports = load Reports Reports->PATH;
+}
+
+quit()
+{
+}
+
+run(nil: ref Draw->Context, nil: ref Reports->Report, errorc: chan of string,
+ nil: list of (int, list of ref Alphabet->Value),
+ args: list of ref Alphabet->Value): ref Alphabet->Value
+{
+ r := chan of string;
+ fd := sys->create((hd tl args).s().i, Sys->OWRITE, 8r666);
+ if(fd == nil){
+ report(errorc, sys->sprint("error: cannot create %q: %r", (hd tl args).s().i));
+ return nil;
+ }
+ spawn createproc(r, (hd args).f().i, fd);
+ return ref Value.Vr(r);
+}
+
+createproc(r: chan of string, f: chan of ref Sys->FD, fd: ref Sys->FD)
+{
+ if(<-r != nil){
+ <-f;
+ f <-= nil;
+ exit;
+ }
+ <-f;
+ f <-= fd;
+ r <-= nil;
+}
diff --git a/appl/alphabet/main/dial.b b/appl/alphabet/main/dial.b
new file mode 100644
index 00000000..e8521b45
--- /dev/null
+++ b/appl/alphabet/main/dial.b
@@ -0,0 +1,85 @@
+implement Dial,Mainmodule;
+include "sys.m";
+ sys: Sys;
+include "draw.m";
+include "sh.m";
+include "alphabet/reports.m";
+ reports: Reports;
+ Report, report: import reports;
+include "alphabet.m";
+ alphabet: Alphabet;
+ Value: import alphabet;
+
+Dial: module {};
+
+typesig(): string
+{
+ return "ws";
+}
+
+init()
+{
+ sys = load Sys Sys->PATH;
+ alphabet = load Alphabet Alphabet->PATH;
+ reports = load Reports Reports->PATH;
+}
+
+quit()
+{
+}
+
+run(nil: ref Draw->Context, r: ref Reports->Report, errorc: chan of string,
+ nil: list of (int, list of ref Alphabet->Value),
+ args: list of ref Alphabet->Value): ref Alphabet->Value
+{
+ w := chan of ref Sys->FD;
+ addr := (hd args).s().i;
+ (ok, c) := sys->dial(addr, nil);
+ if(ok == -1){
+ report(errorc, sys->sprint("dial: cannot dial %q: %r", addr));
+ return nil;
+ }
+ f := chan of ref Sys->FD;
+ spawn dialproc(f, c.dfd, r.start("dial"));
+ return ref Value.Vw(f);
+}
+
+dialproc(f: chan of ref Sys->FD, fd0: ref Sys->FD, errorc: chan of string)
+{
+ f <-= fd0;
+ fd1 := <-f;
+ if(fd1 == nil)
+ reports->quit(errorc);
+ wstream(fd0, fd1, errorc);
+ reports->quit(errorc);
+}
+
+wstream(fd0, fd1: ref Sys->FD, errorc: chan of string)
+{
+ sync := chan[2] of int;
+ qc := chan of int;
+ spawn stream(fd0, fd1, sync, qc, errorc);
+ spawn stream(fd1, fd0, sync, qc, errorc);
+ <-qc;
+ kill(<-sync);
+ kill(<-sync);
+}
+
+stream(fd0, fd1: ref Sys->FD, sync, qc: chan of int, errorc: chan of string)
+{
+ sync <-= sys->pctl(0, nil);
+ buf := array[Sys->ATOMICIO] of byte;
+ while((n := sys->read(fd0, buf, len buf)) > 0){
+ if(sys->write(fd1, buf, n) == -1){
+ report(errorc, sys->sprint("write error: %r"));
+ break;
+ }
+ }
+ qc <-= 1;
+ exit;
+}
+
+kill(pid: int)
+{
+ sys->fprint(sys->open("#p/"+string pid+"/ctl", Sys->OWRITE), "kill");
+}
diff --git a/appl/alphabet/main/echo.b b/appl/alphabet/main/echo.b
new file mode 100644
index 00000000..3b01c951
--- /dev/null
+++ b/appl/alphabet/main/echo.b
@@ -0,0 +1,51 @@
+implement Echo, Mainmodule;
+include "sys.m";
+ sys: Sys;
+include "draw.m";
+include "sh.m";
+include "alphabet/reports.m";
+ reports: Reports;
+ Report, report: import reports;
+include "alphabet.m";
+ alphabet: Alphabet;
+ Value: import alphabet;
+
+Echo: module {};
+
+typesig(): string
+{
+ return "fs-n";
+}
+
+init()
+{
+ sys = load Sys Sys->PATH;
+ alphabet = load Alphabet Alphabet->PATH;
+ reports = load Reports Reports->PATH;
+}
+
+quit()
+{
+}
+
+run(nil: ref Draw->Context, nil: ref Reports->Report, nil: chan of string,
+ opts: list of (int, list of ref Alphabet->Value),
+ args: list of ref Alphabet->Value): ref Alphabet->Value
+{
+ f := chan of ref Sys->FD;
+ s := (hd args).s().i;
+ if(opts == nil)
+ s[len s] = '\n';
+ spawn echoproc(f, s);
+ return ref Value.Vf(f);
+}
+
+echoproc(f: chan of ref Sys->FD, s: string)
+{
+ f <-= nil;
+ fd := <-f;
+ if(fd == nil)
+ exit;
+ sys->fprint(fd, "%s", s);
+ sys->write(fd, array[0] of byte, 0);
+}
diff --git a/appl/alphabet/main/export.b b/appl/alphabet/main/export.b
new file mode 100644
index 00000000..5e9b986e
--- /dev/null
+++ b/appl/alphabet/main/export.b
@@ -0,0 +1,52 @@
+implement Export,Mainmodule;
+include "sys.m";
+ sys: Sys;
+include "draw.m";
+include "sh.m";
+include "alphabet/reports.m";
+ reports: Reports;
+ Report, report: import reports;
+include "alphabet.m";
+ alphabet: Alphabet;
+ Value: import alphabet;
+
+Export: module {};
+
+typesig(): string
+{
+ return "ws";
+}
+
+init()
+{
+ sys = load Sys Sys->PATH;
+ alphabet = load Alphabet Alphabet->PATH;
+ reports = load Reports Reports->PATH;
+}
+
+quit()
+{
+}
+
+run(nil: ref Draw->Context, r: ref Reports->Report, nil: chan of string,
+ nil: list of (int, list of ref Alphabet->Value),
+ args: list of ref Alphabet->Value): ref Alphabet->Value
+{
+ w := chan of ref Sys->FD;
+ addr := (hd args).s().i;
+ f := chan of ref Sys->FD;
+ spawn exportproc(f, (hd args).s().i, r.start("export"));
+ return ref Value.Vw(f);
+}
+
+exportproc(f: chan of ref Sys->FD, dir: string, errorc: chan of string)
+{
+ f <-= nil;
+ fd := <-f;
+ if(fd == nil)
+ reports->quit(errorc);
+ errorc <-= nil;
+ if(sys->export(fd, dir, Sys->EXPASYNC) == -1)
+ report(errorc, sys->sprint("cannot export: %r"));
+ reports->quit(errorc);
+}
diff --git a/appl/alphabet/main/fd.b b/appl/alphabet/main/fd.b
new file mode 100644
index 00000000..11d10828
--- /dev/null
+++ b/appl/alphabet/main/fd.b
@@ -0,0 +1,83 @@
+implement Fd, Mainmodule;
+include "sys.m";
+ sys: Sys;
+include "draw.m";
+include "sh.m";
+include "alphabet/reports.m";
+ reports: Reports;
+ Report, report: import reports;
+include "alphabet.m";
+ alphabet: Alphabet;
+ Value: import alphabet;
+
+Fd: module {};
+
+typesig(): string
+{
+ return "ws";
+}
+
+init()
+{
+ sys = load Sys Sys->PATH;
+ alphabet = load Alphabet Alphabet->PATH;
+ reports = load Reports Reports->PATH;
+}
+
+quit()
+{
+}
+
+run(nil: ref Draw->Context, r: ref Reports->Report, errorc: chan of string,
+ nil: list of (int, list of ref Alphabet->Value),
+ args: list of ref Alphabet->Value): ref Alphabet->Value
+{
+ fd := sys->fildes(int (hd args).s().i);
+ if(fd == nil){
+ report(errorc, sys->sprint("error: no such file descriptor %q", (hd args).s().i));
+ return nil;
+ }
+ f := chan of ref Sys->FD;
+ spawn readfdproc(f, fd, r.start("stdin"));
+ return ref Value.Vw(f);
+}
+
+readfdproc(f: chan of ref Sys->FD, fd0: ref Sys->FD, errorc: chan of string)
+{
+ f <-= fd0;
+ fd1 := <-f;
+ if(fd1 == nil)
+ reports->quit(errorc);
+ wstream(fd0, fd1, errorc);
+ reports->quit(errorc);
+}
+
+wstream(fd0, fd1: ref Sys->FD, errorc: chan of string)
+{
+ sync := chan[2] of int;
+ qc := chan of int;
+ spawn stream(fd0, fd1, sync, qc, errorc);
+ spawn stream(fd1, fd0, sync, qc, errorc);
+ <-qc;
+ kill(<-sync);
+ kill(<-sync);
+}
+
+stream(fd0, fd1: ref Sys->FD, sync, qc: chan of int, errorc: chan of string)
+{
+ sync <-= sys->pctl(0, nil);
+ buf := array[Sys->ATOMICIO] of byte;
+ while((n := sys->read(fd0, buf, len buf)) > 0){
+ if(sys->write(fd1, buf, n) == -1){
+ report(errorc, sys->sprint("write error: %r"));
+ break;
+ }
+ }
+ qc <-= 1;
+ exit;
+}
+
+kill(pid: int)
+{
+ sys->fprint(sys->open("#p/"+string pid+"/ctl", Sys->OWRITE), "kill");
+}
diff --git a/appl/alphabet/main/filter.b b/appl/alphabet/main/filter.b
new file mode 100644
index 00000000..f532f529
--- /dev/null
+++ b/appl/alphabet/main/filter.b
@@ -0,0 +1,114 @@
+implement Filter, Mainmodule;
+include "sys.m";
+ sys: Sys;
+include "draw.m";
+include "sh.m";
+ sh: Sh;
+ Context: import sh;
+include "bufio.m";
+ bufio: Bufio;
+ Iobuf: import bufio;
+include "alphabet/reports.m";
+ reports: Reports;
+ Report, report: import reports;
+include "alphabet.m";
+ alphabet: Alphabet;
+ Value: import alphabet;
+
+Filter: module {};
+
+typesig(): string
+{
+ return "ffcs*"; # XXX option to suppress stderr?
+}
+
+init()
+{
+ sys = load Sys Sys->PATH;
+ alphabet = load Alphabet Alphabet->PATH;
+ reports = load Reports Reports->PATH;
+ bufio = load Bufio Bufio->PATH;
+ sh = load Sh Sh->PATH;
+ sh->initialise();
+}
+
+quit()
+{
+}
+
+run(drawctxt: ref Draw->Context, report: ref Reports->Report, nil: chan of string,
+ nil: list of (int, list of ref Value),
+ args: list of ref Value): ref Value
+{
+ f := chan of ref Sys->FD;
+ a: list of ref Sh->Listnode;
+ for(al := tl tl args; al != nil; al = tl al)
+ a = ref Sh->Listnode(nil, (hd al).s().i) :: a;
+ spawn filterproc(drawctxt, (hd args).f().i, f, (hd tl args).c().i, rev(a), report.start("filter"));
+ return ref Value.Vf(f);
+}
+
+filterproc(drawctxt: ref Draw->Context,
+ f0,
+ f1: chan of ref Sys->FD,
+ c: ref Sh->Cmd,
+ args: list of ref Sh->Listnode,
+ errorc: chan of string)
+{
+ (fd0, fd1) := startfilter(f0, f1, errorc);
+ sys->pipe(p := array[2] of ref Sys->FD);
+ spawn stderrproc(p[0], errorc);
+ p[0] = nil;
+
+ # i hate this stuff.
+ sys->pctl(Sys->FORKFD, nil);
+ sys->dup(fd0.fd, 0);
+ sys->dup(fd1.fd, 1);
+ sys->dup(p[1].fd, 2);
+ fd0 = fd1 = nil;
+ p = nil;
+ sys->pctl(Sys->NEWFD, 0::1::2::nil);
+ Context.new(drawctxt).run(ref Sh->Listnode(c, nil)::args, 0);
+ sys->fprint(sys->fildes(2), "");
+}
+
+# read side (when it's an argument):
+# read proposed new fd
+# write actual fd for them to write to (creating pipe in necessary)
+#
+# write side (when you're returning it):
+# write a proposed new fd (or nil if no suggestion)
+# read actual fd for writing
+startfilter(f0, f1: chan of ref Sys->FD, errorc: chan of string): (ref Sys->FD, ref Sys->FD)
+{
+ f1 <-= nil;
+ if((fd1 := <-f1) == nil){
+ <-f0;
+ f0 <-= nil;
+ reports->quit(errorc);
+ }
+ if((fd0 := <-f0) == nil){
+ sys->pipe(p := array[2] of ref Sys->FD);
+ f0 <-= p[1];
+ fd0 = p[0];
+ }else
+ f0 <-= nil;
+ return (fd0, fd1);
+}
+
+stderrproc(fd: ref Sys->FD, errorc: chan of string)
+{
+ iob := bufio->fopen(fd, Sys->OREAD);
+ while((s := iob.gets('\n')) != nil)
+ if(len s > 1)
+ errorc <-= s[0:len s - 1];
+ errorc <-= nil;
+}
+
+rev[T](l: list of T): list of T
+{
+ r: list of T;
+ for(; l != nil; l = tl l)
+ r = hd l :: r;
+ return r;
+} \ No newline at end of file
diff --git a/appl/alphabet/main/genfilter.b b/appl/alphabet/main/genfilter.b
new file mode 100644
index 00000000..9a920d7e
--- /dev/null
+++ b/appl/alphabet/main/genfilter.b
@@ -0,0 +1,79 @@
+implement Myfilter, Mainmodule;
+include "sys.m";
+ sys: Sys;
+include "draw.m";
+include "sh.m";
+include "bufio.m";
+ bufio: Bufio;
+ Iobuf: import bufio;
+include "alphabet/reports.m";
+ reports: Reports;
+ Report, report: import reports;
+include "alphabet.m";
+ alphabet: Alphabet;
+ Value: import alphabet;
+
+Myfilter: module {};
+
+typesig(): string
+{
+ return "ff";
+}
+
+init()
+{
+ sys = load Sys Sys->PATH;
+ alphabet = load Alphabet Alphabet->PATH;
+ reports = load Reports Reports->PATH;
+ bufio = load Bufio Bufio->PATH;
+}
+
+quit()
+{
+}
+
+run(drawctxt: ref Draw->Context, report: ref Reports->Report, nil: chan of string,
+ nil: list of (int, list of ref Alphabet->Value),
+ args: list of ref Alphabet->Value): ref Alphabet->Value
+{
+ f := chan of ref Sys->FD;
+ spawn filterproc(drawctxt, (hd args).f().i, f, report.start("myfilter"));
+ return ref Value.Vf(f);
+}
+
+filterproc(nil: ref Draw->Context, f0, f1: chan of ref Sys->FD, errorc: chan of string)
+{
+ (fd0, fd1) := startfilter(f0, f1, errorc);
+ iob0 := bufio->fopen(fd0, Sys->OREAD);
+ iob1 := bufio->fopen(fd1, Sys->OWRITE);
+
+ # XXX your filter here!
+ while((s := iob0.gets('\n')) != nil){
+ d := array of byte s;
+ iob1.puts("data "+string len d+"\n");
+ iob1.write(d, len d);
+ }exception{
+ "write on closed pipe" =>
+ ;
+ }
+ iob1.flush();
+ sys->fprint(fd1, "");
+ reports->quit(errorc);
+}
+
+startfilter(f0, f1: chan of ref Sys->FD, errorc: chan of string): (ref Sys->FD, ref Sys->FD)
+{
+ f1 <-= nil;
+ if((fd1 := <-f1) == nil){
+ <-f0;
+ f0 <-= nil;
+ reports->quit(errorc);
+ }
+ if((fd0 := <-f0) == nil){
+ sys->pipe(p := array[2] of ref Sys->FD);
+ f0 <-= p[1];
+ fd0 = p[0];
+ }else
+ f0 <-= nil;
+ return (fd0, fd1);
+}
diff --git a/appl/alphabet/main/mkfile b/appl/alphabet/main/mkfile
new file mode 100644
index 00000000..ff2d95fb
--- /dev/null
+++ b/appl/alphabet/main/mkfile
@@ -0,0 +1,36 @@
+<../../../mkconfig
+
+TARG=\
+ auth.dis\
+ cat.dis\
+ create.dis\
+ dial.dis\
+ echo.dis\
+ env.dis\
+ export.dis\
+ fd.dis\
+ filter.dis\
+ mount.dis\
+ par.dis\
+ parse.dis\
+ pretty.dis\
+ print.dis\
+ read.dis\
+ readall.dis\
+ rewrite.dis\
+ seq.dis\
+ unparse.dis\
+ w2fd.dis\
+ wait.dis\
+
+SYSMODULES=\
+ alphabet.m\
+ alphabet/reports.m\
+ draw.m\
+ sh.m\
+ sys.m\
+
+DISBIN=$ROOT/dis/alphabet/main
+
+<$ROOT/mkfiles/mkdis
+LIMBOFLAGS=-F $LIMBOFLAGS
diff --git a/appl/alphabet/main/mount.b b/appl/alphabet/main/mount.b
new file mode 100644
index 00000000..1b27617d
--- /dev/null
+++ b/appl/alphabet/main/mount.b
@@ -0,0 +1,80 @@
+implement Mount,Mainmodule;
+include "sys.m";
+ sys: Sys;
+include "draw.m";
+include "sh.m";
+include "alphabet/reports.m";
+ reports: Reports;
+ Report, report: import reports;
+include "alphabet.m";
+ alphabet: Alphabet;
+ Value: import alphabet;
+
+Mount: module {};
+
+typesig(): string
+{
+ return "rws-a-b-c-xs";
+}
+
+init()
+{
+ sys = load Sys Sys->PATH;
+ alphabet = load Alphabet Alphabet->PATH;
+ reports = load Reports Reports->PATH;
+}
+
+quit()
+{
+}
+
+After, Before, Create: con 1<<iota;
+
+run(nil: ref Draw->Context, report: ref Reports->Report, nil: chan of string,
+ opts: list of (int, list of ref Alphabet->Value),
+ args: list of ref Alphabet->Value): ref Alphabet->Value
+{
+ flag := Sys->MREPL;
+ aname := "";
+ for(; opts != nil; opts = tl opts){
+ case (hd opts).t0 {
+ 'a' =>
+ flag = After & (flag&Sys->MCREATE);
+ 'b' =>
+ flag = Before & (flag&Sys->MCREATE);
+ 'c' =>
+ flag |= Create;
+ 'x' =>
+ aname = (hd (hd opts).t1).s().i;
+ }
+ }
+ r := chan of string;
+ spawn mountproc(r, (hd args).w().i, (hd tl args).s().i, aname, flag, report.start("mount"));
+ return ref Value.Vr(r);
+}
+
+mountproc(r: chan of string, w: chan of ref Sys->FD, dir, aname: string, flag: int, errorc: chan of string)
+{
+ if(<-r != nil){
+ errorc <-= nil;
+ <-w;
+ w <-= nil;
+ exit;
+ }
+ fd := <-w;
+ if(fd == nil){
+ sys->pipe(p := array[2] of ref Sys->FD);
+ w <-= p[0];
+ fd = p[1];
+ }else
+ w <-= nil;
+ if(sys->mount(fd, nil, dir, flag, aname) == -1){
+ e := sys->sprint("mount error on %#q: %r", dir);
+ report(errorc, e);
+ r <-= e;
+ exit;
+ }
+
+ errorc <-= nil;
+ r <-= nil;
+}
diff --git a/appl/alphabet/main/par.b b/appl/alphabet/main/par.b
new file mode 100644
index 00000000..d2b47ef3
--- /dev/null
+++ b/appl/alphabet/main/par.b
@@ -0,0 +1,50 @@
+implement Seq, Mainmodule;
+include "sys.m";
+ sys: Sys;
+include "draw.m";
+include "sh.m";
+include "alphabet/reports.m";
+include "alphabet.m";
+ alphabet: Alphabet;
+ Value: import alphabet;
+
+Seq: module {};
+
+typesig(): string
+{
+ return "rr*";
+}
+
+init()
+{
+ sys = load Sys Sys->PATH;
+ alphabet = load Alphabet Alphabet->PATH;
+}
+
+quit()
+{
+}
+
+run(nil: ref Draw->Context, nil: ref Reports->Report, nil: chan of string,
+ nil: list of (int, list of ref Alphabet->Value),
+ args: list of ref Alphabet->Value): ref Alphabet->Value
+{
+ spawn parproc(r := chan of string, args);
+ return ref Value.Vr(r);
+}
+
+parproc(r: chan of string, args: list of ref Alphabet->Value)
+{
+ if(<-r != nil){
+ for(; args != nil; args = tl args)
+ (hd args).r().i <-= "die!";
+ }else{
+ status := "";
+ for(a := args; a != nil; a = tl a)
+ (hd a).r().i <-= nil;
+ for(; args != nil; args = tl args)
+ if((e := <-(hd args).r().i) != nil)
+ status = e;
+ r <-= status;
+ }
+}
diff --git a/appl/alphabet/main/parse.b b/appl/alphabet/main/parse.b
new file mode 100644
index 00000000..c02ba124
--- /dev/null
+++ b/appl/alphabet/main/parse.b
@@ -0,0 +1,43 @@
+implement Parse, Mainmodule;
+include "sys.m";
+ sys: Sys;
+include "draw.m";
+include "sh.m";
+ sh: Sh;
+include "alphabet/reports.m";
+ reports: Reports;
+ Report, report: import reports;
+include "alphabet.m";
+ alphabet: Alphabet;
+ Value: import alphabet;
+
+Parse: module {};
+
+typesig(): string
+{
+ return "cs";
+}
+
+init()
+{
+ sys = load Sys Sys->PATH;
+ alphabet = load Alphabet Alphabet->PATH;
+ sh = load Sh Sh->PATH;
+ sh->initialise();
+}
+
+quit()
+{
+}
+
+run(nil: ref Draw->Context, nil: ref Reports->Report, errorc: chan of string,
+ nil: list of (int, list of ref Value),
+ args: list of ref Value): ref Value
+{
+ (c, err) := sh->parse((hd args).s().i);
+ if(c == nil){
+ report(errorc, sys->sprint("parse: parse %q failed: %s", (hd args).s().i, err));
+ return nil;
+ }
+ return ref Value.Vc(c);
+}
diff --git a/appl/alphabet/main/pretty.b b/appl/alphabet/main/pretty.b
new file mode 100644
index 00000000..52d8b32f
--- /dev/null
+++ b/appl/alphabet/main/pretty.b
@@ -0,0 +1,116 @@
+implement Pretty, Mainmodule;
+include "sys.m";
+ sys: Sys;
+include "draw.m";
+include "sh.m";
+ sh: Sh;
+ n_BLOCK, n_VAR, n_BQ, n_BQ2, n_REDIR,
+ n_DUP, n_LIST, n_SEQ, n_CONCAT, n_PIPE, n_ADJ,
+ n_WORD, n_NOWAIT, n_SQUASH, n_COUNT,
+ n_ASSIGN, n_LOCAL,
+ GLOB: import Sh;
+include "alphabet/reports.m";
+ reports: Reports;
+ Report, report: import reports;
+include "alphabet.m";
+ alphabet: Alphabet;
+ Value: import alphabet;
+
+Pretty: module {};
+
+typesig(): string
+{
+ return "sc";
+}
+
+init()
+{
+ sys = load Sys Sys->PATH;
+ alphabet = load Alphabet Alphabet->PATH;
+ sh = load Sh Sh->PATH;
+ sh->initialise();
+}
+
+quit()
+{
+}
+
+run(nil: ref Draw->Context, nil: ref Reports->Report, nil: chan of string,
+ nil: list of (int, list of ref Value),
+ args: list of ref Value): ref Value
+{
+ {
+ return ref Value.Vs(pretty((hd args).c().i, 0));
+ }exception{
+ "bad expr" =>
+ return nil;
+ }
+}
+
+pretty(n: ref Sh->Cmd, depth: int): string
+{
+ if (n == nil)
+ return nil;
+ s: string;
+ case n.ntype {
+ n_BLOCK =>
+ s = "{\n"+tabs(depth+1)+pretty(n.left,depth+1) + "\n"+tabs(depth)+"}";
+ n_VAR =>
+ s = "$" + pretty(n.left, depth);
+ n_LIST =>
+ s = "(" + pretty(n.left, depth) + ")";
+ n_SEQ =>
+ s = pretty(n.left, depth) + "\n"+tabs(depth)+pretty(n.right, depth);
+ n_PIPE =>
+ s = pretty(n.left, depth) + " |\n"+tabs(depth)+pretty(n.right, depth);
+ n_ADJ =>
+ s = pretty(n.left, depth) + " " + pretty(n.right, depth);
+ n_WORD =>
+ s = quote(n.word, 1);
+ n_BQ2 =>
+ # if we can't do it, revert to ugliness.
+ {
+ s = "\"" + pretty(n.left, depth);
+ } exception {
+ "bad expr" =>
+ s = sh->cmd2string(n);
+ }
+ * =>
+ raise "bad expr";
+ }
+ return s;
+}
+
+tabs(n: int): string
+{
+ s: string;
+ while(n-- > 0)
+ s[len s] = '\t';
+ return s;
+}
+
+# stolen from sh.y
+quote(s: string, glob: int): string
+{
+ needquote := 0;
+ t := "";
+ for (i := 0; i < len s; i++) {
+ case s[i] {
+ '{' or '}' or '(' or ')' or '`' or '&' or ';' or '=' or '>' or '<' or '#' or
+ '|' or '*' or '[' or '?' or '$' or '^' or ' ' or '\t' or '\n' or '\r' =>
+ needquote = 1;
+ '\'' =>
+ t[len t] = '\'';
+ needquote = 1;
+ GLOB =>
+ if (glob) {
+ if (i < len s - 1)
+ i++;
+ }
+ }
+ t[len t] = s[i];
+ }
+ if (needquote || t == nil)
+ t = "'" + t + "'";
+ return t;
+}
diff --git a/appl/alphabet/main/print.b b/appl/alphabet/main/print.b
new file mode 100644
index 00000000..12327934
--- /dev/null
+++ b/appl/alphabet/main/print.b
@@ -0,0 +1,55 @@
+implement Print,Mainmodule;
+include "sys.m";
+ sys: Sys;
+include "draw.m";
+include "sh.m";
+include "alphabet/reports.m";
+ reports: Reports;
+ Report, report: import reports;
+include "alphabet.m";
+ alphabet: Alphabet;
+ Value: import alphabet;
+
+Print: module {};
+
+typesig(): string
+{
+ return "rfs";
+}
+
+init()
+{
+ sys = load Sys Sys->PATH;
+ alphabet = load Alphabet Alphabet->PATH;
+ reports = load Reports Reports->PATH;
+}
+
+quit()
+{
+}
+
+run(nil: ref Draw->Context, nil: ref Reports->Report, errorc: chan of string,
+ nil: list of (int, list of ref Alphabet->Value),
+ args: list of ref Alphabet->Value): ref Alphabet->Value
+{
+ r := chan of string;
+ fd := sys->fildes(int (hd tl args).s().i);
+ if(fd == nil){
+ report(errorc, sys->sprint("error: no such fd %q", (hd tl args).s().i));
+ return nil;
+ }
+ spawn printproc(r, (hd args).f().i, fd);
+ return ref Value.Vr(r);
+}
+
+printproc(r: chan of string, f: chan of ref Sys->FD, fd: ref Sys->FD)
+{
+ if(<-r != nil){
+ <-f;
+ f <-= nil;
+ exit;
+ }
+ <-f;
+ f <-= fd;
+ r <-= nil;
+}
diff --git a/appl/alphabet/main/read.b b/appl/alphabet/main/read.b
new file mode 100644
index 00000000..ebc4d156
--- /dev/null
+++ b/appl/alphabet/main/read.b
@@ -0,0 +1,56 @@
+implement Read,Mainmodule;
+include "sys.m";
+ sys: Sys;
+include "draw.m";
+include "sh.m";
+include "alphabet/reports.m";
+ reports: Reports;
+ Report, report: import reports;
+include "alphabet.m";
+ alphabet: Alphabet;
+ Value: import alphabet;
+
+Read: module{};
+
+typesig(): string
+{
+ return "fs";
+}
+
+init()
+{
+ sys = load Sys Sys->PATH;
+ alphabet = load Alphabet Alphabet->PATH;
+ reports = load Reports Reports->PATH;
+}
+
+quit()
+{
+}
+
+run(nil: ref Draw->Context, r: ref Reports->Report, errorc: chan of string,
+ nil: list of (int, list of ref Alphabet->Value),
+ args: list of ref Alphabet->Value): ref Alphabet->Value
+{
+ f := chan of ref Sys->FD;
+ file := (hd args).s().i;
+ if((fd0 := sys->open(file, Sys->OREAD)) == nil){
+ report(errorc, sys->sprint("cannot open %q: %r", file));
+ return nil;
+ }
+ spawn readproc(f, fd0, r.start("read"));
+ return ref Value.Vf(f);
+}
+
+readproc(f: chan of ref Sys->FD, fd0: ref Sys->FD, errorc: chan of string)
+{
+ f <-= fd0;
+ fd1 := <-f;
+ if(fd1 == nil)
+ reports->quit(errorc);
+ buf := array[8192] of byte;
+ while((n := sys->read(fd0, buf, len buf)) > 0)
+ sys->write(fd1, buf, n);
+ sys->write(fd1, array[0] of byte, 0);
+ reports->quit(errorc);
+}
diff --git a/appl/alphabet/main/readall.b b/appl/alphabet/main/readall.b
new file mode 100644
index 00000000..b8697332
--- /dev/null
+++ b/appl/alphabet/main/readall.b
@@ -0,0 +1,46 @@
+implement F2s, Mainmodule;
+include "sys.m";
+ sys: Sys;
+include "draw.m";
+include "sh.m";
+include "alphabet/reports.m";
+ reports: Reports;
+ Report, report: import reports;
+include "alphabet.m";
+ alphabet: Alphabet;
+ Value: import alphabet;
+
+F2s: module {};
+
+typesig(): string
+{
+ return "sf";
+}
+
+init()
+{
+ sys = load Sys Sys->PATH;
+ alphabet = load Alphabet Alphabet->PATH;
+}
+
+quit()
+{
+}
+
+run(nil: ref Draw->Context, nil: ref Reports->Report, nil: chan of string,
+ nil: list of (int, list of ref Value),
+ args: list of ref Value): ref Value
+{
+ f := (hd args).f().i;
+ fd := <-f;
+ if(fd == nil){
+ sys->pipe(p := array[2] of ref Sys->FD);
+ f <-= p[1];
+ fd = p[0];
+ }
+ s: string;
+ buf := array[Sys->ATOMICIO] of byte;
+ while((n := sys->read(fd, buf, len buf)) > 0)
+ s += string buf[0:n];
+ return ref Value.Vs(s);
+}
diff --git a/appl/alphabet/main/rewrite.b b/appl/alphabet/main/rewrite.b
new file mode 100644
index 00000000..96a6e205
--- /dev/null
+++ b/appl/alphabet/main/rewrite.b
@@ -0,0 +1,97 @@
+implement Rewrite, Mainmodule;
+include "sys.m";
+ sys: Sys;
+include "draw.m";
+include "sh.m";
+ sh: Sh;
+ Context: import sh;
+include "alphabet/reports.m";
+ reports: Reports;
+ report: import reports;
+include "alphabet.m";
+ Value: import Alphabet;
+
+Rewrite: module {};
+
+typesig(): string
+{
+ return "ccc-ds";
+}
+
+init()
+{
+ sys = load Sys Sys->PATH;
+ sh = load Sh Sh->PATH;
+ sh->initialise();
+ reports = load Reports Reports->PATH;
+}
+
+quit()
+{
+}
+
+run(drawctxt: ref Draw->Context, nil: ref Reports->Report, errorc: chan of string,
+ opts: list of (int, list of ref Value),
+ args: list of ref Value): ref Value
+{
+ c := chan of ref Value;
+ spawn rewriteproc(drawctxt, errorc, opts, args, c);
+ return <-c;
+}
+
+# we need a separate process so that we can create a shell context
+# without worrying about opening an already-opened wait file.
+rewriteproc(drawctxt: ref Draw->Context, errorc: chan of string,
+ opts: list of (int, list of ref Value),
+ args: list of ref Value,
+ c: chan of ref Value)
+{
+ c <-= rewrite(drawctxt, errorc, opts, args);
+}
+
+rewrite(drawctxt: ref Draw->Context, errorc: chan of string,
+ opts: list of (int, list of ref Value),
+ args: list of ref Value): ref Value
+{
+ alphabet := load Alphabet Alphabet->PATH;
+ if(alphabet == nil){
+ report(errorc, sys->sprint("rewrite: cannot load %q: %r", Alphabet->PATH));
+ return nil;
+ }
+ Value: import alphabet;
+ alphabet->init();
+ expr := (hd args).c().i;
+ decls := (hd tl args).c().i;
+ ctxt := Context.new(drawctxt);
+ {
+ ctxt.run(w("load")::w("alphabet")::nil, 0);
+ ctxt.run(c(decls) :: nil, 0);
+ dstarg: list of ref Sh->Listnode;
+ if(opts != nil)
+ dstarg = w((hd (hd opts).t1).s().i) :: nil;
+ ctxt.run(w("{x=${rewrite $1 $2}}") :: c(expr) :: dstarg, 0);
+ } exception e {
+ "fail:*" =>
+ ctxt.run(w("clear")::nil, 0);
+ report(errorc, "rewrite failed: "+e[5:]);
+ return nil;
+ }
+ r := ctxt.get("x");
+ if(len r != 2 || (hd r).cmd == nil){
+ ctxt.run(w("clear")::nil, 0);
+ report(errorc, "rewrite not available, strange... (len "+string len r+")");
+ return nil;
+ }
+ ctxt.run(w("clear")::nil, 0);
+ return ref Value.Vc((hd r).cmd);
+}
+
+c(c: ref Sh->Cmd): ref Sh->Listnode
+{
+ return ref Sh->Listnode(c, nil);
+}
+
+w(w: string): ref Sh->Listnode
+{
+ return ref Sh->Listnode(nil, w);
+}
diff --git a/appl/alphabet/main/rw.b b/appl/alphabet/main/rw.b
new file mode 100644
index 00000000..74ede534
--- /dev/null
+++ b/appl/alphabet/main/rw.b
@@ -0,0 +1,50 @@
+implement Mainmodule;
+include "sys.m";
+ sys: Sys;
+include "draw.m";
+include "sh.m";
+include "alphabet/reports.m";
+ reports: Reports;
+ Report, report, quit: import reports;
+include "alphabet.m";
+ alphabet: Alphabet;
+ Value: import alphabet;
+
+typesig(): string
+{
+ return "fs";
+}
+
+init()
+{
+ sys = load Sys Sys->PATH;
+ alphabet = load Alphabet Alphabet->PATH;
+ reports = load Reports Reports->PATH;
+}
+
+run(nil: ref Draw->Context, r: ref Reports->Report, errorc: chan of string,
+ nil: list of (int, list of ref Alphabet->Value),
+ args: list of ref Alphabet->Value): ref Alphabet->Value
+{
+ f := chan of ref Sys->FD;
+ file := (hd args).s().i;
+ if((fd0 := sys->open(file, Sys->OREAD)) == nil){
+ report(errorc, sys->sprint("cannot open %q: %r", file));
+ return nil;
+ }
+ spawn readproc(f, fd0, r.start("read"));
+ return ref Value.F(f);
+}
+
+readproc(f: chan of ref Sys->FD, fd0: ref Sys->FD, errorc: chan of string)
+{
+ f <-= fd0;
+ fd1 := <-f;
+ if(fd1 == nil)
+ quit(errorc);
+ buf := array[8192] of byte;
+ while((n := sys->read(fd0, buf, len buf)) > 0)
+ sys->write(fd1, buf, n);
+ sys->write(fd1, array[0] of byte, 0);
+ quit(errorc);
+}
diff --git a/appl/alphabet/main/seq.b b/appl/alphabet/main/seq.b
new file mode 100644
index 00000000..8e062738
--- /dev/null
+++ b/appl/alphabet/main/seq.b
@@ -0,0 +1,66 @@
+implement Seq, Mainmodule;
+include "sys.m";
+ sys: Sys;
+include "draw.m";
+include "sh.m";
+include "alphabet/reports.m";
+include "alphabet.m";
+ alphabet: Alphabet;
+ Value: import alphabet;
+
+Seq: module {};
+
+typesig(): string
+{
+ return "rr*-a-o";
+}
+
+init()
+{
+ sys = load Sys Sys->PATH;
+ alphabet = load Alphabet Alphabet->PATH;
+}
+
+quit()
+{
+}
+
+run(nil: ref Draw->Context, nil: ref Reports->Report, nil: chan of string,
+ opts: list of (int, list of ref Alphabet->Value),
+ args: list of ref Alphabet->Value): ref Alphabet->Value
+{
+ stop := -1;
+ for(; opts != nil; opts = tl opts){
+ case (hd opts).t0 {
+ 'a' =>
+ stop = 0;
+ 'o' =>
+ stop = 1;
+ }
+ }
+ spawn seqproc(r := chan of string, args, stop);
+ return ref Value.Vr(r);
+}
+
+seqproc(r: chan of string, args: list of ref Alphabet->Value, stop: int)
+{
+ status := "";
+ if(<-r == nil){
+pid := sys->pctl(0, nil);
+sys->print("%d. seq %d args\n", pid, len args);
+ for(; args != nil; args = tl args){
+ sr := (hd args).r().i;
+sys->print("%d. started\n", pid);
+ sr <-= nil;
+ status = <-sr;
+sys->print("%d. got status\n", pid);
+ if((status == nil) == stop)
+ break;
+ }
+ }else
+ r = nil;
+ for(; args != nil; args = tl args)
+ (hd args).r().i <-= "die!";
+ if(r != nil)
+ r <-= status;
+}
diff --git a/appl/alphabet/main/unparse.b b/appl/alphabet/main/unparse.b
new file mode 100644
index 00000000..11aa0d48
--- /dev/null
+++ b/appl/alphabet/main/unparse.b
@@ -0,0 +1,38 @@
+implement Unparse, Mainmodule;
+include "sys.m";
+ sys: Sys;
+include "draw.m";
+include "sh.m";
+ sh: Sh;
+include "alphabet/reports.m";
+ reports: Reports;
+ Report, report: import reports;
+include "alphabet.m";
+ alphabet: Alphabet;
+ Value: import alphabet;
+
+Unparse: module {};
+
+typesig(): string
+{
+ return "sc";
+}
+
+init()
+{
+ sys = load Sys Sys->PATH;
+ alphabet = load Alphabet Alphabet->PATH;
+ sh = load Sh Sh->PATH;
+ sh->initialise();
+}
+
+quit()
+{
+}
+
+run(nil: ref Draw->Context, nil: ref Reports->Report, nil: chan of string,
+ nil: list of (int, list of ref Value),
+ args: list of ref Value): ref Value
+{
+ return ref Value.Vs(sh->cmd2string((hd args).c().i));
+}
diff --git a/appl/alphabet/main/w2fd.b b/appl/alphabet/main/w2fd.b
new file mode 100644
index 00000000..ab7e3a70
--- /dev/null
+++ b/appl/alphabet/main/w2fd.b
@@ -0,0 +1,61 @@
+implement ToFD,Mainmodule;
+include "sys.m";
+ sys: Sys;
+include "draw.m";
+include "sh.m";
+include "alphabet/reports.m";
+ reports: Reports;
+ Report: import reports;
+include "alphabet.m";
+ alphabet: Alphabet;
+ Value: import alphabet;
+
+ToFD: module {};
+
+typesig(): string
+{
+ return "fw";
+}
+
+init()
+{
+ alphabet = load Alphabet Alphabet->PATH;
+ reports = load Reports Reports->PATH;
+}
+
+quit()
+{
+}
+
+run(nil: ref Draw->Context, r: ref Reports->Report, nil: chan of string,
+ nil: list of (int, list of ref Alphabet->Value),
+ args: list of ref Alphabet->Value): ref Alphabet->Value
+{
+ sys = load Sys Sys->PATH;
+ f := chan of ref Sys->FD;
+ spawn tofdproc(f, (hd args).w().i, r.start("2fd"));
+ return ref Value.Vf(f);
+}
+
+tofdproc(f, w: chan of ref Sys->FD, errorc: chan of string)
+{
+ fd0 := <-w;
+ f <-= fd0;
+ fd1 := <-f;
+ if(fd1 == nil) # asked to quit? tell w to quit too.
+ w <-= nil;
+ else
+ if(fd0 == nil) # no proposed fd? give 'em the one we've just got.
+ w <-= fd1;
+ else{ # otherwise one-way stream from w to f.
+ w <-= nil;
+ buf := array[Sys->ATOMICIO] of byte;
+ while((n := sys->read(fd0, buf, len buf)) > 0){
+ if(sys->write(fd1, buf, n) == -1){
+ reports->report(errorc, sys->sprint("write error: %r"));
+ break;
+ }
+ }
+ }
+ reports->quit(errorc);
+}
diff --git a/appl/alphabet/main/wait.b b/appl/alphabet/main/wait.b
new file mode 100644
index 00000000..04bf88c6
--- /dev/null
+++ b/appl/alphabet/main/wait.b
@@ -0,0 +1,35 @@
+implement Wait, Mainmodule;
+include "sys.m";
+ sys: Sys;
+include "draw.m";
+include "sh.m";
+include "alphabet/reports.m";
+include "alphabet.m";
+ alphabet: Alphabet;
+ Value: import alphabet;
+
+Wait: module {};
+
+typesig(): string
+{
+ return "sr";
+}
+
+init()
+{
+ sys = load Sys Sys->PATH;
+ alphabet = load Alphabet Alphabet->PATH;
+}
+
+quit()
+{
+}
+
+run(nil: ref Draw->Context, nil: ref Reports->Report, nil: chan of string,
+ nil: list of (int, list of ref Alphabet->Value),
+ args: list of ref Alphabet->Value): ref Alphabet->Value
+{
+ r := (hd args).r().i;
+ r <-= nil;
+ return ref Value.Vs(<-r);
+}