LLVM API Documentation
00001 //===- Win32/Program.cpp - Win32 Program Implementation ------- -*- C++ -*-===// 00002 // 00003 // The LLVM Compiler Infrastructure 00004 // 00005 // This file was developed by Jeff Cohen and is distributed under the 00006 // University of Illinois Open Source License. See LICENSE.TXT for details. 00007 // 00008 //===----------------------------------------------------------------------===// 00009 // 00010 // This file provides the Win32 specific implementation of the Program class. 00011 // 00012 //===----------------------------------------------------------------------===// 00013 00014 #include "Win32.h" 00015 #include <malloc.h> 00016 00017 //===----------------------------------------------------------------------===// 00018 //=== WARNING: Implementation here must contain only Win32 specific code 00019 //=== and must not be UNIX code 00020 //===----------------------------------------------------------------------===// 00021 00022 namespace llvm { 00023 using namespace sys; 00024 00025 // This function just uses the PATH environment variable to find the program. 00026 Path 00027 Program::FindProgramByName(const std::string& progName) { 00028 00029 // Check some degenerate cases 00030 if (progName.length() == 0) // no program 00031 return Path(); 00032 Path temp; 00033 if (!temp.setFile(progName)) // invalid name 00034 return Path(); 00035 if (temp.executable()) // already executable as is 00036 return temp; 00037 00038 // At this point, the file name is valid and its not executable. 00039 // Let Windows search for it. 00040 char buffer[MAX_PATH]; 00041 char *dummy = NULL; 00042 DWORD len = SearchPath(NULL, progName.c_str(), ".exe", MAX_PATH, 00043 buffer, &dummy); 00044 00045 // See if it wasn't found. 00046 if (len == 0) 00047 return Path(); 00048 00049 // See if we got the entire path. 00050 if (len < MAX_PATH) 00051 return Path(buffer); 00052 00053 // Buffer was too small; grow and retry. 00054 while (true) { 00055 char *b = reinterpret_cast<char *>(_alloca(len+1)); 00056 DWORD len2 = SearchPath(NULL, progName.c_str(), ".exe", len+1, b, &dummy); 00057 00058 // It is unlikely the search failed, but it's always possible some file 00059 // was added or removed since the last search, so be paranoid... 00060 if (len2 == 0) 00061 return Path(); 00062 else if (len2 <= len) 00063 return Path(b); 00064 00065 len = len2; 00066 } 00067 } 00068 00069 // 00070 int 00071 Program::ExecuteAndWait(const Path& path, 00072 const std::vector<std::string>& args) { 00073 if (!path.executable()) 00074 throw path.get() + " is not executable"; 00075 00076 // Windows wants a command line, not an array of args, to pass to the new 00077 // process. We have to concatenate them all, while quoting the args that 00078 // have embedded spaces. 00079 00080 // First, determine the length of the command line. 00081 std::string progname(path.getLast()); 00082 unsigned len = progname.length() + 1; 00083 if (progname.find(' ') != std::string::npos) 00084 len += 2; 00085 00086 for (unsigned i = 0; i < args.size(); i++) { 00087 len += args[i].length() + 1; 00088 if (args[i].find(' ') != std::string::npos) 00089 len += 2; 00090 } 00091 00092 // Now build the command line. 00093 char *command = reinterpret_cast<char *>(_alloca(len)); 00094 char *p = command; 00095 00096 bool needsQuoting = progname.find(' ') != std::string::npos; 00097 if (needsQuoting) 00098 *p++ = '"'; 00099 memcpy(p, progname.c_str(), progname.length()); 00100 p += progname.length(); 00101 if (needsQuoting) 00102 *p++ = '"'; 00103 *p++ = ' '; 00104 00105 for (unsigned i = 0; i < args.size(); i++) { 00106 const std::string& arg = args[i]; 00107 needsQuoting = arg.find(' ') != std::string::npos; 00108 if (needsQuoting) 00109 *p++ = '"'; 00110 memcpy(p, arg.c_str(), arg.length()); 00111 p += arg.length(); 00112 if (needsQuoting) 00113 *p++ = '"'; 00114 *p++ = ' '; 00115 } 00116 00117 *p = 0; 00118 00119 // Create a child process. 00120 STARTUPINFO si; 00121 memset(&si, 0, sizeof(si)); 00122 si.cb = sizeof(si); 00123 00124 PROCESS_INFORMATION pi; 00125 memset(&pi, 0, sizeof(pi)); 00126 00127 if (!CreateProcess(path.get().c_str(), command, NULL, NULL, FALSE, 0, 00128 NULL, NULL, &si, &pi)) 00129 { 00130 ThrowError(std::string("Couldn't execute program '") + path.get() + "'"); 00131 } 00132 00133 // Wait for it to terminate. 00134 WaitForSingleObject(pi.hProcess, INFINITE); 00135 00136 // Get its exit status. 00137 DWORD status; 00138 BOOL rc = GetExitCodeProcess(pi.hProcess, &status); 00139 00140 // Done with the handles; go close them. 00141 CloseHandle(pi.hProcess); 00142 CloseHandle(pi.hThread); 00143 00144 if (!rc) 00145 ThrowError(std::string("Failed getting status for program '") + path.get() + "'"); 00146 00147 return status; 00148 } 00149 00150 } 00151 // vim: sw=2 smartindent smarttab tw=80 autoindent expandtab