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