code: 9ferno

ref: bbe261d58359dbbcfc2f0108323f3fae688a568c
dir: /appl/alphabet/main/filter.b/

View raw version
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;
}