Subversion Repositories Games.Chess Giants

Rev

Rev 140 | Rev 150 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 140 Rev 149
Line 2... Line 2...
2
 
2
 
3
#include "common.h"
3
#include "common.h"
-
 
4
 
-
 
5
#include <fcntl.h>
-
 
6
 
-
 
7
// definitions used in this module only
-
 
8
#define RD 0
-
 
9
#define WR 1
-
 
10
#define CLOSE_PIPE(pipe) if (pipe[RD] != -1) _close (pipe[RD]); pipe[RD] = -1; if (pipe[WR] != -1) _close (pipe[WR]); pipe[WR] = -1
4
 
11
 
5
 
12
 
6
// global variables used in this module only
13
// global variables used in this module only
7
static wchar_t chessenginemodule_path[MAX_PATH];
14
static wchar_t chessenginemodule_path[MAX_PATH];
8
static wchar_t chessenginemodule_pathname[MAX_PATH];
15
static wchar_t chessenginemodule_pathname[MAX_PATH];
9
static wchar_t chessengineinitfile_pathname[MAX_PATH];
16
static wchar_t chessengineinitfile_pathname[MAX_PATH];
10
static PROCESS_INFORMATION PlayerEngine_pi;
17
static PROCESS_INFORMATION PlayerEngine_pi;
11
static HANDLE hChessEngineStdinRd;
18
static int chessgiants_to_engine[2]; // RD and WR
12
static HANDLE hChessEngineStdinWr;
-
 
13
static HANDLE hChessEngineStdoutRd;
19
static int engine_to_chessgiants[2]; // RD and WR
14
static HANDLE hChessEngineStdoutWr;
-
 
15
static int current_obstinacy;
20
static int current_obstinacy;
16
static bool is_hint_pending;
21
static bool is_hint_pending;
17
 
22
 
18
// prototypes of local functions
23
// prototypes of local functions
19
static void PlayerEngine_Recv (player_t *player);
24
static void PlayerEngine_Recv (player_t *player);
Line 27... Line 32...
27
   // stdout are redirected to the handles we give it, so that we may read/write to it.
32
   // stdout are redirected to the handles we give it, so that we may read/write to it.
28
 
33
 
29
   engineprogram_t *program;
34
   engineprogram_t *program;
30
   wchar_t widechar_buffer[256];
35
   wchar_t widechar_buffer[256];
31
   SYSTEM_INFO sysinfo;
36
   SYSTEM_INFO sysinfo;
-
 
37
   HANDLE hStdOut[2] = { NULL, NULL };
-
 
38
   HANDLE hStdIn[2] = { NULL, NULL };
32
   SECURITY_ATTRIBUTES saAttr;
39
   SECURITY_ATTRIBUTES saAttr;
33
   STARTUPINFO si;
40
   STARTUPINFO si;
34
   int try_index;
41
   int try_index;
35
   FILE *fp;
42
   FILE *fp;
36
 
43
 
37
   // reset stuff first
44
   // reset stuff first
38
   hChessEngineStdinRd = NULL;
-
 
39
   hChessEngineStdinWr = NULL;
-
 
40
   hChessEngineStdoutRd = NULL;
-
 
41
   hChessEngineStdoutWr = NULL;
-
 
42
   player->wants_hint = false;
45
   player->wants_hint = false;
43
 
46
 
44
   // quick access to engine program
47
   // quick access to engine program
45
   program = &options.engine.programs[options.engine.selected_program];
48
   program = &options.engine.programs[options.engine.selected_program];
46
 
49
 
47
   // build the chess engine module path and pathname
50
   // build the chess engine module path and pathname
48
   swprintf_s (chessenginemodule_path, WCHAR_SIZEOF (chessenginemodule_path), L"%s/engines/%s", app_path, program->folder);
51
   swprintf_s (chessenginemodule_path, WCHAR_SIZEOF (chessenginemodule_path), L"%s/engines/%s", app_path, program->folder);
49
   swprintf_s (chessenginemodule_pathname, WCHAR_SIZEOF (chessenginemodule_pathname), L"%s/engines/%s/%s", app_path, program->folder, program->cmdline);
52
   swprintf_s (chessenginemodule_pathname, WCHAR_SIZEOF (chessenginemodule_pathname), L"%s/engines/%s/%s", app_path, program->folder, program->cmdline);
50
 
53
 
51
   // prepare the pipes' security attributes
54
   // build the I/O pipes
52
   memset (&saAttr, 0, sizeof (saAttr));
55
   memset (&saAttr, 0, sizeof (saAttr)); // prepare the pipes' security attributes
53
   saAttr.nLength = sizeof (SECURITY_ATTRIBUTES);
56
   saAttr.nLength = sizeof (SECURITY_ATTRIBUTES);
54
   saAttr.bInheritHandle = true; // set the bInheritHandle flag so pipe handles are inherited
57
   saAttr.bInheritHandle = true; // set the bInheritHandle flag so pipe handles are inherited
55
 
-
 
56
   // create a pipe for the child process's stdout
58
   CreatePipe (&hStdIn[RD], &hStdIn[WR], &saAttr, 0); // create a pipe for the child process's stdin
57
   CreatePipe (&hChessEngineStdoutRd, &hChessEngineStdoutWr, &saAttr, 0);
59
   CreatePipe (&hStdOut[RD], &hStdOut[WR], &saAttr, 0); // create a pipe for the child process's stdout
-
 
60
   SetHandleInformation (hStdIn[WR], HANDLE_FLAG_INHERIT, 0); // ensure the write handle to the pipe for STDIN is not inherited
58
   SetHandleInformation (hChessEngineStdoutRd, HANDLE_FLAG_INHERIT, 0); // ensure the read handle to the pipe for STDOUT is not inherited
61
   SetHandleInformation (hStdOut[RD], HANDLE_FLAG_INHERIT, 0); // ensure the read handle to the pipe for STDOUT is not inherited
59
 
-
 
60
   // create a pipe for the child process's stdin
62
   engine_to_chessgiants[RD] = _open_osfhandle ((intptr_t) hStdOut[RD], _O_BINARY);
-
 
63
   engine_to_chessgiants[WR] = _open_osfhandle ((intptr_t) hStdOut[WR], _O_BINARY | _O_APPEND);
61
   CreatePipe (&hChessEngineStdinRd, &hChessEngineStdinWr, &saAttr, 0);
64
   chessgiants_to_engine[RD] = _open_osfhandle ((intptr_t) hStdIn[RD], _O_BINARY);
62
   SetHandleInformation (hChessEngineStdinWr, HANDLE_FLAG_INHERIT, 0); // ensure the write handle to the pipe for STDIN is not inherited. 
65
   chessgiants_to_engine[WR] = _open_osfhandle ((intptr_t) hStdIn[WR], _O_BINARY | _O_APPEND);
63
 
66
 
64
   // spawn the chess engine process with redirected input and output
67
   // spawn the chess engine process with redirected input and output
65
   memset (&si, 0, sizeof (si));
68
   memset (&si, 0, sizeof (si));
66
   si.cb = sizeof (STARTUPINFOA);
69
   si.cb = sizeof (STARTUPINFOA);
67
   si.dwFlags = STARTF_USESTDHANDLES;
70
   si.dwFlags = STARTF_USESTDHANDLES;
68
   si.hStdInput = hChessEngineStdinRd;
71
   si.hStdInput = hStdIn[RD];
69
   si.hStdOutput = hChessEngineStdoutWr;
72
   si.hStdOutput = hStdOut[WR];
70
   si.hStdError = hChessEngineStdoutWr;
73
   si.hStdError = hStdOut[WR];
71
   if (!CreateProcess (chessenginemodule_pathname, // module pathname
74
   if (!CreateProcess (chessenginemodule_pathname, // module pathname
72
                       program->cmdline, // command line
75
                       program->cmdline, // command line
73
                       NULL, NULL,
76
                       NULL, NULL,
74
                       true, // handles are inherited
77
                       true, // handles are inherited
75
                       CREATE_NO_WINDOW | DETACHED_PROCESS | CREATE_NEW_PROCESS_GROUP,
78
                       CREATE_NO_WINDOW | DETACHED_PROCESS | CREATE_NEW_PROCESS_GROUP,
Line 159... Line 162...
159
   // send the engine a quit command
162
   // send the engine a quit command
160
   Player_SendBuffer_Add (player, 1000, options.engine.programs[options.engine.selected_program].command_quit);
163
   Player_SendBuffer_Add (player, 1000, options.engine.programs[options.engine.selected_program].command_quit);
161
   Player_SendBuffer_Add (player, 1000, L"\n"); // since the format string was read from the options, don't forget to end it with a carriage return
164
   Player_SendBuffer_Add (player, 1000, L"\n"); // since the format string was read from the options, don't forget to end it with a carriage return
162
   PlayerEngine_Send (player);
165
   PlayerEngine_Send (player);
163
 
166
 
164
   // close the pipe handles
167
   // close the pipes
165
   if (hChessEngineStdinRd)
-
 
166
      CloseHandle (hChessEngineStdinRd);
168
   CLOSE_PIPE (chessgiants_to_engine);
167
   hChessEngineStdinRd = NULL;
-
 
168
   if (hChessEngineStdinWr)
-
 
169
      CloseHandle (hChessEngineStdinWr);
-
 
170
   hChessEngineStdinWr = NULL;
-
 
171
   if (hChessEngineStdoutRd)
-
 
172
      CloseHandle (hChessEngineStdoutRd);
-
 
173
   hChessEngineStdoutRd = NULL;
169
   CLOSE_PIPE (engine_to_chessgiants);
174
   if (hChessEngineStdoutWr)
-
 
175
      CloseHandle (hChessEngineStdoutWr);
-
 
176
   hChessEngineStdoutWr = NULL;
-
 
177
 
170
 
178
   // check 10 times if the engine process has ended cleanly
171
   // check 10 times if the engine process has ended cleanly
179
   for (attempt_index = 0; attempt_index < 10; attempt_index++)
172
   for (attempt_index = 0; attempt_index < 10; attempt_index++)
180
   {
173
   {
181
      if (GetExitCodeProcess (PlayerEngine_pi.hProcess, &exit_code) && (exit_code != STILL_ACTIVE))
174
      if (GetExitCodeProcess (PlayerEngine_pi.hProcess, &exit_code) && (exit_code != STILL_ACTIVE))
Line 560... Line 553...
560
 
553
 
561
static void PlayerEngine_Recv (player_t *player)
554
static void PlayerEngine_Recv (player_t *player)
562
{
555
{
563
   // helper function to read data from the pipe communicating with the game engine process
556
   // helper function to read data from the pipe communicating with the game engine process
564
 
557
 
565
   unsigned long amount_to_read;
558
   //unsigned long amount_to_read;
566
   unsigned long read_count;
559
   unsigned long read_count;
567
   int byte_index;
-
 
568
   int rewrite_index;
-
 
569
   int length;
560
   int length;
570
   unsigned int initial_pos;
561
   unsigned int initial_pos;
571
 
562
 
572
   // get reception buffer's initial end position
563
   // get reception buffer's initial end position
573
   initial_pos = wcslen (player->recvbuffer);
564
   initial_pos = wcslen (player->recvbuffer);
-
 
565
   length = initial_pos;
574
 
566
 
575
   // as long as the pipe reports us there is data to read...
567
   // as long as the pipe reports us there is data to read, read one byte at a time
576
   while (PeekNamedPipe (hChessEngineStdoutRd, NULL, 0, NULL, &amount_to_read, NULL) && (amount_to_read > 0))
568
   while (!_eof (engine_to_chessgiants[RD]))
577
   {
569
   {
578
      if (!ReadFile (hChessEngineStdoutRd, player->ascii_recvbuffer, min (amount_to_read, (unsigned long) player->recvbuffer_size - 1), &read_count, NULL))
570
      read_count = _read (engine_to_chessgiants[RD], player->ascii_recvbuffer, 1);
-
 
571
      if (read_count == 0)
579
         break; // read the pipe; if it fails, stop trying
572
         break; // read the pipe; if it fails, stop trying
-
 
573
      if ((player->ascii_recvbuffer[0] == '\r') || (player->ascii_recvbuffer[0] == '%'))
-
 
574
         continue; // ignore carriage returns and percent signs
580
 
575
 
581
      // parse all received data and eradicate all carriage returns and percent signs
576
      // convert the received character to wide char and append it to recvbuffer
582
      rewrite_index = 0;
-
 
583
      for (byte_index = 0; byte_index < (int) read_count; byte_index++)
-
 
584
         if ((player->ascii_recvbuffer[byte_index] != '\r') && (player->ascii_recvbuffer[byte_index] != '%'))
-
 
585
         {
-
 
586
            player->ascii_recvbuffer[rewrite_index] = player->ascii_recvbuffer[byte_index];
-
 
587
            rewrite_index++;
-
 
588
         }
-
 
589
      player->ascii_recvbuffer[rewrite_index] = 0; // terminate the buffer ourselves
577
      player->ascii_recvbuffer[1] = 0; // terminate the received string ourselves
590
 
-
 
591
      // convert to wide char and append it to recvbuffer
-
 
592
      length = wcslen (player->recvbuffer);
-
 
593
      ConvertToWideChar (&player->recvbuffer[length], player->recvbuffer_size - length, player->ascii_recvbuffer);
578
      ConvertToWideChar (&player->recvbuffer[length], player->recvbuffer_size - length, player->ascii_recvbuffer);
-
 
579
      length++; // there's one more character in the player's recv buffer
594
   }
580
   }
595
 
581
 
596
   // write what we received (if we received anything)
582
   // write what we received (if we received anything)
597
   if (wcslen (player->recvbuffer) > initial_pos)
583
   if (wcslen (player->recvbuffer) > initial_pos)
598
      Debug_Log (L"===================================RECEIVED:===================================\n%s\n", &player->recvbuffer[initial_pos]);
584
      Debug_Log (L"===================================RECEIVED:===================================\n%s\n", &player->recvbuffer[initial_pos]);
Line 620... Line 606...
620
   line_pointer = player->sendbuffer; // start at the first character
606
   line_pointer = player->sendbuffer; // start at the first character
621
   while ((line_pointer = wcsgets (widechar_buffer, WCHAR_SIZEOF (widechar_buffer), line_pointer)) != NULL)
607
   while ((line_pointer = wcsgets (widechar_buffer, WCHAR_SIZEOF (widechar_buffer), line_pointer)) != NULL)
622
   {
608
   {
623
      wcscat_s (widechar_buffer, WCHAR_SIZEOF (widechar_buffer), L"\n"); // put the carriage return back
609
      wcscat_s (widechar_buffer, WCHAR_SIZEOF (widechar_buffer), L"\n"); // put the carriage return back
624
      ConvertTo7BitASCII (ascii_buffer, sizeof (ascii_buffer), widechar_buffer); // convert to ASCII
610
      ConvertTo7BitASCII (ascii_buffer, sizeof (ascii_buffer), widechar_buffer); // convert to ASCII
625
      WriteFile (hChessEngineStdinWr, ascii_buffer, strlen (ascii_buffer), &amount_written, NULL); // send data
611
      amount_written = _write (chessgiants_to_engine[WR], ascii_buffer, strlen (ascii_buffer)); // send data
626
   }
612
   }
627
 
613
 
628
   player->sendbuffer[0] = 0; // what we had to send has been sent, reset the send buffer
614
   player->sendbuffer[0] = 0; // what we had to send has been sent, reset the send buffer
629
   player->sendbuffer_locked = false; // and unlock it
615
   player->sendbuffer_locked = false; // and unlock it
630
 
616