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 |
18 | static int chessgiants_to_engine[2]; // RD and WR |
| 12 | static HANDLE hChessEngineStdinWr; |
- | |
| 13 | static |
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 | // |
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 |
58 | CreatePipe (&hStdIn[RD], &hStdIn[WR], &saAttr, 0); // create a pipe for the child process's stdin |
| 57 | CreatePipe (& |
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 ( |
61 | SetHandleInformation (hStdOut[RD], HANDLE_FLAG_INHERIT, 0); // ensure the read handle to the pipe for STDOUT is not inherited |
| 59 | - | ||
| 60 |
|
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 |
|
64 | chessgiants_to_engine[RD] = _open_osfhandle ((intptr_t) hStdIn[RD], _O_BINARY); |
| 62 |
|
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 = |
71 | si.hStdInput = hStdIn[RD]; |
| 69 | si.hStdOutput = |
72 | si.hStdOutput = hStdOut[WR]; |
| 70 | si.hStdError = |
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 |
167 | // close the pipes |
| 165 | if (hChessEngineStdinRd) |
- | |
| 166 |
|
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 |
|
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 |
|
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 ( |
568 | while (!_eof (engine_to_chessgiants[RD])) |
| 577 | { |
569 | { |
| 578 |
|
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 | // |
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[ |
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 |
|
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 | ||