14 #define ErrorBufferSize 4096
15 #define dwMaxHandles 32
19 static char ErrorBuffer[ErrorBufferSize];
23 static bool pipex_eof_input(pipex_t *pipex);
24 static void pipex_set_eof_input(pipex_t *pipex);
25 static void pipex_set_active(pipex_t *pipex);
26 static int pipex_read_data(pipex_t *pipex);
27 static void pipex_read_input(pipex_t *pipex);
33 static char * win32_error(){
35 FORMAT_MESSAGE_FROM_SYSTEM,
47 static DWORD WINAPI ThreadProc(LPVOID lpParam){
48 pipex_t *p=(pipex_t *) lpParam;
49 while(!pipex_eof_input(p)){
50 if(p->nReadEnd<LINE_INPUT_MAX_CHAR-1){
53 // wait until there is room in buffer
62 void pipex_open(pipex_t *pipex,
64 const char *szWorkingDir,
65 const char *szProcFile) {
66 DWORD dwMode, dwThreadId;
67 HANDLE hStdinRead, hStdinWrite, hStdoutRead, hStdoutWrite, hThread;
68 SECURITY_ATTRIBUTES sa;
70 PROCESS_INFORMATION pi;
76 if (szProcFile == NULL) {
77 pipex->hInput = GetStdHandle(STD_INPUT_HANDLE);
78 pipex->hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
79 pipex->bConsole = GetConsoleMode(pipex->hInput, &dwMode);
82 sa.nLength = sizeof(SECURITY_ATTRIBUTES);
83 sa.bInheritHandle = TRUE;
84 sa.lpSecurityDescriptor = NULL;
85 CreatePipe(&hStdinRead, &hStdinWrite, &sa, 0);
86 CreatePipe(&hStdoutRead, &hStdoutWrite, &sa, 0);
87 si.cb = sizeof(STARTUPINFO);
88 si.lpReserved = si.lpDesktop = si.lpTitle = NULL;
89 si.dwFlags = STARTF_USESTDHANDLES;
91 si.lpReserved2 = NULL;
92 si.hStdInput = hStdinRead;
93 si.hStdOutput = hStdoutWrite;
94 si.hStdError = hStdoutWrite;
95 if((szCurrentDir = _getcwd( NULL, 0 )) == NULL )
96 my_fatal("pipex_open(): no current directory: %s\n",
98 if(_chdir(szWorkingDir)){
99 my_fatal("pipex_open(): cannot change directory: %s\n",
102 if(CreateProcess(NULL,
107 DETACHED_PROCESS | CREATE_NEW_PROCESS_GROUP,
112 pipex->hProcess=pi.hProcess;
113 CloseHandle(pi.hThread);
114 CloseHandle(hStdinRead);
115 CloseHandle(hStdoutWrite);
116 pipex->hInput = hStdoutRead;
117 pipex->hOutput = hStdinWrite;
118 pipex->bConsole = FALSE;
121 my_fatal("pipex_open(): %s",win32_error());
123 _chdir(szCurrentDir);
125 if (pipex->bConsole) {
126 SetConsoleMode(pipex->hInput,
127 dwMode & ~(ENABLE_MOUSE_INPUT | ENABLE_WINDOW_INPUT));
128 FlushConsoleInputBuffer(pipex->hInput);
130 fdInput=_open_osfhandle((long) pipex->hInput,_O_RDONLY);
132 my_fatal("pipex_open(): %s",strerror(errno));
134 pipex->fpInput=fdopen(fdInput,"r");
135 if(pipex->fpInput==NULL){
136 my_fatal("pipex_open(): %s",strerror(errno));
139 pipex->lpFeedEnd = NULL;
140 InitializeCriticalSection(&(pipex->CriticalSection));
141 pipex->hEvent=CreateEvent(NULL, // default security
143 FALSE, // not signaled
146 if(!(pipex->hEvent)){
147 my_fatal("pipex_open(): %s",win32_error());
149 hThread=CreateThread(NULL, // default security
150 0, // default stacksize
151 ThreadProc, // worker function
152 pipex, // tell worker about ourselves
153 0, // run immediately
154 &dwThreadId // dropped, but needed for the call to work in Win9x
157 my_fatal("pipex_open(): %s",win32_error());
159 pipex->dwWriteIndex=0;
160 pipex_set_active(pipex);
164 // pipex_wait_event(pipex)
166 void pipex_wait_event(pipex_t *pipex[]){
167 HANDLE hHandles[dwMaxHandles];
168 DWORD dwHandleCount=0;
170 while((p=pipex[dwHandleCount])!=NULL){
171 ASSERT((p->hEvent)!=0);
172 if(dwHandleCount>=dwMaxHandles){
173 my_fatal("pipex_wait_event(): Too many objects to wait for");
175 hHandles[dwHandleCount++]=p->hEvent;
177 WaitForMultipleObjects(dwHandleCount, // count
179 FALSE, // return if one object is signaled
180 INFINITE // no timeout
186 void pipex_send_eof(pipex_t *pipex) {
187 my_log("Adapter->%s: EOF\n",pipex->name);
188 CloseHandle(pipex->hOutput);
193 void pipex_exit(pipex_t *pipex) {
194 CloseHandle(pipex->hInput);
195 CloseHandle(pipex->hOutput);
198 if(GetExitCodeProcess(pipex->hProcess,&lpexit)){
199 if(lpexit==STILL_ACTIVE)
200 //must be java,hammer it down!
201 TerminateProcess(pipex->hProcess,lpexit);
203 CloseHandle(pipex->hProcess);
208 static bool pipex_eof_input(pipex_t *pipex){
210 EnterCriticalSection(&(pipex->CriticalSection));
211 ret=(pipex->state)&PIPEX_EOF;
212 LeaveCriticalSection(&(pipex->CriticalSection));
216 // pipex_set_eof_input()
218 static void pipex_set_eof_input(pipex_t *pipex){
219 EnterCriticalSection(&(pipex->CriticalSection));
220 (pipex->state)|=PIPEX_EOF;
221 LeaveCriticalSection(&(pipex->CriticalSection));
222 // not quit the right place
223 my_log("%s->Adapter: EOF\n",pipex->name);
230 * This function returns TRUE if and only if the pipes have succesfully
231 * been created and the client has been started.
235 bool pipex_active(pipex_t *pipex){
237 EnterCriticalSection(&(pipex->CriticalSection));
238 ret=(pipex->state)&PIPEX_ACTIVE;
239 LeaveCriticalSection(&(pipex->CriticalSection));
243 // pipex_set_active()
245 static void pipex_set_active(pipex_t *pipex){
246 EnterCriticalSection(&(pipex->CriticalSection));
247 (pipex->state)|=PIPEX_ACTIVE;
248 LeaveCriticalSection(&(pipex->CriticalSection));
253 static int pipex_read_data(pipex_t *pipex){
256 // No protection. Access to nReadEnd is atomic.
257 // It is not a problem that nReadEnd becomes smaller after the call.
258 // This just means we have read less than we could have.
259 ret=fgets(pipex->lpReadBuffer,
260 LINE_INPUT_MAX_CHAR-(pipex->nReadEnd),
263 pipex_set_eof_input(pipex);
264 (pipex->lpReadBuffer)[0]='\0';
267 dwBytes=strlen(pipex->lpReadBuffer);
268 (pipex->lpReadBuffer)[dwBytes]='\0';
272 // pipex_read_input()
274 static void pipex_read_input(pipex_t *pipex) {
276 BOOL bSetEvent=FALSE;
277 // ReadData is outside the critical section otherwise everything
278 // would block during the blocking read
279 ret=pipex_read_data(pipex);
280 EnterCriticalSection(&(pipex->CriticalSection));
281 if(!pipex_eof_input(pipex)){
282 if(ret+(pipex->nReadEnd)>=LINE_INPUT_MAX_CHAR){
283 my_fatal("pipex_read_input(): Internal error: buffer overflow\n");
285 memcpy((pipex->lpBuffer)+(pipex->nReadEnd),(pipex->lpReadBuffer),ret+1);
286 (pipex->nReadEnd) += ret;
287 if(!(pipex->lpFeedEnd)){
289 (char *) memchr(pipex->lpBuffer,'\n',pipex->nReadEnd);
291 if(pipex->lpFeedEnd){
293 }else if((pipex->nReadEnd)>=LINE_INPUT_MAX_CHAR-1){
294 my_fatal("pipex_read_input(): LINE_INPUT_MAX_CHAR is equal to %d which is too small to contain a full line of engine output or GUI input.\n",LINE_INPUT_MAX_CHAR);
297 LeaveCriticalSection(&(pipex->CriticalSection));
298 if(pipex_eof_input(pipex) || bSetEvent){
299 SetEvent(pipex->hEvent);
306 * This function returns TRUE if and only if the input buffer does not
307 * contain a full line of data and EOF was encountered by
308 * the working thread.
312 bool pipex_eof(pipex_t *pipex){
314 EnterCriticalSection(&(pipex->CriticalSection));
315 if((pipex->lpFeedEnd) != NULL){
317 }else if(pipex_eof_input(pipex)){
322 LeaveCriticalSection(&(pipex->CriticalSection));
329 * This function returns FALSE if and only if the asynchronously filled
330 * input buffer does not contain a full line of data.
331 * In other words it operates in non-blocking mode.
335 bool pipex_readln_nb(pipex_t *pipex, char *szLineStr) {
340 EnterCriticalSection(&(pipex->CriticalSection));
341 if ((pipex->lpFeedEnd) == NULL) {
344 nFeedEnd = pipex->lpFeedEnd - pipex->lpBuffer;
345 memcpy(szLineStr, pipex->lpBuffer, nFeedEnd+1);
346 szLineStr[nFeedEnd] = '\0';
348 // temp hack: stolen from util.c
349 // remove CRs and LFs
352 while ((c=szLineStr[src++]) != '\0') {
353 if (c != '\r' && c != '\n') szLineStr[dst++] = c;
355 szLineStr[dst] = '\0';
356 ASSERT(strchr(szLineStr,'\n')==NULL)
357 ASSERT(strchr(szLineStr,'\r')==NULL)
360 pipex->nReadEnd -= nFeedEnd;
361 memcpy(pipex->lpBuffer, pipex->lpBuffer + nFeedEnd, pipex->nReadEnd+1);
363 (char *) memchr(pipex->lpBuffer, '\n', pipex->nReadEnd);
366 LeaveCriticalSection(&(pipex->CriticalSection));
368 my_log("%s->Adapter: %s\n",pipex->name,szLineStr);
376 * This function returns FALSE if and only if EOF has been encountered by
377 * the working thread and no full line of data is present in the input buffer.
379 * If there is a full line of data present in the input buffer it returns
382 * If none of these conditions is satisfied it blocks.
384 * As the name say this function is strictly for line input.
385 * An incomplete line of data (i.e. not ending with \n) is lost when EOF
390 bool pipex_readln(pipex_t *pipex, char *szLineStr) {
391 while(!pipex_eof(pipex)){
392 if (pipex_readln_nb(pipex,szLineStr)) {
395 WaitForSingleObject(pipex->hEvent,INFINITE);
402 // GetWin32Priority()
404 static DWORD GetWin32Priority(int nice)
407 REALTIME_PRIORITY_CLASS 0x00000100
408 HIGH_PRIORITY_CLASS 0x00000080
409 ABOVE_NORMAL_PRIORITY_CLASS 0x00008000
410 NORMAL_PRIORITY_CLASS 0x00000020
411 BELOW_NORMAL_PRIORITY_CLASS 0x00004000
412 IDLE_PRIORITY_CLASS 0x00000040
414 if (nice < -15) return 0x00000080;
415 if (nice < 0) return 0x00008000;
416 if (nice == 0) return 0x00000020;
417 if (nice < 15) return 0x00004000;
421 // pipex_set_priority()
423 void pipex_set_priority(pipex_t *pipex, int value){
425 if(!SetPriorityClass(pipex->hProcess,
426 GetWin32Priority(value))){
427 my_log("POLYGLOT Unable to change priority\n");
432 // pipex_set_affinit()
434 void pipex_set_affinity(pipex_t *pipex, int value){
435 if(pipex->hProcess) return;
436 if(value==-1) return;
438 typedef void (WINAPI *SPAM)(HANDLE, int);
440 pSPAM = (SPAM) GetProcAddress(
441 GetModuleHandle(TEXT("kernel32.dll")),
442 "SetProcessAffinityMask");
444 // [HGM] avoid crash on Win95 by first checking if API call exists
445 pSPAM(pipex->hProcess,value);
447 my_log("POLYGLOT API call \"SetProcessAffinityMask\" not available\n");
453 void pipex_write(pipex_t *pipex, const char *szLineStr) {
455 size=sizeof(pipex->szWriteBuffer)-pipex->dwWriteIndex;
456 written=snprintf(pipex->szWriteBuffer + pipex->dwWriteIndex,
460 // snprintf returns how many bytes should have been written
461 // (not including the trailing zero)
462 // old versions of glibc and msvcrt return -1 in
463 // case of truncated output.
464 if(written>=size || written<0){
465 my_fatal("engine_send(): write_buffer overflow\n");
467 pipex->dwWriteIndex+=written;
474 void pipex_writeln(pipex_t *pipex, const char *szLineStr) {
476 DWORD dwLengthWriteBuffer;
477 my_log("Adapter->%s: %s\n",pipex->name,pipex->szWriteBuffer);
478 pipex_write(pipex, szLineStr);
480 dwLengthWriteBuffer = strlen(pipex->szWriteBuffer);
481 if(dwLengthWriteBuffer>=sizeof(pipex->szWriteBuffer)-3){
482 my_fatal("pipex_writeln(): write buffer overflow\n");
484 pipex->szWriteBuffer[dwLengthWriteBuffer] = '\r';
485 pipex->szWriteBuffer[dwLengthWriteBuffer + 1] = '\n';
486 // for easy debugging
487 pipex->szWriteBuffer[dwLengthWriteBuffer + 2] = '\0';
488 WriteFile(pipex->hOutput, pipex->szWriteBuffer,
489 dwLengthWriteBuffer + 2,
492 printf("%s\n",pipex->szWriteBuffer);
495 pipex->dwWriteIndex = 0;