Add forgotten files 1.4.70b
[polyglot.git] / pipe.cpp
index f12a787..170da4a 100644 (file)
--- a/pipe.cpp
+++ b/pipe.cpp
 #include "pipe.h"
 #include "util.h"
 
+// functions
+
+DWORD WINAPI ThreadProc(LPVOID lpParam){ 
+    PipeStruct *p=(PipeStruct *) lpParam;
+    while(!p->EOF_input()){
+        if(p->nReadEnd<LINE_INPUT_MAX_CHAR-1){
+            p->ReadInput();
+        }else{
+                // wait until there is room in buffer
+            Sleep(10);
+        }
+    }
+    return 0;
+}
+
+
+
 void PipeStruct::Open(const char *szProcFile) {
-  DWORD dwMode;
-  HANDLE hStdinRead, hStdinWrite, hStdoutRead, hStdoutWrite;
-  SECURITY_ATTRIBUTES sa;
-  STARTUPINFO si;
-  PROCESS_INFORMATION pi;
-  state=0;
-  if (szProcFile == NULL) {
-    hInput = GetStdHandle(STD_INPUT_HANDLE);
-    hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
-    bConsole = GetConsoleMode(hInput, &dwMode);
-    state|=PIPE_ACTIVE;
-    
-  } else {
-    sa.nLength = sizeof(SECURITY_ATTRIBUTES);
-    sa.bInheritHandle = TRUE;
-    sa.lpSecurityDescriptor = NULL;
-    CreatePipe(&hStdinRead, &hStdinWrite, &sa, 0);
-    CreatePipe(&hStdoutRead, &hStdoutWrite, &sa, 0);
-    si.cb = sizeof(STARTUPINFO);
-    si.lpReserved = si.lpDesktop = si.lpTitle = NULL;
-    si.dwFlags = STARTF_USESTDHANDLES;
-    si.cbReserved2 = 0;
-    si.lpReserved2 = NULL;
-    si.hStdInput = hStdinRead;
-    si.hStdOutput = hStdoutWrite;
-    si.hStdError = hStdoutWrite;
-    if(CreateProcess(NULL, (LPSTR) szProcFile, NULL, NULL, TRUE, DETACHED_PROCESS | CREATE_NEW_PROCESS_GROUP, NULL, NULL, &si, &pi)){
-        state|=PIPE_ACTIVE;
-        hProcess=pi.hProcess;
-        CloseHandle(pi.hThread);
-        CloseHandle(hStdinRead);
-        CloseHandle(hStdoutWrite);
-        hInput = hStdoutRead;
-        hOutput = hStdinWrite;
-        bConsole = FALSE;
+    DWORD dwMode, dwThreadId;
+    HANDLE hStdinRead, hStdinWrite, hStdoutRead, hStdoutWrite;
+    SECURITY_ATTRIBUTES sa;
+    STARTUPINFO si;
+    PROCESS_INFORMATION pi;
+    int fdInput;
+    state=0;
+    if (szProcFile == NULL) {
+        hInput = GetStdHandle(STD_INPUT_HANDLE);
+        hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
+        bConsole = GetConsoleMode(hInput, &dwMode);
+        bPipe=FALSE;
+    } else {
+        sa.nLength = sizeof(SECURITY_ATTRIBUTES);
+        sa.bInheritHandle = TRUE;
+        sa.lpSecurityDescriptor = NULL;
+        CreatePipe(&hStdinRead, &hStdinWrite, &sa, 0);
+        CreatePipe(&hStdoutRead, &hStdoutWrite, &sa, 0);
+        si.cb = sizeof(STARTUPINFO);
+        si.lpReserved = si.lpDesktop = si.lpTitle = NULL;
+        si.dwFlags = STARTF_USESTDHANDLES;
+        si.cbReserved2 = 0;
+        si.lpReserved2 = NULL;
+        si.hStdInput = hStdinRead;
+        si.hStdOutput = hStdoutWrite;
+        si.hStdError = hStdoutWrite;
+        if(CreateProcess(NULL,
+                         (LPSTR) szProcFile,
+                         NULL,
+                         NULL,
+                         TRUE,
+                         DETACHED_PROCESS | CREATE_NEW_PROCESS_GROUP,
+                         NULL,
+                         NULL,
+                         &si,
+                         &pi)){
+            hProcess=pi.hProcess;
+            CloseHandle(pi.hThread);
+            CloseHandle(hStdinRead);
+            CloseHandle(hStdoutWrite);
+            hInput = hStdoutRead;
+            hOutput = hStdinWrite;
+            bConsole = FALSE;
+            bPipe=TRUE;
+        }else{
+            my_fatal("PipeStruct::Open(): %s",my_error());
+        }
     }
-  }
-  if (bConsole) {
-    SetConsoleMode(hInput, dwMode & ~(ENABLE_MOUSE_INPUT | ENABLE_WINDOW_INPUT));
-    FlushConsoleInputBuffer(hInput);
-  } else {
-    nBytesLeft = 0;
-  }
-  nReadEnd = 0;
+    if (bConsole) {
+        SetConsoleMode(hInput,
+                       dwMode & ~(ENABLE_MOUSE_INPUT | ENABLE_WINDOW_INPUT));
+        FlushConsoleInputBuffer(hInput);
+    } 
+    fdInput=_open_osfhandle((long) hInput,_O_RDONLY);
+    if(fdInput==-1){
+        my_fatal("PipeStruct::Open(): %s",my_error());
+    }
+    fpInput=fdopen(fdInput,"r");
+    if(fpInput==NULL){
+        my_fatal("PipeStruct::Open(): %s",my_error());
+    }
+    nReadEnd = 0;
+    lpFeedEnd = NULL;
+    InitializeCriticalSection(&CriticalSection);
+    hEvent=CreateEvent(NULL,           // default security
+                       FALSE,          // auto reset
+                       FALSE,          // not signaled
+                       NULL            // nameless
+                       );
+    if(!hEvent){
+        my_fatal("PipeStruct::Open(): %s",my_error());
+    }
+    hThread=CreateThread(NULL,         // default security
+                         0,            // default stacksize
+                         ThreadProc,   // worker function
+                         this,         // tell worker about ourselves
+                         0,            // run immediately
+                         &dwThreadId   // dropped, but needed for the call to work in Win9x
+                         );          
+    if(!hThread){
+        my_fatal("PipeStruct::Open(): %s",my_error());
+    }
+    set_Active();
 }
 
+
 void PipeStruct::Close(void) const {
-  CloseHandle(hOutput);
+    CloseHandle(hOutput);
 }
 
 void PipeStruct::Kill(void) const {
-  CloseHandle(hInput);
-  CloseHandle(hOutput);
-  DWORD lpexit;
-
-  if(GetExitCodeProcess(hProcess,&lpexit)){
-       if(lpexit==STILL_ACTIVE)
-       //must be java,hammer it down!
-       TerminateProcess(hProcess,lpexit);
-  }
+    CloseHandle(hInput);
+    CloseHandle(hOutput);
+    DWORD lpexit;
+    
+    if(GetExitCodeProcess(hProcess,&lpexit)){
+        if(lpexit==STILL_ACTIVE)
+                //must be java,hammer it down!
+            TerminateProcess(hProcess,lpexit);
+    }
        CloseHandle(hProcess);
 }
 
-bool PipeStruct::EOF_(void){   // EOF is defined
-    return state&PIPE_EOF;
+bool PipeStruct::EOF_input(void){   // EOF is defined
+    int ret;
+    EnterCriticalSection(&CriticalSection);
+    ret=state&PIPE_EOF;
+    LeaveCriticalSection(&CriticalSection);
+    return ret;
+}
+
+void PipeStruct::set_EOF_input(void){
+    EnterCriticalSection(&CriticalSection);
+    state|=PIPE_EOF;
+    LeaveCriticalSection(&CriticalSection);
 }
 
 bool PipeStruct::Active(void){
-    return state&PIPE_ACTIVE;
+    int ret;
+    EnterCriticalSection(&CriticalSection);
+    ret=state&PIPE_ACTIVE;
+    LeaveCriticalSection(&CriticalSection);
+    return ret;
 }
 
-void PipeStruct::ReadInput(void) {
-  DWORD dwBytes;
-  if(ReadFile(hInput, szBuffer + nReadEnd, LINE_INPUT_MAX_CHAR - nReadEnd, &dwBytes, NULL)){
-      nReadEnd += dwBytes;
-      if (nBytesLeft > 0) {
-          nBytesLeft -= dwBytes;
-      }
-  }else{
-      state|=PIPE_EOF;   // if we are here there should be data!
-  }
+void PipeStruct::set_Active(void){
+    EnterCriticalSection(&CriticalSection);
+    state|=PIPE_ACTIVE;
+    LeaveCriticalSection(&CriticalSection);
 }
 
-bool PipeStruct::CheckInput(void) {
-  DWORD dwEvents, dwBytes;
-  if (bConsole) { // a tty, or an un-redirected handle
-    GetNumberOfConsoleInputEvents(hInput, &dwEvents);
-    if (dwEvents > 1) {
-      return TRUE;
-    } else {
-      return FALSE;
+int PipeStruct::ReadData(void){
+    DWORD dwBytes;
+    char * ret;
+        // No protection. Access to nReadEnd is atomic.
+        // It is not a problem that nReadEnd becomes smaller after the call.
+        // This just means we have read less than we could have. 
+    ret=fgets(lpReadBuffer,LINE_INPUT_MAX_CHAR-nReadEnd,fpInput);
+    if(!ret){
+        set_EOF_input();
+        lpReadBuffer[0]='\0';
+        return 0;
     }
-  } else { // a handle redirected to a pipe or a file
-    if (nBytesLeft > 0) {
-      return TRUE;
-    } else {
-      if (PeekNamedPipe(hInput, NULL, 0, NULL, &dwBytes, NULL)) {
-        nBytesLeft = dwBytes;
-        return nBytesLeft > 0; // a pipe
-      } else {
-        return TRUE; // a file, always TRUE
-      }
-    }
-  }
+    dwBytes=strlen(lpReadBuffer);
+    lpReadBuffer[dwBytes]='\0';
+    return dwBytes;
 }
 
-void PipeStruct::LineOutput(const char *szLineStr) const {
+void PipeStruct::ReadInput(void) {
   DWORD dwBytes;
-  int nStrLen;
-  char szWriteBuffer[LINE_INPUT_MAX_CHAR];
-  nStrLen = strlen(szLineStr);
-  memcpy(szWriteBuffer, szLineStr, nStrLen);
-  szWriteBuffer[nStrLen] = '\r';
-  szWriteBuffer[nStrLen + 1] = '\n';
-  WriteFile(hOutput, szWriteBuffer, nStrLen + 2, &dwBytes, NULL);
+  int ret;
+  BOOL bSetEvent=FALSE;
+      // ReadData is outside the critical section otherwise everything
+      // would block during the blocking read
+  ret=ReadData();
+  EnterCriticalSection(&CriticalSection);
+  if(!EOF_input()){
+      if(ret+nReadEnd>=LINE_INPUT_MAX_CHAR){
+          my_fatal("PipeStruct::ReadInput(): Internal error: buffer overflow\n");
+      }
+      memcpy(lpBuffer+nReadEnd,lpReadBuffer,ret+1);
+      nReadEnd += ret;
+      if(!lpFeedEnd){
+          lpFeedEnd = (char *) memchr(lpBuffer, '\n', nReadEnd);
+      }
+      if(lpFeedEnd){
+          bSetEvent=TRUE;
+      }else if(nReadEnd>=LINE_INPUT_MAX_CHAR-1){
+          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);
+      }
+  }
+  LeaveCriticalSection(&CriticalSection);
+  if(EOF_input() || bSetEvent){
+      SetEvent(hEvent);
+  }
 }
 
-
+bool PipeStruct::EOF_(void){
+  int ret;
+  EnterCriticalSection(&CriticalSection);
+  if(lpFeedEnd != NULL){
+    ret=FALSE;
+  }else if(EOF_input()){
+    ret=TRUE;
+  }else{
+    ret=FALSE;
+  }
+  LeaveCriticalSection(&CriticalSection);
+  return ret;
+}
 
 bool PipeStruct::GetBuffer(char *szLineStr) {
-  char *lpFeedEnd;
   int nFeedEnd;
-  lpFeedEnd = (char *) memchr(szBuffer, '\n', nReadEnd);
+  int ret;
+  EnterCriticalSection(&CriticalSection);
   if (lpFeedEnd == NULL) {
-    return FALSE;
+    ret=FALSE;
   } else {
-    nFeedEnd = lpFeedEnd - szBuffer;
-    memcpy(szLineStr, szBuffer, nFeedEnd);
+    nFeedEnd = lpFeedEnd - lpBuffer;
+    memcpy(szLineStr, lpBuffer, nFeedEnd);
     if (szLineStr[nFeedEnd - 1] == '\r') {
       szLineStr[nFeedEnd - 1] = '\0';
     } else {
@@ -138,32 +227,39 @@ bool PipeStruct::GetBuffer(char *szLineStr) {
     }
     nFeedEnd ++;
     nReadEnd -= nFeedEnd;
-    memcpy(szBuffer, szBuffer + nFeedEnd, nReadEnd);
-    return TRUE;
+    memcpy(lpBuffer, lpBuffer + nFeedEnd, nReadEnd);
+    lpFeedEnd = (char *) memchr(lpBuffer, '\n', nReadEnd);
+    ret=TRUE;
   }
+  LeaveCriticalSection(&CriticalSection);
+  return ret;
 }
 
-bool PipeStruct::LineInput(char *szLineStr) {
-  if (GetBuffer(szLineStr)) {
-    return TRUE;
-  }
-  if (CheckInput()) {
-    ReadInput();
-    if (GetBuffer(szLineStr)) {
-      return TRUE;
-    } else {
-      if (nReadEnd == LINE_INPUT_MAX_CHAR) {
-        memcpy(szLineStr, szBuffer, LINE_INPUT_MAX_CHAR - 1);
-        szLineStr[LINE_INPUT_MAX_CHAR - 1] = '\0';
-        szBuffer[0] = szBuffer[LINE_INPUT_MAX_CHAR - 1];
-        nReadEnd = 1;
-        return TRUE;
-      } else {
-        return FALSE;
-      }
+
+
+void PipeStruct::LineInput(char *szLineStr) {
+  while(!EOF_()){
+        if (GetBuffer(szLineStr)) {
+            break;
+        }else{
+            WaitForSingleObject(hEvent,INFINITE);
+        }
     }
-  } else {
-    return FALSE;
+}
+
+void PipeStruct::LineOutput(const char *szLineStr) const {
+  DWORD dwBytes;
+  int nStrLen;
+  char szWriteBuffer[LINE_INPUT_MAX_CHAR];
+  if(bPipe){
+      nStrLen = strlen(szLineStr);
+      memcpy(szWriteBuffer, szLineStr, nStrLen);
+      szWriteBuffer[nStrLen] = '\r';
+      szWriteBuffer[nStrLen + 1] = '\n';
+      WriteFile(hOutput, szWriteBuffer, nStrLen + 2, &dwBytes, NULL);
+  }else{
+      printf("%s\n",szLineStr);
+      fflush(stdout);
   }
 }
 #endif