98e93bcbb82562569e25672396f2a366fc66255d
[openafs.git] / src / lwp / waitkey.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  *
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 /*
11  * LWP_WaitForKeystroke - wait indefinitely or for a specified number of
12  * seconds for keyboard input.
13  *
14  * If seconds < 0, LWP_WaitForKeystroke will wait indefinitely.
15  * If seconds == 0, LWP_WaitForKeystroke will just determine if data is now
16  *      present.
17  * Otherwise, wait "seconds" for data.
18  *
19  * Return 1 if data available.
20  */
21
22 #include <afsconfig.h>
23 #include <afs/param.h>
24
25
26 #include <stdio.h>
27 #include <sys/types.h>
28 #ifdef AFS_NT40_ENV
29 #include <time.h>
30 #include <conio.h>
31 #include <assert.h>
32 #else
33 #include <sys/time.h>
34 #include <unistd.h>
35 #endif
36 #include <string.h>
37 #include "lwp.h"
38
39 #define LWP_KEYSTROKE_DELAY   250       /* 250ms. Must be < 1000 */
40 #define LWP_MAXLINELEN  256
41
42 #ifdef AFS_NT40_ENV
43 /* LWP_WaitForKeystroke : Wait until a key has been struck or time (secconds)
44  * runs out and return to caller. The NT version of this function will return
45  * immediately after a key has been pressed (doesn't wait for cr).
46  * Input:
47  *   seconds: wait for <seconds> seconds before returning. If seconds < 0,
48  *            wait infinitely.
49  * Return Value:
50  *    1:  Keyboard input available
51  *    0:  seconds elapsed. Timeout.
52  */
53 int
54 LWP_WaitForKeystroke(int seconds)
55 {
56     time_t startTime, nowTime;
57     double timeleft = 1;
58     struct timeval twait;
59
60     time(&startTime);
61
62     twait.tv_sec = 0;
63     twait.tv_usec = LWP_KEYSTROKE_DELAY;
64
65     if (seconds >= 0)
66         timeleft = seconds;
67
68     do {
69         /* check if we have a keystroke */
70         if (_kbhit())
71             return 1;
72
73         if (timeleft == 0)
74             break;
75
76         /* sleep for  LWP_KEYSTROKE_DELAY ms and let other
77          * process run some*/
78         IOMGR_Select(0, 0, 0, 0, &twait);
79
80         if (seconds > 0) {      /* we only worry about elapsed time if
81                                  * not looping forever (seconds < 0) */
82             /* now check elapsed time */
83             time(&nowTime);
84             timeleft = seconds - difftime(nowTime, startTime);
85         }
86     }
87     while (timeleft > 0);
88
89     return 0;
90 }
91
92 /* LWP_GetLine() - Waits indefinitely until a newline has been typed
93  * and then returns the line typed.
94  *
95  * This is trivial in unix, but requires some processing on NT.
96  *   we basically read all chars into a buffer until we hit a newline and
97  *   then return it to the user.
98  * Return Value:
99  *   n - a whole line has been read.(has n chars)
100  *   0 - buf not big enough.
101  *   -1 - line with only EOF
102  */
103
104 int
105 LWP_GetLine(char *linebuf, int len)
106 {
107     int cnt = 0;
108     int ch = 0;
109
110     fflush(stdin);
111     /* loop until a new line has been entered */
112     while (ch != '\r' && cnt < len - 1) {
113         LWP_WaitForKeystroke(-1);
114         ch = getch();
115
116         if ((ch == EOF) && (cnt == 0))
117             return -1;
118
119         if (ch == '\b') {       /* print and throw away a backspace */
120             if (!cnt)           /* if we are at the start of the line don't bspace */
121                 continue;
122             /* print a space to delete char and move cursor back */
123             printf("\b \b");
124             cnt--;
125         } else {
126             putchar(ch);
127             linebuf[cnt++] = ch;
128         }
129     }
130
131     if (ch == '\r') {           /* got a cr. translate to nl */
132         linebuf[cnt - 1] = '\n';
133         linebuf[cnt] = '\0';
134         putchar('\n');
135         return cnt;
136     } else {                    /* buffer too small */
137         linebuf[cnt] = '\0';
138         return 0;
139     }
140
141 }
142 #else
143 /* LWP_WaitForKeystroke(Unix) :Wait until a key has been struck or time (secconds)
144  * runs out and return to caller. The Unix version will actually wait until
145  * a <cr> has been entered before returning.
146  * Input:
147  *   seconds: wait for <seconds> seconds before returning. If seconds < 0,
148  *            wait infinitely.
149  * Return Value:
150  *    1:  Keyboard input available
151  *    0:  seconds elapsed. Timeout.
152  */
153 int
154 LWP_WaitForKeystroke(int seconds)
155 {
156     fd_set rdfds;
157     int code;
158     struct timeval twait;
159     struct timeval *tp = NULL;
160
161 #ifdef AFS_LINUX20_ENV
162     if (stdin->_IO_read_ptr < stdin->_IO_read_end)
163         return 1;
164 #else
165 #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
166 #if defined(AFS_DFBSD_ENV)
167     struct appx_sbuf {
168       unsigned char *_base;
169       int     _size;
170     };
171     struct APPX_FILE
172     {
173       struct __FILE_public    pub;
174       struct  appx_sbuf _bf;     /* the buffer (at least 1 byte, if !NULL) */
175     };
176     struct APPX_FILE *appx_stdin = (struct APPX_FILE *) stdin;
177     if (appx_stdin->_bf._size > 0)
178         return 1;
179 #else
180     if (stdin->_bf._size > 0)
181         return 1;
182 #endif
183 #else
184     if (stdin->_cnt > 0)
185         return 1;
186 #endif
187 #endif
188
189     FD_ZERO(&rdfds);
190     FD_SET(fileno(stdin), &rdfds);
191
192     if (seconds >= 0) {
193         twait.tv_sec = seconds;
194         twait.tv_usec = 0;
195         tp = &twait;
196     }
197
198     code = IOMGR_Select(1 + fileno(stdin), &rdfds, NULL, NULL, tp);
199
200     return (code == 1) ? 1 : 0;
201 }
202
203 /* LWP_GetLine() - Waits indefinitely until a newline has been typed
204  * and then returns the line typed.
205  *
206  * This is trivial in unix, but requires some processing on NT.
207  *   we basically read all chars into a buffer until we hit a newline and
208  *   then return it to the user.
209  * Return Value:
210  *   n - a whole line has been read.(has n chars)
211  *   0 - buf not big enough.
212  *   -1 - line with only EOF
213  */
214
215 int
216 LWP_GetLine(char *linebuf, int len)
217 {
218     int linelen;
219     char *s;
220
221     LWP_WaitForKeystroke(-1);
222
223     s = fgets(linebuf, len, stdin);
224     if (s == NULL)
225         return -1;
226
227     linelen = strlen(linebuf);
228     if (linebuf[linelen - 1] != '\n')   /* buffer too small */
229         return 0;
230     else
231         return linelen;
232 }
233
234 #endif /* else NT40 */
235
236 /* LWP_GetResponseKey() - Waits for a specified period of time and
237  * returns a char when one has been typed by the user.
238  * Input:
239  *    seconds - how long to wait for a key press.
240  *    *key    - char entered by user
241  * Return Values:
242  *    0 - Time ran out before the user typed a key.
243  *    1 - Valid char is being returned.
244  */
245
246 int
247 LWP_GetResponseKey(int seconds, char *key)
248 {
249     int rc;
250
251     if (key == NULL)
252         return 0;               /* need space to store char */
253
254
255     fflush(stdin);              /* flush all existing data and start anew */
256
257
258     rc = LWP_WaitForKeystroke(seconds);
259     if (rc == 0) {              /* time ran out */
260         *key = 0;
261         return rc;
262     }
263
264     /* now read the char. */
265 #ifdef AFS_NT40_ENV
266     *key = getche();            /* get char and echo it to screen */
267 #else
268     *key = (char)getchar();
269 #endif
270
271     return rc;
272 }