Annotation of gforth/io.c, revision 1.10

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

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