/*************************************************************************** io_engine.cpp - description ------------------- begin : Sat Jun 30 2001 copyright : (C) 2003 by Troy Corbin Jr. email : tcorbin@users.sourceforge.net ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include #include #include #include #include #include #include #include "io_engine.moc" #include "definitions.h" #include "proto_base.h" #include "proto_xboard.h" #include "proto_uci.h" io_engine::io_engine( TQWidget *parent, resource *Rsrc ) : io_base( parent, Rsrc ) { myType = io_base::LOCAL; engine = NULL; Log = NULL; proto = NULL; SafeToSend = TRUE; CleanBuffer = TRUE; SendSIGINT = FALSE; Forced = TRUE; Protocol = XBoard; FIFO_In = ""; FIFO_Out = ""; } // io_engine::~io_engine() { if( engine ) { Kill(); } if( Log ) { Log->close(); delete Log; } if( proto ) { delete proto; } } /////////////////////////////////////// // // io_engine::Start // /////////////////////////////////////// void io_engine::Start( const int side ) { TQStringList args; unsigned int tmp; int ID; bool Army; /* Stop accidents */ if( engine != NULL ) return; engine = new TDEProcess(); /* Convert 'side' to 'ID' */ if( side == WHITE ) { ID = ENGINE_WHITE; Army = WHITE; } else if( side == BLACK ) { ID = ENGINE_BLACK; Army = BLACK; } else if( side == WHITE_HELPER ) { ID = ENGINE_WHITE_BK; Army = WHITE; } else { ID = ENGINE_BLACK_BK; Army = BLACK; } /* Get and parse engine config from resource */ for( IT = myResource->engines.begin(); IT != myResource->engines.end(); ++IT ) { if( (*IT).CurrentRef & ID ) break; } if( IT == myResource->engines.end() ) { kdError() << "io_engine::Start: Can not find engine resource ID " << ID << endl; return; } /* ...protocol */ Protocol = (*IT).Protocol; switch( Protocol ) { case UCI: proto = new proto_uci( myID ); break; case XBoard: default: proto = new proto_xboard( myID ); break; } connect( proto, TQT_SIGNAL( output( const TQString& ) ), this, TQT_SLOT( WriteFIFO( const TQString& ) ) ); connect( proto, TQT_SIGNAL( output( const Command& ) ), this, TQT_SLOT( recvProtoCMD( const Command& ) ) ); /* ...engine's display name */ proto->parse( Command( myID, CMD_Set_Name, (*IT).Name ) ); /* ...engine file name */ (*engine) << (*IT).Filename; /* ...command line arguments */ args = TQStringList::split( TQString(" "), (*IT).Arguments, FALSE ); for( tmp = 0; tmp < args.count(); tmp++ ) { (*engine) << args[tmp]; } /* ...log file */ if( !(*IT).LogFile.isEmpty() ) { Log = new TQFile( (*IT).LogFile ); if( !Log->open( IO_WriteOnly | IO_Append ) ) if( !Log->open( IO_WriteOnly ) ) kdError() << "io_engine::Start: Can not open " << (*IT).LogFile << " for writing." << endl; } /* Showtime */ if( !engine->start( TDEProcess::NotifyOnExit, TDEProcess::All ) ) { kdError() << "io_engine::Start: Can not run the engine: " << (*IT).Filename << endl; return; } connect( engine, TQT_SIGNAL( wroteStdin( TDEProcess* ) ), this, TQT_SLOT( SendClear( TDEProcess* ) ) ); connect( engine, TQT_SIGNAL( receivedStdout( TDEProcess*, char*, int ) ), this, TQT_SLOT( Recv( TDEProcess*, char*, int ) ) ); connect( engine, TQT_SIGNAL( receivedStderr( TDEProcess*, char*, int ) ), this, TQT_SLOT( Recv( TDEProcess*, char*, int ) ) ); proto->parse( Command( myID, CMD_Init ) ); if( myResource->OPTION_Ponder ) proto->parse( Command( myID, CMD_Ponder ) ); else proto->parse( Command( myID, CMD_No_Pondering ) ); proto->parse( Command( myID, CMD_NewGame ) ); if( Army == WHITE ) proto->parse( Command( myID, CMD_Play_White ) ); else proto->parse( Command( myID, CMD_Play_Black ) ); return; } /////////////////////////////////////// // // io_engine::Kill // /////////////////////////////////////// void io_engine::Kill( void ) { proto->parse( Command( myID, CMD_Exit ) ); if( engine != NULL ) delete engine; } /////////////////////////////////////// // // io_engine::sendToChild // /////////////////////////////////////// void io_engine::sendToChild( void ) { if( !SafeToSend || FIFO_Out.isEmpty() || !engine->isRunning() ) return; /* Interrupt those engines that want or need it */ if( SendSIGINT ) { engine->kill( SIGINT ); SendSIGINT = FALSE; } /* Write it */ SafeToSend = FALSE; if( engine->writeStdin( FIFO_Out.latin1(), FIFO_Out.length() ) ) { /* Print the output to the log file */ if( Log ) { FIFO_Out.prepend( "<- " ); Log->writeBlock( FIFO_Out.latin1(), FIFO_Out.length() ); } FIFO_Out = ""; } else kdError() << "io_engine::sendToChild: Could not write to engine." << endl; } /////////////////////////////////////// // // io_engine::Recv // /////////////////////////////////////// void io_engine::Recv( TDEProcess*, char *buffer, int bufLen ) { char *newBuff = new char[bufLen + 1]; strncpy( newBuff, buffer, bufLen ); newBuff[bufLen] = 0; FIFO_In += newBuff; delete newBuff; if( FIFO_In.contains( TQChar('\n') ) ) { TQString proc = FIFO_In.left( FIFO_In.findRev( TQChar('\n') ) ); FIFO_In = FIFO_In.right( FIFO_In.length() - proc.length() ); /* Split and Parse Full Lines of Input */ TQStringList strList = TQStringList::split( "\n", proc ); for( unsigned int loop = 0; loop < strList.count(); loop++ ) { /* Print the input to the log file */ if( Log ) { TQString data = "-> " + strList[loop] + "\n"; Log->writeBlock( data.latin1(), data.length() ); } proto->parse( strList[loop] ); } } return; } /////////////////////////////////////// // // io_engine::WriteFIFO // /////////////////////////////////////// void io_engine::WriteFIFO( const TQString &Data ) { TQString data = Data; if( data.isEmpty() ) return; if( data.right(1) != "\n" ) data += "\n"; FIFO_Out += data; sendToChild(); return; } /////////////////////////////////////// // // io_engine::recvCMD // /////////////////////////////////////// void io_engine::recvCMD( const Command &command ) { proto->parse( command ); } /////////////////////////////////////// // // io_engine::recvProtoCMD // /////////////////////////////////////// void io_engine::recvProtoCMD( const Command &command ) { Command cmd = command; switch( cmd.getCommand() ) { /* Command: Send_SIGTERM */ case CMD_Send_SIGTERM: engine->kill(); break; /* Command: Send_SIGINT */ case CMD_Send_SIGINT: SendSIGINT = TRUE; break; /* Command to Core */ default: emit sendCMD( command ); break; } } void io_engine::SendClear( TDEProcess* ) { SafeToSend = TRUE; if( !FIFO_Out.isEmpty() ) sendToChild(); }