File:  [gforth] / gforth / engine / io.c
Revision 1.4: download - view: text, annotated - select for diffs
Fri Aug 22 19:23:20 1997 UTC (26 years, 8 months ago) by pazsan
Branches: MAIN
CVS tags: HEAD
Fixed bug with key? on Digital "Uhnix"

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

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