Sane C++ Libraries
C++ Platform Abstraction Libraries
Process.h
1// Copyright (c) Stefano Cristiano
2// SPDX-License-Identifier: MIT
3#pragma once
4
5#include "../Containers/IntrusiveDoubleLinkedList.h"
6#include "../File/FileDescriptor.h"
7#include "../Strings/SmallString.h"
8#include "ProcessDescriptor.h"
9
10namespace SC
11{
12struct SC_COMPILER_EXPORT Process;
13struct SC_COMPILER_EXPORT ProcessChain;
14struct ProcessID;
15struct ProcessEnvironment;
16} // namespace SC
17
20
23
26{
27 int32_t pid = 0;
28};
29
62
64{
66 {
68 Options();
69 };
70
71 struct StdStream
72 {
73 // clang-format off
75 StdStream(String& externalString) { operation = Operation::String; string = &externalString;}
76
78 StdStream(Vector<char>& externalVector) { operation = Operation::Vector; vector = &externalVector; }
79 // clang-format on
80
83 {
84 operation = Operation::FileDescriptor;
85 (void)file.get(fileDescriptor, Result::Error("Invalid redirection file descriptor"));
86 file.detach();
87 }
88
90 {
91 operation = Operation::ExternalPipe;
92 pipeDescriptor = &pipe;
93 }
94
95 protected:
97 {
98 };
99 StdStream() = default;
100 StdStream(AlreadySetup) { operation = Operation::AlreadySetup; }
101 friend struct Process;
102 friend struct ProcessChain;
103
104 enum class Operation
105 {
106 AlreadySetup,
107 Inherit,
108 Ignore,
109 ExternalPipe,
111 Vector,
112 String,
113 WritableSpan,
114 ReadableSpan
115 };
116 Operation operation = Operation::Inherit;
117
118 Span<const char> readableSpan;
119 Span<char> writableSpan;
120
121 String* string;
122 Vector<char>* vector;
123
124 FileDescriptor::Handle fileDescriptor;
125
126 PipeDescriptor* pipeDescriptor;
127 };
128
129 struct StdOut : public StdStream
130 {
131 // clang-format off
132 struct Ignore{};
133 struct Inherit{};
134
136 StdOut(Ignore) { operation = Operation::Ignore; }
137
139 StdOut(Inherit) { operation = Operation::Inherit; }
140
142 StdOut(Span<char> span) { operation = Operation::WritableSpan; writableSpan = span; }
143
144 using StdStream::StdStream;
145 friend struct ProcessChain;
146 // clang-format on
147 };
148
149 using StdErr = StdOut;
150
151 struct StdIn : public StdStream
152 {
153 // clang-format off
154 struct Inherit{};
155
157 StdIn(Inherit) { operation = Operation::Inherit; }
158
160 template <int N> StdIn(const char (&item)[N]) : StdIn(StringView({item, N - 1}, true, StringEncoding::Ascii)) {}
161
163 StdIn(StringView string) : StdIn(string.toCharSpan()) {}
164
166 StdIn(Span<const char> span) { operation = Operation::ReadableSpan; readableSpan = span;}
167
168 using StdStream::StdStream;
169 friend struct ProcessChain;
170 // clang-format on
171 };
172
176
178 [[nodiscard]] Result waitForExitSync();
179
188 const StdOut& stdOut = StdOut::Inherit{}, //
189 const StdIn& stdIn = StdIn::Inherit{}, //
190 const StdErr& stdErr = StdErr::Inherit{})
191 {
192 SC_TRY(formatArguments(cmd));
193 return launch(stdOut, stdIn, stdErr);
194 }
195
203 [[nodiscard]] Result exec(Span<const StringView> cmd, //
204 const StdOut& stdOut = StdOut::Inherit{}, //
205 const StdIn& stdIn = StdIn::Inherit{}, //
206 const StdErr& stdErr = StdErr::Inherit{})
207 {
208 SC_TRY(launch(cmd, stdOut, stdIn, stdErr));
209 return waitForExitSync();
210 }
211
213 int32_t getExitStatus() const { return exitStatus.status; }
214
216 [[nodiscard]] Result setWorkingDirectory(StringView processWorkingDirectory);
217
219 void inheritParentEnvironmentVariables(bool inherit) { inheritEnv = inherit; }
220
222 [[nodiscard]] Result setEnvironment(StringView environmentVariable, StringView value);
223
225 static size_t getNumberOfProcessors();
226
229
230 private:
232
233 FileDescriptor stdInFd;
234 FileDescriptor stdOutFd;
235 FileDescriptor stdErrFd;
236
237 [[nodiscard]] Result launch(const StdOut& stdOutput, const StdIn& stdInput, const StdErr& stdError);
238
239 [[nodiscard]] Result formatArguments(Span<const StringView> cmd);
240
241 StringNative<255> currentDirectory = StringEncoding::Native;
242
243 // On Windows command holds the concatenation of executable and arguments.
244 // On Posix command holds the concatenation of executable and arguments SEPARATED BY null-terminators (\0).
245 // This is done so that in this single buffer with no allocation (under 255) or a single allocation (above 255)
246 // we can track all arguments to be passed to execve.
248#if !SC_PLATFORM_WINDOWS // On Posix we need to track the "sub-strings" hidden in command
249 static constexpr size_t MAX_NUM_ARGUMENTS = 64;
250 size_t commandArgumentsByteOffset[MAX_NUM_ARGUMENTS]; // Tracking length of each argument in the command string
251 size_t commandArgumentsNumber = 0; // Counts number of arguments (including executable name)
252#endif
253
255
256 static constexpr size_t MAX_NUM_ENVIRONMENT = 256;
257
258 size_t environmentByteOffset[MAX_NUM_ENVIRONMENT]; // Tracking length of each environment variable
259 size_t environmentNumber = 0; // Counts number of environment variable
260
261 bool inheritEnv = true;
262
263 friend struct IntrusiveDoubleLinkedList<Process>;
264 friend struct ProcessChain;
265 ProcessChain* parent = nullptr;
266
267 Process* next = nullptr;
268 Process* prev = nullptr;
269 struct Internal;
270
271 Result launchImplementation();
272};
273
291{
292 Process::Options options;
297 [[nodiscard]] Result pipe(Process& process, const Span<const StringView> cmd);
298
302 [[nodiscard]] Result launch(const Process::StdOut& stdOut = Process::StdOut::Inherit{}, //
303 const Process::StdIn& stdIn = Process::StdIn::Inherit{}, //
304 const Process::StdErr& stdErr = Process::StdErr::Inherit{});
305
308 [[nodiscard]] Result waitForExitSync();
309
312 [[nodiscard]] Result exec(const Process::StdOut& stdOut = Process::StdOut::Inherit{}, //
313 const Process::StdIn& stdIn = Process::StdIn::Inherit{}, //
314 const Process::StdErr& stdErr = Process::StdErr::Inherit{})
315 {
316 SC_TRY(launch(stdOut, stdIn, stdErr));
317 return waitForExitSync();
318 }
319
320 private:
321 IntrusiveDoubleLinkedList<Process> processes;
322};
323
329{
332
333 ProcessEnvironment(const ProcessEnvironment&) = delete;
335 ProcessEnvironment& operator=(const ProcessEnvironment&) = delete;
336 ProcessEnvironment& operator=(ProcessEnvironment&&) = delete;
337
339 [[nodiscard]] size_t size() const { return numberOfEnvironment; }
340
345 [[nodiscard]] bool get(size_t index, StringView& name, StringView& value) const;
346
351 [[nodiscard]] bool contains(StringView variableName, size_t* index = nullptr);
352
353 private:
354 size_t numberOfEnvironment = 0;
355#if SC_PLATFORM_WINDOWS
356 static constexpr size_t MAX_ENVIRONMENTS = 256;
357
358 StringView envStrings[MAX_ENVIRONMENTS];
359 wchar_t* environment = nullptr;
360#else
361 char** environment = nullptr;
362#endif
363};
#define SC_COMPILER_EXPORT
Macro for symbol visibility in non-MSVC compilers.
Definition: Compiler.h:78
int int32_t
Platform independent (4) bytes signed int.
Definition: PrimitiveTypes.h:46
#define SC_TRY(expression)
Checks the value of the given expression and if failed, returns this value to caller.
Definition: Result.h:47
@ Ascii
Encoding is ASCII.
@ Native
Encoding is UTF8.
Wraps an OS File descriptor to read and write to and from it.
Definition: FileDescriptor.h:57
An Intrusive Double Linked List.
Definition: IntrusiveDoubleLinkedList.h:22
Descriptor representing a Pipe used for InterProcess Communication (IPC)
Definition: FileDescriptor.h:202
Definition: Process.h:66
bool windowsHide
[Windows] Hides child process window (default == Process::isWindowsConsoleSubsystem)
Definition: Process.h:67
Definition: Process.h:154
Definition: Process.h:152
StdIn(StringView string)
Fills standard input with content of a StringView.
Definition: Process.h:163
StdIn(const char(&item)[N])
Fills standard input with content of a C-String.
Definition: Process.h:160
StdIn(Span< const char > span)
Fills standard input with content of a Span.
Definition: Process.h:166
StdIn(Inherit)
Inherits child process Input from parent process.
Definition: Process.h:157
Definition: Process.h:132
Definition: Process.h:133
Definition: Process.h:130
StdOut(Span< char > span)
Read the process standard output/error into the given Span.
Definition: Process.h:142
StdOut(Ignore)
Ignores child process standard output/error (child process output will be silenced)
Definition: Process.h:136
StdOut(Inherit)
Inherits child process standard output/error (child process will print into parent process console)
Definition: Process.h:139
Definition: Process.h:97
Definition: Process.h:72
StdStream(Vector< char > &externalVector)
Read the process standard output/error into the given Vector.
Definition: Process.h:78
StdStream(String &externalString)
Read the process standard output/error into the given String.
Definition: Process.h:75
StdStream(FileDescriptor &&file)
Redirects child process standard output/error to a given file descriptor.
Definition: Process.h:82
Execute multiple child processes chaining input / output between them.
Definition: Process.h:291
Result exec(const Process::StdOut &stdOut=Process::StdOut::Inherit{}, const Process::StdIn &stdIn=Process::StdIn::Inherit{}, const Process::StdErr &stdErr=Process::StdErr::Inherit{})
Launch the entire chain of processes and waits for the results (calling ProcessChain::waitForExitSync...
Definition: Process.h:312
Result launch(const Process::StdOut &stdOut=Process::StdOut::Inherit{}, const Process::StdIn &stdIn=Process::StdIn::Inherit{}, const Process::StdErr &stdErr=Process::StdErr::Inherit{})
Launch the entire chain of processes.
Result pipe(Process &process, const Span< const StringView > cmd)
Add a process to the chain, with given arguments.
Result waitForExitSync()
Waits (blocking) for entire process chain to exit.
Definition: ProcessDescriptor.h:44
Wraps an OS Process descriptor.
Definition: ProcessDescriptor.h:42
Reads current process environment variables.
Definition: Process.h:329
bool get(size_t index, StringView &name, StringView &value) const
Get the environmnent variable at given index, returning its name and value.
bool contains(StringView variableName, size_t *index=nullptr)
Checks if an environment variable exists in current process.
size_t size() const
Returns the total number of environment variables for current process.
Definition: Process.h:339
Execute a child process with standard file descriptors redirection.
Definition: Process.h:64
int32_t getExitStatus() const
gets the return code from the exited child process (valid only after exec or waitForExitSync)
Definition: Process.h:213
Result exec(Span< const StringView > cmd, const StdOut &stdOut=StdOut::Inherit{}, const StdIn &stdIn=StdIn::Inherit{}, const StdErr &stdErr=StdErr::Inherit{})
Executes a child process with the given arguments, waiting (blocking) until it's fully finished.
Definition: Process.h:203
Result setWorkingDirectory(StringView processWorkingDirectory)
Sets the starting working directory of the process that will be launched / executed.
Result setEnvironment(StringView environmentVariable, StringView value)
Sets the environment variable for the newly spawned child process.
Result launch(Span< const StringView > cmd, const StdOut &stdOut=StdOut::Inherit{}, const StdIn &stdIn=StdIn::Inherit{}, const StdErr &stdErr=StdErr::Inherit{})
Launch child process with the given arguments.
Definition: Process.h:187
Options options
Options for the child process (hide console window etc.)
Definition: Process.h:175
void inheritParentEnvironmentVariables(bool inherit)
Controls if the newly spawned child process will inherit parent process environment variables.
Definition: Process.h:219
ProcessID processID
ID of the process (can be the same as handle on some OS)
Definition: Process.h:174
static bool isWindowsConsoleSubsystem()
Returns true only under Windows if executable is compiled with /SUBSYSTEM:Console
static size_t getNumberOfProcessors()
Returns number of (virtual) processors available.
ProcessDescriptor handle
Handle to the OS process.
Definition: Process.h:173
Result waitForExitSync()
Waits (blocking) for process to exit after launch. It can only be called if Process::launch succeeded...
Native os handle to a process identifier.
Definition: Process.h:26
An ascii string used as boolean result. SC_TRY macro forwards errors to caller.
Definition: Result.h:11
static constexpr Result Error(const char(&msg)[numChars])
Constructs an Error from a pointer to an ASCII string literal.
Definition: Result.h:23
String with compile time configurable inline storage (small string optimization)
Definition: SmallString.h:21
View over a contiguous sequence of items (pointer + size in elements).
Definition: Span.h:20
A non-modifiable owning string with associated encoding.
Definition: String.h:30
Non-owning view over a range of characters with UTF Encoding.
Definition: StringView.h:47
A contiguous sequence of heap allocated elements.
Definition: Vector.h:51