/*********************************************************************
*                         COPYRIGHT NOTICE                           *
**********************************************************************
*        This software is copyright (C) 1982 by Pavel Curtis         *
*                                                                    *
*        Permission is granted to reproduce and distribute           *
*        this file by any means so long as no fee is charged         *
*        above a nominal handling fee and so long as this            *
*        notice is always included in the copies.                    *
*                                                                    *
*        Other rights are reserved except as explicitly granted      *
*        by written permission of the author.                        *
*                Pavel Curtis                                        *
*                Computer Science Dept.                              *
*                405 Upson Hall                                      *
*                Cornell University                                  *
*                Ithaca, NY 14853                                    *
*                                                                    *
*                Ph- (607) 256-4934                                  *
*                                                                    *
*                Pavel.Cornell@Udel-Relay   (ARPAnet)                *
*                decvax!cornell!pavel       (UUCPnet)                *
*********************************************************************/

/*
**	lib_getch.c
**
**	The routine getch().
**
** $Log:	RCS/lib_getch.v $
 * Revision 2.1  82/10/25  14:47:29  pavel
 * Added Copyright Notice
 * 
 * Revision 2.0  82/10/25  13:45:19  pavel
 * Beta-one Test Release
 * 
**
*/

static char RCSid[] =
	"$Header:   RCS/lib_getch.v  Revision 2.1  82/10/25  14:47:29  pavel  Exp$";

#include <signal.h>
#include "curses.h"
#include "curses.priv.h"

#define nextc()       (SP->_backcnt > 0  ?  SP->_backbuf[--SP->_backcnt] \
                                         :  getc(SP->_ifp))
				       
#define putback(ch)   SP->_backbuf[SP->_backcnt++] = ch


wgetch(win)
WINDOW	*win;
{
	bool	setHere = FALSE;	/* cbreak mode was set here         */
	short	ch;                     /* 'short' because of keypad codes  */
        short   kgetch();

#ifdef TRACE
	if (_tracing)
	    _tracef("wgetch(%o) called", win);
#endif

	if (! win->_scroll  &&  (win->_flags & _FULLWIN)
						&&  win->_curx == win->_maxx
						&&  win->_cury == win->_maxy)
	    return(ERR);

#ifdef FIONREAD
	if (win->_nodelay)
	{
	    long	count;

	    ioctl(fileno(SP->_ifp), FIONREAD, &count);

	    if (! count)
		return(-1);
	}
#endif

	if (SP->_echo  &&  ! (SP->_raw  ||  SP->_cbreak))
	{
		cbreak();
		setHere = TRUE;
	}

        if (win->_use_keypad)
            ch = kgetch();
        else
	    ch = nextc();

	if (SP->_echo  &&  ch < 0400)    /* ch < 0400 => not a keypad key */
	{
	    mvwaddch(curscr, win->_begy + win->_cury,
                             win->_begx + win->_curx, ch | win->_attrs);
	    waddch(win, ch | win->_attrs);
	}

	if (setHere)
	    nocbreak();

	return(ch);
}



/*
**      short
**      kgetch()
**
**      Get an input character, but take care of keypad sequences, returning
**      an appropriate code when one matches the input.  After each character
**      is received, set a one-second alarm call.  If no more of the sequence
**      is received by the time the alarm goes off, pass through the sequence
**      gotten so far.
**
*/

static  bool    alarmed;

static
short
kgetch()
{
        struct try  *ptr;
	char        ch;
	char        buffer[10];     /* Assume no sequences longer than 10 */
	char        *bufp = buffer;
	int         (*oldsig)();
	int         sigalrm();

	ptr = SP->_keytry;
	
	oldsig = signal(SIGALRM, sigalrm);
	alarmed = FALSE;
	
	do
	{
	    ch = nextc();
	    if (ch != EOF)              /* getc() returns EOF on error, too */
	        *(bufp++) = ch;
	    if (alarmed)
	        break;
	    
	    while (ptr != NULL  &&  ptr->ch != ch)
	        ptr = ptr->sibling;
	    
	    if (ptr != NULL)
	    {
	        if (ptr->value != NULL)
		{
		    alarm(0);
		    signal(SIGALRM, oldsig);
		    return(ptr->value);
		}
		else
		{
		    ptr = ptr->child;
		    alarm(1);
	        }
	    }
	    
	} while (ptr != NULL);
	
	alarm(0);
	signal(SIGALRM, oldsig);
	
	while (--bufp > buffer)
	    putback(*bufp);
	    
	return(*bufp);
}


static
sigalrm()
{
        alarmed = TRUE;
	signal(SIGALRM, sigalrm);
}
