From 577bfc0dae16a9e64b6f234b511b6e1a5b843878 Mon Sep 17 00:00:00 2001 From: Keith Winstein Date: Sat, 13 Aug 2011 17:10:19 -0400 Subject: [PATCH] Import of server, all hooked together --- Makefile | 7 +- completeterminal.cpp | 23 ++++- completeterminal.hpp | 8 +- networktransport.cpp | 4 +- networktransport.hpp | 3 +- parser.cpp | 10 +++ parser.hpp | 19 +++- parserstate.cpp | 46 +++++----- parserstate.hpp | 52 +++++------ rtm-server.cpp | 191 ++++++++++++++++++++++++++++++++++++++++ templates.cpp | 2 + termemu.cpp | 1 - terminal.cpp | 7 ++ terminal.hpp | 4 +- terminaldispatcher.cpp | 6 ++ terminaldispatcher.hpp | 2 + terminalframebuffer.hpp | 11 +++ terminaluserinput.hpp | 2 + user.cpp | 18 +++- user.hpp | 9 +- 20 files changed, 355 insertions(+), 70 deletions(-) create mode 100644 rtm-server.cpp diff --git a/Makefile b/Makefile index 0e941c4..7633922 100644 --- a/Makefile +++ b/Makefile @@ -1,8 +1,8 @@ proto = userinput.proto -source = parse.cpp parserstate.cpp parser.cpp templates.cpp terminal.cpp termemu.cpp parseraction.cpp terminalfunctions.cpp swrite.cpp terminalframebuffer.cpp terminaldispatcher.cpp terminaluserinput.cpp terminaldisplay.cpp network.cpp ntester.cpp ocb.cpp base64.cpp encrypt.cpp decrypt.cpp crypto.cpp networktransport.cpp networkinstruction.cpp user.cpp userinput.pb.cc completeterminal.cpp +source = parse.cpp parserstate.cpp parser.cpp templates.cpp terminal.cpp termemu.cpp parseraction.cpp terminalfunctions.cpp swrite.cpp terminalframebuffer.cpp terminaldispatcher.cpp terminaluserinput.cpp terminaldisplay.cpp network.cpp ntester.cpp ocb.cpp base64.cpp encrypt.cpp decrypt.cpp crypto.cpp networktransport.cpp networkinstruction.cpp user.cpp userinput.pb.cc completeterminal.cpp rtm-server.cpp objects = parserstate.o parser.o templates.o terminal.o parseraction.o terminalfunctions.o swrite.o terminalframebuffer.o terminaldispatcher.o terminaluserinput.o terminaldisplay.o network.o ocb.o base64.o crypto.o networktransport.o networkinstruction.o user.o userinput.pb.o completeterminal.o repos = templates.rpo -executables = parse termemu ntester encrypt decrypt +executables = parse termemu ntester encrypt decrypt rtm-server CXX = g++ CXXFLAGS = -g --std=c++0x -pedantic -Werror -Wall -Wextra -Weffc++ -fno-implicit-templates -fno-default-inline -pipe -D_FILE_OFFSET_BITS=64 -D_XOPEN_SOURCE=500 -D_GNU_SOURCE -D_BSD_SOURCE @@ -26,6 +26,9 @@ encrypt: encrypt.o $(objects) ntester # serialize link steps because of -frepo decrypt: decrypt.o $(objects) encrypt # serialize link steps because of -frepo $(CXX) $(CXXFLAGS) -o $@ decrypt.o $(objects) $(LIBS) +rtm-server: rtm-server.o $(objects) decrypt # serialize link steps because of -frepo + $(CXX) $(CXXFLAGS) -o $@ rtm-server.o $(objects) $(LIBS) + templates.o: templates.cpp $(CXX) $(CXXFLAGS) -frepo -c -o $@ $< diff --git a/completeterminal.cpp b/completeterminal.cpp index 2cfa53c..9138ca7 100644 --- a/completeterminal.cpp +++ b/completeterminal.cpp @@ -2,8 +2,9 @@ using namespace std; using namespace Parser; +using namespace Terminal; -string Terminal::Complete::act( const string &str ) +string Complete::act( const string &str ) { for ( unsigned int i = 0; i < str.size(); i++ ) { /* parse octet into up to three actions */ @@ -22,9 +23,27 @@ string Terminal::Complete::act( const string &str ) return terminal.read_octets_to_host(); } -string Terminal::Complete::act( const Action *act ) +string Complete::act( const Action *act ) { /* apply action to terminal */ act->act_on_terminal( &terminal ); return terminal.read_octets_to_host(); } + +/* interface for Network::Transport */ +string Complete::diff_from( const Complete &existing ) +{ + return Terminal::Display::new_frame( true, existing.get_fb(), terminal.get_fb() ); +} + +void Complete::apply_string( string diff ) +{ + string terminal_to_host = act( diff ); + assert( terminal_to_host.empty() ); +} + +bool Complete::operator==( Complete const &x ) const +{ + assert( parser == x.parser ); + return terminal == x.terminal; +} diff --git a/completeterminal.hpp b/completeterminal.hpp index e8bc4b5..ae5f763 100644 --- a/completeterminal.hpp +++ b/completeterminal.hpp @@ -21,7 +21,13 @@ namespace Terminal { std::string open( void ) { return terminal.open(); } std::string close( void ) { return terminal.close(); } - const Framebuffer & get_fb( void ) { return terminal.get_fb(); } + const Framebuffer & get_fb( void ) const { return terminal.get_fb(); } + + /* interface for Network::Transport */ + void subtract( const Complete * ) {} + std::string diff_from( const Complete &existing ); + void apply_string( std::string diff ); + bool operator==( const Complete &x ) const; }; } diff --git a/networktransport.cpp b/networktransport.cpp index d749d6f..53bc7f5 100644 --- a/networktransport.cpp +++ b/networktransport.cpp @@ -149,7 +149,7 @@ void Transport::update_assumed_receiver_state( void ) template void Transport::rationalize_states( void ) { - MyState * const known_receiver_state = &sent_states.front().state; + const MyState * known_receiver_state = &sent_states.front().state; current_state.subtract( known_receiver_state ); @@ -257,7 +257,7 @@ string Transport::get_remote_diff( void ) string ret( received_states.back().state.diff_from( last_receiver_state ) ); - MyState * const oldest_receiver_state = &received_states.front().state; + const RemoteState *oldest_receiver_state = &received_states.front().state; for ( typename list< TimestampedState >::reverse_iterator i = received_states.rbegin(); i != received_states.rend(); diff --git a/networktransport.hpp b/networktransport.hpp index 67dd390..92e94a3 100644 --- a/networktransport.hpp +++ b/networktransport.hpp @@ -105,7 +105,7 @@ namespace Network { /* simple receiver */ list< TimestampedState > received_states; - MyState last_receiver_state; /* the state we were in when user last queried state */ + RemoteState last_receiver_state; /* the state we were in when user last queried state */ FragmentAssembly fragments; @@ -125,6 +125,7 @@ namespace Network { string get_key( void ) { return connection.get_key(); } MyState &get_current_state( void ) { return current_state; } + void set_current_state( const MyState &x ) { current_state = x; } string get_remote_diff( void ); diff --git a/parser.cpp b/parser.cpp index 79d8d16..f1b176e 100644 --- a/parser.cpp +++ b/parser.cpp @@ -120,3 +120,13 @@ std::list Parser::UTF8Parser::input( char c ) return ret; } + +Parser::Parser::Parser( const Parser &other ) + : state( other.state ) +{} + +Parser::Parser & Parser::Parser::operator=( const Parser &other ) +{ + state = other.state; + return *this; +} diff --git a/parser.hpp b/parser.hpp index 62804c4..4103f62 100644 --- a/parser.hpp +++ b/parser.hpp @@ -18,19 +18,25 @@ #endif namespace Parser { + static StateFamily family; + class Parser { private: - StateFamily family; - State *state; + State const *state; public: - Parser() : family(), state( &family.s_Ground ) {} + Parser() : state( &family.s_Ground ) {} - Parser( const Parser & ); + Parser( const Parser &other ); Parser & operator=( const Parser & ); ~Parser() {} std::list input( wchar_t ch ); + + bool operator==( const Parser &x ) const + { + return state == x.state; + } }; static const size_t BUF_SIZE = 8; @@ -46,6 +52,11 @@ namespace Parser { UTF8Parser(); std::list input( char c ); + + bool operator==( const UTF8Parser &x ) const + { + return parser == x.parser; + } }; } diff --git a/parserstate.cpp b/parserstate.cpp index bb051bb..0dbe55c 100644 --- a/parserstate.cpp +++ b/parserstate.cpp @@ -3,7 +3,7 @@ using namespace Parser; -Transition State::anywhere_rule( wchar_t ch ) +Transition State::anywhere_rule( wchar_t ch ) const { if ( (ch == 0x18) || (ch == 0x1A) || ((0x80 <= ch) && (ch <= 0x8F)) @@ -27,7 +27,7 @@ Transition State::anywhere_rule( wchar_t ch ) return Transition( NULL, NULL ); /* don't allocate an Ignore action */ } -Transition State::input( wchar_t ch ) +Transition State::input( wchar_t ch ) const { Transition ret = anywhere_rule( ch ); if ( !ret.next_state ) { @@ -56,7 +56,7 @@ static bool GLGR ( wchar_t ch ) || ( (0xA0 <= ch) && (ch <= 0xFF) ) ); /* GR area */ } -Transition Ground::input_state_rule( wchar_t ch ) +Transition Ground::input_state_rule( wchar_t ch ) const { if ( C0_prime( ch ) ) { return Transition( new Execute ); @@ -69,12 +69,12 @@ Transition Ground::input_state_rule( wchar_t ch ) return Transition(); } -Action *Escape::enter( void ) +Action *Escape::enter( void ) const { return new Clear; } -Transition Escape::input_state_rule( wchar_t ch ) +Transition Escape::input_state_rule( wchar_t ch ) const { if ( C0_prime( ch ) ) { return Transition( new Execute ); @@ -112,7 +112,7 @@ Transition Escape::input_state_rule( wchar_t ch ) return Transition(); } -Transition Escape_Intermediate::input_state_rule( wchar_t ch ) +Transition Escape_Intermediate::input_state_rule( wchar_t ch ) const { if ( C0_prime( ch ) ) { return Transition( new Execute ); @@ -129,12 +129,12 @@ Transition Escape_Intermediate::input_state_rule( wchar_t ch ) return Transition(); } -Action *CSI_Entry::enter( void ) +Action *CSI_Entry::enter( void ) const { return new Clear; } -Transition CSI_Entry::input_state_rule( wchar_t ch ) +Transition CSI_Entry::input_state_rule( wchar_t ch ) const { if ( C0_prime( ch ) ) { return Transition( new Execute ); @@ -164,7 +164,7 @@ Transition CSI_Entry::input_state_rule( wchar_t ch ) return Transition(); } -Transition CSI_Param::input_state_rule( wchar_t ch ) +Transition CSI_Param::input_state_rule( wchar_t ch ) const { if ( C0_prime( ch ) ) { return Transition( new Execute ); @@ -189,7 +189,7 @@ Transition CSI_Param::input_state_rule( wchar_t ch ) return Transition(); } -Transition CSI_Intermediate::input_state_rule( wchar_t ch ) +Transition CSI_Intermediate::input_state_rule( wchar_t ch ) const { if ( C0_prime( ch ) ) { return Transition( new Execute ); @@ -210,7 +210,7 @@ Transition CSI_Intermediate::input_state_rule( wchar_t ch ) return Transition(); } -Transition CSI_Ignore::input_state_rule( wchar_t ch ) +Transition CSI_Ignore::input_state_rule( wchar_t ch ) const { if ( C0_prime( ch ) ) { return Transition( new Execute ); @@ -223,12 +223,12 @@ Transition CSI_Ignore::input_state_rule( wchar_t ch ) return Transition(); } -Action *DCS_Entry::enter( void ) +Action *DCS_Entry::enter( void ) const { return new Clear; } -Transition DCS_Entry::input_state_rule( wchar_t ch ) +Transition DCS_Entry::input_state_rule( wchar_t ch ) const { if ( (0x20 <= ch) && (ch <= 0x2F) ) { return Transition( new Collect, &family->s_DCS_Intermediate ); @@ -253,7 +253,7 @@ Transition DCS_Entry::input_state_rule( wchar_t ch ) return Transition(); } -Transition DCS_Param::input_state_rule( wchar_t ch ) +Transition DCS_Param::input_state_rule( wchar_t ch ) const { if ( ( (0x30 <= ch) && (ch <= 0x39) ) || ( ch == 0x3B ) ) { return Transition( new Param ); @@ -274,7 +274,7 @@ Transition DCS_Param::input_state_rule( wchar_t ch ) return Transition(); } -Transition DCS_Intermediate::input_state_rule( wchar_t ch ) +Transition DCS_Intermediate::input_state_rule( wchar_t ch ) const { if ( (0x20 <= ch) && (ch <= 0x2F) ) { return Transition( new Collect ); @@ -291,17 +291,17 @@ Transition DCS_Intermediate::input_state_rule( wchar_t ch ) return Transition(); } -Action *DCS_Passthrough::enter( void ) +Action *DCS_Passthrough::enter( void ) const { return new Hook; } -Action *DCS_Passthrough::exit( void ) +Action *DCS_Passthrough::exit( void ) const { return new Unhook; } -Transition DCS_Passthrough::input_state_rule( wchar_t ch ) +Transition DCS_Passthrough::input_state_rule( wchar_t ch ) const { if ( C0_prime( ch ) || ( (0x20 <= ch) && (ch <= 0x7E) ) ) { return Transition( new Put ); @@ -314,7 +314,7 @@ Transition DCS_Passthrough::input_state_rule( wchar_t ch ) return Transition(); } -Transition DCS_Ignore::input_state_rule( wchar_t ch ) +Transition DCS_Ignore::input_state_rule( wchar_t ch ) const { if ( ch == 0x9C ) { return Transition( &family->s_Ground ); @@ -323,17 +323,17 @@ Transition DCS_Ignore::input_state_rule( wchar_t ch ) return Transition(); } -Action *OSC_String::enter( void ) +Action *OSC_String::enter( void ) const { return new OSC_Start; } -Action *OSC_String::exit( void ) +Action *OSC_String::exit( void ) const { return new OSC_End; } -Transition OSC_String::input_state_rule( wchar_t ch ) +Transition OSC_String::input_state_rule( wchar_t ch ) const { if ( (0x20 <= ch) && (ch <= 0x7F) ) { return Transition( new OSC_Put ); @@ -346,7 +346,7 @@ Transition OSC_String::input_state_rule( wchar_t ch ) return Transition(); } -Transition SOS_PM_APC_String::input_state_rule( wchar_t ch ) +Transition SOS_PM_APC_String::input_state_rule( wchar_t ch ) const { if ( ch == 0x9C ) { return Transition( &family->s_Ground ); diff --git a/parserstate.hpp b/parserstate.hpp index 2bfc236..c344a00 100644 --- a/parserstate.hpp +++ b/parserstate.hpp @@ -9,17 +9,17 @@ namespace Parser { class State { protected: - virtual Transition input_state_rule( wchar_t ch ) = 0; + virtual Transition input_state_rule( wchar_t ch ) const = 0; StateFamily *family; private: - Transition anywhere_rule( wchar_t ch ); + Transition anywhere_rule( wchar_t ch ) const; public: void setfamily( StateFamily *s_family ) { family = s_family; } - Transition input( wchar_t ch ); - virtual Action *enter( void ) { return new Ignore; } - virtual Action *exit( void ) { return new Ignore; } + Transition input( wchar_t ch ) const; + virtual Action *enter( void ) const { return new Ignore; } + virtual Action *exit( void ) const { return new Ignore; } State() : family( NULL ) {}; virtual ~State() {}; @@ -29,58 +29,58 @@ namespace Parser { }; class Ground : public State { - Transition input_state_rule( wchar_t ch ); + Transition input_state_rule( wchar_t ch ) const; }; class Escape : public State { - Action *enter( void ); - Transition input_state_rule( wchar_t ch ); + Action *enter( void ) const; + Transition input_state_rule( wchar_t ch ) const; }; class Escape_Intermediate : public State { - Transition input_state_rule( wchar_t ch ); + Transition input_state_rule( wchar_t ch ) const; }; class CSI_Entry : public State { - Action *enter( void ); - Transition input_state_rule( wchar_t ch ); + Action *enter( void ) const; + Transition input_state_rule( wchar_t ch ) const; }; class CSI_Param : public State { - Transition input_state_rule( wchar_t ch ); + Transition input_state_rule( wchar_t ch ) const; }; class CSI_Intermediate : public State { - Transition input_state_rule( wchar_t ch ); + Transition input_state_rule( wchar_t ch ) const; }; class CSI_Ignore : public State { - Transition input_state_rule( wchar_t ch ); + Transition input_state_rule( wchar_t ch ) const; }; class DCS_Entry : public State { - Action *enter( void ); - Transition input_state_rule( wchar_t ch ); + Action *enter( void ) const; + Transition input_state_rule( wchar_t ch ) const; }; class DCS_Param : public State { - Transition input_state_rule( wchar_t ch ); + Transition input_state_rule( wchar_t ch ) const; }; class DCS_Intermediate : public State { - Transition input_state_rule( wchar_t ch ); + Transition input_state_rule( wchar_t ch ) const; }; class DCS_Passthrough : public State { - Action *enter( void ); - Transition input_state_rule( wchar_t ch ); - Action *exit( void ); + Action *enter( void ) const; + Transition input_state_rule( wchar_t ch ) const; + Action *exit( void ) const; }; class DCS_Ignore : public State { - Transition input_state_rule( wchar_t ch ); + Transition input_state_rule( wchar_t ch ) const; }; class OSC_String : public State { - Action *enter( void ); - Transition input_state_rule( wchar_t ch ); - Action *exit( void ); + Action *enter( void ) const; + Transition input_state_rule( wchar_t ch ) const; + Action *exit( void ) const; }; class SOS_PM_APC_String : public State { - Transition input_state_rule( wchar_t ch ); + Transition input_state_rule( wchar_t ch ) const; }; } diff --git a/rtm-server.cpp b/rtm-server.cpp new file mode 100644 index 0000000..f5a64f2 --- /dev/null +++ b/rtm-server.cpp @@ -0,0 +1,191 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "networktransport.hpp" +#include "completeterminal.hpp" +#include "swrite.hpp" +#include "user.hpp" + +void serve( int host_fd ); + +using namespace std; + +int main( void ) +{ + int master; + struct termios child_termios; + + /* Adopt implementation locale */ + if ( NULL == setlocale( LC_ALL, "" ) ) { + perror( "setlocale" ); + exit( 1 ); + } + + /* Verify locale calls for UTF-8 */ + if ( strcmp( nl_langinfo( CODESET ), "UTF-8" ) != 0 ) { + fprintf( stderr, "stm requires a UTF-8 locale.\n" ); + exit( 1 ); + } + + /* Verify terminal configuration */ + if ( tcgetattr( STDIN_FILENO, &child_termios ) < 0 ) { + perror( "tcgetattr" ); + exit( 1 ); + } + + if ( !(child_termios.c_iflag & IUTF8) ) { + fprintf( stderr, "Warning: Locale is UTF-8 but termios IUTF8 flag not set. Setting IUTF8 flag.\n" ); + child_termios.c_iflag |= IUTF8; + } + + /* Fork child process */ + pid_t child = forkpty( &master, NULL, &child_termios, NULL ); + + if ( child == -1 ) { + perror( "forkpty" ); + exit( 1 ); + } + + if ( child == 0 ) { + /* child */ + if ( setenv( "TERM", "xterm", true ) < 0 ) { + perror( "setenv" ); + exit( 1 ); + } + + /* ask ncurses to send UTF-8 instead of ISO 2022 for line-drawing chars */ + if ( setenv( "NCURSES_NO_UTF8_ACS", "1", true ) < 0 ) { + perror( "setenv" ); + exit( 1 ); + } + + /* get shell name */ + struct passwd *pw = getpwuid( geteuid() ); + if ( pw == NULL ) { + perror( "getpwuid" ); + exit( 1 ); + } + + char *my_argv[ 2 ]; + my_argv[ 0 ] = strdup( pw->pw_shell ); + assert( my_argv[ 0 ] ); + my_argv[ 1 ] = NULL; + + if ( execve( pw->pw_shell, my_argv, environ ) < 0 ) { + perror( "execve" ); + exit( 1 ); + } + exit( 0 ); + } else { + /* parent */ + serve( master ); + } + + printf( "[stm is exiting.]\n" ); + + return 0; +} + +void serve( int host_fd ) +{ + /* get initial window size */ + struct winsize window_size; + if ( ioctl( STDIN_FILENO, TIOCGWINSZ, &window_size ) < 0 ) { + perror( "ioctl TIOCGWINSZ" ); + return; + } + + /* tell child process */ + if ( ioctl( host_fd, TIOCSWINSZ, &window_size ) < 0 ) { + perror( "ioctl TIOCSWINSZ" ); + return; + } + + /* open parser and terminal */ + Terminal::Complete terminal( window_size.ws_col, window_size.ws_row ); + + /* open network */ + Network::UserStream blank; + Network::Transport< Terminal::Complete, Network::UserStream > network( terminal, blank ); + + printf( "key= %s port= %d\n", network.get_key().c_str(), network.port() ); + + /* prepare to poll for events */ + struct pollfd pollfds[ 2 ]; + + pollfds[ 0 ].fd = network.fd(); + pollfds[ 0 ].events = POLLIN; + + pollfds[ 1 ].fd = host_fd; + pollfds[ 1 ].events = POLLIN; + + uint64_t last_remote_num = network.get_remote_state_num(); + + while ( 1 ) { + network.set_current_state( terminal ); + + int active_fds = poll( pollfds, 2, network.tick() ); + if ( active_fds < 0 ) { + perror( "poll" ); + break; + } + + if ( pollfds[ 0 ].revents & POLLIN ) { + /* packet received from the network */ + network.recv(); + + /* is new user input available for the terminal? */ + if ( network.get_remote_state_num() != last_remote_num ) { + string terminal_to_host; + + Network::UserStream us; + us.apply_string( network.get_remote_diff() ); + /* apply userstream to terminal */ + for ( size_t i = 0; i < us.size(); i++ ) { + terminal_to_host += terminal.act( us.get_action( i ) ); + } + + /* write any writeback octets back to the host */ + if ( swrite( host_fd, terminal_to_host.c_str(), terminal_to_host.length() ) < 0 ) { + break; + } + } + } + + if ( pollfds[ 1 ].revents & POLLIN ) { + /* input from the host needs to be fed to the terminal */ + const int buf_size = 16384; + char buf[ buf_size ]; + + /* fill buffer if possible */ + ssize_t bytes_read = read( pollfds[ 1 ].fd, buf, buf_size ); + if ( bytes_read == 0 ) { /* EOF */ + return; + } else if ( bytes_read < 0 ) { + perror( "read" ); + return; + } + + /* write any writeback octets back to the host */ + string terminal_to_host = terminal.act( string( buf, bytes_read ) ); + if ( swrite( host_fd, terminal_to_host.c_str(), terminal_to_host.length() ) < 0 ) { + break; + } + } + + if ( (pollfds[ 0 ].revents | pollfds[ 1 ].revents) + & (POLLERR | POLLHUP | POLLNVAL) ) { + break; + } + } +} diff --git a/templates.cpp b/templates.cpp index 66ee288..d3a601a 100644 --- a/templates.cpp +++ b/templates.cpp @@ -5,6 +5,7 @@ #include #include "terminal.hpp" +#include "completeterminal.hpp" #include "user.hpp" #include "networktransport.cpp" @@ -29,5 +30,6 @@ template class vector; template class vector; template class Transport; +template class Transport; template class deque; diff --git a/termemu.cpp b/termemu.cpp index ba5d9ad..c8150a3 100644 --- a/termemu.cpp +++ b/termemu.cpp @@ -28,7 +28,6 @@ const size_t buf_size = 16384; void emulate_terminal( int fd ); -int copy( int src, int dest ); int main( void ) { diff --git a/terminal.cpp b/terminal.cpp index a56b7d4..0ae582a 100644 --- a/terminal.cpp +++ b/terminal.cpp @@ -152,3 +152,10 @@ void Emulator::resize( size_t s_width, size_t s_height ) { fb.resize( s_width, s_height ); } + +bool Emulator::operator==( Emulator const &x ) const +{ + assert( dispatch == x.dispatch ); + assert( user == x.user ); + return fb == x.fb; +} diff --git a/terminal.hpp b/terminal.hpp index b90763c..6e04543 100644 --- a/terminal.hpp +++ b/terminal.hpp @@ -49,7 +49,9 @@ namespace Terminal { std::string open( void ); /* put user cursor keys in application mode */ std::string close( void ); /* restore user cursor keys */ - const Framebuffer & get_fb( void ) { return fb; } + const Framebuffer & get_fb( void ) const { return fb; } + + bool operator==( Emulator const &x ) const; }; } diff --git a/terminaldispatcher.cpp b/terminaldispatcher.cpp index 1d3d35b..4e35130 100644 --- a/terminaldispatcher.cpp +++ b/terminaldispatcher.cpp @@ -189,3 +189,9 @@ void Dispatcher::OSC_start( const Parser::OSC_Start *act ) OSC_string.clear(); act->handled = true; } + +bool Dispatcher::operator==( const Dispatcher &x ) const +{ + return ( params == x.params ) && ( parsed_params == x.parsed_params ) && ( parsed == x.parsed ) + && ( dispatch_chars == x.dispatch_chars ) && ( OSC_string == x.OSC_string ) && ( terminal_to_host == x.terminal_to_host ); +} diff --git a/terminaldispatcher.hpp b/terminaldispatcher.hpp index 205b299..7830534 100644 --- a/terminaldispatcher.hpp +++ b/terminaldispatcher.hpp @@ -76,6 +76,8 @@ namespace Terminal { void OSC_put( const Parser::OSC_Put *act ); void OSC_start( const Parser::OSC_Start *act ); void OSC_dispatch( const Parser::OSC_End *act, Framebuffer *fb ); + + bool operator==( const Dispatcher &x ) const; }; } diff --git a/terminalframebuffer.hpp b/terminalframebuffer.hpp index 4a99f27..8704c9d 100644 --- a/terminalframebuffer.hpp +++ b/terminalframebuffer.hpp @@ -151,6 +151,12 @@ namespace Terminal { void resize( int s_width, int s_height ); DrawState( int s_width, int s_height ); + + bool operator==( const DrawState &x ) const + { + /* XXX other fields not necessary to compare -- for now */ + return ( width == x.width ) && ( height == x.height ) && ( renditions == x.renditions ); + } }; class Framebuffer { @@ -227,6 +233,11 @@ namespace Terminal { void reset_cell( Cell *c ) { c->reset( ds.get_background_rendition() ); } void reset_row( Row *r ) { r->reset( ds.get_background_rendition() ); } + + bool operator==( const Framebuffer &x ) const + { + return ( rows == x.rows ) && ( window_title == x.window_title ) && ( ds == x.ds ); + } }; } diff --git a/terminaluserinput.hpp b/terminaluserinput.hpp index e7f02c0..7ad8702 100644 --- a/terminaluserinput.hpp +++ b/terminaluserinput.hpp @@ -16,6 +16,8 @@ namespace Terminal { std::string input( const Parser::UserByte *act, bool application_mode_cursor_keys ); + + bool operator==( const UserInput &x ) const { return last_byte == x.last_byte; } }; } diff --git a/user.cpp b/user.cpp index 8e1755d..ce666e9 100644 --- a/user.cpp +++ b/user.cpp @@ -8,9 +8,9 @@ using namespace Parser; using namespace Network; using namespace ClientBuffers; -void UserStream::subtract( UserStream * const prefix ) +void UserStream::subtract( const UserStream *prefix ) { - for ( deque::iterator i = prefix->actions.begin(); + for ( deque::const_iterator i = prefix->actions.begin(); i != prefix->actions.end(); i++ ) { assert( !actions.empty() ); @@ -19,7 +19,7 @@ void UserStream::subtract( UserStream * const prefix ) } } -string UserStream::diff_from( UserStream const & existing ) +string UserStream::diff_from( const UserStream &existing ) { deque::iterator my_it = actions.begin(); @@ -83,3 +83,15 @@ void UserStream::apply_string( string diff ) } } +const Parser::Action *UserStream::get_action( unsigned int i ) +{ + switch( actions[ i ].type ) { + case UserByteType: + return &( actions[ i ].userbyte ); + case ResizeType: + return &( actions[ i ].resize ); + default: + assert( false ); + return NULL; + } +} diff --git a/user.hpp b/user.hpp index cea00c2..2d2fb4e 100644 --- a/user.hpp +++ b/user.hpp @@ -40,13 +40,14 @@ namespace Network { void push_back( Parser::UserByte s_userbyte ) { actions.push_back( UserEvent( s_userbyte ) ); } void push_back( Parser::Resize s_resize ) { actions.push_back( UserEvent( s_resize ) ); } - list get_actions( void ); + size_t size( void ) { return actions.size(); } + const Parser::Action *get_action( unsigned int i ); /* interface for Network::Transport */ - void subtract( UserStream * const prefix ); - string diff_from( UserStream const & existing ); + void subtract( const UserStream *prefix ); + string diff_from( const UserStream &existing ); void apply_string( string diff ); - bool operator==( UserStream const &x ) const { return actions == x.actions; } + bool operator==( const UserStream &x ) const { return actions == x.actions; } }; }