xref: /csrg-svn/games/tetris/input.c (revision 60854)
157268Sbostic /*-
2*60854Sbostic  * Copyright (c) 1992, 1993
3*60854Sbostic  *	The Regents of the University of California.  All rights reserved.
457268Sbostic  *
557288Sbostic  * This code is derived from software contributed to Berkeley by
657288Sbostic  * Chris Torek and Darren F. Provine.
757288Sbostic  *
857268Sbostic  * %sccs.include.redist.c%
957268Sbostic  *
10*60854Sbostic  *	@(#)input.c	8.1 (Berkeley) 05/31/93
1157268Sbostic  */
1257268Sbostic 
1357268Sbostic /*
1457268Sbostic  * Tetris input.
1557268Sbostic  */
1657268Sbostic 
1757268Sbostic #include <sys/types.h>
1857268Sbostic #include <sys/time.h>
1957288Sbostic 
2057268Sbostic #include <errno.h>
2157268Sbostic #include <unistd.h>
2257268Sbostic 
2357268Sbostic #include "input.h"
2457268Sbostic #include "tetris.h"
2557268Sbostic 
2657268Sbostic /* return true iff the given timeval is positive */
2757268Sbostic #define	TV_POS(tv) \
2857268Sbostic 	((tv)->tv_sec > 0 || ((tv)->tv_sec == 0 && (tv)->tv_usec > 0))
2957268Sbostic 
3057268Sbostic /* subtract timeval `sub' from `res' */
3157268Sbostic #define	TV_SUB(res, sub) \
3257268Sbostic 	(res)->tv_sec -= (sub)->tv_sec; \
3357268Sbostic 	(res)->tv_usec -= (sub)->tv_usec; \
3457268Sbostic 	if ((res)->tv_usec < 0) { \
3557268Sbostic 		(res)->tv_usec += 1000000; \
3657268Sbostic 		(res)->tv_sec--; \
3757268Sbostic 	}
3857268Sbostic 
3957268Sbostic /*
4057268Sbostic  * Do a `read wait': select for reading from stdin, with timeout *tvp.
4157268Sbostic  * On return, modify *tvp to reflect the amount of time spent waiting.
4257268Sbostic  * It will be positive only if input appeared before the time ran out;
4357268Sbostic  * otherwise it will be zero or perhaps negative.
4457268Sbostic  *
4557268Sbostic  * If tvp is nil, wait forever, but return if select is interrupted.
4657268Sbostic  *
4757268Sbostic  * Return 0 => no input, 1 => can read() from stdin
4857268Sbostic  */
4957268Sbostic int
rwait(tvp)5057268Sbostic rwait(tvp)
5157268Sbostic 	register struct timeval *tvp;
5257268Sbostic {
5357268Sbostic 	int i;
5457268Sbostic 	struct timeval starttv, endtv, *s;
5557268Sbostic 	extern int errno;
5657268Sbostic #define	NILTZ ((struct timezone *)0)
5757268Sbostic 
5857268Sbostic 	/*
5957268Sbostic 	 * Someday, select() will do this for us.
6057268Sbostic 	 * Just in case that day is now, and no one has
6157268Sbostic 	 * changed this, we use a temporary.
6257268Sbostic 	 */
6357268Sbostic 	if (tvp) {
6457268Sbostic 		(void) gettimeofday(&starttv, NILTZ);
6557268Sbostic 		endtv = *tvp;
6657268Sbostic 		s = &endtv;
6757268Sbostic 	} else
6857268Sbostic 		s = 0;
6957268Sbostic again:
7057268Sbostic 	i = 1;
7157268Sbostic 	switch (select(1, (fd_set *)&i, (fd_set *)0, (fd_set *)0, s)) {
7257268Sbostic 
7357268Sbostic 	case -1:
7457268Sbostic 		if (tvp == 0)
7557268Sbostic 			return (-1);
7657268Sbostic 		if (errno == EINTR)
7757268Sbostic 			goto again;
7857268Sbostic 		stop("select failed, help");
7957268Sbostic 		/* NOTREACHED */
8057268Sbostic 
8157268Sbostic 	case 0:	/* timed out */
8257268Sbostic 		tvp->tv_sec = 0;
8357268Sbostic 		tvp->tv_usec = 0;
8457268Sbostic 		return (0);
8557268Sbostic 	}
8657268Sbostic 	if (tvp) {
8757268Sbostic 		/* since there is input, we may not have timed out */
8857268Sbostic 		(void) gettimeofday(&endtv, NILTZ);
8957268Sbostic 		TV_SUB(&endtv, &starttv);
9057268Sbostic 		TV_SUB(tvp, &endtv);	/* adjust *tvp by elapsed time */
9157268Sbostic 	}
9257268Sbostic 	return (1);
9357268Sbostic }
9457268Sbostic 
9557268Sbostic /*
9657268Sbostic  * `sleep' for the current turn time (using select).
9757268Sbostic  * Eat any input that might be available.
9857268Sbostic  */
9957268Sbostic void
tsleep()10057268Sbostic tsleep()
10157268Sbostic {
10257268Sbostic 	struct timeval tv;
10357268Sbostic 	char c;
10457268Sbostic 
10557268Sbostic 	tv.tv_sec = 0;
10657268Sbostic 	tv.tv_usec = fallrate;
10757268Sbostic 	while (TV_POS(&tv))
10857268Sbostic 		if (rwait(&tv) && read(0, &c, 1) != 1)
10957268Sbostic 			break;
11057268Sbostic }
11157268Sbostic 
11257268Sbostic /*
11357268Sbostic  * Eat up any input (used at end of game).
11457268Sbostic  */
11557268Sbostic void
eat_input()11657268Sbostic eat_input()
11757268Sbostic {
11857268Sbostic 	struct timeval tv;
11957268Sbostic 	char c;
12057268Sbostic 
12157268Sbostic 	do {
12257268Sbostic 		tv.tv_sec = tv.tv_usec = 0;
12357268Sbostic 	} while (rwait(&tv) && read(0, &c, 1) == 1);
12457268Sbostic }
12557268Sbostic 
12657268Sbostic /*
12757268Sbostic  * getchar with timeout.
12857268Sbostic  */
12957268Sbostic int
tgetchar()13057268Sbostic tgetchar()
13157268Sbostic {
13257268Sbostic 	static struct timeval timeleft;
13357268Sbostic 	char c;
13457268Sbostic 
13557268Sbostic 	/*
13657268Sbostic 	 * Reset timeleft to fallrate whenever it is not positive.
13757268Sbostic 	 * In any case, wait to see if there is any input.  If so,
13857268Sbostic 	 * take it, and update timeleft so that the next call to
13957268Sbostic 	 * tgetchar() will not wait as long.  If there is no input,
14057268Sbostic 	 * make timeleft zero or negative, and return -1.
14157268Sbostic 	 *
14257268Sbostic 	 * Most of the hard work is done by rwait().
14357268Sbostic 	 */
14457268Sbostic 	if (!TV_POS(&timeleft)) {
14557268Sbostic 		faster();	/* go faster */
14657268Sbostic 		timeleft.tv_sec = 0;
14757268Sbostic 		timeleft.tv_usec = fallrate;
14857268Sbostic 	}
14957268Sbostic 	if (!rwait(&timeleft))
15057268Sbostic 		return (-1);
15157268Sbostic 	if (read(0, &c, 1) != 1)
15257268Sbostic 		stop("end of file, help");
15357268Sbostic 	return ((int)(unsigned char)c);
15457268Sbostic }
155