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

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

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