File:  [gforth] / gforth / Attic / io.c
Revision 1.14: download - view: text, annotated - select for diffs
Thu Jan 25 16:45:52 1996 UTC (23 years, 4 months ago) by anton
Branches: MAIN
CVS tags: HEAD
eliminated "make realclean"; it's dangerous and useless.
eliminated relocation stuff in the kernal; was buggy and useless.
SIGPIPE now returns control to Forth.
Implemented form, rows, and cols; SIGWINCH updates these (on good OS's).
changed popen and pclose to open-pipe and close-pipe.

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

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