#define	ANY	(256-1)
#define	LIST	(256-2)
#define	RANGE	(256-3)
#define	EOF	(256-4)
char	*crontab	"/usr/lib/crontab";
char	*crontmp	"/tmp/crontmp";
char	*aend;
char	*itime[2];
int	*loct;
int	*localtime();
int	reset();
int	flag;

main()
{
	register i, t;
	register char *cp;
	extern char end[];

/***	setuid(1);	***/
	itime[0] = fork();
	if(itime[0])
		exit();
	setexit();
	signal(1, reset);
	time(itime);
	while(*localtime(itime))
		if(itime[1]-- == 0)
			itime[0]--;

loop:
	init();
	for(i=60; i; i--) {
		loct = localtime(itime);
		for(cp = end; *cp != EOF;) {
			flag = 0;
			cp = cmp(cp, loct[1]); /* minute */
			cp = cmp(cp, loct[2]); /* hour */
			cp = cmp(cp, loct[3]); /* day */
			cp = cmp(cp, loct[4]); /* month */
			cp = cmp(cp, loct[6]); /* day of week */
			if(flag == 0) {
				slp();
				ex(cp);
			}
			while(*cp++ != 0)
				;
		}
		t = itime[1] + 60;
		if(t < itime[1])
			itime[0]++;
		itime[1] = t;
	}
	slp();
	goto loop;
}

cmp(p, v)
char *p;
{
	register char *cp;

	cp = p;
	switch(*cp++) {

	case ANY:
		return(cp);

	case LIST:
		while(*cp != LIST)
			if(*cp++ == v) {
				while(*cp++ != LIST)
					;
				return(cp);
			}
		flag++;
		return(cp+1);

	case RANGE:
		if(*cp > v || cp[1] < v)
			flag++;
		return(cp+2);
	}
	if(cp[-1] != v)
		flag++;
	return(cp);
}

slp()
{
	register i;
	int	t[2];

	time(t);
	i = itime[1] - t[1];
	if(i > 0)
		sleep(i);
}

ex(s)
char *s;
{
	register i;
	int stat;	/***/

	if(fork()) {
		wait(&stat);	/***/
		return;
	}
	for(i=0; s[i]; i++);
	close(0);
	creat(crontmp, 0600);
	write(0, s, i);
	close(0);
	open(crontmp, 0);
	unlink(crontmp);
	if(fork())
		exit();
	execl("/bin/sh", "sh", "-t", 0);
	exit();
}

init()
{
	int ib[131], t[10];	/***/
	register i, c;
	register char *cp;
	char *ocp;
	int n;
	extern char end[];

	if(fopen(crontab, ib) < 0) {
		write(1, "cannot open table\n", 18);
		exit();
	}
	cp = end;
	if(aend == 0)
		aend = cp;

loop:
	ocp = cp;
	if(cp+100 > aend) {
		aend =+ 512;
		brk(aend);
	}
	for(i=0;; i++) {
		do
			c = getc(ib);
		while(c == ' ' || c == '\t');
		if(c <= 0 || c == '\n')
			goto ignore;
		if(i == 5)
			break;
		if(c == '*') {
			*cp++ = ANY;
			continue;
		}
		n = 0;
		while(c >= '0' && c <= '9') {
			n = n*10 + c-'0';
			c = getc(ib);
		}
		if(n < 0 || n > 100)
			goto ignore;
		if(c == ',')
			goto list;
		if(c == '-')
			goto range;
		if(c != '\t' && c != ' ')
			goto ignore;
		*cp++ = n;
		continue;

	list:
		*cp++ = LIST;
		*cp++ = n;
	list1:
		n = 0;
		c = getc(ib);
		while(c >= '0' && c <= '9') {
			n = n*10 + c-'0';
			c = getc(ib);
		}
		if(n < 0 || n > 100)
			goto ignore;
		*cp++ = n;
		if(c == ',')
			goto list1;
		if(c != '\t' && c != ' ')
			goto ignore;
		*cp++ = LIST;
		continue;

	range:
		*cp++ = RANGE;
		*cp++ = n;
		n = 0;
		c = getc(ib);
		while(c >= '0' && c <= '9') {
			n = n*10 + c-'0';
			c = getc(ib);
		}
		if(n < 0 || n > 100)
			goto ignore;
		if(c != '\t' && c != ' ')
			goto ignore;
		*cp++ = n;
	}
	while(c != '\n') {
		if(c <= 0)
			goto ignore;
		if(c == '%')
			c = '\n';
		*cp++ = c;
		c = getc(ib);
	}
	*cp++ = '\n';
	*cp++ = 0;
	goto loop;

ignore:
	cp = ocp;
	while(c != '\n') {
		if(c <= 0) {
			close(ib[0]);
			*cp++ = EOF;
			*cp++ = EOF;
			aend = cp;
			brk(aend);
			return;
		}
		c = getc(ib);
	}
	goto loop;
}
