[gforth] / gforth / engine / io.c  

gforth: gforth/engine/io.c


1 : anton 1.10 /* direct key io driver
2 : anton 1.1
3 : anton 1.12 Copyright (C) 1995,1996,1997,1998,1999 Free Software Foundation, Inc.
4 : anton 1.1
5 :     This file is part of Gforth.
6 :    
7 :     Gforth is free software; you can redistribute it and/or
8 :     modify it under the terms of the GNU General Public License
9 :     as published by the Free Software Foundation; either version 2
10 :     of the License, or (at your option) any later version.
11 :    
12 :     This program is distributed in the hope that it will be useful,
13 :     but WITHOUT ANY WARRANTY; without even the implied warranty of
14 :     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 :     GNU General Public License for more details.
16 :    
17 :     You should have received a copy of the GNU General Public License
18 :     along with this program; if not, write to the Free Software
19 :     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 :    
21 :     The following is stolen from the readline library for bash
22 :     */
23 :    
24 :     /*
25 :     Use -D_POSIX_VERSION for POSIX systems.
26 :     */
27 :    
28 :     #include "config.h"
29 : pazsan 1.7 #include <sys/time.h>
30 :     #include <sys/types.h>
31 : anton 1.1 #include <unistd.h>
32 :    
33 :     #if defined(apollo) || defined(_WIN32)
34 :     #define _POSIX_VERSION
35 :     #endif
36 :    
37 : pazsan 1.6 #if !defined(Solaris) && defined(sun) && defined(__svr4__)
38 :     #define Solaris
39 :     typedef unsigned int uint32_t;
40 :     #endif
41 :    
42 : anton 1.1 #include <stdio.h>
43 :     #include <signal.h>
44 :     #include <string.h>
45 :     #if !defined(apollo) && !defined(MSDOS)
46 :     #include <sys/ioctl.h>
47 :     #endif
48 :     #include <fcntl.h>
49 :     #include <sys/file.h>
50 :     #if defined(Solaris) && !defined(FIONREAD)
51 :     #include <sys/filio.h>
52 :     #endif
53 :     #include <setjmp.h>
54 :     #include "forth.h"
55 :     #include "io.h"
56 :    
57 :     #ifndef MSDOS
58 :     #if defined (__GNUC__)
59 :     # define alloca __builtin_alloca
60 :     #else
61 :     # if defined (sparc) || defined (HAVE_ALLOCA_H)
62 :     # include <alloca.h>
63 :     # endif
64 :     #endif
65 :    
66 :     #define NEW_TTY_DRIVER
67 :     #define HAVE_BSD_SIGNALS
68 :     /*
69 :     #ifndef apollo
70 :     #define USE_XON_XOFF
71 :     #endif
72 :     */
73 :    
74 :     #define HANDLE_SIGNALS
75 :    
76 :     /* Some USG machines have BSD signal handling (sigblock, sigsetmask, etc.) */
77 :     #if defined (USG) && !defined (hpux)
78 :     #undef HAVE_BSD_SIGNALS
79 :     #endif
80 :    
81 :     /* System V machines use termio. */
82 :     #if !defined (_POSIX_VERSION)
83 :     # if defined (USG) || defined (hpux) || defined (Xenix) || defined (sgi) || defined (DGUX) || defined (ultrix) || defined (Solaris) || defined(_WIN32)
84 :     # undef NEW_TTY_DRIVER
85 :     # define TERMIO_TTY_DRIVER
86 :     # include <termio.h>
87 :     # if !defined (TCOON)
88 :     # define TCOON 1
89 :     # endif
90 :     # endif /* USG || hpux || Xenix || sgi || DUGX || ultrix*/
91 :     #endif /* !_POSIX_VERSION */
92 :    
93 :     /* Posix systems use termios and the Posix signal functions. */
94 : pazsan 1.5 #if defined (_POSIX_VERSION) || defined (NeXT)
95 : anton 1.1 # if !defined (TERMIOS_MISSING)
96 :     # undef NEW_TTY_DRIVER
97 :     # define TERMIOS_TTY_DRIVER
98 :     # include <termios.h>
99 :     # endif /* !TERMIOS_MISSING */
100 : pazsan 1.5 #endif /* _POSIX_VERSION || NeXT */
101 :    
102 :     #if defined (_POSIX_VERSION)
103 : anton 1.1 # define HAVE_POSIX_SIGNALS
104 :     # if !defined (O_NDELAY)
105 :     # define O_NDELAY O_NONBLOCK /* Posix-style non-blocking i/o */
106 :     # endif /* O_NDELAY */
107 :     #endif /* _POSIX_VERSION */
108 :    
109 :     /* Other (BSD) machines use sgtty. */
110 :     #if defined (NEW_TTY_DRIVER)
111 :     #include <sgtty.h>
112 :     #endif
113 :    
114 :     /* Define _POSIX_VDISABLE if we are not using the `new' tty driver and
115 :     it is not already defined. It is used both to determine if a
116 :     special character is disabled and to disable certain special
117 :     characters. Posix systems should set to 0, USG systems to -1. */
118 :     #if !defined (NEW_TTY_DRIVER) && !defined (_POSIX_VDISABLE)
119 : pazsan 1.5 # if defined (_POSIX_VERSION) || defined (NeXT)
120 : anton 1.1 # define _POSIX_VDISABLE 0
121 :     # else /* !_POSIX_VERSION */
122 :     # define _POSIX_VDISABLE -1
123 :     # endif /* !_POSIX_VERSION */
124 :     #endif /* !NEW_TTY_DRIVER && !_POSIX_VDISABLE */
125 :    
126 :     #include <errno.h>
127 :     /* extern int errno; */
128 :    
129 :     #if defined (SHELL)
130 :     # include <posixstat.h>
131 :     #else
132 :     # include <sys/stat.h>
133 :     #endif /* !SHELL */
134 :     /* #define HACK_TERMCAP_MOTION */
135 :    
136 :     #if defined (USG) && defined (hpux)
137 :     # if !defined (USGr3)
138 :     # define USGr3
139 :     # endif /* USGr3 */
140 :     #endif /* USG && hpux */
141 :    
142 :     #if (defined (_POSIX_VERSION) || defined (USGr3)) && !defined(apollo)
143 :     # include <dirent.h>
144 :     # define direct dirent
145 :     # if defined (_POSIX_VERSION)
146 :     # define D_NAMLEN(d) (strlen ((d)->d_name))
147 :     # else /* !_POSIX_VERSION */
148 :     # define D_NAMLEN(d) ((d)->d_reclen)
149 :     # endif /* !_POSIX_VERSION */
150 :     #else /* !_POSIX_VERSION && !USGr3 */
151 :     # define D_NAMLEN(d) ((d)->d_namlen)
152 :     # if !defined (USG)
153 :     # include <sys/dir.h>
154 :     # else /* USG */
155 :     # if defined (Xenix)
156 :     # include <sys/ndir.h>
157 :     # else /* !Xenix */
158 :     # include <ndir.h>
159 :     # endif /* !Xenix */
160 :     # endif /* USG */
161 :     #endif /* !POSIX_VERSION && !USGr3 */
162 :    
163 :     #if defined (USG) && defined (TIOCGWINSZ)
164 :     # include <sys/stream.h>
165 :     # if defined (USGr4) || defined (USGr3)
166 :     # if defined (Symmetry) || defined (_SEQUENT_)
167 :     # include <sys/pte.h>
168 :     # else
169 :     # include <sys/ptem.h>
170 :     # endif /* !Symmetry || _SEQUENT_ */
171 :     # endif /* USGr4 */
172 :     #endif /* USG && TIOCGWINSZ */
173 :    
174 :     #if defined (TERMIOS_TTY_DRIVER)
175 :     static struct termios otio;
176 :     #else
177 :     static struct termio otio;
178 :     #endif /* !TERMIOS_TTY_DRIVER */
179 :    
180 :     /* Non-zero means echo characters as they are read. */
181 :     int readline_echoing_p = 1;
182 :    
183 :     /* The character that can generate an EOF. Really read from
184 :     the terminal driver... just defaulted here. */
185 :    
186 :     #ifndef CTRL
187 :     #define CTRL(key) ((key)-'@')
188 :     #endif
189 :    
190 :     static int eof_char = CTRL ('D');
191 :    
192 :     /* **************************************************************** */
193 :     /* */
194 :     /* Saving and Restoring the TTY */
195 :     /* */
196 :     /* **************************************************************** */
197 :    
198 :     /* Non-zero means that the terminal is in a prepped state. */
199 :     int terminal_prepped = 0;
200 :    
201 :     #if defined (NEW_TTY_DRIVER)
202 :    
203 :     /* Standard flags, including ECHO. */
204 :     static int original_tty_flags = 0;
205 :    
206 :     /* Local mode flags, like LPASS8. */
207 :     static int local_mode_flags = 0;
208 :    
209 :     /* Terminal characters. This has C-s and C-q in it. */
210 :     static struct tchars original_tchars;
211 :    
212 :     /* Local special characters. This has the interrupt characters in it. */
213 :     #if defined (TIOCGLTC)
214 :     static struct ltchars original_ltchars;
215 :     #endif
216 :    
217 :     /* Bind KEY to FUNCTION. Returns non-zero if KEY is out of range. */
218 :    
219 :     #if defined (TIOCGETC)
220 :     #if defined (USE_XON_XOFF)
221 :    
222 :     int
223 :     bind_key (key, function)
224 :     int key;
225 :     Function *function;
226 :     {
227 :     if (key < 0)
228 :     return (key);
229 :    
230 :     if (key > 127 && key < 256)
231 :     {
232 :     if (keymap[ESC].type == ISKMAP)
233 :     {
234 :     Keymap escmap = (Keymap)keymap[ESC].function;
235 :    
236 :     key -= 128;
237 :     escmap[key].type = ISFUNC;
238 :     escmap[key].function = function;
239 :     return (0);
240 :     }
241 :     return (key);
242 :     }
243 :    
244 :     keymap[key].type = ISFUNC;
245 :     keymap[key].function = function;
246 :     return (0);
247 :     }
248 :     #endif
249 :     #endif
250 :    
251 :     /* We use this to get and set the tty_flags. */
252 :     static struct sgttyb the_ttybuff;
253 :    
254 :     #if defined (USE_XON_XOFF)
255 :     /* If the terminal was in xoff state when we got to it, then xon_char
256 :     contains the character that is supposed to start it again. */
257 :     static int xon_char, xoff_state;
258 :     #endif /* USE_XON_XOFF */
259 :    
260 :     /* **************************************************************** */
261 :     /* */
262 :     /* Bogus Flow Control */
263 :     /* */
264 :     /* **************************************************************** */
265 :    
266 :     restart_output (count, key)
267 :     int count, key;
268 :     {
269 :     int fildes = fileno (stdin);
270 :     #if defined (TIOCSTART)
271 :     #if defined (apollo)
272 :     ioctl (&fildes, TIOCSTART, 0);
273 :     #else
274 :     ioctl (fildes, TIOCSTART, 0);
275 :     #endif /* apollo */
276 :    
277 :     #else
278 :     # if defined (TERMIOS_TTY_DRIVER)
279 :     tcflow (fildes, TCOON);
280 :     # else
281 :     # if defined (TCXONC)
282 :     ioctl (fildes, TCXONC, TCOON);
283 :     # endif /* TCXONC */
284 :     # endif /* !TERMIOS_TTY_DRIVER */
285 :     #endif /* TIOCSTART */
286 :     }
287 :    
288 :     /* Put the terminal in CBREAK mode so that we can detect key presses. */
289 :     void prep_terminal ()
290 :     {
291 :     int tty = fileno (stdin);
292 :     #if defined (HAVE_BSD_SIGNALS)
293 :     int oldmask;
294 :     #endif /* HAVE_BSD_SIGNALS */
295 :    
296 :     if (terminal_prepped)
297 :     return;
298 :    
299 :     if (!isatty(tty)) { /* added by MdG */
300 :     terminal_prepped = 1; /* added by MdG */
301 :     return; /* added by MdG */
302 :     } /* added by MdG */
303 :    
304 :     oldmask = sigblock (sigmask (SIGINT));
305 :    
306 :     /* We always get the latest tty values. Maybe stty changed them. */
307 :     ioctl (tty, TIOCGETP, &the_ttybuff);
308 :     original_tty_flags = the_ttybuff.sg_flags;
309 :    
310 :     readline_echoing_p = (original_tty_flags & ECHO);
311 :    
312 :     #if defined (TIOCLGET)
313 :     ioctl (tty, TIOCLGET, &local_mode_flags);
314 :     #endif
315 :    
316 :     #if !defined (ANYP)
317 :     # define ANYP (EVENP | ODDP)
318 :     #endif
319 :    
320 :     /* If this terminal doesn't care how the 8th bit is used,
321 :     then we can use it for the meta-key. We check by seeing
322 :     if BOTH odd and even parity are allowed. */
323 :     if (the_ttybuff.sg_flags & ANYP)
324 :     {
325 :     #if defined (PASS8)
326 :     the_ttybuff.sg_flags |= PASS8;
327 :     #endif
328 :    
329 :     /* Hack on local mode flags if we can. */
330 :     #if defined (TIOCLGET) && defined (LPASS8)
331 :     {
332 :     int flags;
333 :     flags = local_mode_flags | LPASS8;
334 :     ioctl (tty, TIOCLSET, &flags);
335 :     }
336 :     #endif /* TIOCLGET && LPASS8 */
337 :     }
338 :    
339 :     #if defined (TIOCGETC)
340 :     {
341 :     struct tchars temp;
342 :    
343 :     ioctl (tty, TIOCGETC, &original_tchars);
344 :     temp = original_tchars;
345 :    
346 :     #if defined (USE_XON_XOFF)
347 :     /* Get rid of C-s and C-q.
348 :     We remember the value of startc (C-q) so that if the terminal is in
349 :     xoff state, the user can xon it by pressing that character. */
350 :     xon_char = temp.t_startc;
351 :     temp.t_stopc = -1;
352 :     temp.t_startc = -1;
353 :    
354 :     /* If there is an XON character, bind it to restart the output. */
355 :     if (xon_char != -1)
356 :     bind_key (xon_char, restart_output);
357 :     #endif /* USE_XON_XOFF */
358 :    
359 :     /* If there is an EOF char, bind eof_char to it. */
360 :     if (temp.t_eofc != -1)
361 :     eof_char = temp.t_eofc;
362 :    
363 :     #if defined (NO_KILL_INTR)
364 :     /* Get rid of C-\ and C-c. */
365 :     temp.t_intrc = temp.t_quitc = -1;
366 :     #endif /* NO_KILL_INTR */
367 :    
368 :     ioctl (tty, TIOCSETC, &temp);
369 :     }
370 :     #endif /* TIOCGETC */
371 :    
372 :     #if defined (TIOCGLTC)
373 :     {
374 :     struct ltchars temp;
375 :    
376 :     ioctl (tty, TIOCGLTC, &original_ltchars);
377 :     temp = original_ltchars;
378 :    
379 :     /* Make the interrupt keys go away. Just enough to make people
380 :     happy. */
381 :     temp.t_dsuspc = -1; /* C-y */
382 :     temp.t_lnextc = -1; /* C-v */
383 :    
384 :     ioctl (tty, TIOCSLTC, &temp);
385 :     }
386 :     #endif /* TIOCGLTC */
387 :    
388 :     the_ttybuff.sg_flags &= ~(ECHO | CRMOD);
389 :     the_ttybuff.sg_flags |= CBREAK;
390 :     ioctl (tty, TIOCSETN, &the_ttybuff);
391 :    
392 :     terminal_prepped = 1;
393 :    
394 :     #if defined (HAVE_BSD_SIGNALS)
395 :     sigsetmask (oldmask);
396 :     #endif
397 :     }
398 :    
399 :     /* Restore the terminal to its original state. */
400 :     void deprep_terminal ()
401 :     {
402 :     int tty = fileno (stdin);
403 :     #if defined (HAVE_BSD_SIGNALS)
404 :     int oldmask;
405 :     #endif
406 :    
407 :     if (!terminal_prepped)
408 :     return;
409 :    
410 :     /* Added by MdG */
411 :     if (!isatty(tty)) {
412 :     terminal_prepped = 0;
413 :     return;
414 :     }
415 :    
416 :     oldmask = sigblock (sigmask (SIGINT));
417 :    
418 :     the_ttybuff.sg_flags = original_tty_flags;
419 :     ioctl (tty, TIOCSETN, &the_ttybuff);
420 :     readline_echoing_p = 1;
421 :    
422 :     #if defined (TIOCLGET)
423 :     ioctl (tty, TIOCLSET, &local_mode_flags);
424 :     #endif
425 :    
426 :     #if defined (TIOCSLTC)
427 :     ioctl (tty, TIOCSLTC, &original_ltchars);
428 :     #endif
429 :    
430 :     #if defined (TIOCSETC)
431 :     ioctl (tty, TIOCSETC, &original_tchars);
432 :     #endif
433 :     terminal_prepped = 0;
434 :    
435 :     #if defined (HAVE_BSD_SIGNALS)
436 :     sigsetmask (oldmask);
437 :     #endif
438 :     }
439 :    
440 :     #else /* !defined (NEW_TTY_DRIVER) */
441 :    
442 :     #if !defined (VMIN)
443 :     #define VMIN VEOF
444 :     #endif
445 :    
446 :     #if !defined (VTIME)
447 :     #define VTIME VEOL
448 :     #endif
449 :    
450 :     void prep_terminal ()
451 :     {
452 :     int tty = fileno (stdin);
453 :     #if defined (TERMIOS_TTY_DRIVER)
454 :     struct termios tio;
455 :     #else
456 :     struct termio tio;
457 :     #endif /* !TERMIOS_TTY_DRIVER */
458 :    
459 :     #if defined (HAVE_POSIX_SIGNALS)
460 :     sigset_t set, oset;
461 :     #else
462 :     # if defined (HAVE_BSD_SIGNALS)
463 :     int oldmask;
464 :     # endif /* HAVE_BSD_SIGNALS */
465 :     #endif /* !HAVE_POSIX_SIGNALS */
466 :    
467 :     if (terminal_prepped)
468 :     return;
469 :    
470 :     if (!isatty(tty)) { /* added by MdG */
471 :     terminal_prepped = 1; /* added by MdG */
472 :     return; /* added by MdG */
473 :     } /* added by MdG */
474 :    
475 :     /* Try to keep this function from being INTerrupted. We can do it
476 :     on POSIX and systems with BSD-like signal handling. */
477 :     #if defined (HAVE_POSIX_SIGNALS)
478 :     sigemptyset (&set);
479 :     sigemptyset (&oset);
480 :     sigaddset (&set, SIGINT);
481 :     sigprocmask (SIG_BLOCK, &set, &oset);
482 :     #else /* !HAVE_POSIX_SIGNALS */
483 :     # if defined (HAVE_BSD_SIGNALS)
484 :     oldmask = sigblock (sigmask (SIGINT));
485 :     # endif /* HAVE_BSD_SIGNALS */
486 :     #endif /* !HAVE_POSIX_SIGNALS */
487 :    
488 :     #if defined (TERMIOS_TTY_DRIVER)
489 :     tcgetattr (tty, &tio);
490 :     #else
491 :     ioctl (tty, TCGETA, &tio);
492 :     #endif /* !TERMIOS_TTY_DRIVER */
493 :    
494 :     otio = tio;
495 :    
496 :     readline_echoing_p = (tio.c_lflag & ECHO);
497 :    
498 :     tio.c_lflag &= ~(ICANON | ECHO);
499 :    
500 :     if (otio.c_cc[VEOF] != _POSIX_VDISABLE)
501 :     eof_char = otio.c_cc[VEOF];
502 :    
503 :     #if defined (USE_XON_XOFF)
504 :     #if defined (IXANY)
505 :     tio.c_iflag &= ~(IXON | IXOFF | IXANY);
506 :     #else
507 :     /* `strict' Posix systems do not define IXANY. */
508 :     tio.c_iflag &= ~(IXON | IXOFF);
509 :     #endif /* IXANY */
510 :     #endif /* USE_XON_XOFF */
511 :    
512 :     /* Only turn this off if we are using all 8 bits. */
513 :     if ((tio.c_cflag & CSIZE) == CS8)
514 :     tio.c_iflag &= ~(ISTRIP | INPCK);
515 :    
516 :     /* Make sure we differentiate between CR and NL on input. */
517 :     tio.c_iflag &= ~(ICRNL | INLCR);
518 :    
519 :     #if !defined (HANDLE_SIGNALS)
520 :     tio.c_lflag &= ~ISIG;
521 :     #else
522 :     tio.c_lflag |= ISIG;
523 :     #endif
524 :    
525 :     tio.c_cc[VMIN] = 1;
526 :     tio.c_cc[VTIME] = 0;
527 :    
528 :     /* Turn off characters that we need on Posix systems with job control,
529 :     just to be sure. This includes ^Y and ^V. This should not really
530 :     be necessary. */
531 :     #if defined (TERMIOS_TTY_DRIVER) && defined (_POSIX_JOB_CONTROL)
532 :    
533 :     #if defined (VLNEXT)
534 :     tio.c_cc[VLNEXT] = _POSIX_VDISABLE;
535 :     #endif
536 :    
537 :     #if defined (VDSUSP)
538 :     tio.c_cc[VDSUSP] = _POSIX_VDISABLE;
539 :     #endif
540 :    
541 :     #endif /* POSIX && JOB_CONTROL */
542 :    
543 :     #if defined (TERMIOS_TTY_DRIVER)
544 :     tcsetattr (tty, TCSADRAIN, &tio);
545 :     tcflow (tty, TCOON); /* Simulate a ^Q. */
546 :     #else
547 :     ioctl (tty, TCSETAW, &tio);
548 :     ioctl (tty, TCXONC, 1); /* Simulate a ^Q. */
549 :     #endif /* !TERMIOS_TTY_DRIVER */
550 :    
551 :     terminal_prepped = 1;
552 :    
553 :     #if defined (HAVE_POSIX_SIGNALS)
554 :     sigprocmask (SIG_SETMASK, &oset, (sigset_t *)NULL);
555 :     #else
556 :     # if defined (HAVE_BSD_SIGNALS)
557 :     sigsetmask (oldmask);
558 :     # endif /* HAVE_BSD_SIGNALS */
559 :     #endif /* !HAVE_POSIX_SIGNALS */
560 :     }
561 :    
562 :     void deprep_terminal ()
563 :     {
564 :     int tty = fileno (stdin);
565 :    
566 :     /* Try to keep this function from being INTerrupted. We can do it
567 :     on POSIX and systems with BSD-like signal handling. */
568 :     #if defined (HAVE_POSIX_SIGNALS)
569 :     sigset_t set, oset;
570 :     #else /* !HAVE_POSIX_SIGNALS */
571 :     # if defined (HAVE_BSD_SIGNALS)
572 :     int oldmask;
573 :     # endif /* HAVE_BSD_SIGNALS */
574 :     #endif /* !HAVE_POSIX_SIGNALS */
575 :    
576 :     if (!terminal_prepped)
577 :     return;
578 :    
579 :     /* Added by MdG */
580 :     if (!isatty(tty)) {
581 :     terminal_prepped = 0;
582 :     return;
583 :     }
584 :    
585 :     #if defined (HAVE_POSIX_SIGNALS)
586 :     sigemptyset (&set);
587 :     sigemptyset (&oset);
588 :     sigaddset (&set, SIGINT);
589 :     sigprocmask (SIG_BLOCK, &set, &oset);
590 :     #else /* !HAVE_POSIX_SIGNALS */
591 :     # if defined (HAVE_BSD_SIGNALS)
592 :     oldmask = sigblock (sigmask (SIGINT));
593 :     # endif /* HAVE_BSD_SIGNALS */
594 :     #endif /* !HAVE_POSIX_SIGNALS */
595 :    
596 :     #if defined (TERMIOS_TTY_DRIVER)
597 :     tcsetattr (tty, TCSADRAIN, &otio);
598 :     tcflow (tty, TCOON); /* Simulate a ^Q. */
599 :     #else /* TERMIOS_TTY_DRIVER */
600 :     ioctl (tty, TCSETAW, &otio);
601 :     ioctl (tty, TCXONC, 1); /* Simulate a ^Q. */
602 :     #endif /* !TERMIOS_TTY_DRIVER */
603 :    
604 :     terminal_prepped = 0;
605 :    
606 :     #if defined (HAVE_POSIX_SIGNALS)
607 :     sigprocmask (SIG_SETMASK, &oset, (sigset_t *)NULL);
608 :     #else /* !HAVE_POSIX_SIGNALS */
609 :     # if defined (HAVE_BSD_SIGNALS)
610 :     sigsetmask (oldmask);
611 :     # endif /* HAVE_BSD_SIGNALS */
612 :     #endif /* !HAVE_POSIX_SIGNALS */
613 :     }
614 :     #endif /* NEW_TTY_DRIVER */
615 :    
616 :     /* If a character is available to be read, then read it
617 :     and stuff it into IBUFFER. Otherwise, just return. */
618 :    
619 :     long pending = -1L;
620 :    
621 : pazsan 1.7 long key_avail (FILE * stream)
622 : anton 1.1 {
623 :     int tty = fileno (stream);
624 : pazsan 1.4 int chars_avail = pending;
625 : anton 1.1 int result;
626 :    
627 :     if(!terminal_prepped) prep_terminal();
628 :    
629 :     #ifndef _WIN32
630 : pazsan 1.7 if(isatty (tty)) {
631 :     result = ioctl (tty, FIONREAD, &chars_avail);
632 :     }
633 : anton 1.1 #else
634 :     {
635 : pazsan 1.7 fd_set selin;
636 :     static int now[2] = { 0 , 0 };
637 :     int res;
638 :    
639 :     FD_ZERO(&selin);
640 :     FD_SET(tty, &selin);
641 :     chars_avail=select(1, &selin, NULL, NULL, now);
642 : anton 1.1 }
643 :     #endif
644 : pazsan 1.7
645 :     if(chars_avail == -1L) {
646 :     unsigned char inchar;
647 :    
648 :     fcntl(tty, F_SETFL, O_NDELAY);
649 :     result = read(tty, &inchar, sizeof(char));
650 :     if(result == sizeof(char)) {
651 :     chars_avail = 1;
652 :     pending = (long)inchar;
653 :     } else {
654 :     chars_avail = 0;
655 : anton 1.1 }
656 : pazsan 1.7 fcntl(tty, F_SETFL, 0);
657 :     }
658 : anton 1.1
659 :     return chars_avail;
660 :     }
661 :    
662 :     /* Get a key from the buffer of characters to be read.
663 :     Return the key in KEY.
664 :     Result is KEY if there was a key, or 0 if there wasn't. */
665 :    
666 :     /* When compiling and running in the `Posix' environment, Ultrix does
667 :     not restart system calls, so this needs to do it. */
668 :    
669 : anton 1.11 Cell getkey(FILE * stream)
670 : anton 1.1 {
671 : anton 1.11 Cell result;
672 : anton 1.1 unsigned char c;
673 :    
674 : anton 1.11 if(!terminal_prepped)
675 :     prep_terminal();
676 : anton 1.1
677 :     while (pending < 0)
678 :     {
679 :     result = read (fileno (stream), &c, sizeof (char));
680 :    
681 :     if (result == sizeof (char))
682 :     return /* (c == 0x7F ? 0x08 :*/ c /*)*/;
683 :    
684 :     /* If zero characters are returned, then the file that we are
685 :     reading from is empty! Return EOF in that case. */
686 :     if (result == 0)
687 : pazsan 1.9 return (EOF);
688 : anton 1.1
689 :     /* If the error that we received was SIGINT, then try again,
690 :     this is simply an interrupted system call to read ().
691 :     Otherwise, some error ocurred, also signifying EOF. */
692 :     if (errno != EINTR)
693 :     return (EOF);
694 :     }
695 :    
696 : anton 1.11 /* otherwise there is a character pending;
697 :     return it and delete pending char */
698 :     result = (Cell) pending;
699 : anton 1.1 pending = -1L;
700 :    
701 :     return result;
702 :     }
703 :    
704 :     #ifdef TEST
705 :    
706 :     #include <time.h>
707 :    
708 :     int timewait=100000;
709 :    
710 :     int main()
711 :     {
712 :     unsigned char c;
713 :    
714 :     prep_terminal();
715 :    
716 :     do
717 :     {
718 :     int i=0;
719 :    
720 :     while(!key_avail(stdin))
721 :     {
722 :     printf("%04d",i);
723 :     fflush(stdout);
724 :     {
725 :     struct timeval timeout;
726 :     timeout.tv_sec=timewait/1000000;
727 :     timeout.tv_usec=timewait%1000000;
728 :     (void)select(0,0,0,0,&timeout);
729 :     }
730 :     i++;
731 :     printf("\b\b\b\b");
732 :     fflush(stdout);
733 :     }
734 :     c = getkey(stdin);
735 :     printf("%02x,",(int)c);
736 :     fflush(stdout);
737 :     } while(c != 0x1B);
738 :    
739 :     deprep_terminal();
740 :     puts("");
741 :     }
742 :     #endif
743 :     #endif /* MSDOS */
744 :    

CVS Admin

Powered by ViewCVS 1.0-dev
(Powered by ViewCVS)

ViewCVS and CVS Help