#!/afs/athena/contrib/perl/perl
#
# by Albert Dvornik <bert@mit.edu>
#
# $Id$

package pipecmd;

sub set_upstream_cmd {
    ($err_upstream, @cmd_upstream) = @_;
}

sub set_downstream_cmd {
    ($err_downstream, @cmd_downstream) = @_;
}

sub pid_handler {
    local($pid, $handler) = @_;
    $error{$pid} = $handler;
}

sub clear_pid_handlers {
    undef %error;
}

sub run {
    local($pid);
    local(*DOWNSTREAM, *UPSTREAM);

    pipe(DOWNSTREAM, UPSTREAM) || die "pipe() failed: $!\nquitting";

    $pid = fork();
    if ($pid < 0) {		# error
	die "fork() failed: $!\nquitting";
    } elsif (!$pid) {		# child
	open(STDOUT, ">&UPSTREAM") || die "reopen() failed: $!\nquitting";
	close(DOWNSTREAM);   # ...or we have termination problems
	exec @cmd_upstream;
	die "exec() failed: $!\nquitting";
    }
    close(UPSTREAM);
    &pid_handler($pid, $err_upstream);

    $pid = fork();
    if ($pid < 0) {		# error
	die "fork() failed: $!\nquitting";
    } elsif (!$pid) {		# child
	open(STDIN, ">&DOWNSTREAM") || die "reopen() failed: $!\nquitting";
	exec @cmd_downstream;
	die "exec() failed: $!\nquitting";
    }
    close(DOWNSTREAM);
    &pid_handler($pid, $err_downstream);
}

sub wait {
    local($handle_if_zero, $debug) = @_;
    local($pid);

    while (($pid = wait) >= 0) {
	if ($? || $handle_if_zero) {
	    local($err,$sig) = ($? >> 8, $? & 0xFF);
	    print "process $pid returned with exit code $err (signal $sig).\n"
		if $debug;
	    if ($error{$pid}) {
		package main;  # eval the thing in main, not pipecmd
		local($err,$sig) = ($pipecmd'err, $pipecmd'sig);
		eval $pipecmd'error{$pipecmd'pid};
	    }
	}
    }

    &clear_pid_handlers;
}

1;
