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