1 | //===-- Program.cpp - Implement OS Program Concept --------------*- C++ -*-===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | // |
9 | // This file implements the operating system Program concept. |
10 | // |
11 | //===----------------------------------------------------------------------===// |
12 | |
13 | #include "llvm/Support/Program.h" |
14 | #include "llvm/ADT/StringRef.h" |
15 | #include "llvm/Config/llvm-config.h" |
16 | #include "llvm/Support/raw_ostream.h" |
17 | using namespace llvm; |
18 | using namespace sys; |
19 | |
20 | //===----------------------------------------------------------------------===// |
21 | //=== WARNING: Implementation here must contain only TRULY operating system |
22 | //=== independent code. |
23 | //===----------------------------------------------------------------------===// |
24 | |
25 | static bool Execute(ProcessInfo &PI, StringRef Program, |
26 | ArrayRef<StringRef> Args, |
27 | std::optional<ArrayRef<StringRef>> Env, |
28 | ArrayRef<std::optional<StringRef>> Redirects, |
29 | unsigned MemoryLimit, std::string *ErrMsg, |
30 | BitVector *AffinityMask); |
31 | |
32 | int sys::ExecuteAndWait(StringRef Program, ArrayRef<StringRef> Args, |
33 | std::optional<ArrayRef<StringRef>> Env, |
34 | ArrayRef<std::optional<StringRef>> Redirects, |
35 | unsigned SecondsToWait, unsigned MemoryLimit, |
36 | std::string *ErrMsg, bool *ExecutionFailed, |
37 | std::optional<ProcessStatistics> *ProcStat, |
38 | BitVector *AffinityMask) { |
39 | assert(Redirects.empty() || Redirects.size() == 3); |
40 | ProcessInfo PI; |
41 | if (Execute(PI, Program, Args, Env, Redirects, MemoryLimit, ErrMsg, |
42 | AffinityMask)) { |
43 | if (ExecutionFailed) |
44 | *ExecutionFailed = false; |
45 | ProcessInfo Result = Wait( |
46 | PI, SecondsToWait: SecondsToWait == 0 ? std::nullopt : std::optional(SecondsToWait), |
47 | ErrMsg, ProcStat); |
48 | return Result.ReturnCode; |
49 | } |
50 | |
51 | if (ExecutionFailed) |
52 | *ExecutionFailed = true; |
53 | |
54 | return -1; |
55 | } |
56 | |
57 | ProcessInfo sys::ExecuteNoWait(StringRef Program, ArrayRef<StringRef> Args, |
58 | std::optional<ArrayRef<StringRef>> Env, |
59 | ArrayRef<std::optional<StringRef>> Redirects, |
60 | unsigned MemoryLimit, std::string *ErrMsg, |
61 | bool *ExecutionFailed, BitVector *AffinityMask) { |
62 | assert(Redirects.empty() || Redirects.size() == 3); |
63 | ProcessInfo PI; |
64 | if (ExecutionFailed) |
65 | *ExecutionFailed = false; |
66 | if (!Execute(PI, Program, Args, Env, Redirects, MemoryLimit, ErrMsg, |
67 | AffinityMask)) |
68 | if (ExecutionFailed) |
69 | *ExecutionFailed = true; |
70 | |
71 | return PI; |
72 | } |
73 | |
74 | bool sys::commandLineFitsWithinSystemLimits(StringRef Program, |
75 | ArrayRef<const char *> Args) { |
76 | SmallVector<StringRef, 8> StringRefArgs; |
77 | StringRefArgs.reserve(N: Args.size()); |
78 | for (const char *A : Args) |
79 | StringRefArgs.emplace_back(Args&: A); |
80 | return commandLineFitsWithinSystemLimits(Program, Args: StringRefArgs); |
81 | } |
82 | |
83 | void sys::printArg(raw_ostream &OS, StringRef Arg, bool Quote) { |
84 | const bool Escape = Arg.find_first_of(Chars: " \"\\$" ) != StringRef::npos; |
85 | |
86 | if (!Quote && !Escape) { |
87 | OS << Arg; |
88 | return; |
89 | } |
90 | |
91 | // Quote and escape. This isn't really complete, but good enough. |
92 | OS << '"'; |
93 | for (const auto c : Arg) { |
94 | if (c == '"' || c == '\\' || c == '$') |
95 | OS << '\\'; |
96 | OS << c; |
97 | } |
98 | OS << '"'; |
99 | } |
100 | |
101 | // Include the platform-specific parts of this class. |
102 | #ifdef LLVM_ON_UNIX |
103 | #include "Unix/Program.inc" |
104 | #endif |
105 | #ifdef _WIN32 |
106 | #include "Windows/Program.inc" |
107 | #endif |
108 | |