Annotation of gforth/io.c, revision 1.9

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

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