Annotation of gforth/engine/io.c, revision 1.2

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

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