diff options
Diffstat (limited to 'appl/alphabet/main/filter.b')
| -rw-r--r-- | appl/alphabet/main/filter.b | 114 |
1 files changed, 114 insertions, 0 deletions
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 |
