You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
knights/knights/io_engine.cpp

313 lines
7.3 KiB

/***************************************************************************
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 <tqregexp.h>
#include <tqfile.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( 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();
}