1 /* $OpenBSD: input.c,v 1.19 2017/08/13 02:12:16 tedu 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 <sys/time.h> 43 44 #include <errno.h> 45 #include <poll.h> 46 #include <time.h> 47 #include <unistd.h> 48 49 #include "input.h" 50 #include "tetris.h" 51 52 /* return true iff the given timespec is positive */ 53 #define TS_POS(ts) \ 54 ((ts)->tv_sec > 0 || ((ts)->tv_sec == 0 && (ts)->tv_nsec > 0)) 55 56 /* 57 * Do a `read wait': poll for reading from stdin, with timeout *limit. 58 * On return, subtract the time spent waiting from *limit. 59 * It will be positive only if input appeared before the time ran out; 60 * otherwise it will be zero or perhaps negative. 61 * 62 * If limit is NULL, wait forever, but return if poll is interrupted. 63 * 64 * Return 0 => no input, 1 => can read() from stdin, -1 => interrupted 65 */ 66 int 67 rwait(struct timespec *limit) 68 { 69 struct timespec start, end, elapsed; 70 struct pollfd pfd[1]; 71 72 pfd[0].fd = STDIN_FILENO; 73 pfd[0].events = POLLIN; 74 75 if (limit != NULL) 76 clock_gettime(CLOCK_MONOTONIC, &start); 77 again: 78 switch (ppoll(pfd, 1, limit, NULL)) { 79 case -1: 80 if (limit == NULL) 81 return (-1); 82 if (errno == EINTR) 83 goto again; 84 stop("poll failed, help"); 85 case 0: /* timed out */ 86 timespecclear(limit); 87 return (0); 88 } 89 if (limit != NULL) { 90 /* we have input, so subtract the elapsed time from *limit */ 91 clock_gettime(CLOCK_MONOTONIC, &end); 92 timespecsub(&end, &start, &elapsed); 93 timespecsub(limit, &elapsed, limit); 94 } 95 return (1); 96 } 97 98 /* 99 * `sleep' for the current turn time and eat any 100 * input that becomes available. 101 */ 102 void 103 tsleep(void) 104 { 105 struct timespec ts; 106 char c; 107 108 ts.tv_sec = 0; 109 ts.tv_nsec = fallrate; 110 while (TS_POS(&ts)) 111 if (rwait(&ts) && read(STDIN_FILENO, &c, 1) != 1) 112 break; 113 } 114 115 /* 116 * getchar with timeout. 117 */ 118 int 119 tgetchar(void) 120 { 121 static struct timespec timeleft; 122 char c; 123 124 /* 125 * Reset timeleft to fallrate whenever it is not positive. 126 * In any case, wait to see if there is any input. If so, 127 * take it, and update timeleft so that the next call to 128 * tgetchar() will not wait as long. If there is no input, 129 * make timeleft zero or negative, and return -1. 130 * 131 * Most of the hard work is done by rwait(). 132 */ 133 if (!TS_POS(&timeleft)) { 134 faster(); /* go faster */ 135 timeleft.tv_sec = 0; 136 timeleft.tv_nsec = fallrate; 137 } 138 if (!rwait(&timeleft)) 139 return (-1); 140 if (read(STDIN_FILENO, &c, 1) != 1) 141 stop("end of file, help"); 142 return ((int)(unsigned char)c); 143 } 144