/* * Copyright 2012 Joe Burmeister * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sub license, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice (including the * next paragraph) shall be included in all copies or substantial portions * of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. * */ #if defined (_WIN32) && ! defined (__CYGWIN__) #include #include #include struct pipe_process_pair { int pipefd; HANDLE process; }; typedef struct pipe_process_pair pipe_process_pair; static struct pipe_process_pair pairs[128]; FILE *win_popen_biglimit( const char *command, const char *mode ); int win_pclose_biglimit(FILE *stream); FILE *win_popen_biglimit( const char *command, const char *mode ) { PROCESS_INFORMATION piProcInfo; STARTUPINFO siStartInfo; if (mode[0] == '\0' || mode[1] != '\0') return NULL; int pipefds[2] = {0}; if (_pipe(pipefds, 4096, O_TEXT)) return NULL; ZeroMemory(&siStartInfo, sizeof(STARTUPINFO)); ZeroMemory(&piProcInfo, sizeof(PROCESS_INFORMATION)); siStartInfo.cb = sizeof(STARTUPINFO); siStartInfo.dwFlags = STARTF_USESTDHANDLES; int fd_index = 0; /* * Return correct pipe handle and close handle not returned or used. */ if (mode[0] == 'r') { siStartInfo.hStdOutput = siStartInfo.hStdError = (HANDLE)_get_osfhandle(pipefds[1]); if ( ! SetHandleInformation(siStartInfo.hStdOutput, HANDLE_FLAG_INHERIT, TRUE) ) goto Error; } else if (mode[0] == 'w') { fd_index = 1; siStartInfo.hStdInput = (HANDLE)_get_osfhandle(pipefds[0]); if ( ! SetHandleInformation(siStartInfo.hStdInput, HANDLE_FLAG_INHERIT, 0) ) goto Error; } else goto Error; if (CreateProcess(NULL, (LPSTR)command, NULL, NULL, TRUE, 0, /* no NEW_CONSOLE by default for Ctrl+C handling */ NULL, NULL, &siStartInfo, &piProcInfo) ) { CloseHandle(piProcInfo.hThread); FILE* result = NULL; pipe_process_pair* pair = pairs; for(; pair < &pairs[sizeof(pairs)/sizeof(pipe_process_pair)]; ++pair) { if (!pair->process) { pair->pipefd = pipefds[fd_index]; pair->process = piProcInfo.hProcess; result = _fdopen(pair->pipefd, mode); if (!result) pair->process = NULL; break; } } if (!result) { CloseHandle(piProcInfo.hProcess); goto Error; } /* Close reference not required in this process. */ _close(pipefds[!fd_index]); return result; } Error: if (siStartInfo.hStdOutput != NULL) CloseHandle(siStartInfo.hStdOutput); if (siStartInfo.hStdInput != NULL) CloseHandle(siStartInfo.hStdInput); _close(pipefds[0]); _close(pipefds[1]); return NULL; } int win_pclose_biglimit(FILE *stream) { int fd = fileno(stream); pipe_process_pair* pair = pairs; for(; pair < &pairs[sizeof(pairs)/sizeof(pipe_process_pair)]; ++pair) { if (pair->pipefd == fd) { WaitForSingleObject(pair->process, INFINITE); DWORD exitcode = -1; if (!GetExitCodeProcess(pair->process, &exitcode)) exitcode = -1; CloseHandle(pair->process); pair->process = NULL; return exitcode; } } return -1; } #endif