
1: /* $NetBSD: input.c,v 1.9 2003/08/07 09:37:47 agc Exp $ */ 2: 3: /*- 4: * Copyright (c) 1992, 1993 5: * The Regents of the University of California. All rights reserved. 6: * 7: * This code is derived from software contributed to Berkeley by 8: * Chris Torek and Darren F. Provine. 9: * 10: * Redistribution and use in source and binary forms, with or without 11: * modification, are permitted provided that the following conditions 12: * are met: 13: * 1. Redistributions of source code must retain the above copyright 14: * notice, this list of conditions and the following disclaimer. 15: * 2. Redistributions in binary form must reproduce the above copyright 16: * notice, this list of conditions and the following disclaimer in the 17: * documentation and/or other materials provided with the distribution. 18: * 3. Neither the name of the University nor the names of its contributors 19: * may be used to endorse or promote products derived from this software 20: * without specific prior written permission. 21: * 22: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32: * SUCH DAMAGE. 33: * 34: * @(#)input.c 8.1 (Berkeley) 5/31/93 35: */ 36: 37: /* 38: * Tetris input. 39: */ 40: 41: #include <sys/types.h> 42: #include <sys/time.h> 43: #include <sys/poll.h> 44: 45: #include <errno.h> 46: #include <unistd.h> 47: 48: #include "input.h" 49: #include "tetris.h" 50: 51: /* return true iff the given timeval is positive */ 52: #define TV_POS(tv) \ 53: ((tv)->tv_sec > 0 || ((tv)->tv_sec == 0 && (tv)->tv_usec > 0)) 54: 55: /* subtract timeval `sub' from `res' */ 56: #define TV_SUB(res, sub) \ 57: (res)->tv_sec -= (sub)->tv_sec; \ 58: (res)->tv_usec -= (sub)->tv_usec; \ 59: if ((res)->tv_usec < 0) { \ 60: (res)->tv_usec += 1000000; \ 61: (res)->tv_sec--; \ 62: } 63: 64: /* 65: * Do a `read wait': poll for reading from stdin, with timeout *tvp. 66: * On return, modify *tvp to reflect the amount of time spent waiting. 67: * It will be positive only if input appeared before the time ran out; 68: * otherwise it will be zero or perhaps negative. 69: * 70: * If tvp is nil, wait forever, but return if poll is interrupted. 71: * 72: * Return 0 => no input, 1 => can read() from stdin 73: */ 74: int 75: rwait(tvp) 76: struct timeval *tvp; 77: { 78: struct pollfd set[1]; 79: struct timeval starttv, endtv; 80: int timeout; 81: #define NILTZ ((struct timezone *)0) 82: 83: if (tvp) { 84: (void) gettimeofday(&starttv, NILTZ); 85: endtv = *tvp; 86: timeout = tvp->tv_sec * 1000 + tvp->tv_usec / 1000; 87: } else 88: timeout = INFTIM; 89: again: 90: set[0].fd = STDIN_FILENO; 91: set[0].events = POLLIN; 92: switch (poll(set, 1, timeout)) { 93: 94: case -1: 95: if (tvp == 0) 96: return (-1); 97: if (errno == EINTR) 98: goto again; 99: stop("poll failed, help"); 100: /* NOTREACHED */ 101: 102: case 0: /* timed out */ 103: tvp->tv_sec = 0; 104: tvp->tv_usec = 0; 105: return (0); 106: } 107: if (tvp) { 108: /* since there is input, we may not have timed out */ 109: (void) gettimeofday(&endtv, NILTZ); 110: TV_SUB(&endtv, &starttv); 111: TV_SUB(tvp, &endtv); /* adjust *tvp by elapsed time */ 112: } 113: return (1); 114: } 115: 116: /* 117: * `sleep' for the current turn time. 118: * Eat any input that might be available. 119: */ 120: void 121: tsleep() 122: { 123: struct timeval tv; 124: char c; 125: 126: tv.tv_sec = 0; 127: tv.tv_usec = fallrate; 128: while (TV_POS(&tv)) 129: if (rwait(&tv) && read(0, &c, 1) != 1) 130: break; 131: } 132: 133: /* 134: * getchar with timeout. 135: */ 136: int 137: tgetchar() 138: { 139: static struct timeval timeleft; 140: char c; 141: 142: /* 143: * Reset timeleft to fallrate whenever it is not positive. 144: * In any case, wait to see if there is any input. If so, 145: * take it, and update timeleft so that the next call to 146: * tgetchar() will not wait as long. If there is no input, 147: * make timeleft zero or negative, and return -1. 148: * 149: * Most of the hard work is done by rwait(). 150: */ 151: if (!TV_POS(&timeleft)) { 152: faster(); /* go faster */ 153: timeleft.tv_sec = 0; 154: timeleft.tv_usec = fallrate; 155: } 156: if (!rwait(&timeleft)) 157: return (-1); 158: if (read(0, &c, 1) != 1) 159: stop("end of file, help"); 160: return ((int)(unsigned char)c); 161: }