/* * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS C runtime library * FILE: lib/sdk/crt/stdio/popen.c * PURPOSE: Pipe Functions * PROGRAMMERS: Eric Kohl * Hartmut Birr * Also adapted from Wine team code by Andreas Maier. */ #include <precomp.h> #include <tchar.h> #ifdef _UNICODE #define sT "S" #else #define sT "s" #endif #define MK_STR(s) #s int msvcrt_alloc_fd(HANDLE hand, int flag); //FIXME: Remove unsigned split_oflags(unsigned oflags); //FIXME: Remove #ifndef _UNICODE struct popen_handle *popen_handles = NULL; DWORD popen_handles_size = 0; void msvcrt_free_popen_data(void) { free(popen_handles); } #endif /* * @implemented */ FILE *_tpopen (const _TCHAR *cm, const _TCHAR *md) /* program name, pipe mode */ { _TCHAR *szCmdLine=NULL; _TCHAR *szComSpec=NULL; _TCHAR *s; FILE *ret; HANDLE hReadPipe, hWritePipe; BOOL result; STARTUPINFO StartupInfo; PROCESS_INFORMATION ProcessInformation; SECURITY_ATTRIBUTES sa = {sizeof(SECURITY_ATTRIBUTES), NULL, TRUE}; struct popen_handle *container; DWORD i; TRACE(MK_STR(_tpopen)"('%"sT"', '%"sT"')\n", cm, md); if (cm == NULL) return NULL; szComSpec = _tgetenv(_T("COMSPEC")); if (szComSpec == NULL) { szComSpec = _T("cmd.exe"); } s = max(_tcsrchr(szComSpec, '\\'), _tcsrchr(szComSpec, '/')); if (s == NULL) s = szComSpec; else s++; szCmdLine = malloc((_tcslen(s) + 4 + _tcslen(cm) + 1) * sizeof(_TCHAR)); if (szCmdLine == NULL) { return NULL; } _tcscpy(szCmdLine, s); s = _tcsrchr(szCmdLine, '.'); if (s) *s = 0; _tcscat(szCmdLine, _T(" /C ")); _tcscat(szCmdLine, cm); if ( !CreatePipe(&hReadPipe,&hWritePipe,&sa,1024)) { free (szCmdLine); return NULL; } memset(&ProcessInformation, 0, sizeof(ProcessInformation)); memset(&StartupInfo, 0, sizeof(STARTUPINFO)); StartupInfo.cb = sizeof(STARTUPINFO); if (*md == 'r' ) { StartupInfo.hStdInput = GetStdHandle(STD_INPUT_HANDLE); StartupInfo.hStdOutput = hWritePipe; StartupInfo.dwFlags |= STARTF_USESTDHANDLES; } else if ( *md == 'w' ) { StartupInfo.hStdInput = hReadPipe; StartupInfo.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE); StartupInfo.dwFlags |= STARTF_USESTDHANDLES; } if (StartupInfo.dwFlags & STARTF_USESTDHANDLES) StartupInfo.hStdError = GetStdHandle(STD_ERROR_HANDLE); result = CreateProcess(szComSpec, szCmdLine, NULL, NULL, TRUE, 0, NULL, NULL, &StartupInfo, &ProcessInformation); free (szCmdLine); if (result == FALSE) { CloseHandle(hReadPipe); CloseHandle(hWritePipe); return NULL; } CloseHandle(ProcessInformation.hThread); _mlock(_POPEN_LOCK); for(i=0; i<popen_handles_size; i++) { if (!popen_handles[i].f) break; } if (i==popen_handles_size) { i = (popen_handles_size ? popen_handles_size*2 : 8); container = realloc(popen_handles, i*sizeof(*container)); if (!container) goto error; popen_handles = container; container = popen_handles+popen_handles_size; memset(container, 0, (i-popen_handles_size)*sizeof(*container)); popen_handles_size = i; } else container = popen_handles+i; if ( *md == 'r' ) { ret = _tfdopen(msvcrt_alloc_fd(hReadPipe, split_oflags(_fmode)) , _T("r")); CloseHandle(hWritePipe); } else { ret = _tfdopen( msvcrt_alloc_fd(hWritePipe, split_oflags(_fmode)) , _T("w")); CloseHandle(hReadPipe); } container->f = ret; container->proc = ProcessInformation.hProcess; _munlock(_POPEN_LOCK); return ret; error: _munlock(_POPEN_LOCK); if (ProcessInformation.hProcess != 0) CloseHandle(ProcessInformation.hProcess); return NULL; } #ifndef _UNICODE /* * @implemented */ int CDECL _pclose(FILE* file) { HANDLE h; DWORD i; if (!MSVCRT_CHECK_PMT(file != NULL)) return -1; _mlock(_POPEN_LOCK); for(i=0; i<popen_handles_size; i++) { if (popen_handles[i].f == file) break; } if(i == popen_handles_size) { _munlock(_POPEN_LOCK); *_errno() = EBADF; return -1; } h = popen_handles[i].proc; popen_handles[i].f = NULL; _munlock(_POPEN_LOCK); fclose(file); if(WaitForSingleObject(h, INFINITE)==WAIT_FAILED || !GetExitCodeProcess(h, &i)) { _dosmaperr(GetLastError()); CloseHandle(h); return -1; } CloseHandle(h); return i; } #endif