File:  [gforth] / gforth / engine / io.c
Revision 1.2: download - view: text, annotated - select for diffs
Sun Jun 15 19:43:48 1997 UTC (24 years, 4 months ago) by pazsan
Branches: MAIN
CVS tags: HEAD
Some bug fixes.

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

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