-
Notifications
You must be signed in to change notification settings - Fork 7
process.hpp
Not Enough Standards' process management utilities are defined in header <nes/process.hpp>
This header contains everything you need in order to create and manage child processes, and also get and set informations of the current process.
The class nes::process
is used to create child processes.
The namespace nes::this_process
is used to get informations or modify the current process.
nes::process
is the main class of this header. On construction, this class create a child process that can be detached, waited or killed. The behaviour and interface of this class is similar to std::thread
, so if you are used to use std::thread
you won't get any trouble using nes::process
.
nes::process::id
is a trivially copyable type that serves as a unique identifier of a process within the system.
nes::process_options
is a bitmask type that specifies additional options for nes::process
.
nes::this_process
namespace can be used to get the current process id, the current process working directory, and to modify the current process working directory.
Header | Notes |
---|---|
<nes/pipe.hpp> (optional) |
If the file <nes/pipe.hpp> is not present then you can not redirect child processes' standard streams. |
#if __has_include("pipe.hpp")
#define NES_PROCESS_PIPE_EXTENSION
#include "pipe.hpp"
#endif
namespace nes
{
enum class process_options : std::uint32_t
{
none = 0x00,
#ifdef NES_PROCESS_PIPE_EXTENSION
grab_stdout = 0x10,
grab_stderr = 0x20,
grab_stdin = 0x40
#endif
};
constexpr process_options operator&(process_options left, process_options right) noexcept;
constexpr process_options& operator&=(process_options& left, process_options right) noexcept;
constexpr process_options operator|(process_options left, process_options right) noexcept;
constexpr process_options& operator|=(process_options& left, process_options right) noexcept;
constexpr process_options operator^(process_options left, process_options right) noexcept;
constexpr process_options& operator^=(process_options& left, process_options right) noexcept;
constexpr process_options operator~(process_options value) noexcept;
class process
{
public:
using native_handle_type = /*implementation-defined*/;
using return_code_type = /*implementation-defined*/;
using id = /*implementation-defined*/;
public:
constexpr process() noexcept = default;
explicit process(const std::string& path, const std::string& working_directory);
explicit process(const std::string& path, process_options options);
explicit process(const std::string& path, const std::vector<std::string>& args, process_options options);
explicit process(const std::string& path, const std::string& working_directory, process_options options);
explicit process(const std::string& path, std::vector<std::string> args = std::vector<std::string>{}, const std::string& working_directory = std::string{}, process_options options = process_options{});
~process();
process(const process&) = delete;
process& operator=(const process&) = delete;
process(process&& other) noexcept;
process& operator=(process&& other) noexcept;
void join();
bool joinable() const noexcept;
bool active() const;
void detach();
bool kill();
return_code_type return_code() const noexcept;
native_handle_type native_handle() const noexcept;
id get_id() const noexcept;
#ifdef NES_PROCESS_PIPE_EXTENSION
pipe_ostream& stdin_stream() noexcept;
pipe_istream& stdout_stream() noexcept;
pipe_istream& stderr_stream() noexcept;
#endif
};
constexpr bool operator==(process::id lhs, process::id rhs) noexcept;
constexpr bool operator!=(process::id lhs, process::id rhs) noexcept;
constexpr bool operator<(process::id lhs, process::id rhs) noexcept;
constexpr bool operator<=(process::id lhs, process::id rhs) noexcept;
constexpr bool operator>(process::id lhs, process::id rhs) noexcept;
constexpr bool operator>=(process::id lhs, process::id rhs) noexcept;
namespace this_process
{
inline process::id get_id() noexcept;
inline std::string working_directory();
inline bool change_working_directory(const std::string& path);
}
}
template<typename CharT, typename Traits>
std::basic_ostream<CharT, Traits>& operator<<(std::basic_ostream<CharT, Traits>& os, nes::process::id id);
namespace std
{
template<>
struct hash<nes::process::id>;
}
Here is an example in which we create a child process.
main.cpp
is the main file of the parent process.
other.cpp
is the main file of the child process.
Output
is the standard output of the parent process.
#include <iostream>
#include <nes/process.hpp>
int main()
{
//nes::this_process namespace can be used to modify current process or get informations about it.
std::cout << "Current process has id " << nes::this_process::get_id() << std::endl;
std::cout << "Its current directory is \"" << nes::this_process::working_directory() << "\"" << std::endl;
//Create a child process
nes::process other{"other_process", {"Hey!", "\\\"12\"\"\\\\", "\\42\\", "It's \"me\"!"}, nes::process_options::grab_stdout};
//Read the entire standard output of the child process. (nes::process_options::grab_stdout must be specified on process creation)
std::cout << other.stdout_stream().rdbuf() << std::endl;
//As a std::thread, a nes::process must be joined if it is not detached.
if(other.joinable())
other.join();
//Once joined, we can check its return code.
std::cout << "Other process ended with code: " << other.return_code() << std::endl;
}
#include <iostream>
#include <nes/process.hpp>
int main(int argc, char** argv)
{
//Display some informations about this process
std::cout << "Hello world! I'm Other!\n";
std::cout << "You gaved me " << argc << " arguments:";
for(int i{}; i < argc; ++i)
std::cout << "[" << argv[i] << "] ";
std::cout << '\n';
std::cout << "My working directory is \"" << nes::this_process::working_directory() << "\"" << std::endl;
}
Current process has id 3612
Its current directory is "/..."
Hello world! I'm Other!
You gaved me 5 arguments:[not_enough_standards_other.exe] [Hey!] [\"12""\\\] [\42\] [It's "me"!]
My working directory is "/..."
Other process ended with code: 0