diff --git a/Makefile b/Makefile index bb646d7..40e89c6 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ -source = parse.cpp parserstate.cpp parser.cpp templates.cpp terminal.cpp termemu.cpp parseraction.cpp terminalcsi.cpp swrite.cpp -objects = parserstate.o parser.o templates.o terminal.o parseraction.o terminalcsi.o swrite.o +source = parse.cpp parserstate.cpp parser.cpp templates.cpp terminal.cpp termemu.cpp parseraction.cpp terminalcsi.cpp swrite.cpp terminalframebuffer.cpp terminalactionstate.cpp +objects = parserstate.o parser.o templates.o terminal.o parseraction.o terminalcsi.o swrite.o terminalframebuffer.o terminalactionstate.o repos = templates.rpo executables = parse termemu diff --git a/parseraction.cpp b/parseraction.cpp index f958456..4ffc4ae 100644 --- a/parseraction.cpp +++ b/parseraction.cpp @@ -1,8 +1,21 @@ +#include +#include + #include "parseraction.hpp" #include "terminal.hpp" using namespace Parser; +std::string Parser::str( void ) +{ + char thechar[ 10 ] = { 0 }; + if ( char_present ) { + snprintf( thechar, 10, isprint( ch ) ? "(%lc)" : "(0x%x)", act->ch ); + } + + return name() + std::string( thechar ); +} + void Print::act_on_terminal( Terminal::Emulator *emu ) { emu->print( this ); diff --git a/parseraction.hpp b/parseraction.hpp index 2c00ea6..9402a09 100644 --- a/parseraction.hpp +++ b/parseraction.hpp @@ -15,6 +15,8 @@ namespace Parser { wchar_t ch; bool handled; + std::string str( void ); + virtual std::string name( void ) = 0; virtual void act_on_terminal( Terminal::Emulator * ) {}; diff --git a/terminal.cpp b/terminal.cpp index 2c79836..82f0e72 100644 --- a/terminal.cpp +++ b/terminal.cpp @@ -9,50 +9,9 @@ using namespace Terminal; -Cell::Cell() - : overlapping_cell( NULL ), - contents(), - overlapped_cells(), - fallback( false ) -{} - -Cell::Cell( const Cell &x ) - : overlapping_cell( x.overlapping_cell ), - contents( x.contents ), - overlapped_cells( x.overlapped_cells ), - fallback( x.fallback ) -{} - -Cell & Cell::operator=( const Cell &x ) -{ - overlapping_cell = x.overlapping_cell; - contents = x.contents; - overlapped_cells = x.overlapped_cells; - fallback = x.fallback; - - return *this; -} - -Row::Row( size_t s_width ) - : cells( s_width ) -{} - Emulator::Emulator( size_t s_width, size_t s_height ) - : parser(), - width( s_width ), height( s_height ), - cursor_col( 0 ), cursor_row( 0 ), - combining_char_col( 0 ), combining_char_row( 0 ), - rows( height, Row( width ) ), - params(), dispatch_chars(), terminal_to_host(), - errors(), parsed_params() -{ - -} - -Emulator::~Emulator() -{ - -} + : parser(), fb( s_height, s_width ), as(), terminal_to_host() +{} std::string Emulator::input( char c, int actfd ) { @@ -67,56 +26,19 @@ std::string Emulator::input( char c, int actfd ) act->act_on_terminal( this ); + /* print out debugging information */ if ( (actfd > 0) && ( !act->handled ) ) { char actsum[ 64 ]; - char thechar[ 10 ] = { 0 }; - if ( act->char_present ) { - if ( isprint( act->ch ) ) { - snprintf( thechar, 10, "(%lc)", act->ch ); - } else { - snprintf( thechar, 10, "(0x%x)", act->ch ); - } - } - snprintf( actsum, 64, "%s%s[disp=%s,param=%s] ", - act->name().c_str(), - thechar, - dispatch_chars.c_str(), - params.c_str() ); - + snprintf( actsum, 64, "%s%s ", act->str().c_str(), as.str().c_str() ); swrite( actfd, actsum ); } - delete act; } + /* the user is supposed to send this string to the host, as if typed */ return terminal_to_host; } -void Emulator::scroll( int N ) -{ - assert( N >= 0 ); - - for ( int i = 0; i < N; i++ ) { - rows.pop_front(); - rows.push_back( Row( width ) ); - cursor_row--; - combining_char_row--; - } -} - -void Emulator::newgrapheme( void ) -{ - combining_char_col = cursor_col; - combining_char_row = cursor_row; -} - -void Emulator::autoscroll( void ) -{ - if ( cursor_row >= height ) { /* scroll */ - scroll( cursor_row - height + 1 ); - } -} - void Emulator::execute( Parser::Execute *act ) { assert( act->char_present ); @@ -171,13 +93,12 @@ void Emulator::print( Parser::Print *act ) } autoscroll(); + newgrapheme(); this_cell = &rows[ cursor_row ].cells[ cursor_col ]; this_cell->reset(); this_cell->contents.push_back( act->ch ); - newgrapheme(); - if ( (cursor_col < width - 1) && (chwidth == 2) ) { Cell *next_cell = &rows[ cursor_row ].cells[ cursor_col + 1 ]; this_cell->overlapped_cells.push_back( next_cell ); @@ -246,34 +167,6 @@ void Emulator::debug_printout( int fd ) swrite( fd, screen.c_str() ); } -void Emulator::param( Parser::Param *act ) -{ - assert( act->char_present ); - assert( (act->ch == ';') || ( (act->ch >= '0') && (act->ch <= '9') ) ); - if ( params.length() < 100 ) { - /* enough for 16 five-char params plus 15 semicolons */ - params.push_back( act->ch ); - act->handled = true; - } -} - -void Emulator::collect( Parser::Collect *act ) -{ - assert( act->char_present ); - if ( ( dispatch_chars.length() < 8 ) /* never should need more than 2 */ - && ( act->ch <= 255 ) ) { /* ignore non-8-bit */ - dispatch_chars.push_back( act->ch ); - act->handled = true; - } -} - -void Emulator::clear( Parser::Clear *act ) -{ - params.clear(); - dispatch_chars.clear(); - act->handled = true; -} - void Emulator::CSI_dispatch( Parser::CSI_Dispatch *act ) { /* add final char to dispatch key */ @@ -317,69 +210,3 @@ void Emulator::Esc_dispatch( Parser::Esc_Dispatch *act ) act->handled = true; } } - -void Emulator::parse_params( void ) -{ - parsed_params.clear(); - const char *str = params.c_str(); - const char *segment_begin = str; - - while ( 1 ) { - const char *segment_end = strchr( segment_begin, ';' ); - if ( segment_end == NULL ) { - break; - } - - errno = 0; - char *endptr; - int val = strtol( segment_begin, &endptr, 10 ); - if ( endptr == segment_begin ) { - val = -1; - } - if ( errno == 0 ) { - parsed_params.push_back( val ); - } - - segment_begin = segment_end + 1; - } - - /* get last param */ - errno = 0; - char *endptr; - int val = strtol( segment_begin, &endptr, 10 ); - if ( endptr == segment_begin ) { - val = -1; - } - if ( errno == 0 ) { - parsed_params.push_back( val ); - } -} - -int Emulator::getparam( size_t N, int defaultval ) -{ - int ret = defaultval; - if ( parsed_params.size() > N ) { - ret = parsed_params[ N ]; - } - if ( ret < 1 ) ret = defaultval; - - return ret; -} - -void Cell::reset( void ) -{ - contents.clear(); - fallback = false; - - if ( overlapping_cell ) { - assert( overlapped_cells.size() == 0 ); - } else { - for ( std::vector::iterator i = overlapped_cells.begin(); - i != overlapped_cells.end(); - i++ ) { - (*i)->overlapping_cell = NULL; - (*i)->reset(); - } - overlapped_cells.clear(); - } -} diff --git a/terminal.hpp b/terminal.hpp index db07bf6..805e72f 100644 --- a/terminal.hpp +++ b/terminal.hpp @@ -7,30 +7,10 @@ #include #include "parser.hpp" +#include "terminalframebuffer.hpp" +#include "terminalactionstate.hpp" namespace Terminal { - class Cell { - public: - Cell *overlapping_cell; - std::vector contents; - std::vector overlapped_cells; - char fallback; /* first character is combining character */ - - Cell(); - - Cell( const Cell & ); - Cell & operator=( const Cell & ); - - void reset( void ); -}; - - class Row { - public: - std::vector cells; - - Row( size_t s_width ); - }; - class Emulator { friend void Parser::Print::act_on_terminal( Emulator * ); friend void Parser::Execute::act_on_terminal( Emulator * ); @@ -42,17 +22,10 @@ namespace Terminal { private: Parser::UTF8Parser parser; - - int width, height; - int cursor_col, cursor_row; - int combining_char_col, combining_char_row; - - std::deque rows; - std::string params; - std::string dispatch_chars; + Framebuffer fb; + ActionState as; std::string terminal_to_host; - std::string errors; /* action methods */ void print( Parser::Print *act ); @@ -63,14 +36,6 @@ namespace Terminal { void CSI_dispatch( Parser::CSI_Dispatch *act ); void Esc_dispatch( Parser::Esc_Dispatch *act ); - void scroll( int N ); - void autoscroll( void ); - void newgrapheme( void ); - - void parse_params( void ); - std::vector parsed_params; - int getparam( size_t N, int defaultval ); - /* CSI and Escape methods */ void CSI_EL( void ); void CSI_ED( void ); @@ -80,15 +45,9 @@ namespace Terminal { public: Emulator( size_t s_width, size_t s_height ); - ~Emulator(); std::string input( char c, int debug_fd ); - void resize( size_t s_width, size_t s_height ); - - size_t get_width( void ) { return width; } - size_t get_height( void ) { return height; } - void debug_printout( int fd ); }; } diff --git a/terminalactionstate.cpp b/terminalactionstate.cpp new file mode 100644 index 0000000..8178837 --- /dev/null +++ b/terminalactionstate.cpp @@ -0,0 +1,106 @@ +#include + +#include "terminalactionstate.hpp" +#include "parseraction.hpp" + +using namespace Terminal; + +ActionState::ActionState() + : params(), parsed_params(), parsed( false ), dispatch_chars() +{} + +void newparamchar( Parser::Param *act ) +{ + assert( act->char_present ); + assert( (act->ch == ';') || ( (act->ch >= '0') && (act->ch <= '9') ) ); + if ( params.length() < 100 ) { + /* enough for 16 five-char params plus 15 semicolons */ + params.push_back( act->ch ); + act->handled = true; + } + parsed = false; +} + +void ActionState::collect( Parser::Collect *act ) +{ + assert( act->char_present ); + if ( ( dispatch_chars.length() < 8 ) /* never should need more than 2 */ + && ( act->ch <= 255 ) ) { /* ignore non-8-bit */ + dispatch_chars.push_back( act->ch ); + act->handled = true; + } +} + +void ActionState::clear( Parser::Clear *act ) +{ + params.clear(); + dispatch_chars.clear(); + parsed = false; + act->handled = true; +} + +void ActionState::parse_params( void ) +{ + if ( parsed ) { + return; + } + + parsed_params.clear(); + const char *str = params.c_str(); + const char *segment_begin = str; + + while ( 1 ) { + const char *segment_end = strchr( segment_begin, ';' ); + if ( segment_end == NULL ) { + break; + } + + errno = 0; + char *endptr; + int val = strtol( segment_begin, &endptr, 10 ); + if ( endptr == segment_begin ) { + val = -1; + } + if ( errno == 0 ) { + parsed_params.push_back( val ); + } + + segment_begin = segment_end + 1; + } + + /* get last param */ + errno = 0; + char *endptr; + int val = strtol( segment_begin, &endptr, 10 ); + if ( endptr == segment_begin ) { + val = -1; + } + if ( errno == 0 ) { + parsed_params.push_back( val ); + } + + parsed = true; +} + +int ActionState::getparam( size_t N, int defaultval ) +{ + int ret = defaultval; + if ( !parsed ) { + parse_params(); + } + + if ( parsed_params.size() > N ) { + ret = parsed_params[ N ]; + } + if ( ret < 1 ) ret = defaultval; + + return ret; +} + +std::string ActionState::str( void ) +{ + char assum[ 64 ]; + snprintf( assum, 64, "[dispatch=%s params=%s]", + dispatch_chars.c_str(), params.c_str() ); + return std::string( assum ); +} diff --git a/terminalactionstate.hpp b/terminalactionstate.hpp new file mode 100644 index 0000000..9c1cc63 --- /dev/null +++ b/terminalactionstate.hpp @@ -0,0 +1,35 @@ +#ifndef TERMINALACTIONSTATE_HPP +#define TERMINALACTIONSTATE_HPP + +#include + +namespace Parser { + class Param; + class Collect; + class Clear; +} + +namespace Terminal { + class ActionState { + private: + std::string params; + std::vector parsed_params; + bool parsed; + + std::string dispatch_chars; + + void parse_params( void ); + + public: + ActionState(); + int getparam( size_t N, int defaultval ); + + void newparamchar( Parser::Param *act ); + void collect( Parser::Collect *act ); + void clear( Parser::Clear *act ); + + std::string str( void ); + }; +} + +#endif diff --git a/terminalframebuffer.cpp b/terminalframebuffer.cpp new file mode 100644 index 0000000..db5ccd8 --- /dev/null +++ b/terminalframebuffer.cpp @@ -0,0 +1,82 @@ +#include "terminalframebuffer.hpp" + +using namespace Terminal; + +Cell::Cell() + : overlapping_cell( NULL ), + contents(), + overlapped_cells(), + fallback( false ) +{} + +Cell::Cell( const Cell &x ) + : overlapping_cell( x.overlapping_cell ), + contents( x.contents ), + overlapped_cells( x.overlapped_cells ), + fallback( x.fallback ) +{} + +Cell & Cell::operator=( const Cell &x ) +{ + overlapping_cell = x.overlapping_cell; + contents = x.contents; + overlapped_cells = x.overlapped_cells; + fallback = x.fallback; + + return *this; +} + +Row::Row( size_t s_width ) + : cells( s_width ) +{} + +void Cell::reset( void ) +{ + contents.clear(); + fallback = false; + + if ( overlapping_cell ) { + assert( overlapped_cells.size() == 0 ); + } else { + for ( std::vector::iterator i = overlapped_cells.begin(); + i != overlapped_cells.end(); + i++ ) { + (*i)->overlapping_cell = NULL; + (*i)->reset(); + } + overlapped_cells.clear(); + } +} + +Framebuffer::Framebuffer( int s_width, int s_height ) + : width( s_width ), height( s_height ), + cursor_col( 0 ), cursor_row( 0 ), + combining_char_col( 0 ), combining_char_row( 0 ), + rows( height, Row( width ) ) +{} + +void Framebuffer::scroll( int N ) +{ + assert( N >= 0 ); + + for ( int i = 0; i < N; i++ ) { + rows.pop_front(); + rows.push_back( Row( width ) ); + cursor_row--; + combining_char_row--; + } +} + +void Framebuffer::newgrapheme( void ) +{ + combining_char_col = cursor_col; + combining_char_row = cursor_row; +} + +void Framebuffer::autoscroll( void ) +{ + if ( cursor_row >= height ) { /* scroll */ + scroll( cursor_row - height + 1 ); + } +} + diff --git a/terminalframebuffer.hpp b/terminalframebuffer.hpp new file mode 100644 index 0000000..f343cdb --- /dev/null +++ b/terminalframebuffer.hpp @@ -0,0 +1,45 @@ +#ifndef TERMINALFB_HPP +#define TERMINALFB_HPP + +/* Terminal framebuffer */ + +namespace Terminal { + class Cell { + public: + Cell *overlapping_cell; + std::vector contents; + std::vector overlapped_cells; + char fallback; /* first character is combining character */ + + Cell(); + + Cell( const Cell & ); + Cell & operator=( const Cell & ); + + void reset( void ); + }; + + class Row { + public: + std::vector cells; + + Row( size_t s_width ); + }; + + class Framebuffer { + public: + int width, height; + int cursor_col, cursor_row; + int combining_char_col, combining_char_row; + + std::deque rows; + + void scroll( int N ); + void autoscroll( void ); + void newgrapheme( void ); + + Framebuffer( int s_width, int s_height ); + }; +} + +#endif