tin-950824BETA/src/curses.c

/*
 *  Project   : tin - a Usenet reader
 *  Module    : curses.c
 *  Author    : D.Taylor & I.Lea
 *  Created   : 01-01-86
 *  Updated   : 17-05-94
 *  Notes     : This is a screen management library borrowed with permission
 *              from the Elm mail system. This library was hacked to provide
 *              what tin needs.
 *  Copyright : Copyright (c) 1986-94 Dave Taylor & Iain Lea
 *              The Elm Mail System  -  $Revision: 2.1 $   $State: Exp $
 */
 
#include "tin.h"
 
#ifndef ns32000
#   undef   sinix
#endif
#ifdef VMS
#include <descrip.h>
#include <iodef.h>
#include <ssdef.h>
#include <dvidef.h>
#ifdef __GNUC__
#include <sys$routines.h>
#include <lib$routines.h>
#endif
#endif
 
 
#ifdef HAVE_ERRNO_H
#   include <errno.h>
#else
#   include <sys/errno.h>
#endif
 
#define DEFAULT_LINES_ON_TERMINAL   24
#define DEFAULT_COLUMNS_ON_TERMINAL 80
 
int cLINES = DEFAULT_LINES_ON_TERMINAL - 1;
int cCOLS  = DEFAULT_COLUMNS_ON_TERMINAL;
int inverse_okay = TRUE;
static int _inraw = FALSE;  /* are we IN rawmode?    */
int _hp_glitch = FALSE;     /* standout not erased by overwriting on HP terms */
static int xclicks=FALSE;   /* do we have an xterm? */
 
#ifndef INDEX_DAEMON
 
#define     BACKSPACE   '\b'
#define     VERY_LONG_STRING    2500
 
#if (defined(M_AMIGA) && !defined(__SASC)) || defined(COHERENT) || defined(BSD)
#   ifndef BSD4_1
#       include <sgtty.h>
#   else
#       include <termio.h>
#   endif
#else
#   ifndef SYSV
#       ifndef MINIX
#           ifndef QNX42
#               ifdef sinix
#                   include <termios.h>
#               else
#           ifdef VMS
#           include <curses.h>
#           else
#                       include <termio.h>
#                   endif
#               endif
#           endif
#       else
#           include <sgtty.h>
#       endif
#   else
#       if defined(__hpux) || (defined(sun) && defined(SVR4))
#           include <termio.h>
#       endif
#   endif
#endif
 
#define TTYIN   0
 
#ifdef SHORTNAMES
# define _clearinverse  _clrinv
# define _cleartoeoln   _clrtoeoln
# define _cleartoeos    _clr2eos
#endif
 
#ifndef VMS
#if (defined(M_AMIGA) && !defined(__SASC)) || defined(BSD) || defined(MINIX)
#   ifdef TCGETA
#       undef TCGETA
#   endif
#   define TCGETA   TIOCGETP
#   ifdef TCSETAW
#       undef TCSETAW
#   endif
#   define TCSETAW  TIOCSETP
struct sgttyb _raw_tty,
          _original_tty;
#else
#   if !defined(M_AMIGA)
#       if defined(HAVE_TERMIOS_H) || defined(sinix)
#           ifndef TCGETA
#               define TCGETA   STCGETA
#           endif
#           ifndef TCSETA
#               define TCSETAW  STCSETAW
#           endif
struct termios _raw_tty,
          _original_tty;
#       else
#           ifndef M_OS2
struct termio _raw_tty,
          _original_tty;
#           endif
#       endif
#   endif
#endif
#endif /* VMS */
 
static char *_clearscreen, *_moveto, *_cleartoeoln, *_cleartoeos,
            *_setinverse, *_clearinverse, *_setunderline, *_clearunderline,
            *_xclickinit, *_xclickend, *_cursoron, *_cursoroff,
            *_terminalinit, *_terminalend, *_keypadlocal, *_keypadxmit;
 
#ifdef M_AMIGA
static char *_getwinsize;
#endif
 
static int _columns, _line, _lines;
 
#ifdef M_UNIX
static char _terminal[1024];        /* Storage for terminal entry */
static char _capabilities[1024];    /* String for cursor motion */
 
static char *ptr = _capabilities;   /* for buffering         */
 
/* Linux already prototypes the termcap stuff -- and there's more than
 * one variation -- so we don't prototype them in that case.
 */
#if !defined(__GNUC__) && !defined(__hpux)
extern int  tgetent P_((char *, char *));   /* get termcap entry */
extern char *tgetstr P_((char *, char **)); /* Get termcap capability (string) */
extern int  tgetflag P_((char *));          /* Get termcap capability (boolean) */
extern int  tgetnum P_((char *));           /* Get termcap capability (number) */
extern char *tgoto P_((char *, intint));  /* and the goto stuff    */
#endif
 
#endif  /* M_UNIX */
 
static int in_inverse;          /* 1 when in inverse, 0 otherwise */
 
int outchar P_((int c));    /* char output for tputs */
 
#endif /* INDEX_DAEMON */
 
 
void
setup_screen ()
{
#ifndef INDEX_DAEMON
    /*
     * get screen size from termcap entry & setup sizes
     */
    _line = 1;
    ScreenSize (&cLINES, &cCOLS);
    cmd_line = FALSE;
    Raw (TRUE);
    set_win_size (&cLINES, &cCOLS);
 
#endif /* INDEX_DAEMON */
}
 
 
#ifdef M_UNIX
 
int
InitScreen ()
{
#ifndef INDEX_DAEMON
    char termname[40], *p;
 
    if ((p = (char *) getenv ("TERM")) == (char *) 0) {
        fprintf (stderr"%s: TERM variable must be set to use screen capabilities\n", progname);
        return (FALSE);
    }
    if (strcpy (termname, p) == NULL) {
        fprintf (stderr,"%s: Can't get TERM variable\n", progname);
        return (FALSE);
    }
    if (tgetent (_terminal, termname) != 1) {
        fprintf (stderr,"%s: Can't get entry for TERM\n", progname);
        return (FALSE);
    }
 
    /* load in all those pesky values */
    _clearscreen    = tgetstr ("cl", &ptr);
    _moveto         = tgetstr ("cm", &ptr);
    _cleartoeoln    = tgetstr ("ce", &ptr);
    _cleartoeos     = tgetstr ("cd", &ptr);
    _lines          = tgetnum ("li");
    _columns        = tgetnum ("co");
    _setinverse     = tgetstr ("so", &ptr);
    _clearinverse   = tgetstr ("se", &ptr);
    _setunderline   = tgetstr ("us", &ptr);
    _clearunderline = tgetstr ("ue", &ptr);
    _hp_glitch = tgetflag ("xs");
#ifdef HAVE_BROKEN_TGETSTR
    _terminalinit   = "";
    _terminalend    = "";
    _keypadlocal    = "";
    _keypadxmit     = "";
#else
    _terminalinit   = tgetstr ("ti", &ptr);
    _terminalend    = tgetstr ("te", &ptr);
    _keypadlocal    = tgetstr ("ke", &ptr);
    _keypadxmit     = tgetstr ("ks", &ptr);
#endif
    _cursoron = NULL;
    _cursoroff = NULL;
 
    if (STRCMPEQ(termname, "xterm")) {
        xclicks = TRUE;
        _xclickinit = "\033[?9h";
        _xclickend  = "\033[?9l";
    }
 
    InitWin ();
 
    if (!_clearscreen) {
        fprintf (stderr,
            "%s: Terminal must have clearscreen (cl) capability\n",progname);
        return (FALSE);
    }
    if (!_moveto) {
        fprintf (stderr,
            "%s: Terminal must have cursor motion (cm)\n", progname);
        return (FALSE);
    }
    if (!_cleartoeoln) {
        fprintf (stderr,
            "%s: Terminal must have clear to end-of-line (ce)\n", progname);
        return (FALSE);
    }
    if (!_cleartoeos) {
        fprintf (stderr,
            "%s: Terminal must have clear to end-of-screen (cd)\n", progname);
        return (FALSE);
    }
    if (_lines == -1)
        _lines = DEFAULT_LINES_ON_TERMINAL;
    if (_columns == -1)
        _columns = DEFAULT_COLUMNS_ON_TERMINAL;
    /*
     * kludge to workaround no inverse
     */
    if (_setinverse == 0) {
        _setinverse = _setunderline;
        _clearinverse = _clearunderline;
        if (_setinverse == 0)
            draw_arrow_mark = 1;
    }
    return (TRUE);
 
#else
 
    return (FALSE);
 
#endif /* INDEX_DAEMON */
}
 
#else   /* ! M_UNIX  */
 
int
InitScreen ()
{
#ifndef INDEX_DAEMON
 
    char *ptr;
 
    /*
     * we're going to assume a terminal here...
     */
 
    _clearscreen    = "\033[1;1H\033[J";
    _moveto     = "\033[%d;%dH";    /* not a termcap string! */
    _cleartoeoln    = "\033[K";
    _setinverse = "\033[7m";
    _clearinverse   = "\033[0m";
    _setunderline   = "\033[4m";
    _clearunderline = "\033[0m";
    _keypadlocal    = "";
    _keypadxmit = "";
#ifdef M_AMIGA
    _terminalinit   = "\033[12{\033[0 p";
    _terminalend    = "\033[12}\033[ p";
    _cursoron       = "\033[ p";
    _cursoroff      = "\033[0 p";
    _cleartoeos     = "\033[J";
    _getwinsize     = "\2330 q";
#endif
#if defined(M_OS2)
    _cleartoeos = NULL;
    _terminalinit   = NULL;
    _terminalend    = "";
    initscr ();
#endif /* M_OS2 */
#if defined(VMS)
    _cleartoeos     = "\033[J";
    _terminalinit   = NULL;
    _terminalend    = "";
#endif
 
    _lines = _columns = -1;
 
    /*
     * Get lines and columns from environment settings - useful when
     * you're using something other than an Amiga window
     */
 
    if (ptr = getenv ("LINES")) {
        _lines = atol (ptr);
    }
    if (ptr = getenv ("COLUMNS")) {
        _columns = atol (ptr);
    }
 
    /*
     * If that failed, try get a response from the console itself
     */
#ifdef M_AMIGA
    if (_lines == -1 || _columns == -1) {
        _lines = DEFAULT_LINES_ON_TERMINAL;
        _columns = DEFAULT_COLUMNS_ON_TERMINAL;
    } else {
        _terminalinit = NULL;       /* don't do fancy things on a non-amiga console */
        _terminalend = NULL;
        _cursoroff = NULL;
        _cursoron = NULL;
        _getwinsize = NULL;
    }
#endif  /* M_AMIGA */
#ifdef M_OS2
    if (_lines == -1 || _columns == -1) {
        _lines = LINES;
        _columns = COLS;
    }
#endif  /* M_OS2 */
 
    InitWin ();
 
#ifdef VMS
    {
      int input_chan, status;
      int item_code, eightbit;
      struct sensemode {
        short status;
        unsigned char xmit_baud;
        unsigned char rcv_baud;
        unsigned char crfill;
        unsigned char lffill;
        unsigned char parity;
        unsigned char unused;
        char class;
        char type;
        short scr_wid;
        unsigned long tt_char : 24, scr_len : 8;
        unsigned long tt2_char;
      } tty;
      $DESCRIPTOR (input_dsc, "TT");
 
      status = SYS$ASSIGN (&input_dsc, &input_chan, 00);
      if (! (status & 1))
          LIB$STOP (status);
      SYS$QIOW (0, input_chan, IO$_SENSEMODE, &tty, 00,
            &tty.class, 120000);
      item_code = DVI$_TT_EIGHTBIT;
      status = LIB$GETDVI( &item_code, &input_chan, 0, &eightbit, 0,0 );
      _columns = tty.scr_wid;
      _lines = tty.scr_len;
 
    if (eightbit)
     { /* if using eightbit then use CSI (octal 233) rather than ESC "[" */
      _clearscreen  = "\2331;1H\233J";
      _moveto   = "\233%d;%dH"/* not a termcap string! */
      _cleartoeoln  = "\233K";
      _cleartoeos   = "\233J";
      _setinverse   = "\2337m";
      _clearinverse = "\2330m";
      _setunderline = "\2334m";
      _clearunderline   = "\2330m";
      _keypadlocal  = "";
      _keypadxmit   = "";
     }
    else
     {
      _clearscreen  = "\033[1;1H\033[J";
      _moveto   = "\033[%d;%dH";    /* not a termcap string! */
      _cleartoeoln  = "\033[K";
      _cleartoeos   = "\033[J";
      _setinverse   = "\033[7m";
      _clearinverse = "\033[0m";
      _setunderline = "\033[4m";
      _clearunderline   = "\033[0m";
      _keypadlocal  = "";
      _keypadxmit   = "";
     }
#ifdef HAS_IS_XTERM
    if (is_xterm())
     {
      xclicks = TRUE;
      if (eightbit)
       { /* These are the settings for a DECterm but the reply can't easily be parsed */
         /* Reply is of the form - CSI Pe ; Pb ; Pr ; Pc & w
            Where Pe is the event, Pb the button, Pr and Pc the row and column */
/**
         _xclickinit = "\2331;2'z";
         _xclickend = "\2330;0'z";
**/
        }
       else
        {
         _xclickinit = "\033[?9h";
         _xclickend  = "\033[?9l";
        }
     }
#endif
 
    }
#endif
    Raw (FALSE);
 
    return (TRUE);
#else
    return (FALSE);
 
#endif /* INDEX_DAEMON */
}
 
#endif  /* M_UNIX */
 
/*
 *  returns the number of lines and columns on the display.
 */
 
void
ScreenSize (num_lines, num_columns)
    int *num_lines, *num_columns;
{
#ifndef INDEX_DAEMON
 
    if (_lines == 0) _lines = DEFAULT_LINES_ON_TERMINAL;
    if (_columns == 0) _columns = DEFAULT_COLUMNS_ON_TERMINAL;
 
    *num_lines = _lines - 1;        /* assume index from zero*/
    *num_columns = _columns;        /* assume index from one */
 
#endif /* INDEX_DAEMON */
}
 
 
void
InitWin ()
{
#ifndef INDEX_DAEMON
 
    if (_terminalinit) {
        tputs (_terminalinit, 1, outchar);
        fflush (stdout);
    }
    set_keypad_on ();
    set_xclick_on ();
 
#endif /* INDEX_DAEMON */
}
 
 
void
EndWin ()
{
#ifndef INDEX_DAEMON
 
    if (_terminalend) {
        tputs (_terminalend, 1, outchar);
        fflush (stdout);
    }
    set_keypad_off ();
    set_xclick_off ();
 
 
#endif /* INDEX_DAEMON */
}
 
 
void
set_keypad_on ()
{
#ifndef INDEX_DAEMON
#    ifdef HAVE_KEYPAD
    if (use_keypad && _keypadxmit) {
        tputs (_keypadxmit, 1, outchar);
        fflush (stdout);
    }
#    endif
#endif /* INDEX_DAEMON */
}
 
 
void
set_keypad_off ()
{
#ifndef INDEX_DAEMON
#    ifdef HAVE_KEYPAD
    if (use_keypad && _keypadlocal) {
        tputs (_keypadlocal, 1, outchar);
        fflush (stdout);
    }
#    endif
#endif /* INDEX_DAEMON */
}
 
/*
 *  clear the screen: returns -1 if not capable
 */
 
void
ClearScreen ()
{
#ifndef INDEX_DAEMON
 
    tputs (_clearscreen, 1, outchar);
    fflush (stdout);      /* clear the output buffer */
    _line = 1;
 
#endif /* INDEX_DAEMON */
}
 
/*
 *  move cursor to the specified row column on the screen.
 *  0,0 is the top left!
 */
 
#ifdef M_UNIX
 
void
MoveCursor (row, col)
    int row, col;
{
#ifndef INDEX_DAEMON
 
    char *stuff;
 
    stuff = tgoto (_moveto, col, row);
    tputs (stuff, 1, outchar);
    fflush (stdout);
    _line = row + 1;
 
#endif /* INDEX_DAEMON */
}
 
#else   /* ! M_UNIX */
 
void
MoveCursor (row, col)
    int row, col;
{
#ifndef INDEX_DAEMON
 
    char stuff[12], *tgoto();
 
    if (_moveto) {
        sprintf (stuff, _moveto, row+1, col+1);
        tputs (stuff, 1, outchar);
        fflush (stdout);
        _line = row + 1;
    }
 
#endif /* INDEX_DAEMON */
}
 
#endif  /* M_UNIX */
 
/*
 *  clear to end of line
 */
 
void
CleartoEOLN ()
{
#ifndef INDEX_DAEMON
 
    tputs (_cleartoeoln, 1, outchar);
    fflush (stdout);  /* clear the output buffer */
 
#endif /* INDEX_DAEMON */
}
 
/*
 *  clear to end of screen
 */
 
void
CleartoEOS ()
{
#ifndef INDEX_DAEMON
 
    int i;
 
    if (_cleartoeos) {
        tputs (_cleartoeos, 1, outchar);
    } else {
        for (i=_line - 1 ; i < _lines ; i++) {
            MoveCursor (i, 0);
            CleartoEOLN ();
        }
    }
    fflush (stdout);  /* clear the output buffer */
 
#endif /* INDEX_DAEMON */
}
 
/*
 *  set inverse video mode
 */
 
void
StartInverse ()
{
#ifndef INDEX_DAEMON
 
    in_inverse = 1;
    if (_setinverse && inverse_okay)
        tputs (_setinverse, 1, outchar);
    fflush (stdout);
 
#endif /* INDEX_DAEMON */
}
 
/*
 *  compliment of startinverse
 */
 
void
EndInverse ()
{
#ifndef INDEX_DAEMON
 
    in_inverse = 0;
    if (_clearinverse && inverse_okay)
        tputs (_clearinverse, 1, outchar);
    fflush (stdout);
 
#endif /* INDEX_DAEMON */
}
 
/*
 *  toggle inverse video mode
 */
 
void
ToggleInverse ()
{
#ifndef INDEX_DAEMON
 
    if (in_inverse == 0)
        StartInverse();
    else
        EndInverse();
 
#endif /* INDEX_DAEMON */
}
 
/*
 *  returns either 1 or 0, for ON or OFF
 */
 
int
RawState()
{
    return (_inraw);
}
 
/*
 *  state is either TRUE or FALSE, as indicated by call
 */
 
void
Raw (state)
    int state;
{
#ifdef VMS
    if (state == FALSE && _inraw) {
/*    vmsnoraw();*/
      _inraw = 0;
    } else if (state == TRUE && ! _inraw) {
/*    vmsraw();*/
      _inraw = 1;
    }
#else
#if !defined(INDEX_DAEMON) && !defined(M_OS2)
 
#if defined(M_AMIGA) && defined(__SASC)
    _inraw = state;
    rawcon (state);
#else
    if (state == FALSE && _inraw) {
#ifdef HAVE_TCSETATTR
        (void) tcsetattr (TTYIN, TCSANOW, &_original_tty);
#else
        (void) ioctl (TTYIN, TCSETAW, &_original_tty);
#endif
        _inraw = 0;
    } else if (state == TRUE && ! _inraw) {
#ifdef HAVE_TCGETATTR
        (void) tcgetattr (TTYIN, &_original_tty);
        (void) tcgetattr (TTYIN, &_raw_tty);
#else
        (void) ioctl (TTYIN, TCGETA, &_original_tty);   /* current setting */
        (void) ioctl (TTYIN, TCGETA, &_raw_tty);    /* again! */
#endif
 
#if defined(BSD) || defined(M_AMIGA) || defined(MINIX)
        _raw_tty.sg_flags &= ~(ECHO | CRMOD);   /* echo off */
        _raw_tty.sg_flags |= CBREAK;        /* raw on */
#ifdef M_AMIGA
        _raw_tty.sg_flags |= RAW; /* Manx-C 5.2 does not support CBREAK */
#endif
#else
        _raw_tty.c_lflag &= ~(ICANON | ECHO);   /* noecho raw mode        */
        _raw_tty.c_cc[VMIN] = '\01';    /* minimum # of chars to queue    */
        _raw_tty.c_cc[VTIME] = '\0';    /* minimum time to wait for input */
#endif
 
#ifdef HAVE_TCSETATTR
        (void) tcsetattr (TTYIN, TCSANOW, &_raw_tty);
#else
        (void) ioctl (TTYIN, TCSETAW, &_raw_tty);
#endif
        _inraw = 1;
    }
#endif  /* M_AMIGA */
 
#endif /* INDEX_DAEMON */
#endif /* !VMS */
}
 
/*
 *  read a character with Raw mode set!
 */
 
#ifndef VMS
#ifdef M_OS2
 
int
ReadCh ()
{
#ifndef INDEX_DAEMON
 
    extern int errno;
    char ch;
    KBDKEYINFO os2key;
    int rc;
    register int result = 0;
    static secondkey = 0;
 
    if (secondkey) {
        result = secondkey;
        secondkey = 0;
    } else {
        rc = KbdCharIn((PKBDKEYINFO)&os2key, IO_WAIT, 0);
        result = os2key.chChar;
        if (result == 0xe0) {
            result = 0x1b;
            switch (os2key.chScan) {
                case 'H':
                    secondkey = 'A';
                    break;
                case 'P':
                    secondkey = 'B';
                    break;
                case 'K':
                    secondkey = 'D';
                    break;
                case 'M':
                    secondkey = 'C';
                    break;
                case 'I':
                    secondkey = 'I';
                    break;
                case 'Q':
                    secondkey = 'G';
                    break;
                case 'G':
                    secondkey = 'H';
                    break;
                case 'O':
                    secondkey = 'F';
                    break;
                default:
                    secondkey = '?';
            }
        } else if (result == 0x0d) {
            result = 0x0a;
        }
    }
    return ((result == EOF) ? EOF : result & 0xFF);
 
#endif /* INDEX_DAEMON */
}
 
#endif /* M_OS2 */
 
#ifdef M_AMIGA
#include <sprof.h>
 
static int new_lines, new_columns;
 
static int
AmiReadCh (int getscrsize)
{
#ifndef INDEX_DAEMON
 
static unsigned char buf[128];
static int buflen = 0, bufp = 0;
    int result;
    unsigned char ch;
 
    while (getscrsize || buflen == 0) {
PROFILE_OFF();
        result = read (0, (char *)&buf[buflen], 1);
PROFILE_ON();
        if (result <= 0return EOF;
        buflen++;
        if (buf[bufp] == KEY_PREFIX) {
            do {
                result = read (0, (char *)&buf[buflen], 1);
                if (result <= 0return EOF;
            } while (buf[buflen++] < 0x40);
 
            switch (buf[buflen-1])
            {   char *ptr;
                long class;
              case 'r':     /* Window bounds report */
                ptr = (char *)&buf[bufp+1];
                my_strtol(ptr,&ptr,10); ptr++;
                my_strtol(ptr,&ptr,10); ptr++;
                new_lines = my_strtol(ptr,&ptr,10); ptr++;
                new_columns = my_strtol(ptr,&ptr,10);
                buflen = bufp;
                if (getscrsize) return 0;
                break;
              case '|':     /* Raw Input Events */
                ptr = (char *)&buf[bufp+1];
                class = my_strtol(ptr,&ptr,10); ptr++;
                switch (class)
                {   int x,y;
                  case 12:  /* Window resized */
                    buflen = bufp; /* Must do this before raise() */
                    raise(SIGWINCH);
                    break;
#ifdef notdef
                  case 2:   /* Mouse event */
                    /*
                     * At this point we know what button was pressed
                     * but we don't really know where the mouse is.
                     * The <x> and <y> parameters don't help.
                     * Perhaps looking directly in the window's structure
                     * is the easiest thing to do (after finding out where
                     * the window's structure is! Sending an ACTION_INFO
                     * packet to the handler gives us this. I don't know
                     * if there is an easier way.
                     */
                    buflen = bufp;
                    break;
#endif
                  default:
                    buflen = bufp;
                    break;
                }
                break;
            }
        }
    }
 
    ch = buf[bufp++];
    if (bufp >= buflen) buflen = bufp = 0;
    return ch;
#else
    return -1;
#endif /* INDEX_DAEMON */
}
 
int
ReadCh()
{
    return AmiReadCh(0);
}
 
void
AmiGetWinSize(int *lines, int *columns)
{
#ifndef INDEX_DAEMON
    if (_getwinsize) {
        tputs (_getwinsize,1,outchar);  /* identify yourself */
        fflush (stdout);
        AmiReadCh(1);       /* Look for the identification */
        *lines = new_lines;
        *columns = new_columns;
    }
#endif /* INDEX_DAEMON */
}
 
#endif /* M_AMIGA */
 
#ifdef M_UNIX
 
int
ReadCh ()
{
#ifndef INDEX_DAEMON
    extern int errno;
    char ch;
    register int result;
 
#ifdef READ_CHAR_HACK
#undef getc
    while ((result = getc(stdin)) == EOF) {
        if (feof(stdin))
            break;
 
#ifdef EINTR
        if (ferror(stdin) && errno != EINTR)
#else
        if (ferror(stdin))
#endif
            break;
 
        clearerr(stdin);
    }
 
    return ((result == EOF) ? EOF : result & 0xFF);
#else
#  ifdef EINTR
    while ((result = read (0, &ch, 1)) < 0 && errno == EINTR)
        ;   /* spin on signal interrupts */
#  else
 
    result = read (0, &ch, 1);
#  endif
    return((result <= 0 ) ? EOF : ch & 0xFF);
#endif
 
#endif /* INDEX_DAEMON */
}
 
#endif  /* M_UNIX */
#endif  /* !VMS */
 
/*
 *  output a character. From tputs... (Note: this CANNOT be a macro!)
 */
 
int
outchar (c)
    int c;
{
    return fputc (c, stdout);
}
 
/*
 *  setup to monitor mouse buttons if running in a xterm
 */
 
void
xclick (state)
    int state;
{
#ifndef INDEX_DAEMON
    static int prev_state = 999;
 
    if (xclicks && prev_state != state) {
        if (state == TRUE) {
            tputs (_xclickinit, 1, outchar);
        } else {
            tputs (_xclickend, 1, outchar);
        }
        fflush (stdout);
        prev_state = state;
    }
#endif  /* INDEX_DAEMON */
}
 
/*
 *  switch on monitoring of mouse buttons
 */
 
void
set_xclick_on ()
{
    xclick (TRUE);
}
 
/*
 *  switch off monitoring of mouse buttons
 */
 
void
set_xclick_off ()
{
    xclick (FALSE);
}
 
void
cursoron ()
{
#ifndef INDEX_DAEMON
    if (_cursoron)
        tputs (_cursoron, 1, outchar);
#endif
}
 
void
cursoroff ()
{
#ifndef INDEX_DAEMON
    if (_cursoroff)
        tputs (_cursoroff, 1, outchar);
#endif
}