File:  [gforth] / gforth / engine / io.c
Revision 1.6: download - view: text, annotated - select for diffs
Thu Oct 15 09:47:45 1998 UTC (22 years, 11 months ago) by pazsan
Branches: MAIN
CVS tags: HEAD
Fixed braindead problem with Solaris/SunOS 5.6.

    1: /* direct key io driver; signal handler
    2: 
    3:   Copyright (C) 1995 Free Software Foundation, Inc.
    4: 
    5:   This file is part of Gforth.
    6: 
    7:   Gforth is free software; you can redistribute it and/or
    8:   modify it under the terms of the GNU General Public License
    9:   as published by the Free Software Foundation; either version 2
   10:   of the License, or (at your option) any later version.
   11: 
   12:   This program is distributed in the hope that it will be useful,
   13:   but WITHOUT ANY WARRANTY; without even the implied warranty of
   14:   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   15:   GNU General Public License for more details.
   16: 
   17:   You should have received a copy of the GNU General Public License
   18:   along with this program; if not, write to the Free Software
   19:   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
   20: 
   21:   The following is stolen from the readline library for bash
   22: */
   23: 
   24: /*
   25:    Use -D_POSIX_VERSION for POSIX systems.
   26: */
   27: 
   28: #include "config.h"
   29: #include <unistd.h>
   30: 
   31: #if defined(apollo) || defined(_WIN32)
   32: #define _POSIX_VERSION
   33: #endif
   34: 
   35: #if !defined(Solaris) && defined(sun) && defined(__svr4__)
   36: #define Solaris
   37: typedef unsigned int uint32_t;
   38: #endif
   39: 
   40: #include <stdio.h>
   41: #include <signal.h>
   42: #include <string.h>
   43: #include <sys/types.h>
   44: #if !defined(apollo) && !defined(MSDOS)
   45: #include <sys/ioctl.h>
   46: #endif
   47: #include <fcntl.h>
   48: #include <sys/file.h>
   49: #if defined(Solaris) && !defined(FIONREAD)
   50: #include <sys/filio.h>
   51: #endif
   52: #include <setjmp.h>
   53: #include "forth.h"
   54: #include "io.h"
   55: 
   56: #ifndef MSDOS
   57: #if defined (__GNUC__)
   58: #  define alloca __builtin_alloca
   59: #else
   60: #  if defined (sparc) || defined (HAVE_ALLOCA_H)
   61: #    include <alloca.h>
   62: #  endif
   63: #endif
   64: 
   65: #define NEW_TTY_DRIVER
   66: #define HAVE_BSD_SIGNALS
   67: /*
   68: #ifndef apollo
   69: #define USE_XON_XOFF
   70: #endif
   71: */
   72: 
   73: #define HANDLE_SIGNALS
   74: 
   75: /* Some USG machines have BSD signal handling (sigblock, sigsetmask, etc.) */
   76: #if defined (USG) && !defined (hpux)
   77: #undef HAVE_BSD_SIGNALS
   78: #endif
   79: 
   80: /* System V machines use termio. */
   81: #if !defined (_POSIX_VERSION)
   82: #  if defined (USG) || defined (hpux) || defined (Xenix) || defined (sgi) || defined (DGUX) || defined (ultrix) || defined (Solaris) || defined(_WIN32)
   83: #    undef NEW_TTY_DRIVER
   84: #    define TERMIO_TTY_DRIVER
   85: #    include <termio.h>
   86: #    if !defined (TCOON)
   87: #      define TCOON 1
   88: #    endif
   89: #  endif /* USG || hpux || Xenix || sgi || DUGX || ultrix*/
   90: #endif /* !_POSIX_VERSION */
   91: 
   92: /* Posix systems use termios and the Posix signal functions. */
   93: #if defined (_POSIX_VERSION) || defined (NeXT)
   94: #  if !defined (TERMIOS_MISSING)
   95: #    undef NEW_TTY_DRIVER
   96: #    define TERMIOS_TTY_DRIVER
   97: #    include <termios.h>
   98: #  endif /* !TERMIOS_MISSING */
   99: #endif /* _POSIX_VERSION || NeXT */
  100: 
  101: #if defined (_POSIX_VERSION)
  102: #  define HAVE_POSIX_SIGNALS
  103: #  if !defined (O_NDELAY)
  104: #    define O_NDELAY O_NONBLOCK	/* Posix-style non-blocking i/o */
  105: #  endif /* O_NDELAY */
  106: #endif /* _POSIX_VERSION */
  107: 
  108: /* Other (BSD) machines use sgtty. */
  109: #if defined (NEW_TTY_DRIVER)
  110: #include <sgtty.h>
  111: #endif
  112: 
  113: /* Define _POSIX_VDISABLE if we are not using the `new' tty driver and
  114:    it is not already defined.  It is used both to determine if a
  115:    special character is disabled and to disable certain special
  116:    characters.  Posix systems should set to 0, USG systems to -1. */
  117: #if !defined (NEW_TTY_DRIVER) && !defined (_POSIX_VDISABLE)
  118: #  if defined (_POSIX_VERSION) || defined (NeXT)
  119: #    define _POSIX_VDISABLE 0
  120: #  else /* !_POSIX_VERSION */
  121: #    define _POSIX_VDISABLE -1
  122: #  endif /* !_POSIX_VERSION */
  123: #endif /* !NEW_TTY_DRIVER && !_POSIX_VDISABLE */
  124: 
  125: #include <errno.h>
  126: /* extern int errno; */
  127: 
  128: #if defined (SHELL)
  129: #  include <posixstat.h>
  130: #else
  131: #  include <sys/stat.h>
  132: #endif /* !SHELL */
  133: /* #define HACK_TERMCAP_MOTION */
  134: 
  135: #if defined (USG) && defined (hpux)
  136: #  if !defined (USGr3)
  137: #    define USGr3
  138: #  endif /* USGr3 */
  139: #endif /* USG && hpux */
  140: 
  141: #if (defined (_POSIX_VERSION) || defined (USGr3)) && !defined(apollo)
  142: #  include <dirent.h>
  143: #  define direct dirent
  144: #  if defined (_POSIX_VERSION)
  145: #    define D_NAMLEN(d) (strlen ((d)->d_name))
  146: #  else /* !_POSIX_VERSION */
  147: #    define D_NAMLEN(d) ((d)->d_reclen)
  148: #  endif /* !_POSIX_VERSION */
  149: #else /* !_POSIX_VERSION && !USGr3 */
  150: #  define D_NAMLEN(d) ((d)->d_namlen)
  151: #  if !defined (USG)
  152: #    include <sys/dir.h>
  153: #  else /* USG */
  154: #    if defined (Xenix)
  155: #      include <sys/ndir.h>
  156: #    else /* !Xenix */
  157: #      include <ndir.h>
  158: #    endif /* !Xenix */
  159: #  endif /* USG */
  160: #endif /* !POSIX_VERSION && !USGr3 */
  161: 
  162: #if defined (USG) && defined (TIOCGWINSZ)
  163: #  include <sys/stream.h>
  164: #  if defined (USGr4) || defined (USGr3)
  165: #    if defined (Symmetry) || defined (_SEQUENT_)
  166: #      include <sys/pte.h>
  167: #    else
  168: #      include <sys/ptem.h>
  169: #    endif /* !Symmetry || _SEQUENT_ */
  170: #  endif /* USGr4 */
  171: #endif /* USG && TIOCGWINSZ */
  172: 
  173: #if defined (TERMIOS_TTY_DRIVER)
  174: static struct termios otio;
  175: #else
  176: static struct termio otio;
  177: #endif /* !TERMIOS_TTY_DRIVER */
  178: 
  179: /* Non-zero means echo characters as they are read. */
  180: int readline_echoing_p = 1;
  181: 
  182: /* The character that can generate an EOF.  Really read from
  183:    the terminal driver... just defaulted here. */
  184: 
  185: #ifndef CTRL
  186: #define CTRL(key)	((key)-'@')
  187: #endif
  188: 
  189: static int eof_char = CTRL ('D');
  190: 
  191: /* **************************************************************** */
  192: /*								    */
  193: /*		      Saving and Restoring the TTY	    	    */
  194: /*								    */
  195: /* **************************************************************** */
  196: 
  197: /* Non-zero means that the terminal is in a prepped state. */
  198: int terminal_prepped = 0;
  199: 
  200: #if defined (NEW_TTY_DRIVER)
  201: 
  202: /* Standard flags, including ECHO. */
  203: static int original_tty_flags = 0;
  204: 
  205: /* Local mode flags, like LPASS8. */
  206: static int local_mode_flags = 0;
  207: 
  208: /* Terminal characters.  This has C-s and C-q in it. */
  209: static struct tchars original_tchars;
  210: 
  211: /* Local special characters.  This has the interrupt characters in it. */
  212: #if defined (TIOCGLTC)
  213: static struct ltchars original_ltchars;
  214: #endif
  215: 
  216: /* Bind KEY to FUNCTION.  Returns non-zero if KEY is out of range. */
  217: 
  218: #if defined (TIOCGETC)
  219: #if defined (USE_XON_XOFF)
  220: 
  221: int
  222: bind_key (key, function)
  223:      int key;
  224:      Function *function;
  225: {
  226:   if (key < 0)
  227:     return (key);
  228: 
  229:   if (key > 127 && key < 256)
  230:     {
  231:       if (keymap[ESC].type == ISKMAP)
  232: 	{
  233: 	  Keymap escmap = (Keymap)keymap[ESC].function;
  234: 
  235: 	  key -= 128;
  236: 	  escmap[key].type = ISFUNC;
  237: 	  escmap[key].function = function;
  238: 	  return (0);
  239: 	}
  240:       return (key);
  241:     }
  242: 
  243:   keymap[key].type = ISFUNC;
  244:   keymap[key].function = function;
  245:  return (0);
  246: }
  247: #endif
  248: #endif
  249: 
  250: /* We use this to get and set the tty_flags. */
  251: static struct sgttyb the_ttybuff;
  252: 
  253: #if defined (USE_XON_XOFF)
  254: /* If the terminal was in xoff state when we got to it, then xon_char
  255:    contains the character that is supposed to start it again. */
  256: static int xon_char, xoff_state;
  257: #endif /* USE_XON_XOFF */
  258: 
  259: /* **************************************************************** */
  260: /*								    */
  261: /*			Bogus Flow Control      		    */
  262: /*								    */
  263: /* **************************************************************** */
  264: 
  265: restart_output (count, key)
  266:      int count, key;
  267: {
  268:   int fildes = fileno (stdin);
  269: #if defined (TIOCSTART)
  270: #if defined (apollo)
  271:   ioctl (&fildes, TIOCSTART, 0);
  272: #else
  273:   ioctl (fildes, TIOCSTART, 0);
  274: #endif /* apollo */
  275: 
  276: #else
  277: #  if defined (TERMIOS_TTY_DRIVER)
  278:         tcflow (fildes, TCOON);
  279: #  else
  280: #    if defined (TCXONC)
  281:         ioctl (fildes, TCXONC, TCOON);
  282: #    endif /* TCXONC */
  283: #  endif /* !TERMIOS_TTY_DRIVER */
  284: #endif /* TIOCSTART */
  285: }
  286: 
  287: /* Put the terminal in CBREAK mode so that we can detect key presses. */
  288: void prep_terminal ()
  289: {
  290:   int tty = fileno (stdin);
  291: #if defined (HAVE_BSD_SIGNALS)
  292:   int oldmask;
  293: #endif /* HAVE_BSD_SIGNALS */
  294: 
  295:   if (terminal_prepped)
  296:     return;
  297: 
  298:   if (!isatty(tty)) {      /* added by MdG */
  299:     terminal_prepped = 1;      /* added by MdG */
  300:     return;      /* added by MdG */
  301:   }      /* added by MdG */
  302:    
  303:   oldmask = sigblock (sigmask (SIGINT));
  304: 
  305:   /* We always get the latest tty values.  Maybe stty changed them. */
  306:   ioctl (tty, TIOCGETP, &the_ttybuff);
  307:   original_tty_flags = the_ttybuff.sg_flags;
  308: 
  309:   readline_echoing_p = (original_tty_flags & ECHO);
  310: 
  311: #if defined (TIOCLGET)
  312:   ioctl (tty, TIOCLGET, &local_mode_flags);
  313: #endif
  314: 
  315: #if !defined (ANYP)
  316: #  define ANYP (EVENP | ODDP)
  317: #endif
  318: 
  319:   /* If this terminal doesn't care how the 8th bit is used,
  320:      then we can use it for the meta-key.  We check by seeing
  321:      if BOTH odd and even parity are allowed. */
  322:   if (the_ttybuff.sg_flags & ANYP)
  323:     {
  324: #if defined (PASS8)
  325:       the_ttybuff.sg_flags |= PASS8;
  326: #endif
  327: 
  328:       /* Hack on local mode flags if we can. */
  329: #if defined (TIOCLGET) && defined (LPASS8)
  330:       {
  331: 	int flags;
  332: 	flags = local_mode_flags | LPASS8;
  333: 	ioctl (tty, TIOCLSET, &flags);
  334:       }
  335: #endif /* TIOCLGET && LPASS8 */
  336:     }
  337: 
  338: #if defined (TIOCGETC)
  339:   {
  340:     struct tchars temp;
  341: 
  342:     ioctl (tty, TIOCGETC, &original_tchars);
  343:     temp = original_tchars;
  344: 
  345: #if defined (USE_XON_XOFF)
  346:     /* Get rid of C-s and C-q.
  347:        We remember the value of startc (C-q) so that if the terminal is in
  348:        xoff state, the user can xon it by pressing that character. */
  349:     xon_char = temp.t_startc;
  350:     temp.t_stopc = -1;
  351:     temp.t_startc = -1;
  352: 
  353:     /* If there is an XON character, bind it to restart the output. */
  354:     if (xon_char != -1)
  355:       bind_key (xon_char, restart_output);
  356: #endif /* USE_XON_XOFF */
  357: 
  358:     /* If there is an EOF char, bind eof_char to it. */
  359:     if (temp.t_eofc != -1)
  360:       eof_char = temp.t_eofc;
  361: 
  362: #if defined (NO_KILL_INTR)
  363:     /* Get rid of C-\ and C-c. */
  364:     temp.t_intrc = temp.t_quitc = -1;
  365: #endif /* NO_KILL_INTR */
  366: 
  367:     ioctl (tty, TIOCSETC, &temp);
  368:   }
  369: #endif /* TIOCGETC */
  370: 
  371: #if defined (TIOCGLTC)
  372:   {
  373:     struct ltchars temp;
  374: 
  375:     ioctl (tty, TIOCGLTC, &original_ltchars);
  376:     temp = original_ltchars;
  377: 
  378:     /* Make the interrupt keys go away.  Just enough to make people
  379:        happy. */
  380:     temp.t_dsuspc = -1;	/* C-y */
  381:     temp.t_lnextc = -1;	/* C-v */
  382: 
  383:     ioctl (tty, TIOCSLTC, &temp);
  384:   }
  385: #endif /* TIOCGLTC */
  386: 
  387:   the_ttybuff.sg_flags &= ~(ECHO | CRMOD);
  388:   the_ttybuff.sg_flags |= CBREAK;
  389:   ioctl (tty, TIOCSETN, &the_ttybuff);
  390: 
  391:   terminal_prepped = 1;
  392: 
  393: #if defined (HAVE_BSD_SIGNALS)
  394:   sigsetmask (oldmask);
  395: #endif
  396: }
  397: 
  398: /* Restore the terminal to its original state. */
  399: void deprep_terminal ()
  400: {
  401:   int tty = fileno (stdin);
  402: #if defined (HAVE_BSD_SIGNALS)
  403:   int oldmask;
  404: #endif
  405: 
  406:   if (!terminal_prepped)
  407:     return;
  408: 
  409: /* Added by MdG */
  410:   if (!isatty(tty)) {
  411:     terminal_prepped = 0;
  412:     return;
  413:   }
  414:    
  415:   oldmask = sigblock (sigmask (SIGINT));
  416: 
  417:   the_ttybuff.sg_flags = original_tty_flags;
  418:   ioctl (tty, TIOCSETN, &the_ttybuff);
  419:   readline_echoing_p = 1;
  420: 
  421: #if defined (TIOCLGET)
  422:   ioctl (tty, TIOCLSET, &local_mode_flags);
  423: #endif
  424: 
  425: #if defined (TIOCSLTC)
  426:   ioctl (tty, TIOCSLTC, &original_ltchars);
  427: #endif
  428: 
  429: #if defined (TIOCSETC)
  430:   ioctl (tty, TIOCSETC, &original_tchars);
  431: #endif
  432:   terminal_prepped = 0;
  433: 
  434: #if defined (HAVE_BSD_SIGNALS)
  435:   sigsetmask (oldmask);
  436: #endif
  437: }
  438: 
  439: #else  /* !defined (NEW_TTY_DRIVER) */
  440: 
  441: #if !defined (VMIN)
  442: #define VMIN VEOF
  443: #endif
  444: 
  445: #if !defined (VTIME)
  446: #define VTIME VEOL
  447: #endif
  448: 
  449: void prep_terminal ()
  450: {
  451:   int tty = fileno (stdin);
  452: #if defined (TERMIOS_TTY_DRIVER)
  453:   struct termios tio;
  454: #else
  455:   struct termio tio;
  456: #endif /* !TERMIOS_TTY_DRIVER */
  457: 
  458: #if defined (HAVE_POSIX_SIGNALS)
  459:   sigset_t set, oset;
  460: #else
  461: #  if defined (HAVE_BSD_SIGNALS)
  462:   int oldmask;
  463: #  endif /* HAVE_BSD_SIGNALS */
  464: #endif /* !HAVE_POSIX_SIGNALS */
  465: 
  466:   if (terminal_prepped)
  467:     return;
  468: 
  469:   if (!isatty(tty))  {     /* added by MdG */
  470:     terminal_prepped = 1;      /* added by MdG */
  471:     return;      /* added by MdG */
  472:   }      /* added by MdG */
  473:    
  474:   /* Try to keep this function from being INTerrupted.  We can do it
  475:      on POSIX and systems with BSD-like signal handling. */
  476: #if defined (HAVE_POSIX_SIGNALS)
  477:   sigemptyset (&set);
  478:   sigemptyset (&oset);
  479:   sigaddset (&set, SIGINT);
  480:   sigprocmask (SIG_BLOCK, &set, &oset);
  481: #else /* !HAVE_POSIX_SIGNALS */
  482: #  if defined (HAVE_BSD_SIGNALS)
  483:   oldmask = sigblock (sigmask (SIGINT));
  484: #  endif /* HAVE_BSD_SIGNALS */
  485: #endif /* !HAVE_POSIX_SIGNALS */
  486: 
  487: #if defined (TERMIOS_TTY_DRIVER)
  488:   tcgetattr (tty, &tio);
  489: #else
  490:   ioctl (tty, TCGETA, &tio);
  491: #endif /* !TERMIOS_TTY_DRIVER */
  492: 
  493:   otio = tio;
  494: 
  495:   readline_echoing_p = (tio.c_lflag & ECHO);
  496: 
  497:   tio.c_lflag &= ~(ICANON | ECHO);
  498: 
  499:   if (otio.c_cc[VEOF] != _POSIX_VDISABLE)
  500:     eof_char = otio.c_cc[VEOF];
  501: 
  502: #if defined (USE_XON_XOFF)
  503: #if defined (IXANY)
  504:   tio.c_iflag &= ~(IXON | IXOFF | IXANY);
  505: #else
  506:   /* `strict' Posix systems do not define IXANY. */
  507:   tio.c_iflag &= ~(IXON | IXOFF);
  508: #endif /* IXANY */
  509: #endif /* USE_XON_XOFF */
  510: 
  511:   /* Only turn this off if we are using all 8 bits. */
  512:   if ((tio.c_cflag & CSIZE) == CS8)
  513:     tio.c_iflag &= ~(ISTRIP | INPCK);
  514: 
  515:   /* Make sure we differentiate between CR and NL on input. */
  516:   tio.c_iflag &= ~(ICRNL | INLCR);
  517: 
  518: #if !defined (HANDLE_SIGNALS)
  519:   tio.c_lflag &= ~ISIG;
  520: #else
  521:   tio.c_lflag |= ISIG;
  522: #endif
  523: 
  524:   tio.c_cc[VMIN] = 1;
  525:   tio.c_cc[VTIME] = 0;
  526: 
  527:   /* Turn off characters that we need on Posix systems with job control,
  528:      just to be sure.  This includes ^Y and ^V.  This should not really
  529:      be necessary.  */
  530: #if defined (TERMIOS_TTY_DRIVER) && defined (_POSIX_JOB_CONTROL)
  531: 
  532: #if defined (VLNEXT)
  533:   tio.c_cc[VLNEXT] = _POSIX_VDISABLE;
  534: #endif
  535: 
  536: #if defined (VDSUSP)
  537:   tio.c_cc[VDSUSP] = _POSIX_VDISABLE;
  538: #endif
  539: 
  540: #endif /* POSIX && JOB_CONTROL */
  541: 
  542: #if defined (TERMIOS_TTY_DRIVER)
  543:   tcsetattr (tty, TCSADRAIN, &tio);
  544:   tcflow (tty, TCOON);		/* Simulate a ^Q. */
  545: #else
  546:   ioctl (tty, TCSETAW, &tio);
  547:   ioctl (tty, TCXONC, 1);	/* Simulate a ^Q. */
  548: #endif /* !TERMIOS_TTY_DRIVER */
  549: 
  550:   terminal_prepped = 1;
  551: 
  552: #if defined (HAVE_POSIX_SIGNALS)
  553:   sigprocmask (SIG_SETMASK, &oset, (sigset_t *)NULL);
  554: #else
  555: #  if defined (HAVE_BSD_SIGNALS)
  556:   sigsetmask (oldmask);
  557: #  endif /* HAVE_BSD_SIGNALS */
  558: #endif /* !HAVE_POSIX_SIGNALS */
  559: }
  560: 
  561: void deprep_terminal ()
  562: {
  563:   int tty = fileno (stdin);
  564: 
  565:   /* Try to keep this function from being INTerrupted.  We can do it
  566:      on POSIX and systems with BSD-like signal handling. */
  567: #if defined (HAVE_POSIX_SIGNALS)
  568:   sigset_t set, oset;
  569: #else /* !HAVE_POSIX_SIGNALS */
  570: #  if defined (HAVE_BSD_SIGNALS)
  571:   int oldmask;
  572: #  endif /* HAVE_BSD_SIGNALS */
  573: #endif /* !HAVE_POSIX_SIGNALS */
  574: 
  575:   if (!terminal_prepped)
  576:     return;
  577: 
  578: /* Added by MdG */
  579:   if (!isatty(tty)) {
  580:     terminal_prepped = 0;
  581:     return;
  582:   }
  583: 
  584: #if defined (HAVE_POSIX_SIGNALS)
  585:   sigemptyset (&set);
  586:   sigemptyset (&oset);
  587:   sigaddset (&set, SIGINT);
  588:   sigprocmask (SIG_BLOCK, &set, &oset);
  589: #else /* !HAVE_POSIX_SIGNALS */
  590: #  if defined (HAVE_BSD_SIGNALS)
  591:   oldmask = sigblock (sigmask (SIGINT));
  592: #  endif /* HAVE_BSD_SIGNALS */
  593: #endif /* !HAVE_POSIX_SIGNALS */
  594: 
  595: #if defined (TERMIOS_TTY_DRIVER)
  596:   tcsetattr (tty, TCSADRAIN, &otio);
  597:   tcflow (tty, TCOON);		/* Simulate a ^Q. */
  598: #else /* TERMIOS_TTY_DRIVER */
  599:   ioctl (tty, TCSETAW, &otio);
  600:   ioctl (tty, TCXONC, 1);	/* Simulate a ^Q. */
  601: #endif /* !TERMIOS_TTY_DRIVER */
  602: 
  603:   terminal_prepped = 0;
  604: 
  605: #if defined (HAVE_POSIX_SIGNALS)
  606:   sigprocmask (SIG_SETMASK, &oset, (sigset_t *)NULL);
  607: #else /* !HAVE_POSIX_SIGNALS */
  608: #  if defined (HAVE_BSD_SIGNALS)
  609:   sigsetmask (oldmask);
  610: #  endif /* HAVE_BSD_SIGNALS */
  611: #endif /* !HAVE_POSIX_SIGNALS */
  612: }
  613: #endif  /* NEW_TTY_DRIVER */
  614: 
  615: /* If a character is available to be read, then read it
  616:    and stuff it into IBUFFER.  Otherwise, just return. */
  617: 
  618: long pending = -1L;
  619: 
  620: long key_avail (stream)
  621: 	FILE *stream;
  622: {
  623:   int tty = fileno (stream);
  624:   int chars_avail = pending;
  625:   int result;
  626: 
  627:   if(!terminal_prepped)  prep_terminal();
  628: 
  629: #ifndef _WIN32
  630:   result = ioctl (tty, FIONREAD, &chars_avail);
  631: #else
  632:   {
  633:      fd_set selin;
  634:      static int now[2] = { 0 , 0 };
  635:      int res;
  636: 
  637:      FD_ZERO(&selin);
  638:      FD_SET(tty, &selin);
  639:      chars_avail=select(1, &selin, NULL, NULL, now);
  640:   }
  641: #endif
  642: 
  643:   if(chars_avail == -1L)
  644:     {  unsigned char inchar;
  645: 
  646:        fcntl(tty, F_SETFL, O_NDELAY);
  647:        result = read(tty, &inchar, sizeof(char));
  648:        if(result == sizeof(char))
  649:        {
  650:          chars_avail = 1;
  651:          pending = (long)inchar;
  652:        }
  653:        else
  654:          chars_avail = 0;
  655:        fcntl(tty, F_SETFL, 0);
  656:     }
  657: 
  658:   return chars_avail;
  659: }
  660: 
  661: /* Get a key from the buffer of characters to be read.
  662:    Return the key in KEY.
  663:    Result is KEY if there was a key, or 0 if there wasn't. */
  664: 
  665: /* When compiling and running in the `Posix' environment, Ultrix does
  666:    not restart system calls, so this needs to do it. */
  667: 
  668: unsigned char getkey(stream)
  669:      FILE *stream;
  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++)
  985:     signal (sigs_to_throw [i], die_on_signal ? graceful_exit : signal_throw);
  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>