Annotation of gforth/io.c, revision 1.16

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

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