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 |