2005-10-25 01:26:25 +10:00
/** \file input_common.c
2012-11-18 11:23:22 +01:00
2005-09-20 23:26:39 +10:00
Implementation file for the low level input library
*/
# include "config.h"
2006-02-28 23:17:16 +10:00
2005-09-20 23:26:39 +10:00
# include <stdlib.h>
# include <stdio.h>
# include <string.h>
# include <errno.h>
2006-01-19 22:23:22 +10:00
# include <sys/time.h>
# include <sys/types.h>
2005-09-20 23:26:39 +10:00
# include <unistd.h>
# include <wchar.h>
2012-11-24 16:58:30 -08:00
# include <stack>
# include <list>
2006-08-11 05:02:46 +10:00
# ifdef HAVE_SYS_SELECT_H
# include <sys/select.h>
# endif
2006-01-19 22:22:07 +10:00
2006-02-28 23:17:16 +10:00
# include "fallback.h"
2005-09-20 23:26:39 +10:00
# include "util.h"
2006-02-28 23:17:16 +10:00
2005-09-20 23:26:39 +10:00
# include "common.h"
# include "wutil.h"
# include "input_common.h"
# include "env_universal.h"
2011-12-26 21:05:25 -08:00
# include "iothread.h"
2005-09-20 23:26:39 +10:00
/**
Time in milliseconds to wait for another byte to be available for
2008-01-14 02:47:47 +10:00
reading after \ \ x1b is read before assuming that escape key was
2005-09-20 23:26:39 +10:00
pressed , and not an escape sequence .
*/
# define WAIT_ON_ESCAPE 10
2012-11-24 16:58:30 -08:00
/** Characters that have been read and returned by the sequence matching code */
static std : : stack < wint_t , std : : list < wint_t > > lookahead_list ;
2005-09-20 23:26:39 +10:00
2013-04-03 13:49:58 -07:00
/* Queue of pairs of (function pointer, argument) to be invoked */
typedef std : : pair < void ( * ) ( void * ) , void * > callback_info_t ;
typedef std : : queue < callback_info_t , std : : list < callback_info_t > > callback_queue_t ;
static callback_queue_t callback_queue ;
static void input_flush_callbacks ( void ) ;
2012-11-24 16:58:30 -08:00
static bool has_lookahead ( void )
{
return ! lookahead_list . empty ( ) ;
}
static wint_t lookahead_pop ( void )
{
wint_t result = lookahead_list . top ( ) ;
lookahead_list . pop ( ) ;
return result ;
}
static void lookahead_push ( wint_t c )
{
lookahead_list . push ( c ) ;
}
static wint_t lookahead_top ( void )
{
return lookahead_list . top ( ) ;
}
2005-09-20 23:26:39 +10:00
2012-03-25 03:00:38 -07:00
/** Callback function for handling interrupts on reading */
2005-09-20 23:26:39 +10:00
static int ( * interrupt_handler ) ( ) ;
2012-11-18 16:30:30 -08:00
void input_common_init ( int ( * ih ) ( ) )
2005-09-20 23:26:39 +10:00
{
2012-11-18 16:30:30 -08:00
interrupt_handler = ih ;
2005-09-20 23:26:39 +10:00
}
void input_common_destroy ( )
{
2012-11-18 11:23:22 +01:00
2005-09-20 23:26:39 +10:00
}
/**
2013-04-07 12:40:08 -07:00
Internal function used by input_common_readch to read one byte from fd 0. This function should only be called by
2005-09-20 23:26:39 +10:00
input_common_readch ( ) .
*/
static wint_t readb ( )
{
2012-03-26 01:21:10 -07:00
/* do_loop must be set on every path through the loop; leaving it uninitialized allows the static analyzer to assist in catching mistakes. */
2012-11-18 16:30:30 -08:00
unsigned char arr [ 1 ] ;
bool do_loop ;
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
do
{
2013-04-03 13:49:58 -07:00
/* Flush callbacks */
input_flush_callbacks ( ) ;
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
fd_set fdset ;
int fd_max = 0 ;
int ioport = iothread_port ( ) ;
int res ;
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
FD_ZERO ( & fdset ) ;
FD_SET ( 0 , & fdset ) ;
if ( env_universal_server . fd > 0 )
{
FD_SET ( env_universal_server . fd , & fdset ) ;
if ( fd_max < env_universal_server . fd ) fd_max = env_universal_server . fd ;
}
if ( ioport > 0 )
{
FD_SET ( ioport , & fdset ) ;
if ( fd_max < ioport ) fd_max = ioport ;
}
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
res = select ( fd_max + 1 , & fdset , 0 , 0 , 0 ) ;
if ( res = = - 1 )
2012-11-18 11:23:22 +01:00
{
2012-11-18 16:30:30 -08:00
switch ( errno )
2012-11-18 11:23:22 +01:00
{
2012-11-19 00:31:03 -08:00
case EINTR :
case EAGAIN :
2012-11-18 16:30:30 -08:00
{
2012-11-19 00:31:03 -08:00
if ( interrupt_handler )
2012-11-18 16:30:30 -08:00
{
2012-11-19 00:31:03 -08:00
int res = interrupt_handler ( ) ;
if ( res )
{
return res ;
}
2012-11-24 16:58:30 -08:00
if ( has_lookahead ( ) )
2012-11-19 00:31:03 -08:00
{
2012-11-24 16:58:30 -08:00
return lookahead_pop ( ) ;
2012-11-19 00:31:03 -08:00
}
2012-11-18 11:23:22 +01:00
2012-11-19 00:31:03 -08:00
}
2012-11-18 11:23:22 +01:00
2012-11-19 00:31:03 -08:00
do_loop = true ;
break ;
}
default :
{
/*
The terminal has been closed . Save and exit .
*/
return R_EOF ;
}
2012-11-18 16:30:30 -08:00
}
2012-11-18 11:23:22 +01:00
}
2012-11-18 16:30:30 -08:00
else
2012-11-18 11:23:22 +01:00
{
2012-03-26 01:21:10 -07:00
/* Assume we loop unless we see a character in stdin */
do_loop = true ;
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
if ( env_universal_server . fd > 0 & & FD_ISSET ( env_universal_server . fd , & fdset ) )
2012-03-26 01:21:10 -07:00
{
2012-11-18 16:30:30 -08:00
debug ( 3 , L " Wake up on universal variable event " ) ;
2012-03-26 01:21:10 -07:00
env_universal_read_all ( ) ;
2012-11-24 16:58:30 -08:00
if ( has_lookahead ( ) )
2012-03-26 01:21:10 -07:00
{
2012-11-24 16:58:30 -08:00
return lookahead_pop ( ) ;
2012-03-26 01:21:10 -07:00
}
2012-11-18 11:23:22 +01:00
}
2012-11-18 16:30:30 -08:00
if ( ioport > 0 & & FD_ISSET ( ioport , & fdset ) )
{
2012-03-26 01:21:10 -07:00
iothread_service_completion ( ) ;
2012-11-24 16:58:30 -08:00
if ( has_lookahead ( ) )
2012-03-26 01:21:10 -07:00
{
2012-11-24 16:58:30 -08:00
return lookahead_pop ( ) ;
2012-03-26 01:21:10 -07:00
}
2012-11-18 16:30:30 -08:00
}
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
if ( FD_ISSET ( STDIN_FILENO , & fdset ) )
{
if ( read_blocked ( 0 , arr , 1 ) ! = 1 )
{
/* The teminal has been closed. Save and exit. */
return R_EOF ;
}
2012-11-18 11:23:22 +01:00
2012-03-26 01:21:10 -07:00
/* We read from stdin, so don't loop */
2012-11-18 16:30:30 -08:00
do_loop = false ;
}
}
2012-11-18 11:23:22 +01:00
}
2012-11-18 16:30:30 -08:00
while ( do_loop ) ;
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
return arr [ 0 ] ;
2005-09-20 23:26:39 +10:00
}
2012-11-18 16:30:30 -08:00
wchar_t input_common_readch ( int timed )
2005-09-20 23:26:39 +10:00
{
2012-11-24 16:58:30 -08:00
if ( ! has_lookahead ( ) )
2012-11-18 11:23:22 +01:00
{
2012-11-18 16:30:30 -08:00
if ( timed )
2012-11-18 11:23:22 +01:00
{
2012-11-18 16:30:30 -08:00
int count ;
fd_set fds ;
struct timeval tm =
{
0 ,
1000 * WAIT_ON_ESCAPE
}
;
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
FD_ZERO ( & fds ) ;
FD_SET ( 0 , & fds ) ;
count = select ( 1 , & fds , 0 , 0 , & tm ) ;
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
switch ( count )
{
2012-11-19 00:31:03 -08:00
case 0 :
return WEOF ;
2012-11-18 11:23:22 +01:00
2012-11-19 00:31:03 -08:00
case - 1 :
return WEOF ;
break ;
default :
break ;
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
}
}
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
wchar_t res ;
static mbstate_t state ;
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
while ( 1 )
{
wint_t b = readb ( ) ;
char bb ;
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
size_t sz ;
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
if ( ( b > = R_NULL ) & & ( b < R_NULL + 1000 ) )
return b ;
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
bb = b ;
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
sz = mbrtowc ( & res , & bb , 1 , & state ) ;
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
switch ( sz )
{
2012-11-19 00:31:03 -08:00
case ( size_t ) ( - 1 ) :
memset ( & state , ' \0 ' , sizeof ( state ) ) ;
debug ( 2 , L " Illegal input " ) ;
return R_NULL ;
case ( size_t ) ( - 2 ) :
break ;
case 0 :
return 0 ;
default :
return res ;
2012-11-18 16:30:30 -08:00
}
}
2012-11-18 11:23:22 +01:00
}
2012-11-18 16:30:30 -08:00
else
2012-11-18 11:23:22 +01:00
{
2012-11-18 16:30:30 -08:00
if ( ! timed )
{
2012-11-24 16:58:30 -08:00
while ( has_lookahead ( ) & & lookahead_top ( ) = = WEOF )
lookahead_pop ( ) ;
if ( ! has_lookahead ( ) )
2012-11-18 16:30:30 -08:00
return input_common_readch ( 0 ) ;
}
2012-11-18 11:23:22 +01:00
2012-11-24 16:58:30 -08:00
return lookahead_pop ( ) ;
2012-11-18 16:30:30 -08:00
}
2005-09-20 23:26:39 +10:00
}
2012-11-18 16:30:30 -08:00
void input_common_unreadch ( wint_t ch )
2005-09-20 23:26:39 +10:00
{
2012-11-24 16:58:30 -08:00
lookahead_push ( ch ) ;
2005-09-20 23:26:39 +10:00
}
2013-04-03 13:49:58 -07:00
void input_common_add_callback ( void ( * callback ) ( void * ) , void * arg )
{
ASSERT_IS_MAIN_THREAD ( ) ;
callback_queue . push ( callback_info_t ( callback , arg ) ) ;
}
static void input_flush_callbacks ( void )
{
/* Nothing to do if nothing to do */
if ( callback_queue . empty ( ) )
return ;
2013-05-05 02:33:17 -07:00
2013-04-03 13:49:58 -07:00
/* We move the queue into a local variable, so that events queued up during a callback don't get fired until next round. */
callback_queue_t local_queue ;
std : : swap ( local_queue , callback_queue ) ;
while ( ! local_queue . empty ( ) )
{
const callback_info_t & callback = local_queue . front ( ) ;
callback . first ( callback . second ) ; //cute
local_queue . pop ( ) ;
}
}