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