#!mkcmd
# $Id: tmbuf.m,v 1.6 2008/07/10 19:27:51 ksb Exp $
#
# XXX we don't take a max number of lines.
# XXX we don't take a max wait time (for first read)
from '<sys/param.h>'
from '<sys/types.h>'
from '<sys/time.h>'
from '<unistd.h>'
from '<stdlib.h>'
from '<stdio.h>'
from '<signal.h>'
from '<errno.h>'

require "std_help.m" "std_version.m"

basename "tmbuf" ""

number {
	named "iDelay"
	init "5"
	param "seconds"
	help "time to stall between lines (default %qi)"
}

boolean 'e' {
	named "bErrOnEOF"
	init "0"
	help "exit nonzero at EOF, even if some input was processed"
}

# allow "minutes option" which is a bad user interface -- ksb
function 'm' { hidden update "%rtN = %a;%rtT;%rtn *= 60;" }
int 't' {
	named "iMaxdelay" "pcMaxDelay"
	init "0"
	param "seconds"
	help "total time to delay after first read (default forever)"
}

exit {
	named "Pump"
}
%i
static char rcsid[] =
	"$Id: tmbuf.m,v 1.6 2008/07/10 19:27:51 ksb Exp $";

#if FREEBSD || IBMR2
#include <sys/select.h>
#endif

#if !defined(PIPSIZ)
#define PIPSIZ	8192
#endif
%%

%c
/* get out if the long term timer goes off				(ksb)
 */
void
AlarmHandler(i)
int i;
{
	exit(0);
}

/* batch up messages that are close in time to each other	(ksb+wam)
 */
static void
Pump(int dummy)		/*ARGSUSED*/
{
	auto struct timeval tmout;
	auto fd_set myfdset;
	auto int fFirst;
	register int cc, rc;
	register char *pcCursor;
	auto char acLine[PIPSIZ];

	if (SIG_ERR == signal(SIGALRM, AlarmHandler)) {
		fprintf(stderr, "%s: signal: %s\n", progname, strerror(errno));
		exit(1);
	}

	/* Stop on error or EOF but we don't want to exit nonzero
	 * if we've actually done some real data.  We'll wait until
	 * we get executed again and fail at the beginning of
	 * the new process.
	 */
	fFirst = 1;
	do {
		if (0 == (cc = read(0, acLine, sizeof(acLine)))) {
			exit(bErrOnEOF || fFirst);
		}
		if (-1 == cc) {
			fprintf(stderr, "%s: read: %s\n", progname, strerror(errno));
			exit(fFirst);
		} 
		if (fFirst) {
			fFirst = 0;
			alarm(iMaxdelay);
		}
		/* if the output is blocked we might have to spin here
		 */
		pcCursor = acLine;
		for (rc = 0; 0 != cc && -1 != rc; pcCursor += rc, cc -= rc) {
			rc = write(1, pcCursor, cc);
		}
		FD_SET(0, & myfdset);
		tmout.tv_usec = 0;
		tmout.tv_sec = iDelay;
	} while (0 < select(1, &myfdset, (fd_set *)0, (fd_set *)0, & tmout));
}
%%
