#pragma once #include #include #include #include #include #include #include #include #include #include // Forward declare `reproc_t` so we don't have to include reproc.h in the // header. struct reproc_t; /*! The `reproc` namespace wraps all reproc++ declarations. `process` wraps reproc's API inside a C++ class. To avoid exposing reproc's API when using reproc++ all structs, enums and constants of reproc have a replacement in reproc++. Only differences in behaviour compared to reproc are documented. Refer to reproc.h and the examples for general information on how to use reproc. */ namespace reproc { /*! Conversion from reproc `errno` constants to `std::errc` constants: https://en.cppreference.com/w/cpp/error/errc */ using error = std::errc; namespace signal { REPROCXX_EXPORT extern const int kill; REPROCXX_EXPORT extern const int terminate; } /*! Timeout values are passed as `reproc::milliseconds` instead of `int` in reproc++. */ using milliseconds = std::chrono::duration; REPROCXX_EXPORT extern const milliseconds infinite; REPROCXX_EXPORT extern const milliseconds deadline; enum class stop { noop, wait, terminate, kill, }; struct stop_action { stop action; milliseconds timeout; }; struct stop_actions { stop_action first; stop_action second; stop_action third; }; #if defined(_WIN32) using handle = void *; #else using handle = int; #endif struct redirect { enum type { default_, // Unfortunately, both `default` and `auto` are keywords. pipe, parent, discard, // stdout would conflict with a macro on Windows. stdout_, // Unfortunately, class members and nested enum members can't have the same // name. handle_, file_, path_, }; enum type type; reproc::handle handle; FILE *file; const char *path; }; struct options { struct { env::type behavior; /*! Implicitly converts from any STL container of string pairs to the environment format expected by `reproc_start`. */ class env extra; } env = {}; const char *working_directory = nullptr; struct { redirect in; redirect out; redirect err; bool parent; bool discard; FILE *file; const char *path; } redirect = {}; struct stop_actions stop = {}; reproc::milliseconds timeout = reproc::milliseconds(0); reproc::milliseconds deadline = reproc::milliseconds(0); /*! Implicitly converts from string literals to the pointer size pair expected by `reproc_start`. */ class input input; bool nonblocking = false; /*! Make a shallow copy of `options`. */ static options clone(const options &other) { struct options clone; clone.env.behavior = other.env.behavior; // Make sure we make a shallow copy of `environment`. clone.env.extra = other.env.extra.data(); clone.working_directory = other.working_directory; clone.redirect = other.redirect; clone.stop = other.stop; clone.timeout = other.timeout; clone.deadline = other.deadline; clone.input = other.input; return clone; } }; enum class stream { in, out, err, }; class process; namespace event { enum { in = 1 << 0, out = 1 << 1, err = 1 << 2, exit = 1 << 3, deadline = 1 << 4, }; struct source { class process &process; int interests; int events; }; } REPROCXX_EXPORT std::error_code poll(event::source *sources, size_t num_sources, milliseconds timeout = infinite); /*! Improves on reproc's API by adding RAII and changing the API of some functions to be more idiomatic C++. */ class process { public: REPROCXX_EXPORT process(); REPROCXX_EXPORT ~process() noexcept; // Enforce unique ownership of child processes. REPROCXX_EXPORT process(process &&other) noexcept; REPROCXX_EXPORT process &operator=(process &&other) noexcept; /*! `reproc_start` but implicitly converts from STL containers to the arguments format expected by `reproc_start`. */ REPROCXX_EXPORT std::error_code start(const arguments &arguments, const options &options = {}) noexcept; REPROCXX_EXPORT std::pair pid() noexcept; /*! Sets the `fork` option in `reproc_options` and calls `start`. Returns `true` in the child process and `false` in the parent process. */ REPROCXX_EXPORT std::pair fork(const options &options = {}) noexcept; /*! Shorthand for `reproc::poll` that only polls this process. Returns a pair of (events, error). */ REPROCXX_EXPORT std::pair poll(int interests, milliseconds timeout = infinite); /*! `reproc_read` but returns a pair of (bytes read, error). */ REPROCXX_EXPORT std::pair read(stream stream, uint8_t *buffer, size_t size) noexcept; /*! reproc_write` but returns a pair of (bytes_written, error). */ REPROCXX_EXPORT std::pair write(const uint8_t *buffer, size_t size) noexcept; REPROCXX_EXPORT std::error_code close(stream stream) noexcept; /*! `reproc_wait` but returns a pair of (status, error). */ REPROCXX_EXPORT std::pair wait(milliseconds timeout) noexcept; REPROCXX_EXPORT std::error_code terminate() noexcept; REPROCXX_EXPORT std::error_code kill() noexcept; /*! `reproc_stop` but returns a pair of (status, error). */ REPROCXX_EXPORT std::pair stop(stop_actions stop) noexcept; private: REPROCXX_EXPORT friend std::error_code poll(event::source *sources, size_t num_sources, milliseconds timeout); std::unique_ptr impl_; }; }