/**************************************************************
 *
 *	CRISP - Custom Reduced Instruction Set Programmers Editor
 *
 *	(C) Paul Fox, 1989
 *
 *    Please See COPYLEFT notice.
 *
 **************************************************************/
# include	"list.h"
# include	"clk.h"
# include	<signal.h>
SCCSID("@(#) clock.c 1.7, (C) 1989, P. Fox");

# define	MAX_TIMEOUTS	10

struct	callout	{
		int	(*func)();
		int	arg;
		long	id;
		long	timeout;
		};

/*# define ALARM(x) (trace_log("alarm(%d)\n", x), alarm(x))*/
# define ALARM(x) alarm(x)
struct	callout callo[MAX_TIMEOUTS];
int	ntmo = 0;
static	long	clk_id = 0;
int	clock_ticked = FALSE;
int clock_handler();

clk_timeout(func, arg, timeout)
int (*func)();
long	timeout;
{	register struct callout *cp = callo;
	register int i, j;

	clk_remove(func);
	if (ntmo && clock_ticked == FALSE) {
		int	secs = ALARM(0);
		callo[0].timeout = secs;
		}

	timeout /= 1 SECOND;
	if (ntmo == 0)
		goto end_of_function;

	if (ntmo >= MAX_TIMEOUTS-1)
		return 0;
	for (i = 0; i < ntmo; i++, cp++) {
		if (cp->timeout > timeout) {
			for (j = ntmo; j > i; j--)
				callo[j] = callo[j-1];
			cp[1].timeout -= timeout;
			goto end_of_function;
			}
		timeout -= cp->timeout;
		}
end_of_function:
	cp->func = func;
	cp->arg = arg;
	cp->id = ++clk_id;
	cp->timeout = timeout;
	ntmo++;
	if (clock_ticked == FALSE) {
		if (callo[0].timeout == 0)
			clock_handler();
		else {
			signal(SIGALRM, clock_handler);
			ALARM(callo[0].timeout);
			}
		}
	return clk_id;
}
clk_remove(func)
int (*func)();
{	register struct callout *cp;
	register struct callout *cend = &callo[ntmo];

	for (cp = callo; cp < cend; cp++)
		if (cp->func == func) {
			cp[1].timeout += cp->timeout;
			for (; cp < cend; cp++)
				*cp = cp[1];
			ntmo--;
			break;
			}
}
clock_check()
{	int	i;
	int (*func)();
	int	arg;
	int	clock_handler();

	if (clock_ticked == FALSE)
		return 1;
	callo[0].timeout = 0;
	while (ntmo && callo[0].timeout == 0) {
		func = callo[0].func;
		arg = callo[0].arg;
		for (i = 0; i < MAX_TIMEOUTS; i++)
			callo[i] = callo[i+1];
		ntmo--;
		if (func)
			(*func)(arg);
		}
	signal(SIGALRM, clock_handler);
	clock_ticked = FALSE;
	if (ntmo)
		ALARM(callo[0].timeout);
	return 1;
}
clock_handler()
{
	signal(SIGALRM, SIG_IGN);
# if	defined(VMS)
	sys_cancel_io();
# endif
	clock_ticked = TRUE;
}
dump_callo()
{
	int	i;
	trace_log("CALLOUTS = %d\n", ntmo);
	for (i = 0; i < ntmo; i++) {
		trace_log("%d: func=", i);
		trace_log("%08lx ", callo[i].func);
		trace_log("tmo=%ld.\n", callo[i].timeout);
		}
}
