Commit | Line | Data |
---|---|---|
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 | */ | |
49 | int | |
50 | rwait(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; | |
69 | again: | |
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 | */ | |
99 | void | |
100 | tsleep() | |
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 | */ | |
115 | void | |
116 | eat_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 | */ | |
129 | int | |
130 | tgetchar() | |
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 | } |