1218885Sdim//===- Win32/Program.cpp - Win32 Program Implementation ------- -*- C++ -*-===//
2218885Sdim//
3218885Sdim//                     The LLVM Compiler Infrastructure
4218885Sdim//
5218885Sdim// This file is distributed under the University of Illinois Open Source
6218885Sdim// License. See LICENSE.TXT for details.
7218885Sdim//
8218885Sdim//===----------------------------------------------------------------------===//
9218885Sdim//
10218885Sdim// This file provides the Win32 specific implementation of the Program class.
11218885Sdim//
12218885Sdim//===----------------------------------------------------------------------===//
13218885Sdim
14276479Sdim#include "WindowsSupport.h"
15280031Sdim#include "llvm/ADT/StringExtras.h"
16280031Sdim#include "llvm/Support/ConvertUTF.h"
17288943Sdim#include "llvm/Support/Errc.h"
18261991Sdim#include "llvm/Support/FileSystem.h"
19280031Sdim#include "llvm/Support/WindowsError.h"
20280031Sdim#include "llvm/Support/raw_ostream.h"
21218885Sdim#include <cstdio>
22249423Sdim#include <fcntl.h>
23249423Sdim#include <io.h>
24218885Sdim#include <malloc.h>
25218885Sdim
26218885Sdim//===----------------------------------------------------------------------===//
27218885Sdim//=== WARNING: Implementation here must contain only Win32 specific code
28218885Sdim//===          and must not be UNIX code
29218885Sdim//===----------------------------------------------------------------------===//
30218885Sdim
31218885Sdimnamespace llvm {
32218885Sdimusing namespace sys;
33218885Sdim
34261991SdimProcessInfo::ProcessInfo() : ProcessHandle(0), Pid(0), ReturnCode(0) {}
35218885Sdim
36280031SdimErrorOr sys::findProgramByName(StringRef Name,
37280031Sdim                                            ArrayRef<StringRef> Paths) {
38280031Sdim  assert(!Name.empty() && "Must have a name!");
39218885Sdim
40280031Sdim  if (Name.find_first_of("/\\") != StringRef::npos)
41280031Sdim    return std::string(Name);
42218885Sdim
43280031Sdim  const wchar_t *Path = nullptr;
44280031Sdim  std::wstring PathStorage;
45280031Sdim  if (!Paths.empty()) {
46280031Sdim    PathStorage.reserve(Paths.size() * MAX_PATH);
47280031Sdim    for (unsigned i = 0; i < Paths.size(); ++i) {
48280031Sdim      if (i)
49280031Sdim        PathStorage.push_back(L';');
50280031Sdim      StringRef P = Paths[i];
51280031Sdim      SmallVector<wchar_t, MAX_PATH> TmpPath;
52280031Sdim      if (std::error_code EC = windows::UTF8ToUTF16(P, TmpPath))
53280031Sdim        return EC;
54280031Sdim      PathStorage.append(TmpPath.begin(), TmpPath.end());
55280031Sdim    }
56280031Sdim    Path = PathStorage.c_str();
57280031Sdim  }
58218885Sdim
59280031Sdim  SmallVector<wchar_t, MAX_PATH> U16Name;
60280031Sdim  if (std::error_code EC = windows::UTF8ToUTF16(Name, U16Name))
61280031Sdim    return EC;
62218885Sdim
63280031Sdim  SmallVector<StringRef, 12> PathExts;
64280031Sdim  PathExts.push_back("");
65280031Sdim  PathExts.push_back(".exe"); // FIXME: This must be in %PATHEXT%.
66280031Sdim  if (const char *PathExtEnv = std::getenv("PATHEXT"))
67280031Sdim    SplitString(PathExtEnv, PathExts, ";");
68218885Sdim
69280031Sdim  SmallVector<wchar_t, MAX_PATH> U16Result;
70280031Sdim  DWORD Len = MAX_PATH;
71280031Sdim  for (StringRef Ext : PathExts) {
72280031Sdim    SmallVector<wchar_t, MAX_PATH> U16Ext;
73280031Sdim    if (std::error_code EC = windows::UTF8ToUTF16(Ext, U16Ext))
74280031Sdim      return EC;
75218885Sdim
76280031Sdim    do {
77280031Sdim      U16Result.reserve(Len);
78296417Sdim      // Lets attach the extension manually. That is needed for files
79296417Sdim      // with a point in name like aaa.bbb. SearchPathW will not add extension
80296417Sdim      // from its argument to such files because it thinks they already had one.
81296417Sdim      SmallVector<wchar_t, MAX_PATH> U16NameExt;
82296417Sdim      if (std::error_code EC =
83296417Sdim              windows::UTF8ToUTF16(Twine(Name + Ext).str(), U16NameExt))
84296417Sdim        return EC;
85296417Sdim
86296417Sdim      Len = ::SearchPathW(Path, c_str(U16NameExt), nullptr,
87280031Sdim                          U16Result.capacity(), U16Result.data(), nullptr);
88280031Sdim    } while (Len > U16Result.capacity());
89280031Sdim
90280031Sdim    if (Len != 0)
91280031Sdim      break; // Found it.
92280031Sdim  }
93280031Sdim
94280031Sdim  if (Len == 0)
95280031Sdim    return mapWindowsError(::GetLastError());
96280031Sdim
97280031Sdim  U16Result.set_size(Len);
98280031Sdim
99280031Sdim  SmallVector<char, MAX_PATH> U8Result;
100280031Sdim  if (std::error_code EC =
101280031Sdim          windows::UTF16ToUTF8(U16Result.data(), U16Result.size(), U8Result))
102280031Sdim    return EC;
103280031Sdim
104280031Sdim  return std::string(U8Result.begin(), U8Result.end());
105218885Sdim}
106218885Sdim
107261991Sdimstatic HANDLE RedirectIO(const StringRef *path, int fd, std::string* ErrMsg) {
108218885Sdim  HANDLE h;
109218885Sdim  if (path == 0) {
110261991Sdim    if (!DuplicateHandle(GetCurrentProcess(), (HANDLE)_get_osfhandle(fd),
111261991Sdim                         GetCurrentProcess(), &h,
112261991Sdim                         0, TRUE, DUPLICATE_SAME_ACCESS))
113261991Sdim      return INVALID_HANDLE_VALUE;
114218885Sdim    return h;
115218885Sdim  }
116218885Sdim
117261991Sdim  std::string fname;
118261991Sdim  if (path->empty())
119218885Sdim    fname = "NUL";
120218885Sdim  else
121261991Sdim    fname = *path;
122218885Sdim
123218885Sdim  SECURITY_ATTRIBUTES sa;
124218885Sdim  sa.nLength = sizeof(sa);
125218885Sdim  sa.lpSecurityDescriptor = 0;
126218885Sdim  sa.bInheritHandle = TRUE;
127218885Sdim
128261991Sdim  SmallVector<wchar_t, 128> fnameUnicode;
129280031Sdim  if (path->empty()) {
130280031Sdim    // Don't play long-path tricks on "NUL".
131280031Sdim    if (windows::UTF8ToUTF16(fname, fnameUnicode))
132280031Sdim      return INVALID_HANDLE_VALUE;
133280031Sdim  } else {
134280031Sdim    if (path::widenPath(fname, fnameUnicode))
135280031Sdim      return INVALID_HANDLE_VALUE;
136280031Sdim  }
137261991Sdim  h = CreateFileW(fnameUnicode.data(), fd ? GENERIC_WRITE : GENERIC_READ,
138261991Sdim                  FILE_SHARE_READ, &sa, fd == 0 ? OPEN_EXISTING : CREATE_ALWAYS,
139261991Sdim                  FILE_ATTRIBUTE_NORMAL, NULL);
140218885Sdim  if (h == INVALID_HANDLE_VALUE) {
141280031Sdim    MakeErrMsg(ErrMsg, fname + ": Can't open file for " +
142296417Sdim        (fd ? "input" : "output"));
143218885Sdim  }
144218885Sdim
145218885Sdim  return h;
146218885Sdim}
147218885Sdim
148218885Sdim/// ArgNeedsQuotes - Check whether argument needs to be quoted when calling
149218885Sdim/// CreateProcess.
150218885Sdimstatic bool ArgNeedsQuotes(const char *Str) {
151218885Sdim  return Str[0] == '\0' || strpbrk(Str, "\t \"&\'()*<>\\`^|") != 0;
152218885Sdim}
153218885Sdim
154251662Sdim/// CountPrecedingBackslashes - Returns the number of backslashes preceding Cur
155251662Sdim/// in the C string Start.
156251662Sdimstatic unsigned int CountPrecedingBackslashes(const char *Start,
157251662Sdim                                              const char *Cur) {
158251662Sdim  unsigned int Count = 0;
159251662Sdim  --Cur;
160251662Sdim  while (Cur >= Start && *Cur == '\\') {
161251662Sdim    ++Count;
162251662Sdim    --Cur;
163251662Sdim  }
164251662Sdim  return Count;
165251662Sdim}
166218885Sdim
167251662Sdim/// EscapePrecedingEscapes - Append a backslash to Dst for every backslash
168251662Sdim/// preceding Cur in the Start string.  Assumes Dst has enough space.
169251662Sdimstatic char *EscapePrecedingEscapes(char *Dst, const char *Start,
170251662Sdim                                    const char *Cur) {
171251662Sdim  unsigned PrecedingEscapes = CountPrecedingBackslashes(Start, Cur);
172251662Sdim  while (PrecedingEscapes > 0) {
173251662Sdim    *Dst++ = '\\';
174251662Sdim    --PrecedingEscapes;
175251662Sdim  }
176251662Sdim  return Dst;
177251662Sdim}
178251662Sdim
179218885Sdim/// ArgLenWithQuotes - Check whether argument needs to be quoted when calling
180218885Sdim/// CreateProcess and returns length of quoted arg with escaped quotes
181218885Sdimstatic unsigned int ArgLenWithQuotes(const char *Str) {
182251662Sdim  const char *Start = Str;
183251662Sdim  bool Quoted = ArgNeedsQuotes(Str);
184251662Sdim  unsigned int len = Quoted ? 2 : 0;
185218885Sdim
186218885Sdim  while (*Str != '\0') {
187251662Sdim    if (*Str == '\"') {
188251662Sdim      // We need to add a backslash, but ensure that it isn't escaped.
189251662Sdim      unsigned PrecedingEscapes = CountPrecedingBackslashes(Start, Str);
190251662Sdim      len += PrecedingEscapes + 1;
191251662Sdim    }
192251662Sdim    // Note that we *don't* need to escape runs of backslashes that don't
193251662Sdim    // precede a double quote!  See MSDN:
194251662Sdim    // http://msdn.microsoft.com/en-us/library/17w5ykft%28v=vs.85%29.aspx
195218885Sdim
196218885Sdim    ++len;
197218885Sdim    ++Str;
198218885Sdim  }
199218885Sdim
200251662Sdim  if (Quoted) {
201251662Sdim    // Make sure the closing quote doesn't get escaped by a trailing backslash.
202251662Sdim    unsigned PrecedingEscapes = CountPrecedingBackslashes(Start, Str);
203251662Sdim    len += PrecedingEscapes + 1;
204251662Sdim  }
205251662Sdim
206218885Sdim  return len;
207218885Sdim}
208218885Sdim
209261991Sdim}
210218885Sdim
211280031Sdimstatic std::unique_ptr<char[]> flattenArgs(const char **args) {
212218885Sdim  // First, determine the length of the command line.
213218885Sdim  unsigned len = 0;
214218885Sdim  for (unsigned i = 0; args[i]; i++) {
215218885Sdim    len += ArgLenWithQuotes(args[i]) + 1;
216218885Sdim  }
217218885Sdim
218218885Sdim  // Now build the command line.
219276479Sdim  std::unique_ptr<char[]> command(new char[len+1]);
220261991Sdim  char *p = command.get();
221218885Sdim
222218885Sdim  for (unsigned i = 0; args[i]; i++) {
223218885Sdim    const char *arg = args[i];
224251662Sdim    const char *start = arg;
225218885Sdim
226218885Sdim    bool needsQuoting = ArgNeedsQuotes(arg);
227218885Sdim    if (needsQuoting)
228218885Sdim      *p++ = '"';
229218885Sdim
230218885Sdim    while (*arg != '\0') {
231251662Sdim      if (*arg == '\"') {
232251662Sdim        // Escape all preceding escapes (if any), and then escape the quote.
233251662Sdim        p = EscapePrecedingEscapes(p, start, arg);
234218885Sdim        *p++ = '\\';
235251662Sdim      }
236218885Sdim
237218885Sdim      *p++ = *arg++;
238218885Sdim    }
239218885Sdim
240251662Sdim    if (needsQuoting) {
241251662Sdim      // Make sure our quote doesn't get escaped by a trailing backslash.
242251662Sdim      p = EscapePrecedingEscapes(p, start, arg);
243218885Sdim      *p++ = '"';
244251662Sdim    }
245218885Sdim    *p++ = ' ';
246218885Sdim  }
247218885Sdim
248218885Sdim  *p = 0;
249280031Sdim  return command;
250280031Sdim}
251218885Sdim
252280031Sdimstatic bool Execute(ProcessInfo &PI, StringRef Program, const char **args,
253280031Sdim                    const char **envp, const StringRef **redirects,
254280031Sdim                    unsigned memoryLimit, std::string *ErrMsg) {
255280031Sdim  if (!sys::fs::can_execute(Program)) {
256280031Sdim    if (ErrMsg)
257280031Sdim      *ErrMsg = "program not executable";
258280031Sdim    return false;
259280031Sdim  }
260280031Sdim
261296417Sdim  // can_execute may succeed by looking at Program + ".exe". CreateProcessW
262296417Sdim  // will implicitly add the .exe if we provide a command line without an
263296417Sdim  // executable path, but since we use an explicit executable, we have to add
264296417Sdim  // ".exe" ourselves.
265296417Sdim  SmallString<64> ProgramStorage;
266296417Sdim  if (!sys::fs::exists(Program))
267296417Sdim    Program = Twine(Program + ".exe").toStringRef(ProgramStorage);
268296417Sdim
269280031Sdim  // Windows wants a command line, not an array of args, to pass to the new
270280031Sdim  // process.  We have to concatenate them all, while quoting the args that
271280031Sdim  // have embedded spaces (or are empty).
272280031Sdim  std::unique_ptr<char[]> command = flattenArgs(args);
273280031Sdim
274218885Sdim  // The pointer to the environment block for the new process.
275261991Sdim  std::vector<wchar_t> EnvBlock;
276218885Sdim
277218885Sdim  if (envp) {
278218885Sdim    // An environment block consists of a null-terminated block of
279218885Sdim    // null-terminated strings. Convert the array of environment variables to
280218885Sdim    // an environment block by concatenating them.
281261991Sdim    for (unsigned i = 0; envp[i]; ++i) {
282261991Sdim      SmallVector<wchar_t, MAX_PATH> EnvString;
283276479Sdim      if (std::error_code ec = windows::UTF8ToUTF16(envp[i], EnvString)) {
284261991Sdim        SetLastError(ec.value());
285261991Sdim        MakeErrMsg(ErrMsg, "Unable to convert environment variable to UTF-16");
286261991Sdim        return false;
287261991Sdim      }
288218885Sdim
289261991Sdim      EnvBlock.insert(EnvBlock.end(), EnvString.begin(), EnvString.end());
290261991Sdim      EnvBlock.push_back(0);
291218885Sdim    }
292261991Sdim    EnvBlock.push_back(0);
293218885Sdim  }
294218885Sdim
295218885Sdim  // Create a child process.
296261991Sdim  STARTUPINFOW si;
297218885Sdim  memset(&si, 0, sizeof(si));
298218885Sdim  si.cb = sizeof(si);
299218885Sdim  si.hStdInput = INVALID_HANDLE_VALUE;
300218885Sdim  si.hStdOutput = INVALID_HANDLE_VALUE;
301218885Sdim  si.hStdError = INVALID_HANDLE_VALUE;
302218885Sdim
303218885Sdim  if (redirects) {
304218885Sdim    si.dwFlags = STARTF_USESTDHANDLES;
305218885Sdim
306218885Sdim    si.hStdInput = RedirectIO(redirects[0], 0, ErrMsg);
307218885Sdim    if (si.hStdInput == INVALID_HANDLE_VALUE) {
308218885Sdim      MakeErrMsg(ErrMsg, "can't redirect stdin");
309218885Sdim      return false;
310218885Sdim    }
311218885Sdim    si.hStdOutput = RedirectIO(redirects[1], 1, ErrMsg);
312218885Sdim    if (si.hStdOutput == INVALID_HANDLE_VALUE) {
313218885Sdim      CloseHandle(si.hStdInput);
314218885Sdim      MakeErrMsg(ErrMsg, "can't redirect stdout");
315218885Sdim      return false;
316218885Sdim    }
317218885Sdim    if (redirects[1] && redirects[2] && *(redirects[1]) == *(redirects[2])) {
318218885Sdim      // If stdout and stderr should go to the same place, redirect stderr
319218885Sdim      // to the handle already open for stdout.
320261991Sdim      if (!DuplicateHandle(GetCurrentProcess(), si.hStdOutput,
321261991Sdim                           GetCurrentProcess(), &si.hStdError,
322261991Sdim                           0, TRUE, DUPLICATE_SAME_ACCESS)) {
323261991Sdim        CloseHandle(si.hStdInput);
324261991Sdim        CloseHandle(si.hStdOutput);
325261991Sdim        MakeErrMsg(ErrMsg, "can't dup stderr to stdout");
326261991Sdim        return false;
327261991Sdim      }
328218885Sdim    } else {
329218885Sdim      // Just redirect stderr
330218885Sdim      si.hStdError = RedirectIO(redirects[2], 2, ErrMsg);
331218885Sdim      if (si.hStdError == INVALID_HANDLE_VALUE) {
332218885Sdim        CloseHandle(si.hStdInput);
333218885Sdim        CloseHandle(si.hStdOutput);
334218885Sdim        MakeErrMsg(ErrMsg, "can't redirect stderr");
335218885Sdim        return false;
336218885Sdim      }
337218885Sdim    }
338218885Sdim  }
339218885Sdim
340218885Sdim  PROCESS_INFORMATION pi;
341218885Sdim  memset(&pi, 0, sizeof(pi));
342218885Sdim
343218885Sdim  fflush(stdout);
344218885Sdim  fflush(stderr);
345261991Sdim
346261991Sdim  SmallVector<wchar_t, MAX_PATH> ProgramUtf16;
347280031Sdim  if (std::error_code ec = path::widenPath(Program, ProgramUtf16)) {
348261991Sdim    SetLastError(ec.value());
349261991Sdim    MakeErrMsg(ErrMsg,
350261991Sdim               std::string("Unable to convert application name to UTF-16"));
351261991Sdim    return false;
352261991Sdim  }
353261991Sdim
354261991Sdim  SmallVector<wchar_t, MAX_PATH> CommandUtf16;
355276479Sdim  if (std::error_code ec = windows::UTF8ToUTF16(command.get(), CommandUtf16)) {
356261991Sdim    SetLastError(ec.value());
357261991Sdim    MakeErrMsg(ErrMsg,
358261991Sdim               std::string("Unable to convert command-line to UTF-16"));
359261991Sdim    return false;
360261991Sdim  }
361261991Sdim
362261991Sdim  BOOL rc = CreateProcessW(ProgramUtf16.data(), CommandUtf16.data(), 0, 0,
363261991Sdim                           TRUE, CREATE_UNICODE_ENVIRONMENT,
364261991Sdim                           EnvBlock.empty() ? 0 : EnvBlock.data(), 0, &si,
365261991Sdim                           &pi);
366218885Sdim  DWORD err = GetLastError();
367218885Sdim
368218885Sdim  // Regardless of whether the process got created or not, we are done with
369218885Sdim  // the handles we created for it to inherit.
370218885Sdim  CloseHandle(si.hStdInput);
371218885Sdim  CloseHandle(si.hStdOutput);
372218885Sdim  CloseHandle(si.hStdError);
373218885Sdim
374218885Sdim  // Now return an error if the process didn't get created.
375218885Sdim  if (!rc) {
376218885Sdim    SetLastError(err);
377218885Sdim    MakeErrMsg(ErrMsg, std::string("Couldn't execute program '") +
378261991Sdim               Program.str() + "'");
379218885Sdim    return false;
380218885Sdim  }
381218885Sdim
382261991Sdim  PI.Pid = pi.dwProcessId;
383261991Sdim  PI.ProcessHandle = pi.hProcess;
384261991Sdim
385218885Sdim  // Make sure these get closed no matter what.
386234353Sdim  ScopedCommonHandle hThread(pi.hThread);
387218885Sdim
388218885Sdim  // Assign the process to a job if a memory limit is defined.
389234353Sdim  ScopedJobHandle hJob;
390218885Sdim  if (memoryLimit != 0) {
391261991Sdim    hJob = CreateJobObjectW(0, 0);
392218885Sdim    bool success = false;
393234353Sdim    if (hJob) {
394218885Sdim      JOBOBJECT_EXTENDED_LIMIT_INFORMATION jeli;
395218885Sdim      memset(&jeli, 0, sizeof(jeli));
396218885Sdim      jeli.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_PROCESS_MEMORY;
397218885Sdim      jeli.ProcessMemoryLimit = uintptr_t(memoryLimit) * 1048576;
398218885Sdim      if (SetInformationJobObject(hJob, JobObjectExtendedLimitInformation,
399218885Sdim                                  &jeli, sizeof(jeli))) {
400218885Sdim        if (AssignProcessToJobObject(hJob, pi.hProcess))
401218885Sdim          success = true;
402218885Sdim      }
403218885Sdim    }
404218885Sdim    if (!success) {
405218885Sdim      SetLastError(GetLastError());
406218885Sdim      MakeErrMsg(ErrMsg, std::string("Unable to set memory limit"));
407218885Sdim      TerminateProcess(pi.hProcess, 1);
408218885Sdim      WaitForSingleObject(pi.hProcess, INFINITE);
409218885Sdim      return false;
410218885Sdim    }
411218885Sdim  }
412218885Sdim
413218885Sdim  return true;
414218885Sdim}
415218885Sdim
416261991Sdimnamespace llvm {
417261991SdimProcessInfo sys::Wait(const ProcessInfo &PI, unsigned SecondsToWait,
418261991Sdim                      bool WaitUntilChildTerminates, std::string *ErrMsg) {
419261991Sdim  assert(PI.Pid && "invalid pid to wait on, process not started?");
420261991Sdim  assert(PI.ProcessHandle &&
421261991Sdim         "invalid process handle to wait on, process not started?");
422261991Sdim  DWORD milliSecondsToWait = 0;
423261991Sdim  if (WaitUntilChildTerminates)
424261991Sdim    milliSecondsToWait = INFINITE;
425261991Sdim  else if (SecondsToWait > 0)
426261991Sdim    milliSecondsToWait = SecondsToWait * 1000;
427218885Sdim
428261991Sdim  ProcessInfo WaitResult = PI;
429261991Sdim  DWORD WaitStatus = WaitForSingleObject(PI.ProcessHandle, milliSecondsToWait);
430261991Sdim  if (WaitStatus == WAIT_TIMEOUT) {
431261991Sdim    if (SecondsToWait) {
432261991Sdim      if (!TerminateProcess(PI.ProcessHandle, 1)) {
433261991Sdim        if (ErrMsg)
434296417Sdim          MakeErrMsg(ErrMsg, "Failed to terminate timed-out program");
435218885Sdim
436261991Sdim        // -2 indicates a crash or timeout as opposed to failure to execute.
437261991Sdim        WaitResult.ReturnCode = -2;
438261991Sdim        CloseHandle(PI.ProcessHandle);
439261991Sdim        return WaitResult;
440261991Sdim      }
441261991Sdim      WaitForSingleObject(PI.ProcessHandle, INFINITE);
442261991Sdim      CloseHandle(PI.ProcessHandle);
443261991Sdim    } else {
444261991Sdim      // Non-blocking wait.
445261991Sdim      return ProcessInfo();
446218885Sdim    }
447218885Sdim  }
448218885Sdim
449218885Sdim  // Get its exit status.
450218885Sdim  DWORD status;
451261991Sdim  BOOL rc = GetExitCodeProcess(PI.ProcessHandle, &status);
452218885Sdim  DWORD err = GetLastError();
453288943Sdim  if (err != ERROR_INVALID_HANDLE)
454288943Sdim    CloseHandle(PI.ProcessHandle);
455218885Sdim
456218885Sdim  if (!rc) {
457218885Sdim    SetLastError(err);
458261991Sdim    if (ErrMsg)
459296417Sdim      MakeErrMsg(ErrMsg, "Failed getting status for program");
460261991Sdim
461223017Sdim    // -2 indicates a crash or timeout as opposed to failure to execute.
462261991Sdim    WaitResult.ReturnCode = -2;
463261991Sdim    return WaitResult;
464218885Sdim  }
465218885Sdim
466234353Sdim  if (!status)
467261991Sdim    return WaitResult;
468234353Sdim
469234353Sdim  // Pass 10(Warning) and 11(Error) to the callee as negative value.
470234353Sdim  if ((status & 0xBFFF0000U) == 0x80000000U)
471261991Sdim    WaitResult.ReturnCode = static_cast<int>(status);
472261991Sdim  else if (status & 0xFF)
473261991Sdim    WaitResult.ReturnCode = status & 0x7FFFFFFF;
474261991Sdim  else
475261991Sdim    WaitResult.ReturnCode = 1;
476234353Sdim
477261991Sdim  return WaitResult;
478218885Sdim}
479218885Sdim
480280031Sdimstd::error_code sys::ChangeStdinToBinary() {
481280031Sdim  int result = _setmode(_fileno(stdin), _O_BINARY);
482234353Sdim  if (result == -1)
483276479Sdim    return std::error_code(errno, std::generic_category());
484276479Sdim  return std::error_code();
485218885Sdim}
486218885Sdim
487280031Sdimstd::error_code sys::ChangeStdoutToBinary() {
488280031Sdim  int result = _setmode(_fileno(stdout), _O_BINARY);
489234353Sdim  if (result == -1)
490276479Sdim    return std::error_code(errno, std::generic_category());
491276479Sdim  return std::error_code();
492218885Sdim}
493218885Sdim
494280031Sdimstd::error_code
495280031Sdimllvm::sys::writeFileWithEncoding(StringRef FileName, StringRef Contents,
496280031Sdim                                 WindowsEncodingMethod Encoding) {
497280031Sdim  std::error_code EC;
498280031Sdim  llvm::raw_fd_ostream OS(FileName, EC, llvm::sys::fs::OpenFlags::F_Text);
499280031Sdim  if (EC)
500280031Sdim    return EC;
501280031Sdim
502280031Sdim  if (Encoding == WEM_UTF8) {
503280031Sdim    OS << Contents;
504280031Sdim  } else if (Encoding == WEM_CurrentCodePage) {
505280031Sdim    SmallVector<wchar_t, 1> ArgsUTF16;
506280031Sdim    SmallVector<char, 1> ArgsCurCP;
507280031Sdim
508280031Sdim    if ((EC = windows::UTF8ToUTF16(Contents, ArgsUTF16)))
509280031Sdim      return EC;
510280031Sdim
511280031Sdim    if ((EC = windows::UTF16ToCurCP(
512280031Sdim             ArgsUTF16.data(), ArgsUTF16.size(), ArgsCurCP)))
513280031Sdim      return EC;
514280031Sdim
515280031Sdim    OS.write(ArgsCurCP.data(), ArgsCurCP.size());
516280031Sdim  } else if (Encoding == WEM_UTF16) {
517280031Sdim    SmallVector<wchar_t, 1> ArgsUTF16;
518280031Sdim
519280031Sdim    if ((EC = windows::UTF8ToUTF16(Contents, ArgsUTF16)))
520280031Sdim      return EC;
521280031Sdim
522280031Sdim    // Endianness guessing
523280031Sdim    char BOM[2];
524280031Sdim    uint16_t src = UNI_UTF16_BYTE_ORDER_MARK_NATIVE;
525280031Sdim    memcpy(BOM, &src, 2);
526280031Sdim    OS.write(BOM, 2);
527280031Sdim    OS.write((char *)ArgsUTF16.data(), ArgsUTF16.size() << 1);
528280031Sdim  } else {
529280031Sdim    llvm_unreachable("Unknown encoding");
530280031Sdim  }
531280031Sdim
532280031Sdim  if (OS.has_error())
533288943Sdim    return make_error_code(errc::io_error);
534280031Sdim
535280031Sdim  return EC;
536280031Sdim}
537280031Sdim
538296417Sdimbool llvm::sys::commandLineFitsWithinSystemLimits(StringRef Program, ArrayRef<const char*> Args) {
539251662Sdim  // The documented max length of the command line passed to CreateProcess.
540251662Sdim  static const size_t MaxCommandStringLength = 32768;
541296417Sdim  // Account for the trailing space for the program path and the
542296417Sdim  // trailing NULL of the last argument.
543296417Sdim  size_t ArgLength = ArgLenWithQuotes(Program.str().c_str()) + 2;
544251662Sdim  for (ArrayRef<const char*>::iterator I = Args.begin(), E = Args.end();
545251662Sdim       I != E; ++I) {
546296417Sdim    // Account for the trailing space for every arg
547251662Sdim    ArgLength += ArgLenWithQuotes(*I) + 1;
548251662Sdim    if (ArgLength > MaxCommandStringLength) {
549251662Sdim      return false;
550251662Sdim    }
551251662Sdim  }
552251662Sdim  return true;
553218885Sdim}
554251662Sdim}
555