- // pipe.cpp -- somewhat portable pipe implementation that resembles POSIX popen()/pclose() 
-   
- #include "common.h" 
-   
-   
- // definitions used in this module only 
- #define RD 0 
- #define WR 1 
-   
-   
- #ifdef _WIN32 
- typedef struct pipe_s 
- { 
-    PROCESS_INFORMATION procinfo; 
-    int descriptors[2]; // RD and WR 
- } pipe_t; 
- #endif // _WIN32 
-   
-   
- // function prototypes 
- FILE *pipe_open (const wchar_t *shell_command, const wchar_t *mode); 
- int pipe_close (FILE *stream); 
- int pipe_isalive (FILE *stream); 
- int pipe_hasdata (FILE *stream); 
- int pipe_read (FILE *stream, void *dstbuf, int nbytes); 
- int pipe_write (FILE *stream, void *srcbuf, int nbytes); 
-   
-   
- FILE *pipe_open (const wchar_t *shell_command, const wchar_t *mode) 
- { 
-    // wrapper around popen(), and simple reimplementation of it for systems that don't have it 
-    // mode shall be "r", "w", or "r+" 
-   
- #ifdef _WIN32 
-    #define IT_TO_ME 0 
-    #define ME_TO_IT 1 
-    SECURITY_ATTRIBUTES security_attributes; 
-    wchar_t current_path[MAX_PATH]; 
-    wchar_t *command_pathname; 
-    STARTUPINFO startup_info; 
-    HANDLE hStdIO[2][2]; 
-    pipe_t *pipe; 
-   
-    (void) mode; // all pipes are open read-write 
-   
-    command_pathname = (wchar_t *) malloc ((MAX_PATH + 4096) * sizeof (wchar_t)); // should be enough 
-    if (command_pathname == NULL) 
-       return (NULL); 
-   
-    // figure out command pathname out of full command string 
-    wcscpy_s (command_pathname, MAX_PATH + 4096, shell_command); 
-    if ((command_pathname[0] == L'"') && (wcschr (&command_pathname[1], L'"') != NULL)) 
-    { 
-       memmove (command_pathname, &command_pathname[1], (MAX_PATH + 4096 - 1) * sizeof (wchar_t)); 
-       *wcschr (&command_pathname[1], L'"') = 0; 
-    } 
-    else if (wcschr (command_pathname, L' ') != NULL) 
-       *wcschr (command_pathname, L' ') = 0; 
-   
-    // build the bidirectional I/O pipe 
-    pipe = (pipe_t *) malloc (sizeof (pipe_t)); 
-    memset (pipe, 0, sizeof (pipe_t)); 
-    memset (&security_attributes, 0, sizeof (security_attributes)); // prepare the pipes' security attributes 
-    security_attributes.nLength = sizeof (SECURITY_ATTRIBUTES); 
-    security_attributes.bInheritHandle = true; // set the bInheritHandle flag so pipe handles are inherited 
-    hStdIO[0][0] = hStdIO[0][1] = hStdIO[1][0] = hStdIO[1][1] = NULL; 
-    CreatePipe (&hStdIO[ME_TO_IT][RD], &hStdIO[ME_TO_IT][WR], &security_attributes, 0); // create a pipe for the child process's stdin 
-    CreatePipe (&hStdIO[IT_TO_ME][RD], &hStdIO[IT_TO_ME][WR], &security_attributes, 0); // create a pipe for the child process's stdout 
-    SetHandleInformation (hStdIO[ME_TO_IT][WR], HANDLE_FLAG_INHERIT, 0); // ensure the write handle to the pipe for STDIN is not inherited 
-    SetHandleInformation (hStdIO[IT_TO_ME][RD], HANDLE_FLAG_INHERIT, 0); // ensure the read handle to the pipe for STDOUT is not inherited 
-    pipe->descriptors[RD] = _open_osfhandle ((intptr_t) hStdIO[IT_TO_ME][RD], _O_BINARY); 
-    pipe->descriptors[WR] = _open_osfhandle ((intptr_t) hStdIO[ME_TO_IT][WR], _O_BINARY | _O_APPEND); 
-   
-    // spawn the child process with redirected input and output 
-    memset (&startup_info, 0, sizeof (startup_info)); 
-    startup_info.cb = sizeof (STARTUPINFOA); 
-    startup_info.dwFlags = STARTF_USESTDHANDLES; 
-    startup_info.hStdInput = hStdIO[ME_TO_IT][RD]; 
-    startup_info.hStdOutput = hStdIO[IT_TO_ME][WR]; 
-    startup_info.hStdError = hStdIO[IT_TO_ME][WR]; 
-    GetCurrentDirectory (WCHAR_SIZEOF (current_path), current_path); 
-    if (!CreateProcess (command_pathname, (wchar_t *) shell_command, NULL, NULL, true, CREATE_NO_WINDOW | DETACHED_PROCESS | CREATE_NEW_PROCESS_GROUP, NULL, current_path, &startup_info, &pipe->procinfo)) 
-    { 
-       pipe_close ((FILE *) pipe); 
-       free (command_pathname); 
-       return (NULL); 
-    } 
-   
-    // close the handles we won't use, free the command pathname memory space and return a pointer to our pipe object 
-    CloseHandle (hStdIO[IT_TO_ME][WR]); 
-    CloseHandle (hStdIO[ME_TO_IT][RD]); 
-    #undef IT_TO_ME 
-    #undef ME_TO_IT 
-    free (command_pathname); 
-    return ((FILE *) pipe); 
- #else // !_WIN32 
-    return (popen (shell_command, mode)); 
- #endif // _WIN32 
- } 
-   
-   
- int pipe_close (FILE *stream) 
- { 
-    // wrapper around pclose(), and simple reimplementation of it for systems that don't have it 
-   
- #ifdef _WIN32 
-    HANDLE hRemoteThread; 
-    HANDLE hProcessDup; 
-    DWORD handle_flags; 
-    DWORD thread_id; 
-    DWORD exit_code; 
-    pipe_t *pipe; 
-    bool was_duplicated; 
-   
-    pipe = (pipe_t *) stream; // cast FILE * back into our own structure 
-   
-    // close all handles 
-    if (pipe->descriptors[RD] != -1) _close (pipe->descriptors[RD]); pipe->descriptors[RD] = -1; 
-    if (pipe->descriptors[WR] != -1) _close (pipe->descriptors[WR]); pipe->descriptors[WR] = -1; 
-   
-    // terminate process if it hasn't terminated by itself yet 
-    exit_code = 0; 
-    if (GetExitCodeProcess (pipe->procinfo.hProcess, &exit_code) && (exit_code == STILL_ACTIVE)) 
-    { 
-       // taken from Dr. Dobbs. How to terminate any process cleanly: create a remote thread in it, 
-       // and make its start address point right into kernel32's ExitProcess() function... 
-       was_duplicated = (DuplicateHandle (GetCurrentProcess (), pipe->procinfo.hProcess, GetCurrentProcess (), &hProcessDup, PROCESS_ALL_ACCESS, FALSE, 0) != 0); 
-       if (!was_duplicated) 
-          hProcessDup = pipe->procinfo.hProcess; 
-       hRemoteThread = CreateRemoteThread (hProcessDup, NULL, 0, (PTHREAD_START_ROUTINE) GetProcAddress (GetModuleHandle (L"Kernel32"), "ExitProcess"), (void *) 0, 0, &thread_id); 
-       if (hRemoteThread != NULL) 
-       { 
-          WaitForSingleObject (hProcessDup, INFINITE); // must wait process to terminate to guarantee that it has exited 
-          CloseHandle (hRemoteThread); 
-       } 
-       else 
-          TerminateProcess (pipe->procinfo.hProcess, 0); // if process refuses our remote thread, kill it 
-       if (was_duplicated) 
-          CloseHandle (hProcessDup); 
-    } 
-   
-    // close process handles 
-    if (pipe->procinfo.hProcess != NULL) 
-       CloseHandle (pipe->procinfo.hProcess); 
-    if (GetHandleInformation (pipe->procinfo.hThread, &handle_flags)) 
-       CloseHandle (pipe->procinfo.hThread); 
-   
-    // and finally free the pipe structure 
-    free (pipe); 
-    return ((int) exit_code); 
- #else // !_WIN32 
-    return (pclose (stream)); 
- #endif // _WIN32 
- } 
-   
-   
- int pipe_isalive (FILE *stream) 
- { 
-    // wrapper around ioctl() on pipes for systems that don't have it 
-   
- #ifdef _WIN32 
-    DWORD exit_code; 
-    DWORD handle_flags; 
-    if (((pipe_t *) stream)->procinfo.hProcess == 0) 
-       return (1); // if the child process has not been fully started yet, assume the pipe is still alive 
-    else if (((pipe_t *) stream)->procinfo.hProcess == INVALID_HANDLE_VALUE) 
-       return (0); // if the child process handle has been explicitly marked invalid, assume it's already dead 
-    else if (GetHandleInformation (((pipe_t *) stream)->procinfo.hProcess, &handle_flags) == 0) 
-    { 
-       ((pipe_t *) stream)->procinfo.hProcess = INVALID_HANDLE_VALUE; 
-       return (0); // if the process handle is no longer valid but its handle is not marked as such, assume the child is dead 
-    } 
-    else if (GetExitCodeProcess (((pipe_t *) stream)->procinfo.hProcess, &exit_code) == 0) 
-       return (1); // if GetExitCodeProcess() failed, *conservatively* assume the child is still alive 
-    return (exit_code == STILL_ACTIVE); 
- #else // !_WIN32 
-    return (1); // UNIX doesn't provide a portable way for this 
- #endif // _WIN32 
- } 
-   
-   
- int pipe_hasdata (FILE *stream) 
- { 
-    // wrapper around ioctl() on pipes for systems that don't have it 
-   
- #ifdef _WIN32 
-    return (!_eof (((pipe_t *) stream)->descriptors[RD])); 
- #else // !_WIN32 
-    return (feof (stream)); 
- #endif // _WIN32 
- } 
-   
-   
- int pipe_read (FILE *stream, void *dstbuf, int nbytes) 
- { 
-    // wrapper around fread() on pipes for systems that don't support it 
-   
- #ifdef _WIN32 
-    return (_read (((pipe_t *) stream)->descriptors[RD], dstbuf, nbytes)); 
- #else // !_WIN32 
-    return (fread (dstbuf, 1, nbytes, stream)); 
- #endif // _WIN32 
- } 
-   
-   
- int pipe_write (FILE *stream, void *srcbuf, int nbytes) 
- { 
-    // wrapper around fwrite() on pipes for systems that don't support it 
-   
- #ifdef _WIN32 
-    return (_write (((pipe_t *) stream)->descriptors[WR], srcbuf, nbytes)); 
- #else // !_WIN32 
-    return (fwrite (srcbuf, 1, nbytes, stream)); 
- #endif // _WIN32 
- } 
-