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