version 1.4w10UCIb21
[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_()){
10         p->ReadInput();
11     }
12     return 0;
13 }
14
15
16
17 void PipeStruct::Open(const char *szProcFile) {
18     DWORD dwMode;
19     HANDLE hStdinRead, hStdinWrite, hStdoutRead, hStdoutWrite;
20     SECURITY_ATTRIBUTES sa;
21     STARTUPINFO si;
22     PROCESS_INFORMATION pi;
23     state=0;
24     if (szProcFile == NULL) {
25         hInput = GetStdHandle(STD_INPUT_HANDLE);
26         hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
27         bConsole = GetConsoleMode(hInput, &dwMode);
28         bPipe=FALSE;
29     } else {
30         sa.nLength = sizeof(SECURITY_ATTRIBUTES);
31         sa.bInheritHandle = TRUE;
32         sa.lpSecurityDescriptor = NULL;
33         CreatePipe(&hStdinRead, &hStdinWrite, &sa, 0);
34         CreatePipe(&hStdoutRead, &hStdoutWrite, &sa, 0);
35         si.cb = sizeof(STARTUPINFO);
36         si.lpReserved = si.lpDesktop = si.lpTitle = NULL;
37         si.dwFlags = STARTF_USESTDHANDLES;
38         si.cbReserved2 = 0;
39         si.lpReserved2 = NULL;
40         si.hStdInput = hStdinRead;
41         si.hStdOutput = hStdoutWrite;
42         si.hStdError = hStdoutWrite;
43         if(CreateProcess(NULL,
44                          (LPSTR) szProcFile,
45                          NULL,
46                          NULL,
47                          TRUE,
48                          DETACHED_PROCESS | CREATE_NEW_PROCESS_GROUP,
49                          NULL,
50                          NULL,
51                          &si,
52                          &pi)){
53             hProcess=pi.hProcess;
54             CloseHandle(pi.hThread);
55             CloseHandle(hStdinRead);
56             CloseHandle(hStdoutWrite);
57             hInput = hStdoutRead;
58             hOutput = hStdinWrite;
59             bConsole = FALSE;
60             bPipe=TRUE;
61         }else{
62             my_fatal("PipeStruct::Open(): %s",my_error());
63         }
64     }
65     if (bConsole) {
66         SetConsoleMode(hInput,
67                        dwMode & ~(ENABLE_MOUSE_INPUT | ENABLE_WINDOW_INPUT));
68         FlushConsoleInputBuffer(hInput);
69     } 
70     nReadEnd = 0;
71     lpFeedEnd = NULL;
72     InitializeCriticalSection(&CriticalSection);
73     hEvent=CreateEvent(NULL,           // default security
74                        FALSE,          // auto reset
75                        FALSE,          // not signaled
76                        NULL            // nameless
77                        );
78     hThread=CreateThread(NULL,         // default security
79                          0,            // default stacksize
80                          ThreadProc,   // worker function
81                          this,         // tell worker about ourselves
82                          0,            // run immediately
83                          NULL          // nameless
84                          );          
85     
86     set_Active();
87 }
88
89
90 void PipeStruct::Close(void) const {
91     CloseHandle(hOutput);
92 }
93
94 void PipeStruct::Kill(void) const {
95     CloseHandle(hInput);
96     CloseHandle(hOutput);
97     DWORD lpexit;
98     
99     if(GetExitCodeProcess(hProcess,&lpexit)){
100         if(lpexit==STILL_ACTIVE)
101                 //must be java,hammer it down!
102             TerminateProcess(hProcess,lpexit);
103     }
104         CloseHandle(hProcess);
105 }
106
107 bool PipeStruct::EOF_(void){   // EOF is defined
108     int ret;
109     EnterCriticalSection(&CriticalSection);
110     ret=state&PIPE_EOF;
111     LeaveCriticalSection(&CriticalSection);
112     return ret;
113 }
114
115 void PipeStruct::set_EOF_(void){
116     EnterCriticalSection(&CriticalSection);
117     state|=PIPE_EOF;
118     LeaveCriticalSection(&CriticalSection);
119 }
120
121 bool PipeStruct::Active(void){
122     int ret;
123     EnterCriticalSection(&CriticalSection);
124     ret=state&PIPE_ACTIVE;
125     LeaveCriticalSection(&CriticalSection);
126     return ret;
127 }
128
129 void PipeStruct::set_Active(void){
130     EnterCriticalSection(&CriticalSection);
131     state|=PIPE_ACTIVE;
132     LeaveCriticalSection(&CriticalSection);
133 }
134
135 int PipeStruct::ReadData(void){
136     DWORD dwBytes;
137     int ret;
138     
139     if(!bPipe){
140         fgets(lpReadBuffer,LINE_INPUT_MAX_CHAR,stdin);
141         dwBytes=strlen(lpReadBuffer);
142         if(!dwBytes){
143             set_EOF_();
144             lpReadBuffer[0]='\0';
145             return 0;
146         }
147     }else{
148             // Unfortunately we need to use polling here.
149             // Otherwise Windows returns single bytes if
150             // the engine runs at low priority.
151             // This kills performance.
152         while(TRUE){
153             ret=PeekNamedPipe(hInput,
154                               NULL,    // don't read anything yet
155                               0,       // no buffer
156                               NULL,    // no we don't read anything!
157                               &dwBytes,// now we're talking
158                               NULL);   // nono we don't read anything
159             if(!ret){
160                 set_EOF_();
161                 lpReadBuffer[0]='\0';
162                 return 0;
163             }
164             if(dwBytes>0){
165                 break;
166             }else{
167                 Idle();
168             }
169             
170         }
171         ret=ReadFile(hInput,
172                      lpReadBuffer,
173                      LINE_INPUT_MAX_CHAR,
174                      &dwBytes,
175                      NULL);
176         if(!ret){
177             set_EOF_();
178             lpReadBuffer[0]='\0';
179             return 0;
180         }
181     }
182     lpReadBuffer[dwBytes]='\0';
183     return dwBytes;
184 }
185
186 void PipeStruct::ReadInput(void) {
187   DWORD dwBytes;
188   int ret;
189   BOOL bSetEvent=FALSE;
190   ret=ReadData();
191   EnterCriticalSection(&CriticalSection);
192   if(!EOF_()){
193       if(ret+nReadEnd>=LINE_INPUT_MAX_CHAR){
194           my_fatal("PipeStruct::ReadInput(): buffer overflow\n");
195       }
196       memcpy(lpBuffer+nReadEnd,lpReadBuffer,ret);
197       nReadEnd += ret;
198       if(!lpFeedEnd){
199           lpFeedEnd = (char *) memchr(lpBuffer, '\n', nReadEnd);
200       }
201       if(lpFeedEnd){
202           bSetEvent=TRUE;
203       }
204   }
205   LeaveCriticalSection(&CriticalSection);
206   if(EOF_() || bSetEvent){
207       SetEvent(hEvent);
208   }
209 }
210
211 bool PipeStruct::GetBuffer(char *szLineStr) {
212   int nFeedEnd;
213   int ret;
214   EnterCriticalSection(&CriticalSection);
215   if (lpFeedEnd == NULL) {
216     ret=FALSE;
217   } else {
218     nFeedEnd = lpFeedEnd - lpBuffer;
219     memcpy(szLineStr, lpBuffer, nFeedEnd);
220     if (szLineStr[nFeedEnd - 1] == '\r') {
221       szLineStr[nFeedEnd - 1] = '\0';
222     } else {
223       szLineStr[nFeedEnd] = '\0';
224     }
225     nFeedEnd ++;
226     nReadEnd -= nFeedEnd;
227     memcpy(lpBuffer, lpBuffer + nFeedEnd, nReadEnd);
228     lpFeedEnd = (char *) memchr(lpBuffer, '\n', nReadEnd);
229     ret=TRUE;
230   }
231   LeaveCriticalSection(&CriticalSection);
232   return ret;
233 }
234
235 void PipeStruct::LineInput(char *szLineStr) {
236     while(!EOF_()){
237         if (GetBuffer(szLineStr)) {
238             break;
239         }else{
240             WaitForSingleObject(hEvent,INFINITE);
241         }
242     }
243 }
244
245 void PipeStruct::LineOutput(const char *szLineStr) const {
246   DWORD dwBytes;
247   int nStrLen;
248   char szWriteBuffer[LINE_INPUT_MAX_CHAR];
249   if(bPipe){
250       nStrLen = strlen(szLineStr);
251       memcpy(szWriteBuffer, szLineStr, nStrLen);
252       szWriteBuffer[nStrLen] = '\r';
253       szWriteBuffer[nStrLen + 1] = '\n';
254       WriteFile(hOutput, szWriteBuffer, nStrLen + 2, &dwBytes, NULL);
255   }else{
256       printf("%s\n",szLineStr);
257       fflush(stdout);
258   }
259 }
260 #endif