11ef20b8d656dcd6fe7d72e16663eff342856055
[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 #include <roken.h>
26
27 #ifdef HAVE_STDIO_EXT_H
28 #include <stdio_ext.h>
29 #endif
30
31 #ifdef AFS_NT40_ENV
32 #include <conio.h>
33 #endif
34
35 #include "lwp.h"
36
37 #define LWP_KEYSTROKE_DELAY   250       /* 250ms. Must be < 1000 */
38 #define LWP_MAXLINELEN  256
39
40 #ifdef AFS_NT40_ENV
41 /* LWP_WaitForKeystroke : Wait until a key has been struck or time (secconds)
42  * runs out and return to caller. The NT version of this function will return
43  * immediately after a key has been pressed (doesn't wait for cr).
44  * Input:
45  *   seconds: wait for <seconds> seconds before returning. If seconds < 0,
46  *            wait infinitely.
47  * Return Value:
48  *    1:  Keyboard input available
49  *    0:  seconds elapsed. Timeout.
50  */
51 int
52 LWP_WaitForKeystroke(int seconds)
53 {
54     time_t startTime, nowTime;
55     double timeleft = 1;
56 #ifndef AFS_PTHREAD_ENV
57     struct timeval twait;
58
59     twait.tv_sec = 0;
60     twait.tv_usec = LWP_KEYSTROKE_DELAY;
61 #endif
62
63     time(&startTime);
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 #ifdef AFS_PTHREAD_ENV
79         Sleep(LWP_KEYSTROKE_DELAY);
80 #else
81         IOMGR_Select(0, 0, 0, 0, &twait);
82 #endif
83         if (seconds > 0) {      /* we only worry about elapsed time if
84                                  * not looping forever (seconds < 0) */
85             /* now check elapsed time */
86             time(&nowTime);
87             timeleft = seconds - difftime(nowTime, startTime);
88         }
89     }
90     while (timeleft > 0);
91
92     return 0;
93 }
94
95 /* LWP_GetLine() - Waits indefinitely until a newline has been typed
96  * and then returns the line typed.
97  *
98  * This is trivial in unix, but requires some processing on NT.
99  *   we basically read all chars into a buffer until we hit a newline and
100  *   then return it to the user.
101  * Return Value:
102  *   n - a whole line has been read.(has n chars)
103  *   0 - buf not big enough.
104  *   -1 - line with only EOF
105  */
106
107 int
108 LWP_GetLine(char *linebuf, int len)
109 {
110     int cnt = 0;
111     int ch = 0;
112
113     fflush(stdin);
114     /* loop until a new line has been entered */
115     while (ch != '\r' && cnt < len - 1) {
116         LWP_WaitForKeystroke(-1);
117         ch = getch();
118
119         if ((ch == EOF) && (cnt == 0))
120             return -1;
121
122         if (ch == '\b') {       /* print and throw away a backspace */
123             if (!cnt)           /* if we are at the start of the line don't bspace */
124                 continue;
125             /* print a space to delete char and move cursor back */
126             printf("\b \b");
127             cnt--;
128         } else {
129             putchar(ch);
130             linebuf[cnt++] = ch;
131         }
132     }
133
134     if (ch == '\r') {           /* got a cr. translate to nl */
135         linebuf[cnt - 1] = '\n';
136         linebuf[cnt] = '\0';
137         putchar('\n');
138         return cnt;
139     } else {                    /* buffer too small */
140         linebuf[cnt] = '\0';
141         return 0;
142     }
143
144 }
145 #else
146 /* LWP_WaitForKeystroke(Unix) :Wait until a key has been struck or time (secconds)
147  * runs out and return to caller. The Unix version will actually wait until
148  * a <cr> has been entered before returning.
149  * Input:
150  *   seconds: wait for <seconds> seconds before returning. If seconds < 0,
151  *            wait infinitely.
152  * Return Value:
153  *    1:  Keyboard input available
154  *    0:  seconds elapsed. Timeout.
155  */
156 int
157 LWP_WaitForKeystroke(int seconds)
158 {
159     fd_set rdfds;
160     int code;
161     struct timeval twait;
162     struct timeval *tp = NULL;
163
164 #if defined(HAVE_STDIO_EXT_H)
165     if (__fbufsize(stdin) > 0)
166         return 1;
167 #elif defined(AFS_LINUX20_ENV)
168     if (stdin->_IO_read_ptr < stdin->_IO_read_end)
169         return 1;
170 #elif (defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)) && defined(AFS_DFBSD_ENV)
171     struct appx_sbuf {
172       unsigned char *_base;
173       int     _size;
174     };
175     struct APPX_FILE
176     {
177       struct __FILE_public    pub;
178       struct  appx_sbuf _bf;     /* the buffer (at least 1 byte, if !NULL) */
179     };
180     struct APPX_FILE *appx_stdin = (struct APPX_FILE *) stdin;
181     if (appx_stdin->_bf._size > 0)
182         return 1;
183 #elif defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
184     if (stdin->_bf._size > 0)
185         return 1;
186 #else
187     if (stdin->_cnt > 0)
188         return 1;
189 #endif
190
191     FD_ZERO(&rdfds);
192     FD_SET(fileno(stdin), &rdfds);
193
194     if (seconds >= 0) {
195         twait.tv_sec = seconds;
196         twait.tv_usec = 0;
197         tp = &twait;
198     }
199
200 #ifdef AFS_PTHREAD_ENV
201     code = select(1 + fileno(stdin), &rdfds, NULL, NULL, tp);
202 #else
203     code = IOMGR_Select(1 + fileno(stdin), &rdfds, NULL, NULL, tp);
204 #endif
205
206     return (code == 1) ? 1 : 0;
207 }
208
209 /* LWP_GetLine() - Waits indefinitely until a newline has been typed
210  * and then returns the line typed.
211  *
212  * This is trivial in unix, but requires some processing on NT.
213  *   we basically read all chars into a buffer until we hit a newline and
214  *   then return it to the user.
215  * Return Value:
216  *   n - a whole line has been read.(has n chars)
217  *   0 - buf not big enough.
218  *   -1 - line with only EOF
219  */
220
221 int
222 LWP_GetLine(char *linebuf, int len)
223 {
224     int linelen;
225     char *s;
226
227     LWP_WaitForKeystroke(-1);
228
229     s = fgets(linebuf, len, stdin);
230     if (s == NULL)
231         return -1;
232
233     linelen = strlen(linebuf);
234     if (linebuf[linelen - 1] != '\n')   /* buffer too small */
235         return 0;
236     else
237         return linelen;
238 }
239
240 #endif /* else NT40 */
241
242 /* LWP_GetResponseKey() - Waits for a specified period of time and
243  * returns a char when one has been typed by the user.
244  * Input:
245  *    seconds - how long to wait for a key press.
246  *    *key    - char entered by user
247  * Return Values:
248  *    0 - Time ran out before the user typed a key.
249  *    1 - Valid char is being returned.
250  */
251
252 int
253 LWP_GetResponseKey(int seconds, char *key)
254 {
255     int rc;
256
257     if (key == NULL)
258         return 0;               /* need space to store char */
259
260
261     fflush(stdin);              /* flush all existing data and start anew */
262
263
264     rc = LWP_WaitForKeystroke(seconds);
265     if (rc == 0) {              /* time ran out */
266         *key = 0;
267         return rc;
268     }
269
270     /* now read the char. */
271 #ifdef AFS_NT40_ENV
272     *key = getche();            /* get char and echo it to screen */
273 #else
274     *key = (char)getchar();
275 #endif
276
277     return rc;
278 }