Add forgotten files 1.4.70b
[polyglot.git] / pipe.cpp
1 #ifdef _WIN32
2 #include "pipe.h"
3 #include "util.h"
4
5 // functions
6
7 DWORD WINAPI ThreadProc(LPVOID lpParam){ 
8     PipeStruct *p=(PipeStruct *) lpParam;
9     while(!p->EOF_input()){
10         if(p->nReadEnd<LINE_INPUT_MAX_CHAR-1){
11             p->ReadInput();
12         }else{
13                 // wait until there is room in buffer
14             Sleep(10);
15         }
16     }
17     return 0;
18 }
19
20
21
22 void PipeStruct::Open(const char *szProcFile) {
23     DWORD dwMode, dwThreadId;
24     HANDLE hStdinRead, hStdinWrite, hStdoutRead, hStdoutWrite;
25     SECURITY_ATTRIBUTES sa;
26     STARTUPINFO si;
27     PROCESS_INFORMATION pi;
28     int fdInput;
29     state=0;
30     if (szProcFile == NULL) {
31         hInput = GetStdHandle(STD_INPUT_HANDLE);
32         hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
33         bConsole = GetConsoleMode(hInput, &dwMode);
34         bPipe=FALSE;
35     } else {
36         sa.nLength = sizeof(SECURITY_ATTRIBUTES);
37         sa.bInheritHandle = TRUE;
38         sa.lpSecurityDescriptor = NULL;
39         CreatePipe(&hStdinRead, &hStdinWrite, &sa, 0);
40         CreatePipe(&hStdoutRead, &hStdoutWrite, &sa, 0);
41         si.cb = sizeof(STARTUPINFO);
42         si.lpReserved = si.lpDesktop = si.lpTitle = NULL;
43         si.dwFlags = STARTF_USESTDHANDLES;
44         si.cbReserved2 = 0;
45         si.lpReserved2 = NULL;
46         si.hStdInput = hStdinRead;
47         si.hStdOutput = hStdoutWrite;
48         si.hStdError = hStdoutWrite;
49         if(CreateProcess(NULL,
50                          (LPSTR) szProcFile,
51                          NULL,
52                          NULL,
53                          TRUE,
54                          DETACHED_PROCESS | CREATE_NEW_PROCESS_GROUP,
55                          NULL,
56                          NULL,
57                          &si,
58                          &pi)){
59             hProcess=pi.hProcess;
60             CloseHandle(pi.hThread);
61             CloseHandle(hStdinRead);
62             CloseHandle(hStdoutWrite);
63             hInput = hStdoutRead;
64             hOutput = hStdinWrite;
65             bConsole = FALSE;
66             bPipe=TRUE;
67         }else{
68             my_fatal("PipeStruct::Open(): %s",my_error());
69         }
70     }
71     if (bConsole) {
72         SetConsoleMode(hInput,
73                        dwMode & ~(ENABLE_MOUSE_INPUT | ENABLE_WINDOW_INPUT));
74         FlushConsoleInputBuffer(hInput);
75     } 
76     fdInput=_open_osfhandle((long) hInput,_O_RDONLY);
77     if(fdInput==-1){
78         my_fatal("PipeStruct::Open(): %s",my_error());
79     }
80     fpInput=fdopen(fdInput,"r");
81     if(fpInput==NULL){
82         my_fatal("PipeStruct::Open(): %s",my_error());
83     }
84     nReadEnd = 0;
85     lpFeedEnd = NULL;
86     InitializeCriticalSection(&CriticalSection);
87     hEvent=CreateEvent(NULL,           // default security
88                        FALSE,          // auto reset
89                        FALSE,          // not signaled
90                        NULL            // nameless
91                        );
92     if(!hEvent){
93         my_fatal("PipeStruct::Open(): %s",my_error());
94     }
95     hThread=CreateThread(NULL,         // default security
96                          0,            // default stacksize
97                          ThreadProc,   // worker function
98                          this,         // tell worker about ourselves
99                          0,            // run immediately
100                          &dwThreadId   // dropped, but needed for the call to work in Win9x
101                          );          
102     if(!hThread){
103         my_fatal("PipeStruct::Open(): %s",my_error());
104     }
105     set_Active();
106 }
107
108
109 void PipeStruct::Close(void) const {
110     CloseHandle(hOutput);
111 }
112
113 void PipeStruct::Kill(void) const {
114     CloseHandle(hInput);
115     CloseHandle(hOutput);
116     DWORD lpexit;
117     
118     if(GetExitCodeProcess(hProcess,&lpexit)){
119         if(lpexit==STILL_ACTIVE)
120                 //must be java,hammer it down!
121             TerminateProcess(hProcess,lpexit);
122     }
123         CloseHandle(hProcess);
124 }
125
126 bool PipeStruct::EOF_input(void){   // EOF is defined
127     int ret;
128     EnterCriticalSection(&CriticalSection);
129     ret=state&PIPE_EOF;
130     LeaveCriticalSection(&CriticalSection);
131     return ret;
132 }
133
134 void PipeStruct::set_EOF_input(void){
135     EnterCriticalSection(&CriticalSection);
136     state|=PIPE_EOF;
137     LeaveCriticalSection(&CriticalSection);
138 }
139
140 bool PipeStruct::Active(void){
141     int ret;
142     EnterCriticalSection(&CriticalSection);
143     ret=state&PIPE_ACTIVE;
144     LeaveCriticalSection(&CriticalSection);
145     return ret;
146 }
147
148 void PipeStruct::set_Active(void){
149     EnterCriticalSection(&CriticalSection);
150     state|=PIPE_ACTIVE;
151     LeaveCriticalSection(&CriticalSection);
152 }
153
154 int PipeStruct::ReadData(void){
155     DWORD dwBytes;
156     char * ret;
157         // No protection. Access to nReadEnd is atomic.
158         // It is not a problem that nReadEnd becomes smaller after the call.
159         // This just means we have read less than we could have. 
160     ret=fgets(lpReadBuffer,LINE_INPUT_MAX_CHAR-nReadEnd,fpInput);
161     if(!ret){
162         set_EOF_input();
163         lpReadBuffer[0]='\0';
164         return 0;
165     }
166     dwBytes=strlen(lpReadBuffer);
167     lpReadBuffer[dwBytes]='\0';
168     return dwBytes;
169 }
170
171 void PipeStruct::ReadInput(void) {
172   DWORD dwBytes;
173   int ret;
174   BOOL bSetEvent=FALSE;
175       // ReadData is outside the critical section otherwise everything
176       // would block during the blocking read
177   ret=ReadData();
178   EnterCriticalSection(&CriticalSection);
179   if(!EOF_input()){
180       if(ret+nReadEnd>=LINE_INPUT_MAX_CHAR){
181           my_fatal("PipeStruct::ReadInput(): Internal error: buffer overflow\n");
182       }
183       memcpy(lpBuffer+nReadEnd,lpReadBuffer,ret+1);
184       nReadEnd += ret;
185       if(!lpFeedEnd){
186           lpFeedEnd = (char *) memchr(lpBuffer, '\n', nReadEnd);
187       }
188       if(lpFeedEnd){
189           bSetEvent=TRUE;
190       }else if(nReadEnd>=LINE_INPUT_MAX_CHAR-1){
191           my_fatal("PipeStruct::ReadInput(): 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);
192       }
193   }
194   LeaveCriticalSection(&CriticalSection);
195   if(EOF_input() || bSetEvent){
196       SetEvent(hEvent);
197   }
198 }
199
200 bool PipeStruct::EOF_(void){
201   int ret;
202   EnterCriticalSection(&CriticalSection);
203   if(lpFeedEnd != NULL){
204     ret=FALSE;
205   }else if(EOF_input()){
206     ret=TRUE;
207   }else{
208     ret=FALSE;
209   }
210   LeaveCriticalSection(&CriticalSection);
211   return ret;
212 }
213
214 bool PipeStruct::GetBuffer(char *szLineStr) {
215   int nFeedEnd;
216   int ret;
217   EnterCriticalSection(&CriticalSection);
218   if (lpFeedEnd == NULL) {
219     ret=FALSE;
220   } else {
221     nFeedEnd = lpFeedEnd - lpBuffer;
222     memcpy(szLineStr, lpBuffer, nFeedEnd);
223     if (szLineStr[nFeedEnd - 1] == '\r') {
224       szLineStr[nFeedEnd - 1] = '\0';
225     } else {
226       szLineStr[nFeedEnd] = '\0';
227     }
228     nFeedEnd ++;
229     nReadEnd -= nFeedEnd;
230     memcpy(lpBuffer, lpBuffer + nFeedEnd, nReadEnd);
231     lpFeedEnd = (char *) memchr(lpBuffer, '\n', nReadEnd);
232     ret=TRUE;
233   }
234   LeaveCriticalSection(&CriticalSection);
235   return ret;
236 }
237
238
239
240 void PipeStruct::LineInput(char *szLineStr) {
241   while(!EOF_()){
242         if (GetBuffer(szLineStr)) {
243             break;
244         }else{
245             WaitForSingleObject(hEvent,INFINITE);
246         }
247     }
248 }
249
250 void PipeStruct::LineOutput(const char *szLineStr) const {
251   DWORD dwBytes;
252   int nStrLen;
253   char szWriteBuffer[LINE_INPUT_MAX_CHAR];
254   if(bPipe){
255       nStrLen = strlen(szLineStr);
256       memcpy(szWriteBuffer, szLineStr, nStrLen);
257       szWriteBuffer[nStrLen] = '\r';
258       szWriteBuffer[nStrLen + 1] = '\n';
259       WriteFile(hOutput, szWriteBuffer, nStrLen + 2, &dwBytes, NULL);
260   }else{
261       printf("%s\n",szLineStr);
262       fflush(stdout);
263   }
264 }
265 #endif