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.
313 lines
7.3 KiB
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();
|
|
}
|
|
|