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