2005-09-20 23:26:39 +10:00
/** \file input_common.h
Implementation file for the low level input library
*/
# include "config.h"
# include <stdlib.h>
# include <stdio.h>
# include <string.h>
# include <errno.h>
# include <unistd.h>
# include <wchar.h>
# include "util.h"
# include "common.h"
# include "wutil.h"
# include "input_common.h"
# include "env_universal.h"
/**
Time in milliseconds to wait for another byte to be available for
reading after \ e is read before assuming that escape key was
pressed , and not an escape sequence .
*/
# define WAIT_ON_ESCAPE 10
/**
Characters that have been read and returned by the sequence matching code
*/
static wint_t lookahead_arr [ 32 ] ;
/**
Number of entries in lookahead_arr
*/
static int lookahead_count = 0 ;
/**
Callback function for handling interrupts on reading
*/
static int ( * interrupt_handler ) ( ) ;
void input_common_init ( int ( * ih ) ( ) )
{
interrupt_handler = ih ;
}
void input_common_destroy ( )
{
}
/**
Internal function used by input_common_readch to read one byte from fd 1. This function should only be called by
input_common_readch ( ) .
*/
static wint_t readb ( )
{
2005-09-26 08:39:48 +10:00
unsigned char arr [ 1 ] ;
2005-09-20 23:26:39 +10:00
int do_loop = 0 ;
do
{
fd_set fd ;
int fd_max = 1 ;
int res ;
FD_ZERO ( & fd ) ;
FD_SET ( 0 , & fd ) ;
if ( env_universal_server . fd > 0 )
{
FD_SET ( env_universal_server . fd , & fd ) ;
fd_max = env_universal_server . fd + 1 ;
}
do_loop = 0 ;
res = select ( fd_max , & fd , 0 , 0 , 0 ) ;
if ( res = = - 1 )
{
switch ( errno )
{
case EINTR :
case EAGAIN :
{
// wperror( L"select" );
if ( interrupt_handler )
{
int res = interrupt_handler ( ) ;
/* debug( 0,
L " interrupt, %d is %ls " ,
res ,
( res = = R_NULL ? L " good " : L " Bad " ) ) ;
*/
if ( res )
return res ;
}
do_loop = 1 ;
break ;
}
default :
{
debug ( 0 , L " Error while reading input from keyboard, shutting down " ) ;
wperror ( L " read " ) ;
exit ( 1 ) ;
}
}
}
else
{
if ( env_universal_server . fd > 0 )
{
if ( FD_ISSET ( env_universal_server . fd , & fd ) )
{
debug ( 3 , L " Wake up on universal variable event " ) ;
env_universal_read_all ( ) ;
2005-10-12 05:23:43 +10:00
debug ( 3 , L " Return R_NULL " ) ;
2005-09-20 23:26:39 +10:00
return R_NULL ;
}
}
if ( FD_ISSET ( 0 , & fd ) )
{
if ( read_blocked ( 0 , arr , 1 ) = = - 1 )
{
debug ( 0 , L " Error while reading input from keyboard, shutting down " ) ;
wperror ( L " read " ) ;
exit ( 1 ) ;
}
do_loop = 0 ;
}
}
}
while ( do_loop ) ;
return arr [ 0 ] ;
}
wchar_t input_common_readch ( int timed )
{
if ( lookahead_count = = 0 )
{
if ( timed )
{
int count ;
fd_set fds ;
struct timeval tm =
{
0 ,
1000 * WAIT_ON_ESCAPE
}
;
FD_ZERO ( & fds ) ;
FD_SET ( 0 , & fds ) ;
count = select ( 1 , & fds , 0 , 0 , & tm ) ;
switch ( count )
{
case 0 :
return WEOF ;
case - 1 :
return WEOF ;
break ;
default :
break ;
}
}
wchar_t res ;
static mbstate_t state ;
while ( 1 )
{
wint_t b = readb ( ) ;
2005-09-25 05:55:58 +10:00
char bb ;
2005-09-20 23:26:39 +10:00
int sz ;
if ( b = = R_NULL )
return R_NULL ;
2005-09-25 05:55:58 +10:00
bb = b ;
sz = mbrtowc ( & res , & bb , 1 , & state ) ;
2005-09-20 23:26:39 +10:00
switch ( sz )
{
case - 1 :
memset ( & state , ' \0 ' , sizeof ( state ) ) ;
debug ( 2 , L " Illegal input " ) ;
return R_NULL ;
case - 2 :
break ;
case 0 :
return 0 ;
default :
return res ;
}
}
}
else
{
if ( ! timed )
{
while ( ( lookahead_count > = 0 ) & & ( lookahead_arr [ lookahead_count - 1 ] = = WEOF ) )
lookahead_count - - ;
if ( lookahead_count = = 0 )
return input_common_readch ( 0 ) ;
}
return lookahead_arr [ - - lookahead_count ] ;
}
}
void input_common_unreadch ( wint_t ch )
{
lookahead_arr [ lookahead_count + + ] = ch ;
}