Add general dispatcher for CSI and escape functions

This commit is contained in:
Keith Winstein
2011-01-31 04:38:39 -05:00
parent 19e809b16e
commit cda7a87f66
9 changed files with 193 additions and 134 deletions
+2 -2
View File
@@ -1,5 +1,5 @@
source = parse.cpp parserstate.cpp parser.cpp templates.cpp terminal.cpp termemu.cpp parseraction.cpp terminalcsi.cpp swrite.cpp terminalframebuffer.cpp terminaldispatcher.cpp source = parse.cpp parserstate.cpp parser.cpp templates.cpp terminal.cpp termemu.cpp parseraction.cpp terminalfunctions.cpp swrite.cpp terminalframebuffer.cpp terminaldispatcher.cpp
objects = parserstate.o parser.o templates.o terminal.o parseraction.o terminalcsi.o swrite.o terminalframebuffer.o terminaldispatcher.o objects = parserstate.o parser.o templates.o terminal.o parseraction.o terminalfunctions.o swrite.o terminalframebuffer.o terminaldispatcher.o
repos = templates.rpo repos = templates.rpo
executables = parse termemu executables = parse termemu
+2
View File
@@ -1,6 +1,7 @@
#include <vector> #include <vector>
#include <deque> #include <deque>
#include <wchar.h> #include <wchar.h>
#include <string>
#include "terminal.hpp" #include "terminal.hpp"
@@ -14,3 +15,4 @@ template class std::deque<Terminal::Row>;
template class std::vector<Terminal::Cell *>; template class std::vector<Terminal::Cell *>;
template class std::vector<wchar_t>; template class std::vector<wchar_t>;
template class std::vector<int>; template class std::vector<int>;
template class std::map<std::string, Terminal::Function>;
+5 -41
View File
@@ -10,12 +10,12 @@
using namespace Terminal; using namespace Terminal;
Emulator::Emulator( size_t s_width, size_t s_height ) Emulator::Emulator( size_t s_width, size_t s_height )
: parser(), fb( s_width, s_height ), dispatch(), terminal_to_host() : parser(), fb( s_width, s_height ), dispatch()
{} {}
std::string Emulator::input( char c, int actfd ) std::string Emulator::input( char c, int actfd )
{ {
terminal_to_host.clear(); dispatch.terminal_to_host.clear();
std::vector<Parser::Action *> vec = parser.input( c ); std::vector<Parser::Action *> vec = parser.input( c );
@@ -36,7 +36,7 @@ std::string Emulator::input( char c, int actfd )
} }
/* the user is supposed to send this string to the host, as if typed */ /* the user is supposed to send this string to the host, as if typed */
return terminal_to_host; return dispatch.terminal_to_host;
} }
void Emulator::execute( Parser::Execute *act ) void Emulator::execute( Parser::Execute *act )
@@ -118,48 +118,12 @@ void Emulator::print( Parser::Print *act )
void Emulator::CSI_dispatch( Parser::CSI_Dispatch *act ) void Emulator::CSI_dispatch( Parser::CSI_Dispatch *act )
{ {
/* add final char to dispatch key */ dispatch.dispatch( CSI, act, &fb );
assert( act->char_present );
Parser::Collect act2;
act2.char_present = true;
act2.ch = act->ch;
dispatch.collect( &act2 );
std::string dispatch_chars = dispatch.dispatch_chars;
if ( dispatch_chars == "K" ) {
CSI_EL();
act->handled = true;
} else if ( dispatch_chars == "J" ) {
CSI_ED();
act->handled = true;
} else if ( (dispatch_chars == "A")
|| (dispatch_chars == "B")
|| (dispatch_chars == "C")
|| (dispatch_chars == "D")
|| (dispatch_chars == "H")
|| (dispatch_chars == "f") ) {
CSI_cursormove();
act->handled = true;
} else if ( dispatch_chars == "c" ) {
CSI_DA();
act->handled = true;
}
} }
void Emulator::Esc_dispatch( Parser::Esc_Dispatch *act ) void Emulator::Esc_dispatch( Parser::Esc_Dispatch *act )
{ {
/* add final char to dispatch key */ dispatch.dispatch( ESCAPE, act, &fb );
assert( act->char_present );
Parser::Collect act2;
act2.char_present = true;
act2.ch = act->ch;
dispatch.collect( &act2 );
if ( dispatch.dispatch_chars == "#8" ) {
Esc_DECALN();
act->handled = true;
}
} }
void Emulator::debug_printout( int fd ) void Emulator::debug_printout( int fd )
-2
View File
@@ -25,8 +25,6 @@ namespace Terminal {
Framebuffer fb; Framebuffer fb;
Dispatcher dispatch; Dispatcher dispatch;
std::string terminal_to_host;
/* action methods */ /* action methods */
void print( Parser::Print *act ); void print( Parser::Print *act );
void execute( Parser::Execute *act ); void execute( Parser::Execute *act );
-86
View File
@@ -1,86 +0,0 @@
#include <unistd.h>
#include "terminal.hpp"
using namespace Terminal;
static void clearline( Framebuffer *fb, int row, int start, int end )
{
for ( int col = start; col <= end; col++ ) {
fb->get_cell( row, col )->reset();
}
}
void Emulator::CSI_EL( void )
{
/* default: active position to end of line, inclusive */
int start = fb.ds.get_cursor_col(), end = fb.ds.get_width() - 1;
if ( dispatch.params == "1" ) { /* start of screen to active position, inclusive */
start = 0;
end = fb.ds.get_cursor_col();
} else if ( dispatch.params == "2" ) { /* all of line */
start = 0;
}
clearline( &fb, -1, start, end );
}
void Emulator::CSI_ED( void ) {
if ( dispatch.params == "1" ) { /* start of screen to active position, inclusive */
for ( int y = 0; y < fb.ds.get_cursor_row(); y++ ) {
clearline( &fb, y, 0, fb.ds.get_width() - 1 );
}
clearline( &fb, -1, 0, fb.ds.get_cursor_col() );
} else if ( dispatch.params == "2" ) { /* entire screen */
for ( int y = 0; y < fb.ds.get_height(); y++ ) {
clearline( &fb, y, 0, fb.ds.get_width() - 1 );
}
} else { /* active position to end of screen, inclusive */
clearline( &fb, -1, fb.ds.get_cursor_col(), fb.ds.get_width() - 1 );
for ( int y = fb.ds.get_cursor_row() + 1; y < fb.ds.get_height(); y++ ) {
clearline( &fb, y, 0, fb.ds.get_width() - 1 );
}
}
}
void Emulator::CSI_cursormove( void )
{
int num = dispatch.getparam( 0, 1 );
switch ( dispatch.dispatch_chars[ 0 ] ) {
case 'A':
fb.ds.move_row( -num, true );
break;
case 'B':
fb.ds.move_row( num, true );
break;
case 'C':
fb.ds.move_col( num, true );
break;
case 'D':
fb.ds.move_col( -num, true );
break;
case 'H':
case 'f':
int x = dispatch.getparam( 0, 1 );
int y = dispatch.getparam( 1, 1 );
fb.ds.move_row( x - 1 );
fb.ds.move_col( y - 1 );
}
}
void Emulator::CSI_DA( void )
{
terminal_to_host.append( "\033[?1;0c" );
}
void Emulator::Esc_DECALN( void )
{
for ( int y = 0; y < fb.ds.get_height(); y++ ) {
for ( int x = 0; x < fb.ds.get_width(); x++ ) {
fb.get_cell( y, x )->reset();
fb.get_cell( y, x )->contents.push_back( L'E' );
}
}
}
+43 -1
View File
@@ -8,7 +8,8 @@
using namespace Terminal; using namespace Terminal;
Dispatcher::Dispatcher() Dispatcher::Dispatcher()
: params(), parsed_params(), parsed( false ), dispatch_chars() : params(), parsed_params(), parsed( false ), dispatch_chars(),
terminal_to_host()
{} {}
void Dispatcher::newparamchar( Parser::Param *act ) void Dispatcher::newparamchar( Parser::Param *act )
@@ -106,3 +107,44 @@ std::string Dispatcher::str( void )
dispatch_chars.c_str(), params.c_str() ); dispatch_chars.c_str(), params.c_str() );
return std::string( assum ); return std::string( assum );
} }
static void register_function( Function_Type type,
std::string dispatch_chars,
Function f )
{
switch ( type ) {
case ESCAPE:
global_dispatch_registry.escape.insert( dispatch_map_t::value_type( dispatch_chars, f ) );
break;
case CSI:
global_dispatch_registry.CSI.insert( dispatch_map_t::value_type( dispatch_chars, f ) );
break;
}
}
Function::Function( Function_Type type, std::string dispatch_chars,
void (*s_function)( Framebuffer *, Dispatcher * ) )
: function( s_function )
{
register_function( type, dispatch_chars, *this );
}
void Dispatcher::dispatch( Function_Type type, Parser::Action *act, Framebuffer *fb )
{
/* add final char to dispatch key */
assert( act->char_present );
Parser::Collect act2;
act2.char_present = true;
act2.ch = act->ch;
collect( &act2 );
dispatch_map_t *map = (type == ESCAPE) ? &global_dispatch_registry.escape : &global_dispatch_registry.CSI;
dispatch_map_t::const_iterator i = map->find( dispatch_chars );
if ( i == map->end() ) {
return;
} else {
act->handled = true;
return i->second.function( fb, this );
}
}
+34 -1
View File
@@ -3,17 +3,45 @@
#include <vector> #include <vector>
#include <string> #include <string>
#include <map>
namespace Parser { namespace Parser {
class Action;
class Param; class Param;
class Collect; class Collect;
class Clear; class Clear;
class Esc_Dispatch;
class CSI_Dispatch;
} }
namespace Terminal { namespace Terminal {
class Framebuffer;
class Dispatcher;
enum Function_Type { ESCAPE, CSI };
class Function {
public:
Function() : function( NULL ) {}
Function( Function_Type type, std::string dispatch_chars,
void (*s_function)( Framebuffer *, Dispatcher * ) );
void (*function)( Framebuffer *, Dispatcher * );
};
typedef std::map<std::string, Function> dispatch_map_t;
class DispatchRegistry {
public:
dispatch_map_t escape;
dispatch_map_t CSI;
DispatchRegistry() : escape(), CSI() {}
};
static DispatchRegistry global_dispatch_registry;
class Dispatcher { class Dispatcher {
private: private:
public: /* tmp */
std::string params; std::string params;
std::vector<int> parsed_params; std::vector<int> parsed_params;
bool parsed; bool parsed;
@@ -23,6 +51,8 @@ namespace Terminal {
void parse_params( void ); void parse_params( void );
public: public:
std::string terminal_to_host; /* this is the reply string */
Dispatcher(); Dispatcher();
int getparam( size_t N, int defaultval ); int getparam( size_t N, int defaultval );
@@ -31,6 +61,9 @@ namespace Terminal {
void clear( Parser::Clear *act ); void clear( Parser::Clear *act );
std::string str( void ); std::string str( void );
void dispatch( Function_Type type, Parser::Action *act, Framebuffer *fb );
const std::string get_dispatch_chars( void ) { return dispatch_chars; }
}; };
} }
+106
View File
@@ -0,0 +1,106 @@
#include <unistd.h>
#include "terminaldispatcher.hpp"
#include "terminalframebuffer.hpp"
using namespace Terminal;
static void clearline( Framebuffer *fb, int row, int start, int end )
{
for ( int col = start; col <= end; col++ ) {
fb->get_cell( row, col )->reset();
}
}
void CSI_EL( Framebuffer *fb, Dispatcher *dispatch )
{
switch ( dispatch->getparam( 0, 0 ) ) {
case 0: /* default: active position to end of line, inclusive */
clearline( fb, -1, fb->ds.get_cursor_col(), fb->ds.get_width() - 1 );
break;
case 1: /* start of screen to active position, inclusive */
clearline( fb, -1, 0, fb->ds.get_cursor_col() );
break;
case 2: /* all of line */
clearline( fb, -1, 0, fb->ds.get_width() - 1 );
break;
}
}
static Function func_CSI_EL( CSI, "K", CSI_EL );
void CSI_ED( Framebuffer *fb, Dispatcher *dispatch ) {
switch ( dispatch->getparam( 0, 0 ) ) {
case 0: /* active position to end of screen, inclusive */
clearline( fb, -1, fb->ds.get_cursor_col(), fb->ds.get_width() - 1 );
for ( int y = fb->ds.get_cursor_row() + 1; y < fb->ds.get_height(); y++ ) {
clearline( fb, y, 0, fb->ds.get_width() - 1 );
}
break;
case 1: /* start of screen to active position, inclusive */
for ( int y = 0; y < fb->ds.get_cursor_row(); y++ ) {
clearline( fb, y, 0, fb->ds.get_width() - 1 );
}
clearline( fb, -1, 0, fb->ds.get_cursor_col() );
break;
case 2: /* entire screen */
for ( int y = 0; y < fb->ds.get_height(); y++ ) {
clearline( fb, y, 0, fb->ds.get_width() - 1 );
}
break;
}
}
static Function func_CSI_ED( CSI, "J", CSI_ED );
void CSI_cursormove( Framebuffer *fb, Dispatcher *dispatch )
{
int num = dispatch->getparam( 0, 1 );
switch ( dispatch->get_dispatch_chars()[ 0 ] ) {
case 'A':
fb->ds.move_row( -num, true );
break;
case 'B':
fb->ds.move_row( num, true );
break;
case 'C':
fb->ds.move_col( num, true );
break;
case 'D':
fb->ds.move_col( -num, true );
break;
case 'H':
case 'f':
int x = dispatch->getparam( 0, 1 );
int y = dispatch->getparam( 1, 1 );
fb->ds.move_row( x - 1 );
fb->ds.move_col( y - 1 );
}
}
static Function func_CSI_cursormove_A( CSI, "A", CSI_cursormove );
static Function func_CSI_cursormove_B( CSI, "B", CSI_cursormove );
static Function func_CSI_cursormove_C( CSI, "C", CSI_cursormove );
static Function func_CSI_cursormove_D( CSI, "D", CSI_cursormove );
static Function func_CSI_cursormove_H( CSI, "H", CSI_cursormove );
static Function func_CSI_cursormove_f( CSI, "f", CSI_cursormove );
void CSI_DA( Framebuffer *fb __attribute((unused)), Dispatcher *dispatch )
{
dispatch->terminal_to_host.append( "\033[?1;0c" );
}
static Function func_CSI_DA( CSI, "c", CSI_DA );
void Esc_DECALN( Framebuffer *fb, Dispatcher *dispatch __attribute((unused)) )
{
for ( int y = 0; y < fb->ds.get_height(); y++ ) {
for ( int x = 0; x < fb->ds.get_width(); x++ ) {
fb->get_cell( y, x )->reset();
fb->get_cell( y, x )->contents.push_back( L'E' );
}
}
}
static Function func_Esc_DECALN( ESCAPE, "#8", Esc_DECALN );