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

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