input.c

Go to the documentation of this file.
00001 /*      $OpenBSD: input.c,v 1.12 2005/04/13 02:33:08 deraadt Exp $      */
00002 /*    $NetBSD: input.c,v 1.3 1996/02/06 22:47:33 jtc Exp $    */
00003 
00004 /*-
00005  * Copyright (c) 1992, 1993
00006  *      The Regents of the University of California.  All rights reserved.
00007  *
00008  * This code is derived from software contributed to Berkeley by
00009  * Chris Torek and Darren F. Provine.
00010  *
00011  * Redistribution and use in source and binary forms, with or without
00012  * modification, are permitted provided that the following conditions
00013  * are met:
00014  * 1. Redistributions of source code must retain the above copyright
00015  *    notice, this list of conditions and the following disclaimer.
00016  * 2. Redistributions in binary form must reproduce the above copyright
00017  *    notice, this list of conditions and the following disclaimer in the
00018  *    documentation and/or other materials provided with the distribution.
00019  * 3. Neither the name of the University nor the names of its contributors
00020  *    may be used to endorse or promote products derived from this software
00021  *    without specific prior written permission.
00022  *
00023  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
00024  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00025  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00026  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
00027  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00028  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00029  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00030  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00031  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00032  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00033  * SUCH DAMAGE.
00034  *
00035  *      @(#)input.c     8.1 (Berkeley) 5/31/93
00036  */
00037 
00044 /*
00045  * Top input.
00046  */
00047 
00048 #include <sys/types.h>
00049 #include <sys/time.h>
00050 #include <stdio.h>
00051 
00052 #include <stdlib.h>
00053 #include <errno.h>
00054 #include <unistd.h>
00055 #include <str.h>
00056 
00057 #include "input.h"
00058 
00059 #include <async.h>
00060 #include <vfs/vfs.h>
00061 #include <io/console.h>
00062 #include <ipc/console.h>
00063 
00064 #define USEC_COUNT 1000000
00065 
00066 /* return true iff the given timeval is positive */
00067 #define TV_POS(tv) \
00068         ((tv)->tv_sec > 0 || ((tv)->tv_sec == 0 && (tv)->tv_usec > 0))
00069 
00070 /* subtract timeval `sub' from `res' */
00071 #define TV_SUB(res, sub) \
00072         (res)->tv_sec -= (sub)->tv_sec; \
00073         (res)->tv_usec -= (sub)->tv_usec; \
00074         if ((res)->tv_usec < 0) { \
00075                 (res)->tv_usec += 1000000; \
00076                 (res)->tv_sec--; \
00077         }
00078 
00079 /* We will use a hack here - if lastchar is non-zero, it is
00080  * the last character read. We will somehow simulate the select
00081  * semantics.
00082  */
00083 static aid_t getchar_inprog = 0;
00084 static char lastchar = '\0';
00085 
00086 /*
00087  * Do a `read wait': select for reading from stdin, with timeout *tvp.
00088  * On return, modify *tvp to reflect the amount of time spent waiting.
00089  * It will be positive only if input appeared before the time ran out;
00090  * otherwise it will be zero or perhaps negative.
00091  *
00092  * If tvp is nil, wait forever, but return if select is interrupted.
00093  *
00094  * Return 0 => no input, 1 => can read() from stdin
00095  *
00096  */
00097 int rwait(struct timeval *tvp)
00098 {
00099         struct timeval starttv, endtv, *s;
00100         static ipc_call_t charcall;
00101         sysarg_t rc;
00102         
00103         /*
00104          * Someday, select() will do this for us.
00105          * Just in case that day is now, and no one has
00106          * changed this, we use a temporary.
00107          */
00108         if (tvp) {
00109                 (void) gettimeofday(&starttv, NULL);
00110                 endtv = *tvp;
00111                 s = &endtv;
00112         } else
00113                 s = NULL;
00114         
00115         if (!lastchar) {
00116 again:
00117                 if (!getchar_inprog) {
00118                         getchar_inprog = async_send_0(fphone(stdin),
00119                             CONSOLE_GET_EVENT, &charcall);
00120                 }
00121                 
00122                 if (!s)
00123                         async_wait_for(getchar_inprog, &rc);
00124                 else if (async_wait_timeout(getchar_inprog, &rc, s->tv_usec) == ETIMEOUT) {
00125                         tvp->tv_sec = 0;
00126                         tvp->tv_usec = 0;
00127                         return (0);
00128                 }
00129                 
00130                 getchar_inprog = 0;
00131                 if (rc) {
00132                         printf("End of file, bug?\n");
00133                         exit(1);
00134                 }
00135                 
00136                 if (IPC_GET_ARG1(charcall) == KEY_RELEASE)
00137                         goto again;
00138                 
00139                 lastchar = IPC_GET_ARG4(charcall);
00140         }
00141         
00142         if (tvp) {
00143                 /* since there is input, we may not have timed out */
00144                 (void) gettimeofday(&endtv, NULL);
00145                 TV_SUB(&endtv, &starttv);
00146                 TV_SUB(tvp, &endtv);  /* adjust *tvp by elapsed time */
00147         }
00148         
00149         return 1;
00150 }
00151 
00152 /*
00153  * `sleep' for the current turn time (using select).
00154  * Eat any input that might be available.
00155  */
00156 void tsleep(unsigned int sec)
00157 {
00158         struct timeval tv;
00159         
00160         tv.tv_sec = 0;
00161         tv.tv_usec = sec * USEC_COUNT;
00162         while (TV_POS(&tv))
00163                 if (rwait(&tv)) {
00164                         lastchar = '\0';
00165                 } else
00166                         break;
00167 }
00168 
00169 /*
00170  * getchar with timeout.
00171  */
00172 int tgetchar(unsigned int sec)
00173 {
00174         static struct timeval timeleft;
00175         char c;
00176         
00177         /*
00178          * Reset timeleft to USEC_COUNT whenever it is not positive.
00179          * In any case, wait to see if there is any input.  If so,
00180          * take it, and update timeleft so that the next call to
00181          * tgetchar() will not wait as long.  If there is no input,
00182          * make timeleft zero or negative, and return -1.
00183          *
00184          * Most of the hard work is done by rwait().
00185          */
00186         if (!TV_POS(&timeleft)) {
00187                 timeleft.tv_sec = 0;
00188                 timeleft.tv_usec = sec * USEC_COUNT;
00189         }
00190         
00191         if (!rwait(&timeleft))
00192                 return -1;
00193         
00194         c = lastchar;
00195         lastchar = '\0';
00196         return ((int) (unsigned char) c);
00197 }
00198 

Generated on Thu Jun 2 07:45:41 2011 for HelenOS/USB by  doxygen 1.4.7