summaryrefslogtreecommitdiffstats
path: root/knights/io_engine.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'knights/io_engine.cpp')
-rw-r--r--knights/io_engine.cpp312
1 files changed, 312 insertions, 0 deletions
diff --git a/knights/io_engine.cpp b/knights/io_engine.cpp
new file mode 100644
index 0000000..d9a15a7
--- /dev/null
+++ b/knights/io_engine.cpp
@@ -0,0 +1,312 @@
+/***************************************************************************
+ 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 <kprocess.h>
+#include <kicontheme.h>
+
+#include <qregexp.h>
+#include <qfile.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "io_engine.moc"
+#include "definitions.h"
+#include "proto_base.h"
+#include "proto_xboard.h"
+#include "proto_uci.h"
+
+io_engine::io_engine( QWidget *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 )
+{
+ QStringList args;
+ unsigned int tmp;
+ int ID;
+ bool Army;
+
+ /* Stop accidents */
+ if( engine != NULL )
+ return;
+ engine = new KProcess();
+
+ /* 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, SIGNAL( output( const QString& ) ), this, SLOT( WriteFIFO( const QString& ) ) );
+ connect( proto, SIGNAL( output( const Command& ) ), this, 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 = QStringList::split( QString(" "), (*IT).Arguments, FALSE );
+ for( tmp = 0; tmp < args.count(); tmp++ )
+ {
+ (*engine) << args[tmp];
+ }
+
+ /* ...log file */
+ if( !(*IT).LogFile.isEmpty() )
+ {
+ Log = new QFile( (*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( KProcess::NotifyOnExit, KProcess::All ) )
+ {
+ kdError() << "io_engine::Start: Can not run the engine: " << (*IT).Filename << endl;
+ return;
+ }
+ connect( engine, SIGNAL( wroteStdin( KProcess* ) ), this, SLOT( SendClear( KProcess* ) ) );
+ connect( engine, SIGNAL( receivedStdout( KProcess*, char*, int ) ), this, SLOT( Recv( KProcess*, char*, int ) ) );
+ connect( engine, SIGNAL( receivedStderr( KProcess*, char*, int ) ), this, SLOT( Recv( KProcess*, 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( KProcess*, 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( QChar('\n') ) )
+ {
+ QString proc = FIFO_In.left( FIFO_In.findRev( QChar('\n') ) );
+ FIFO_In = FIFO_In.right( FIFO_In.length() - proc.length() );
+
+ /* Split and Parse Full Lines of Input */
+ QStringList strList = QStringList::split( "\n", proc );
+ for( unsigned int loop = 0; loop < strList.count(); loop++ )
+ {
+ /* Print the input to the log file */
+ if( Log )
+ {
+ QString data = "-> " + strList[loop] + "\n";
+ Log->writeBlock( data.latin1(), data.length() );
+ }
+ proto->parse( strList[loop] );
+ }
+ }
+ return;
+}
+///////////////////////////////////////
+//
+// io_engine::WriteFIFO
+//
+///////////////////////////////////////
+void io_engine::WriteFIFO( const QString &Data )
+{
+ QString 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( KProcess* )
+{
+ SafeToSend = TRUE;
+ if( !FIFO_Out.isEmpty() )
+ sendToChild();
+}
+