4.4BSD snapshot (revision 8.1); add 1993 to copyright
[unix-history] / usr / src / games / tetris / input.c
CommitLineData
bc443be7 1/*-
6601dd48
KB
2 * Copyright (c) 1992, 1993
3 * The Regents of the University of California. All rights reserved.
bc443be7 4 *
05932cb9
KB
5 * This code is derived from software contributed to Berkeley by
6 * Chris Torek and Darren F. Provine.
7 *
bc443be7
KB
8 * %sccs.include.redist.c%
9 *
6601dd48 10 * @(#)input.c 8.1 (Berkeley) %G%
bc443be7
KB
11 */
12
13/*
14 * Tetris input.
15 */
16
17#include <sys/types.h>
18#include <sys/time.h>
05932cb9 19
bc443be7
KB
20#include <errno.h>
21#include <unistd.h>
22
23#include "input.h"
24#include "tetris.h"
25
26/* return true iff the given timeval is positive */
27#define TV_POS(tv) \
28 ((tv)->tv_sec > 0 || ((tv)->tv_sec == 0 && (tv)->tv_usec > 0))
29
30/* subtract timeval `sub' from `res' */
31#define TV_SUB(res, sub) \
32 (res)->tv_sec -= (sub)->tv_sec; \
33 (res)->tv_usec -= (sub)->tv_usec; \
34 if ((res)->tv_usec < 0) { \
35 (res)->tv_usec += 1000000; \
36 (res)->tv_sec--; \
37 }
38
39/*
40 * Do a `read wait': select for reading from stdin, with timeout *tvp.
41 * On return, modify *tvp to reflect the amount of time spent waiting.
42 * It will be positive only if input appeared before the time ran out;
43 * otherwise it will be zero or perhaps negative.
44 *
45 * If tvp is nil, wait forever, but return if select is interrupted.
46 *
47 * Return 0 => no input, 1 => can read() from stdin
48 */
49int
50rwait(tvp)
51 register struct timeval *tvp;
52{
53 int i;
54 struct timeval starttv, endtv, *s;
55 extern int errno;
56#define NILTZ ((struct timezone *)0)
57
58 /*
59 * Someday, select() will do this for us.
60 * Just in case that day is now, and no one has
61 * changed this, we use a temporary.
62 */
63 if (tvp) {
64 (void) gettimeofday(&starttv, NILTZ);
65 endtv = *tvp;
66 s = &endtv;
67 } else
68 s = 0;
69again:
70 i = 1;
71 switch (select(1, (fd_set *)&i, (fd_set *)0, (fd_set *)0, s)) {
72
73 case -1:
74 if (tvp == 0)
75 return (-1);
76 if (errno == EINTR)
77 goto again;
78 stop("select failed, help");
79 /* NOTREACHED */
80
81 case 0: /* timed out */
82 tvp->tv_sec = 0;
83 tvp->tv_usec = 0;
84 return (0);
85 }
86 if (tvp) {
87 /* since there is input, we may not have timed out */
88 (void) gettimeofday(&endtv, NILTZ);
89 TV_SUB(&endtv, &starttv);
90 TV_SUB(tvp, &endtv); /* adjust *tvp by elapsed time */
91 }
92 return (1);
93}
94
95/*
96 * `sleep' for the current turn time (using select).
97 * Eat any input that might be available.
98 */
99void
100tsleep()
101{
102 struct timeval tv;
103 char c;
104
105 tv.tv_sec = 0;
106 tv.tv_usec = fallrate;
107 while (TV_POS(&tv))
108 if (rwait(&tv) && read(0, &c, 1) != 1)
109 break;
110}
111
112/*
113 * Eat up any input (used at end of game).
114 */
115void
116eat_input()
117{
118 struct timeval tv;
119 char c;
120
121 do {
122 tv.tv_sec = tv.tv_usec = 0;
123 } while (rwait(&tv) && read(0, &c, 1) == 1);
124}
125
126/*
127 * getchar with timeout.
128 */
129int
130tgetchar()
131{
132 static struct timeval timeleft;
133 char c;
134
135 /*
136 * Reset timeleft to fallrate whenever it is not positive.
137 * In any case, wait to see if there is any input. If so,
138 * take it, and update timeleft so that the next call to
139 * tgetchar() will not wait as long. If there is no input,
140 * make timeleft zero or negative, and return -1.
141 *
142 * Most of the hard work is done by rwait().
143 */
144 if (!TV_POS(&timeleft)) {
145 faster(); /* go faster */
146 timeleft.tv_sec = 0;
147 timeleft.tv_usec = fallrate;
148 }
149 if (!rwait(&timeleft))
150 return (-1);
151 if (read(0, &c, 1) != 1)
152 stop("end of file, help");
153 return ((int)(unsigned char)c);
154}