Annotation of gforth/io.c, revision 1.11

1.11    ! anton       1: /* direct key io driver; signal handler
1.1       anton       2: 
1.11    ! anton       3:   Copyright (C) 1995 Free Software Foundation, Inc.
        !             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
        !             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
1.1       anton      22: */
                     23: 
1.8       anton      24: /*
1.2       benschop   25:    Use -D_POSIX_VERSION for POSIX systems.
                     26: */
                     27: 
1.7       anton      28: #include <unistd.h>
                     29: 
1.8       anton      30: #ifdef apollo
1.2       benschop   31: #define _POSIX_VERSION
                     32: #endif
                     33: 
1.1       anton      34: #include <stdio.h>
                     35: #include <signal.h>
1.10      anton      36: #include <string.h>
1.1       anton      37: #include <sys/types.h>
1.8       anton      38: #ifndef apollo
1.1       anton      39: #include <sys/ioctl.h>
1.2       benschop   40: #endif
1.1       anton      41: #include <fcntl.h>
                     42: #include <sys/file.h>
1.4       anton      43: #include <setjmp.h>
                     44: #include "forth.h"
                     45: #include "io.h"
1.1       anton      46: 
                     47: #if defined (__GNUC__)
                     48: #  define alloca __builtin_alloca
                     49: #else
                     50: #  if defined (sparc) || defined (HAVE_ALLOCA_H)
                     51: #    include <alloca.h>
                     52: #  endif
                     53: #endif
                     54: 
                     55: #define NEW_TTY_DRIVER
                     56: #define HAVE_BSD_SIGNALS
1.5       pazsan     57: /*
1.8       anton      58: #ifndef apollo
1.1       anton      59: #define USE_XON_XOFF
1.2       benschop   60: #endif
1.5       pazsan     61: */
1.1       anton      62: 
1.5       pazsan     63: #define HANDLE_SIGNALS
                     64: 
1.1       anton      65: /* Some USG machines have BSD signal handling (sigblock, sigsetmask, etc.) */
                     66: #if defined (USG) && !defined (hpux)
                     67: #undef HAVE_BSD_SIGNALS
                     68: #endif
                     69: 
                     70: /* System V machines use termio. */
                     71: #if !defined (_POSIX_VERSION)
1.6       pazsan     72: #  if defined (USG) || defined (hpux) || defined (Xenix) || defined (sgi) || defined (DGUX) || defined (ultrix) || defined (Solaris)
1.1       anton      73: #    undef NEW_TTY_DRIVER
                     74: #    define TERMIO_TTY_DRIVER
                     75: #    include <termio.h>
                     76: #    if !defined (TCOON)
                     77: #      define TCOON 1
                     78: #    endif
                     79: #  endif /* USG || hpux || Xenix || sgi || DUGX || ultrix*/
                     80: #endif /* !_POSIX_VERSION */
                     81: 
                     82: /* Posix systems use termios and the Posix signal functions. */
                     83: #if defined (_POSIX_VERSION)
                     84: #  if !defined (TERMIOS_MISSING)
                     85: #    undef NEW_TTY_DRIVER
                     86: #    define TERMIOS_TTY_DRIVER
                     87: #    include <termios.h>
                     88: #  endif /* !TERMIOS_MISSING */
                     89: #  define HAVE_POSIX_SIGNALS
                     90: #  if !defined (O_NDELAY)
                     91: #    define O_NDELAY O_NONBLOCK        /* Posix-style non-blocking i/o */
                     92: #  endif /* O_NDELAY */
                     93: #endif /* _POSIX_VERSION */
                     94: 
                     95: /* Other (BSD) machines use sgtty. */
                     96: #if defined (NEW_TTY_DRIVER)
                     97: #include <sgtty.h>
                     98: #endif
                     99: 
                    100: /* Define _POSIX_VDISABLE if we are not using the `new' tty driver and
                    101:    it is not already defined.  It is used both to determine if a
                    102:    special character is disabled and to disable certain special
                    103:    characters.  Posix systems should set to 0, USG systems to -1. */
                    104: #if !defined (NEW_TTY_DRIVER) && !defined (_POSIX_VDISABLE)
                    105: #  if defined (_POSIX_VERSION)
                    106: #    define _POSIX_VDISABLE 0
                    107: #  else /* !_POSIX_VERSION */
                    108: #    define _POSIX_VDISABLE -1
                    109: #  endif /* !_POSIX_VERSION */
                    110: #endif /* !NEW_TTY_DRIVER && !_POSIX_VDISABLE */
                    111: 
                    112: #include <errno.h>
                    113: extern int errno;
                    114: 
                    115: #if defined (SHELL)
                    116: #  include <posixstat.h>
                    117: #else
                    118: #  include <sys/stat.h>
                    119: #endif /* !SHELL */
                    120: /* #define HACK_TERMCAP_MOTION */
                    121: 
                    122: #if defined (USG) && defined (hpux)
                    123: #  if !defined (USGr3)
                    124: #    define USGr3
                    125: #  endif /* USGr3 */
                    126: #endif /* USG && hpux */
                    127: 
1.8       anton     128: #if (defined (_POSIX_VERSION) || defined (USGr3)) && !defined(apollo)
1.1       anton     129: #  include <dirent.h>
                    130: #  define direct dirent
                    131: #  if defined (_POSIX_VERSION)
                    132: #    define D_NAMLEN(d) (strlen ((d)->d_name))
                    133: #  else /* !_POSIX_VERSION */
                    134: #    define D_NAMLEN(d) ((d)->d_reclen)
                    135: #  endif /* !_POSIX_VERSION */
                    136: #else /* !_POSIX_VERSION && !USGr3 */
                    137: #  define D_NAMLEN(d) ((d)->d_namlen)
                    138: #  if !defined (USG)
                    139: #    include <sys/dir.h>
                    140: #  else /* USG */
                    141: #    if defined (Xenix)
                    142: #      include <sys/ndir.h>
                    143: #    else /* !Xenix */
                    144: #      include <ndir.h>
                    145: #    endif /* !Xenix */
                    146: #  endif /* USG */
                    147: #endif /* !POSIX_VERSION && !USGr3 */
                    148: 
                    149: #if defined (USG) && defined (TIOCGWINSZ)
                    150: #  include <sys/stream.h>
                    151: #  if defined (USGr4) || defined (USGr3)
                    152: #    if defined (Symmetry) || defined (_SEQUENT_)
                    153: #      include <sys/pte.h>
                    154: #    else
                    155: #      include <sys/ptem.h>
                    156: #    endif /* !Symmetry || _SEQUENT_ */
                    157: #  endif /* USGr4 */
                    158: #endif /* USG && TIOCGWINSZ */
                    159: 
                    160: #if defined (TERMIOS_TTY_DRIVER)
                    161: static struct termios otio;
                    162: #else
                    163: static struct termio otio;
                    164: #endif /* !TERMIOS_TTY_DRIVER */
                    165: 
                    166: /* Non-zero means echo characters as they are read. */
                    167: int readline_echoing_p = 1;
                    168: 
                    169: /* The character that can generate an EOF.  Really read from
                    170:    the terminal driver... just defaulted here. */
                    171: 
                    172: #ifndef CTRL
                    173: #define CTRL(key)      ((key)-'@')
                    174: #endif
                    175: 
                    176: static int eof_char = CTRL ('D');
                    177: 
                    178: /* **************************************************************** */
                    179: /*                                                                 */
                    180: /*                   Saving and Restoring the TTY                  */
                    181: /*                                                                 */
                    182: /* **************************************************************** */
                    183: 
                    184: /* Non-zero means that the terminal is in a prepped state. */
                    185: static int terminal_prepped = 0;
                    186: 
                    187: #if defined (NEW_TTY_DRIVER)
                    188: 
                    189: /* Standard flags, including ECHO. */
                    190: static int original_tty_flags = 0;
                    191: 
                    192: /* Local mode flags, like LPASS8. */
                    193: static int local_mode_flags = 0;
                    194: 
                    195: /* Terminal characters.  This has C-s and C-q in it. */
                    196: static struct tchars original_tchars;
                    197: 
                    198: /* Local special characters.  This has the interrupt characters in it. */
                    199: #if defined (TIOCGLTC)
                    200: static struct ltchars original_ltchars;
                    201: #endif
                    202: 
                    203: /* Bind KEY to FUNCTION.  Returns non-zero if KEY is out of range. */
                    204: 
                    205: #if defined (TIOCGETC)
                    206: #if defined (USE_XON_XOFF)
                    207: 
                    208: int
                    209: bind_key (key, function)
                    210:      int key;
                    211:      Function *function;
                    212: {
                    213:   if (key < 0)
                    214:     return (key);
                    215: 
                    216:   if (key > 127 && key < 256)
                    217:     {
                    218:       if (keymap[ESC].type == ISKMAP)
                    219:        {
                    220:          Keymap escmap = (Keymap)keymap[ESC].function;
                    221: 
                    222:          key -= 128;
                    223:          escmap[key].type = ISFUNC;
                    224:          escmap[key].function = function;
                    225:          return (0);
                    226:        }
                    227:       return (key);
                    228:     }
                    229: 
                    230:   keymap[key].type = ISFUNC;
                    231:   keymap[key].function = function;
                    232:  return (0);
                    233: }
                    234: #endif
                    235: #endif
                    236: 
                    237: /* We use this to get and set the tty_flags. */
                    238: static struct sgttyb the_ttybuff;
                    239: 
                    240: #if defined (USE_XON_XOFF)
                    241: /* If the terminal was in xoff state when we got to it, then xon_char
                    242:    contains the character that is supposed to start it again. */
                    243: static int xon_char, xoff_state;
                    244: #endif /* USE_XON_XOFF */
                    245: 
                    246: /* **************************************************************** */
                    247: /*                                                                 */
                    248: /*                     Bogus Flow Control                          */
                    249: /*                                                                 */
                    250: /* **************************************************************** */
                    251: 
                    252: restart_output (count, key)
                    253:      int count, key;
                    254: {
                    255:   int fildes = fileno (stdin);
                    256: #if defined (TIOCSTART)
                    257: #if defined (apollo)
                    258:   ioctl (&fildes, TIOCSTART, 0);
                    259: #else
                    260:   ioctl (fildes, TIOCSTART, 0);
                    261: #endif /* apollo */
                    262: 
                    263: #else
                    264: #  if defined (TERMIOS_TTY_DRIVER)
                    265:         tcflow (fildes, TCOON);
                    266: #  else
                    267: #    if defined (TCXONC)
                    268:         ioctl (fildes, TCXONC, TCOON);
                    269: #    endif /* TCXONC */
                    270: #  endif /* !TERMIOS_TTY_DRIVER */
                    271: #endif /* TIOCSTART */
                    272: }
                    273: 
                    274: /* Put the terminal in CBREAK mode so that we can detect key presses. */
                    275: void prep_terminal ()
                    276: {
                    277:   int tty = fileno (stdin);
                    278: #if defined (HAVE_BSD_SIGNALS)
                    279:   int oldmask;
                    280: #endif /* HAVE_BSD_SIGNALS */
                    281: 
                    282:   if (terminal_prepped)
                    283:     return;
                    284: 
                    285:   oldmask = sigblock (sigmask (SIGINT));
                    286: 
                    287:   /* We always get the latest tty values.  Maybe stty changed them. */
                    288:   ioctl (tty, TIOCGETP, &the_ttybuff);
                    289:   original_tty_flags = the_ttybuff.sg_flags;
                    290: 
                    291:   readline_echoing_p = (original_tty_flags & ECHO);
                    292: 
                    293: #if defined (TIOCLGET)
                    294:   ioctl (tty, TIOCLGET, &local_mode_flags);
                    295: #endif
                    296: 
                    297: #if !defined (ANYP)
                    298: #  define ANYP (EVENP | ODDP)
                    299: #endif
                    300: 
                    301:   /* If this terminal doesn't care how the 8th bit is used,
                    302:      then we can use it for the meta-key.  We check by seeing
                    303:      if BOTH odd and even parity are allowed. */
                    304:   if (the_ttybuff.sg_flags & ANYP)
                    305:     {
                    306: #if defined (PASS8)
                    307:       the_ttybuff.sg_flags |= PASS8;
                    308: #endif
                    309: 
                    310:       /* Hack on local mode flags if we can. */
                    311: #if defined (TIOCLGET) && defined (LPASS8)
                    312:       {
                    313:        int flags;
                    314:        flags = local_mode_flags | LPASS8;
                    315:        ioctl (tty, TIOCLSET, &flags);
                    316:       }
                    317: #endif /* TIOCLGET && LPASS8 */
                    318:     }
                    319: 
                    320: #if defined (TIOCGETC)
                    321:   {
                    322:     struct tchars temp;
                    323: 
                    324:     ioctl (tty, TIOCGETC, &original_tchars);
                    325:     temp = original_tchars;
                    326: 
                    327: #if defined (USE_XON_XOFF)
                    328:     /* Get rid of C-s and C-q.
                    329:        We remember the value of startc (C-q) so that if the terminal is in
                    330:        xoff state, the user can xon it by pressing that character. */
                    331:     xon_char = temp.t_startc;
                    332:     temp.t_stopc = -1;
                    333:     temp.t_startc = -1;
                    334: 
                    335:     /* If there is an XON character, bind it to restart the output. */
                    336:     if (xon_char != -1)
                    337:       bind_key (xon_char, restart_output);
                    338: #endif /* USE_XON_XOFF */
                    339: 
                    340:     /* If there is an EOF char, bind eof_char to it. */
                    341:     if (temp.t_eofc != -1)
                    342:       eof_char = temp.t_eofc;
                    343: 
                    344: #if defined (NO_KILL_INTR)
                    345:     /* Get rid of C-\ and C-c. */
                    346:     temp.t_intrc = temp.t_quitc = -1;
                    347: #endif /* NO_KILL_INTR */
                    348: 
                    349:     ioctl (tty, TIOCSETC, &temp);
                    350:   }
                    351: #endif /* TIOCGETC */
                    352: 
                    353: #if defined (TIOCGLTC)
                    354:   {
                    355:     struct ltchars temp;
                    356: 
                    357:     ioctl (tty, TIOCGLTC, &original_ltchars);
                    358:     temp = original_ltchars;
                    359: 
                    360:     /* Make the interrupt keys go away.  Just enough to make people
                    361:        happy. */
                    362:     temp.t_dsuspc = -1;        /* C-y */
                    363:     temp.t_lnextc = -1;        /* C-v */
                    364: 
                    365:     ioctl (tty, TIOCSLTC, &temp);
                    366:   }
                    367: #endif /* TIOCGLTC */
                    368: 
                    369:   the_ttybuff.sg_flags &= ~(ECHO | CRMOD);
                    370:   the_ttybuff.sg_flags |= CBREAK;
                    371:   ioctl (tty, TIOCSETN, &the_ttybuff);
                    372: 
                    373:   terminal_prepped = 1;
                    374: 
                    375: #if defined (HAVE_BSD_SIGNALS)
                    376:   sigsetmask (oldmask);
                    377: #endif
                    378: }
                    379: 
                    380: /* Restore the terminal to its original state. */
                    381: void deprep_terminal ()
                    382: {
                    383:   int tty = fileno (stdin);
                    384: #if defined (HAVE_BSD_SIGNALS)
                    385:   int oldmask;
                    386: #endif
                    387: 
                    388:   if (!terminal_prepped)
                    389:     return;
                    390: 
                    391:   oldmask = sigblock (sigmask (SIGINT));
                    392: 
                    393:   the_ttybuff.sg_flags = original_tty_flags;
                    394:   ioctl (tty, TIOCSETN, &the_ttybuff);
                    395:   readline_echoing_p = 1;
                    396: 
                    397: #if defined (TIOCLGET)
                    398:   ioctl (tty, TIOCLSET, &local_mode_flags);
                    399: #endif
                    400: 
                    401: #if defined (TIOCSLTC)
                    402:   ioctl (tty, TIOCSLTC, &original_ltchars);
                    403: #endif
                    404: 
                    405: #if defined (TIOCSETC)
                    406:   ioctl (tty, TIOCSETC, &original_tchars);
                    407: #endif
                    408:   terminal_prepped = 0;
                    409: 
                    410: #if defined (HAVE_BSD_SIGNALS)
                    411:   sigsetmask (oldmask);
                    412: #endif
                    413: }
                    414: 
                    415: #else  /* !defined (NEW_TTY_DRIVER) */
                    416: 
                    417: #if !defined (VMIN)
                    418: #define VMIN VEOF
                    419: #endif
                    420: 
                    421: #if !defined (VTIME)
                    422: #define VTIME VEOL
                    423: #endif
                    424: 
                    425: void prep_terminal ()
                    426: {
                    427:   int tty = fileno (stdin);
                    428: #if defined (TERMIOS_TTY_DRIVER)
                    429:   struct termios tio;
                    430: #else
                    431:   struct termio tio;
                    432: #endif /* !TERMIOS_TTY_DRIVER */
                    433: 
                    434: #if defined (HAVE_POSIX_SIGNALS)
                    435:   sigset_t set, oset;
                    436: #else
                    437: #  if defined (HAVE_BSD_SIGNALS)
                    438:   int oldmask;
                    439: #  endif /* HAVE_BSD_SIGNALS */
                    440: #endif /* !HAVE_POSIX_SIGNALS */
                    441: 
                    442:   if (terminal_prepped)
                    443:     return;
                    444: 
                    445:   /* Try to keep this function from being INTerrupted.  We can do it
                    446:      on POSIX and systems with BSD-like signal handling. */
                    447: #if defined (HAVE_POSIX_SIGNALS)
                    448:   sigemptyset (&set);
                    449:   sigemptyset (&oset);
                    450:   sigaddset (&set, SIGINT);
                    451:   sigprocmask (SIG_BLOCK, &set, &oset);
                    452: #else /* !HAVE_POSIX_SIGNALS */
                    453: #  if defined (HAVE_BSD_SIGNALS)
                    454:   oldmask = sigblock (sigmask (SIGINT));
                    455: #  endif /* HAVE_BSD_SIGNALS */
                    456: #endif /* !HAVE_POSIX_SIGNALS */
                    457: 
                    458: #if defined (TERMIOS_TTY_DRIVER)
                    459:   tcgetattr (tty, &tio);
                    460: #else
                    461:   ioctl (tty, TCGETA, &tio);
                    462: #endif /* !TERMIOS_TTY_DRIVER */
                    463: 
                    464:   otio = tio;
                    465: 
                    466:   readline_echoing_p = (tio.c_lflag & ECHO);
                    467: 
                    468:   tio.c_lflag &= ~(ICANON | ECHO);
                    469: 
                    470:   if (otio.c_cc[VEOF] != _POSIX_VDISABLE)
                    471:     eof_char = otio.c_cc[VEOF];
                    472: 
                    473: #if defined (USE_XON_XOFF)
                    474: #if defined (IXANY)
                    475:   tio.c_iflag &= ~(IXON | IXOFF | IXANY);
                    476: #else
                    477:   /* `strict' Posix systems do not define IXANY. */
                    478:   tio.c_iflag &= ~(IXON | IXOFF);
                    479: #endif /* IXANY */
                    480: #endif /* USE_XON_XOFF */
                    481: 
                    482:   /* Only turn this off if we are using all 8 bits. */
                    483:   if ((tio.c_cflag & CSIZE) == CS8)
                    484:     tio.c_iflag &= ~(ISTRIP | INPCK);
                    485: 
                    486:   /* Make sure we differentiate between CR and NL on input. */
                    487:   tio.c_iflag &= ~(ICRNL | INLCR);
                    488: 
                    489: #if !defined (HANDLE_SIGNALS)
                    490:   tio.c_lflag &= ~ISIG;
                    491: #else
                    492:   tio.c_lflag |= ISIG;
                    493: #endif
                    494: 
                    495:   tio.c_cc[VMIN] = 1;
                    496:   tio.c_cc[VTIME] = 0;
                    497: 
                    498:   /* Turn off characters that we need on Posix systems with job control,
                    499:      just to be sure.  This includes ^Y and ^V.  This should not really
                    500:      be necessary.  */
                    501: #if defined (TERMIOS_TTY_DRIVER) && defined (_POSIX_JOB_CONTROL)
                    502: 
                    503: #if defined (VLNEXT)
                    504:   tio.c_cc[VLNEXT] = _POSIX_VDISABLE;
                    505: #endif
                    506: 
                    507: #if defined (VDSUSP)
                    508:   tio.c_cc[VDSUSP] = _POSIX_VDISABLE;
                    509: #endif
                    510: 
                    511: #endif /* POSIX && JOB_CONTROL */
                    512: 
                    513: #if defined (TERMIOS_TTY_DRIVER)
                    514:   tcsetattr (tty, TCSADRAIN, &tio);
                    515:   tcflow (tty, TCOON);         /* Simulate a ^Q. */
                    516: #else
                    517:   ioctl (tty, TCSETAW, &tio);
                    518:   ioctl (tty, TCXONC, 1);      /* Simulate a ^Q. */
                    519: #endif /* !TERMIOS_TTY_DRIVER */
                    520: 
                    521:   terminal_prepped = 1;
                    522: 
                    523: #if defined (HAVE_POSIX_SIGNALS)
                    524:   sigprocmask (SIG_SETMASK, &oset, (sigset_t *)NULL);
                    525: #else
                    526: #  if defined (HAVE_BSD_SIGNALS)
                    527:   sigsetmask (oldmask);
                    528: #  endif /* HAVE_BSD_SIGNALS */
                    529: #endif /* !HAVE_POSIX_SIGNALS */
                    530: }
                    531: 
                    532: void deprep_terminal ()
                    533: {
                    534:   int tty = fileno (stdin);
                    535: 
                    536:   /* Try to keep this function from being INTerrupted.  We can do it
                    537:      on POSIX and systems with BSD-like signal handling. */
                    538: #if defined (HAVE_POSIX_SIGNALS)
                    539:   sigset_t set, oset;
                    540: #else /* !HAVE_POSIX_SIGNALS */
                    541: #  if defined (HAVE_BSD_SIGNALS)
                    542:   int oldmask;
                    543: #  endif /* HAVE_BSD_SIGNALS */
                    544: #endif /* !HAVE_POSIX_SIGNALS */
                    545: 
                    546:   if (!terminal_prepped)
                    547:     return;
                    548: 
                    549: #if defined (HAVE_POSIX_SIGNALS)
                    550:   sigemptyset (&set);
                    551:   sigemptyset (&oset);
                    552:   sigaddset (&set, SIGINT);
                    553:   sigprocmask (SIG_BLOCK, &set, &oset);
                    554: #else /* !HAVE_POSIX_SIGNALS */
                    555: #  if defined (HAVE_BSD_SIGNALS)
                    556:   oldmask = sigblock (sigmask (SIGINT));
                    557: #  endif /* HAVE_BSD_SIGNALS */
                    558: #endif /* !HAVE_POSIX_SIGNALS */
                    559: 
                    560: #if defined (TERMIOS_TTY_DRIVER)
                    561:   tcsetattr (tty, TCSADRAIN, &otio);
                    562:   tcflow (tty, TCOON);         /* Simulate a ^Q. */
                    563: #else /* TERMIOS_TTY_DRIVER */
                    564:   ioctl (tty, TCSETAW, &otio);
                    565:   ioctl (tty, TCXONC, 1);      /* Simulate a ^Q. */
                    566: #endif /* !TERMIOS_TTY_DRIVER */
                    567: 
                    568:   terminal_prepped = 0;
                    569: 
                    570: #if defined (HAVE_POSIX_SIGNALS)
                    571:   sigprocmask (SIG_SETMASK, &oset, (sigset_t *)NULL);
                    572: #else /* !HAVE_POSIX_SIGNALS */
                    573: #  if defined (HAVE_BSD_SIGNALS)
                    574:   sigsetmask (oldmask);
                    575: #  endif /* HAVE_BSD_SIGNALS */
                    576: #endif /* !HAVE_POSIX_SIGNALS */
                    577: }
                    578: #endif  /* NEW_TTY_DRIVER */
                    579: 
                    580: /* If a character is available to be read, then read it
                    581:    and stuff it into IBUFFER.  Otherwise, just return. */
                    582: 
                    583: long pending = -1L;
                    584: 
                    585: long key_avail (stream)
                    586:        FILE *stream;
                    587: {
                    588:   int tty = fileno (stream);
                    589:   long chars_avail = pending;
                    590:   int result;
                    591: 
1.9       pazsan    592:   if(!terminal_prepped)  prep_terminal();
                    593: 
1.1       anton     594: #if defined (FIONREAD)
                    595:   result = ioctl (tty, FIONREAD, &chars_avail);
                    596: #endif
                    597: 
                    598:   if(chars_avail == -1L)
                    599:     {  unsigned char inchar;
                    600: 
                    601:        fcntl(tty, F_SETFL, O_NDELAY);
                    602:        result = read(tty, &inchar, sizeof(char));
                    603:        if(result == sizeof(char))
                    604:        {
                    605:          chars_avail = 1;
                    606:          pending = (long)inchar;
                    607:        }
                    608:        else
                    609:          chars_avail = 0;
                    610:        fcntl(tty, F_SETFL, 0);
                    611:     }
                    612: 
                    613:   return chars_avail;
                    614: }
                    615: 
                    616: /* Get a key from the buffer of characters to be read.
                    617:    Return the key in KEY.
                    618:    Result is KEY if there was a key, or 0 if there wasn't. */
                    619: 
                    620: /* When compiling and running in the `Posix' environment, Ultrix does
                    621:    not restart system calls, so this needs to do it. */
                    622: 
                    623: unsigned char getkey(stream)
                    624:      FILE *stream;
                    625: {
                    626:   int result;
                    627:   unsigned char c;
                    628: 
1.9       pazsan    629:   if(!terminal_prepped)  prep_terminal();
                    630: 
1.1       anton     631:   while (pending < 0)
                    632:     {
                    633:       result = read (fileno (stream), &c, sizeof (char));
                    634: 
                    635:       if (result == sizeof (char))
                    636:         return /* (c == 0x7F ? 0x08 :*/ c /*)*/;
                    637: 
                    638:       /* If zero characters are returned, then the file that we are
                    639:         reading from is empty!  Return EOF in that case. */
                    640:       if (result == 0)
1.9       pazsan    641:        return CTRL('D');
1.1       anton     642: 
                    643:       /* If the error that we received was SIGINT, then try again,
                    644:         this is simply an interrupted system call to read ().
                    645:         Otherwise, some error ocurred, also signifying EOF. */
                    646:       if (errno != EINTR)
                    647:        return (EOF);
                    648:     }
                    649: 
                    650:   result = (int) pending;
                    651:   pending = -1L;
                    652: 
                    653:   return result;
                    654: }
                    655: 
                    656: #ifdef TEST
                    657: 
                    658: #include <time.h>
                    659: 
                    660: int timewait=100000;
                    661: 
                    662: int main()
                    663: {
                    664:        unsigned char c;
                    665: 
                    666:        prep_terminal();
                    667: 
                    668:        do
                    669:        {
                    670:                int i=0;
                    671: 
                    672:                while(!key_avail(stdin))
                    673:                {
                    674:                        printf("%04d",i);
                    675:                        fflush(stdout);
                    676:                        {
                    677:                                struct timeval timeout;
                    678:                                timeout.tv_sec=timewait/1000000;
                    679:                                timeout.tv_usec=timewait%1000000;
                    680:                                (void)select(0,0,0,0,&timeout);
                    681:                        }
                    682:                        i++;
                    683:                        printf("\b\b\b\b");
                    684:                        fflush(stdout);
                    685:                }
                    686:                c = getkey(stdin);
                    687:                printf("%02x,",(int)c);
                    688:                fflush(stdout);
                    689:        }       while(c != 0x1B);
                    690: 
                    691:        deprep_terminal();
                    692:        puts("");
                    693: }
                    694: #endif
                    695: 
1.10      anton     696: 
                    697: /* signal handling adapted from pfe by Dirk Zoller (Copylefted) - anton */
1.1       anton     698: 
                    699: static void
                    700: graceful_exit (int sig)
                    701: {
                    702:   deprep_terminal();
1.10      anton     703:   fprintf (stderr, "\n\n%s.\n", strsignal (sig));
1.4       anton     704:   exit (0x80|sig);
1.1       anton     705: }
                    706: 
1.4       anton     707: jmp_buf throw_jmp_buf;
                    708: 
                    709: static void 
                    710: signal_throw(int sig)
                    711: {
1.10      anton     712:   int code;
                    713:   struct {
                    714:     int signal;
                    715:     int throwcode;
                    716:   } *p, throwtable[] = {
                    717:     { SIGINT, -28 },
                    718:     { SIGFPE, -55 },
                    719:     { SIGBUS, -23 },
                    720:     { SIGSEGV, -9 },
1.4       anton     721:   };
                    722:   signal(sig,signal_throw);
1.10      anton     723:   for (code=-256-sig, p=throwtable; p<throwtable+(sizeof(throwtable)/sizeof(*p)); p++)
                    724:     if (sig == p->signal) {
                    725:       code = p->throwcode;
                    726:       break;
                    727:     }
                    728:   longjmp(throw_jmp_buf,code); /* or use siglongjmp ? */
1.4       anton     729: }
                    730: 
1.5       pazsan    731: static void
                    732: termprep (int sig)
                    733: {
1.9       pazsan    734:   terminal_prepped=0;
1.5       pazsan    735:   signal(sig,termprep);
                    736: }
                    737: 
1.1       anton     738: void
                    739: install_signal_handlers (void)
                    740: {
1.10      anton     741: 
                    742: #if 0
                    743: /* these signals are handled right by default, no need to handle them;
                    744:    they are listed here just for fun */
                    745:   static short sigs_to_default [] = {
                    746: #ifdef SIGCHLD
                    747:     SIGCHLD,
                    748: #endif
                    749: #ifdef SIGINFO
                    750:     SIGINFO,
                    751: #endif
                    752: #ifdef SIGIO
                    753:     SIGIO,
                    754: #endif
                    755: #ifdef SIGLOST
                    756:     SIGLOST,
                    757: #endif
                    758: #ifdef SIGKILL
                    759:     SIGKILL,
                    760: #endif
                    761: #ifdef SIGSTOP
                    762:     SIGSTOP,
                    763: #endif
                    764: #ifdef SIGPWR
                    765:     SIGPWR,
                    766: #endif
                    767: #ifdef SIGMSG
                    768:     SIGMSG,
                    769: #endif
                    770: #ifdef SIGDANGER
                    771:     SIGDANGER,
                    772: #endif
                    773: #ifdef SIGMIGRATE
                    774:     SIGMIGRATE,
                    775: #endif
                    776: #ifdef SIGPRE
                    777:     SIGPRE,
                    778: #endif
                    779: #ifdef SIGVIRT
                    780:     SIGVIRT,
                    781: #endif
                    782: #ifdef SIGGRANT
                    783:     SIGGRANT,
                    784: #endif
                    785: #ifdef SIGRETRACT
                    786:     SIGRETRACT,
                    787: #endif
                    788: #ifdef SIGSOUND
                    789:     SIGSOUND,
                    790: #endif
                    791: #ifdef SIGSAK
                    792:     SIGSAK,
                    793: #endif
                    794: #ifdef SIGTSTP
                    795:     SIGTSTP,
                    796: #endif
                    797: #ifdef SIGTTIN
                    798:     SIGTTIN,
                    799: #endif
                    800: #ifdef SIGTTOU
                    801:     SIGTTOU,
                    802: #endif
                    803: #ifdef SIGWINCH
                    804:     SIGWINCH,
                    805: #endif
                    806: #ifdef SIGSTKFLT
                    807:     SIGSTKFLT,
                    808: #endif
                    809: #ifdef SIGUNUSED
                    810:     SIGUNUSED,
                    811: #endif
                    812:   };
                    813: #endif
                    814: 
                    815:   static short sigs_to_throw [] = {
                    816: #ifdef SIGBREAK
                    817:     SIGBREAK,
                    818: #endif
                    819: #ifdef SIGINT
                    820:     SIGINT,
                    821: #endif
                    822: #ifdef SIGILL
                    823:     SIGILL,
                    824: #endif
                    825: #ifdef SIGEMT
                    826:     SIGEMT,
                    827: #endif
                    828: #ifdef SIGFPE
                    829:     SIGFPE,
                    830: #endif
                    831: #ifdef SIGIOT
                    832:     SIGIOT,
                    833: #endif
                    834: #ifdef SIGSEGV
                    835:     SIGSEGV,
                    836: #endif
                    837: #ifdef SIGALRM
                    838:     SIGALRM,
                    839: #endif
                    840: #ifdef SIGPOLL
                    841:     SIGPOLL,
                    842: #endif
                    843: #ifdef SIGPROF
                    844:     SIGPROF,
                    845: #endif
                    846: #ifdef SIGBUS
                    847:     SIGBUS,
                    848: #endif
                    849: #ifdef SIGSYS
                    850:     SIGSYS,
                    851: #endif
                    852: #ifdef SIGTRAP
                    853:     SIGTRAP,
                    854: #endif
                    855: #ifdef SIGURG
                    856:     SIGURG,
                    857: #endif
                    858: #ifdef SIGUSR1
                    859:     SIGUSR1,
                    860: #endif
                    861: #ifdef SIGUSR2
                    862:     SIGUSR2,
                    863: #endif
                    864: #ifdef SIGVTALRM
                    865:     SIGVTALRM,
                    866: #endif
                    867: #ifdef SIGXFSZ
                    868:     SIGXFSZ,
                    869: #endif
                    870:   };
                    871:   static short sigs_to_quit [] = {
                    872: #ifdef SIGHUP
                    873:     SIGHUP,
                    874: #endif
                    875: #ifdef SIGQUIT
                    876:     SIGQUIT,
                    877: #endif
                    878: #ifdef SIGABRT
                    879:     SIGABRT,
                    880: #endif
                    881: #ifdef SIGPIPE
                    882:     SIGPIPE,
                    883: #endif
                    884: #ifdef SIGTERM
                    885:     SIGTERM,
                    886: #endif
                    887: #ifdef SIGXCPU
                    888:     SIGXCPU,
                    889: #endif
                    890:   };
                    891:   static short sigs_to_termprep [] = {
                    892: #ifdef SIGCONT
                    893:     SIGCONT,
                    894: #endif
                    895:   };
1.1       anton     896:   int i;
                    897: 
                    898: #define DIM(X)         (sizeof (X) / sizeof *(X))
1.10      anton     899: /*
1.1       anton     900:   for (i = 0; i < DIM (sigs_to_ignore); i++)
1.10      anton     901:     signal (sigs_to_ignore [i], SIG_IGN);
                    902: */
                    903:   for (i = 0; i < DIM (sigs_to_throw); i++)
                    904:     signal (sigs_to_throw [i], signal_throw);
1.1       anton     905:   for (i = 0; i < DIM (sigs_to_quit); i++)
                    906:     signal (sigs_to_quit [i], graceful_exit);
1.5       pazsan    907:   for (i = 0; i < DIM (sigs_to_termprep); i++)
                    908:     signal (sigs_to_termprep [i], termprep);
1.1       anton     909: }
                    910: /* end signal handling */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>