#include #include #if __WINDOWS__ #include #include #ifndef __CYGWIN__ #include #endif #define BUFSIZE 1024 void r_sys_perror_str(const char *fun); #define ErrorExit(x) { r_sys_perror(x); return NULL; } static int CreateChildProcess(const char *szCmdline, HANDLE out); char *ReadFromPipe(HANDLE fh); // HACKY static char *getexe(const char *str) { char *ptr, *argv0 = strdup (str); ptr = strchr (argv0, ' '); if (ptr) *ptr = '\0'; argv0 = realloc (argv0, strlen (argv0)+8); strcat (argv0, ".exe"); return argv0; } R_API char *r_sys_cmd_str_w32(const char *cmd) { char *ret = NULL; HANDLE out = NULL; HANDLE in = NULL; SECURITY_ATTRIBUTES saAttr; char *argv0 = getexe (cmd); // Set the bInheritPlugin flag so pipe handles are inherited. saAttr.nLength = sizeof (SECURITY_ATTRIBUTES); saAttr.bInheritHandle = TRUE; saAttr.lpSecurityDescriptor = NULL; HANDLE fh; // Create a pipe for the child process's STDOUT. if (!CreatePipe (&fh, &out, &saAttr, 0)) ErrorExit ("StdoutRd CreatePipe"); // Ensure the read handle to the pipe for STDOUT is not inherited. if (!SetHandleInformation (fh, HANDLE_FLAG_INHERIT, 0) ) ErrorExit ("Stdout SetHandleInformation"); CreateChildProcess (cmd, out); in = CreateFile (argv0, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, NULL); if (in == INVALID_HANDLE_VALUE) { eprintf ("CreateFile (%s)\n", argv0); ErrorExit ("CreateFile"); } // Close the write end of the pipe before reading from the // read end of the pipe, to control child process execution. // The pipe is assumed to have enough buffer space to hold the // data the child process has already written to it. if (!CloseHandle (out)) ErrorExit ("StdOutWr CloseHandle"); ret = ReadFromPipe (fh); free (argv0); return ret; } static int CreateChildProcess(const char *szCmdline, HANDLE out) { PROCESS_INFORMATION piProcInfo; STARTUPINFO siStartInfo; BOOL bSuccess = FALSE; ZeroMemory (&piProcInfo, sizeof (PROCESS_INFORMATION) ); // Set up members of the STARTUPINFO structure. // This structure specifies the STDIN and STDOUT handles for redirection. ZeroMemory (&siStartInfo, sizeof (STARTUPINFO) ); siStartInfo.cb = sizeof(STARTUPINFO); siStartInfo.hStdError = out; siStartInfo.hStdOutput = out; siStartInfo.hStdInput = NULL; siStartInfo.dwFlags |= STARTF_USESTDHANDLES; bSuccess = CreateProcess (NULL, (LPSTR)szCmdline,// command line NULL, // process security attributes NULL, // primary thread security attributes TRUE, // handles are inherited 0, // creation flags NULL, // use parent's environment NULL, // use parent's current directory &siStartInfo, // STARTUPINFO pointer &piProcInfo); // receives PROCESS_INFORMATION if (bSuccess) { CloseHandle (piProcInfo.hProcess); CloseHandle (piProcInfo.hThread); } else r_sys_perror ("CreateProcess"); return bSuccess; } char *ReadFromPipe(HANDLE fh) { DWORD dwRead; CHAR chBuf[BUFSIZE]; BOOL bSuccess = FALSE; char *str; int strl = 0; int strsz = BUFSIZE+1; str = malloc (strsz); for (;;) { bSuccess = ReadFile (fh, chBuf, BUFSIZE, &dwRead, NULL); if (! bSuccess || dwRead == 0) break; chBuf[dwRead] = '\0'; if (strl+dwRead>strsz) { strsz += 4096; str = realloc (str, strsz); if (!str) return NULL; } memcpy (str+strl, chBuf, dwRead); strl += dwRead; } str[strl] = 0; return str; } #endif