Sane C++ Libraries
C++ Platform Abstraction Libraries
SC::ProcessChain Struct Reference

Execute multiple child processes chaining input / output between them. More...

#include <Process.h>

Public Member Functions

Result pipe (Process &process, const Span< const StringView > cmd)
 Add a process to the chain, with given arguments. More...
 
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. More...
 
Result waitForExitSync ()
 Waits (blocking) for entire process chain to exit. More...
 
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) More...
 

Public Attributes

Process::Options options
 

Detailed Description

Execute multiple child processes chaining input / output between them.


Chains multiple child processes together, so that the output of a process becomes input of another (similar to what happens wit the pipe (|) operator on Posix shells).

SC::PipeDescriptor from File library is used to chain read / write endpoints of different processes together.

Example: Inherit stdout file descriptor

// Executes two processes piping output of process p1 to input of process p2.
// Then reads the output of the last process in the chain and check its correctness.
ProcessChain chain;
Process p1, p2;
// Print "Salve\nDoctori" on Windows and Posix and then grep for "Doc"
StringView expectedOutput;
switch (HostPlatform)
{
case Platform::Windows: {
expectedOutput = "Doctori\r\n";
SC_TEST_EXPECT(chain.pipe(p1, {"cmd", "/C", "echo", "Salve", "&", "echo", "Doctori"}));
SC_TEST_EXPECT(chain.pipe(p2, {"findstr", "Doc"}));
}
break;
default: { // Posix
expectedOutput = "Doctori\n";
SC_TEST_EXPECT(chain.pipe(p1, {"echo", "Salve\nDoctori"}));
SC_TEST_EXPECT(chain.pipe(p2, {"grep", "Doc"}));
}
break;
}
String output;
SC_TEST_EXPECT(chain.exec(output));
SC_TEST_EXPECT(output == expectedOutput);
#define SC_TEST_EXPECT(e)
Records a test expectation (eventually aborting or breaking o n failed test)
Definition: Testing.h:113

Example: Read stderr and stdout into a string

// Executes two processes piping output of process p1 to input of process p2.
// Reads p2 stdout and stderr into a pair of Strings.
ProcessChain chain;
Process p1;
StringView expectedOutput;
switch (HostPlatform)
{
case Platform::Windows: {
expectedOutput = "C:\\Windows\\System32\\where.exe\r\n";
SC_TEST_EXPECT(chain.pipe(p1, {"where", "where.exe"}));
}
break;
default: { // Posix
expectedOutput = "DOCTORI\n";
SC_TEST_EXPECT(chain.pipe(p1, {"echo", "DOCTORI"}));
}
break;
}
String stdOut(StringEncoding::Ascii);
String stdErr(StringEncoding::Ascii);
SC_TEST_EXPECT(chain.exec(stdOut, Process::StdIn::Inherit(), stdErr));
SC_TEST_EXPECT(stdOut == expectedOutput);
SC_TEST_EXPECT(stdErr.isEmpty());
@ Ascii
Encoding is ASCII.

Example: Read standard output into a string using a Pipe

// Chain two processes and read the last stdout into a String (using a pipe)
ProcessChain chain;
String output(StringEncoding::Ascii);
Process p1, p2;
StringView expectedOutput;
switch (HostPlatform)
{
case Platform::Windows: {
expectedOutput = "WHERE [/R dir] [/Q] [/F] [/T] pattern...\r\n";
SC_TEST_EXPECT(chain.pipe(p1, {"where", "/?"}));
SC_TEST_EXPECT(chain.pipe(p2, {"findstr", "dir]"}));
}
break;
default: { // Posix
expectedOutput = "sbin\n";
SC_TEST_EXPECT(chain.pipe(p1, {"ls", "/"}));
SC_TEST_EXPECT(chain.pipe(p2, {"grep", "sbin"}));
}
break;
}
PipeDescriptor outputPipe;
SC_TEST_EXPECT(chain.launch(outputPipe));
SC_TEST_EXPECT(outputPipe.readPipe.readUntilEOF(output));
SC_TEST_EXPECT(chain.waitForExitSync());
SC_TEST_EXPECT(output == expectedOutput);

Member Function Documentation

◆ exec()

Result SC::ProcessChain::exec ( const Process::StdOut stdOut = Process::StdOut::Inherit{},
const Process::StdIn stdIn = Process::StdIn::Inherit{},
const Process::StdErr stdErr = Process::StdErr::Inherit{} 
)
inline

Launch the entire chain of processes and waits for the results (calling ProcessChain::waitForExitSync)

Returns
Valid result if given process chain has been launched and waited for exit successfully

◆ launch()

Result SC::ProcessChain::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.

Reading from pipes can be done after launching. You can then call ProcessChain::waitForExitSync to block until the child process is fully finished.

Returns
Valid result if given process chain has been launched successfully

◆ pipe()

Result SC::ProcessChain::pipe ( Process process,
const Span< const StringView cmd 
)

Add a process to the chain, with given arguments.

Parameters
processA non-launched Process object (allocated by caller, must be alive until waitForExitSync)
cmdPath to executable and eventual args for this process
Returns
Invalid result if given process failed to create pipes for I/O redirection

◆ waitForExitSync()

Result SC::ProcessChain::waitForExitSync ( )

Waits (blocking) for entire process chain to exit.

Can be called only after ProcessChain::launch.

Returns
Valid result if the given process chain exited normally without aborting

The documentation for this struct was generated from the following file: