== `environment.hpp` [#environment] === `environment` The `environment` header provides facilities to manipulate the current environment and set it for new processes. An environment is a a `range` of `T` fulfilling these requirements: For `T value` * - std::get<0>(value) must return a type comparable to `key_view`. * - std::get<1>(value) must return a type convertible to `value_view`. [source,cpp] ---- // Namespace for information and functions regarding the calling process. namespace environment { // A char traits type that reflects the OS rules for string representing environment keys. /* Can be an alias of std::char_traits. May only be defined for `char` and `wchar_t`. * * Windows treats keys as case-insensitive yet preserving. The char traits are made to reflect * that behaviour. */ template using key_char_traits = implementation_defined ; // A char traits type that reflects the OS rules for string representing environment values. /* Can be an alias of std::char_traits. May only be defined for `char` and `wchar_t`. */ template using value_char_traits = implementation_defined ; // The character type used by the environment. Either `char` or `wchar_t`. using char_type = implementation_defined ; // The equal character in an environment string used to separate key and value. constexpr char_type equality_sign = implementation_defined; // The delimiter in environemtn lists. Commonly used by the `PATH` variable. constexpr char_type delimiter = implementation_defined; // The native handle of an environment. Note that this can be an owning pointer and is generally not thread safe. using native_handle = implementation_defined; // A forward iterator over string_view used by a value or value_view to iterator through environments that are lists. struct value_iterator; // A view type for a key of an environment struct key_view { using value_type = char_type; using traits_type = key_char_traits; using string_view_type = basic_string_view; using string_type = std::basic_string>; key_view() noexcept = default; key_view( const key_view& p ) = default; key_view( key_view&& p ) noexcept = default; template key_view( const Source& source ); key_view( const char_type * p); key_view( char_type * p); ~key_view() = default; key_view& operator=( const key_view& p ) = default; key_view& operator=( key_view&& p ) noexcept = default; key_view& operator=( string_view_type source ); void swap( key_view& other ) noexcept; string_view_type native() const noexcept; operator string_view_type() const; int compare( const key_view& p ) const noexcept; int compare( string_view_type str ) const; int compare( const value_type* s ) const; template< class CharT, class Traits = std::char_traits, class Alloc = std::allocator > std::basic_string basic_string( const Alloc& alloc = Alloc()) const; std::string string() const; std::wstring wstring() const; string_type native_string() const; friend bool operator==(key_view l, key_view r); friend bool operator!=(key_view l, key_view r); friend bool operator<=(key_view l, key_view r); friend bool operator>=(key_view l, key_view r); friend bool operator< (key_view l, key_view r); friend bool operator> (key_view l, key_view r); bool empty() const; template< class CharT, class Traits > friend std::basic_ostream& operator<<( std::basic_ostream& os, const key_view& p ); template< class CharT, class Traits > friend std::basic_istream& operator>>( std::basic_istream& is, key_view& p ); const value_type * data() const; std::size_t size() const; }; // A view for a value in an environment struct value_view { using value_type = char_type; using string_view_type = basic_cstring_ref>; using string_type = std::basic_string>; using traits_type = value_char_traits; value_view() noexcept = default; value_view( const value_view& p ) = default; value_view( value_view&& p ) noexcept = default; template value_view( const Source& source ); value_view( const char_type * p); value_view( char_type * p); ~value_view() = default; value_view& operator=( const value_view& p ) = default; value_view& operator=( value_view&& p ) noexcept = default; value_view& operator=( string_view_type source ); void swap( value_view& other ) noexcept; string_view_type native() const noexcept ; operator string_view_type() const; operator typename string_view_type::string_view_type() const; int compare( const value_view& p ) const noexcept; int compare( string_view_type str ) const; int compare( const value_type* s ) const; template< class CharT, class Traits = std::char_traits, class Alloc = std::allocator > std::basic_string basic_string( const Alloc& alloc = Alloc() ) const; std::string string() const; std::wstring wstring() const; string_type native_string() const; bool empty() const; friend bool operator==(value_view l, value_view r); friend bool operator!=(value_view l, value_view r); friend bool operator<=(value_view l, value_view r); friend bool operator>=(value_view l, value_view r); friend bool operator< (value_view l, value_view r); friend bool operator> (value_view l, value_view r); template< class CharT, class Traits > friend std::basic_ostream& operator<<( std::basic_ostream& os, const value_view& p ); template< class CharT, class Traits > friend std::basic_istream& operator>>( std::basic_istream& is, value_view& p ); value_iterator begin() const; value_iterator end() const; const char_type * c_str(); const value_type * data() const; std::size_t size() const; }; // A view for a key value pair in an environment struct key_value_pair_view { using value_type = char_type; using string_type = std::basic_string; using string_view_type = basic_cstring_ref; using traits_type = std::char_traits; key_value_pair_view() noexcept = default; key_value_pair_view( const key_value_pair_view& p ) = default; key_value_pair_view( key_value_pair_view&& p ) noexcept = default; template::value>::type> key_value_pair_view( const Source& source ); key_value_pair_view( const char_type * p); key_value_pair_view( char_type * p); ~key_value_pair_view() = default; key_value_pair_view& operator=( const key_value_pair_view& p ) = default; key_value_pair_view& operator=( key_value_pair_view&& p ) noexcept = default; void swap( key_value_pair_view& other ) noexcept; string_view_type native() const noexcept; operator string_view_type() const; operator typename string_view_type::string_view_type() const; int compare( key_value_pair_view p ) const noexcept; int compare( const string_type& str ) const; int compare( string_view_type str ) const; int compare( const value_type* s ) const; template< class CharT, class Traits = std::char_traits, class Alloc = std::allocator > std::basic_string basic_string( const Alloc& alloc = Alloc()) const; std::string string() const; std::wstring wstring() const; string_type native_string() const; bool empty() const; key_view key() const; value_view value() const; friend bool operator==(key_value_pair_view l, key_value_pair_view r); friend bool operator!=(key_value_pair_view l, key_value_pair_view r); friend bool operator<=(key_value_pair_view l, key_value_pair_view r); friend bool operator>=(key_value_pair_view l, key_value_pair_view r); friend bool operator< (key_value_pair_view l, key_value_pair_view r); friend bool operator> (key_value_pair_view l, key_value_pair_view r); template< class CharT, class Traits > friend std::basic_ostream& operator<<( std::basic_ostream& os, const key_value_pair_view& p ); template< class CharT, class Traits > friend std::basic_istream& operator>>( std::basic_istream& is, key_value_pair_view& p ); template inline auto get() const -> typename conditional::type; const value_type * c_str() const noexcept; const value_type * data() const; std::size_t size() const; }; // Allow tuple-likg getters & structured bindings. template<> key_view key_value_pair_view::get<0u>() const; template<> value_view key_value_pair_view::get<1u>() const; // A class representing a key within an environment. struct key { using value_type = char_type; using traits_type = key_char_traits; using string_type = std::basic_string; using string_view_type = basic_string_view; key(); key( const key& p ) = default; key( key&& p ) noexcept = default; key( const string_type& source ); key( string_type&& source ); key( const value_type * raw ); key( value_type * raw ); explicit key(key_view kv); template< class Source > key( const Source& source); key(const typename conditional::value, wchar_t, char>::type * raw); template< class InputIt > key( InputIt first, InputIt last); ~key() = default; key& operator=( const key& p ) = default; key& operator=( key&& p ); key& operator=( string_type&& source ); template< class Source > key& operator=( const Source& source ); key& assign( string_type&& source ); template< class Source > key& assign( const Source& source ); template< class InputIt > key& assign( InputIt first, InputIt last ); void clear(); void swap( key& other ) noexcept; const value_type* c_str() const noexcept; const string_type& native() const noexcept; string_view_type native_view() const noexcept; operator string_type() const; operator string_view_type() const; int compare( const key& p ) const noexcept; int compare( const string_type& str ) const; int compare( string_view_type str ) const; int compare( const value_type* s ) const; template< class CharT, class Traits = std::char_traits, class Alloc = std::allocator > std::basic_string basic_string( const Alloc& alloc = Alloc()) const; std::string string() const; std::wstring wstring() const; const string_type & native_string() const; bool empty() const; friend bool operator==(const key & l, const key & r); friend bool operator!=(const key & l, const key & r); friend bool operator<=(const key & l, const key & r); friend bool operator>=(const key & l, const key & r); friend bool operator< (const key & l, const key & r); friend bool operator> (const key & l, const key & r); template< class CharT, class Traits > friend std::basic_ostream& operator<<( std::basic_ostream& os, const key& p ); template< class CharT, class Traits > friend std::basic_istream& operator>>( std::basic_istream& is, key& p ); const value_type * data() const; std::size_t size() const; }; bool operator==(const value_view &, const value_view); bool operator!=(const value_view &, const value_view); bool operator<=(const value_view &, const value_view); bool operator< (const value_view &, const value_view); bool operator> (const value_view &, const value_view); bool operator>=(const value_view &, const value_view); struct value { using value_type = char_type; using traits_type = value_char_traits; using string_type = std::basic_string; using string_view_type = basic_cstring_ref; value(); value( const value& p ) = default; value( const string_type& source ); value( string_type&& source ); value( const value_type * raw ); value( value_type * raw ); explicit value(value_view kv); template< class Source > value( const Source& source ); value(const typename conditional::value, wchar_t, char>::type * raw); template< class InputIt > value( InputIt first, InputIt last); ~value() = default; value& operator=( const value& p ) = default; value& operator=( value&& p ); value& operator=( string_type&& source ); template< class Source > value& operator=( const Source& source ); value& assign( string_type&& source ); template< class Source > value& assign( const Source& source ); template< class InputIt > value& assign( InputIt first, InputIt last ); void push_back(const value & sv); void clear() {value_.clear();} void swap( value& other ) noexcept; const value_type* c_str() const noexcept; const string_type& native() const noexcept; string_view_type native_view() const noexcept; operator string_type() const; operator string_view_type() const; operator typename string_view_type::string_view_type() const; int compare( const value& p ) const noexcept; int compare( const string_type& str ) const; int compare( string_view_type str ) const; int compare( const value_type* s ) const; template< class CharT, class Traits = std::char_traits, class Alloc = std::allocator > std::basic_string basic_string( const Alloc& alloc = Alloc()) const; std::string string() const; std::wstring wstring() const; const string_type & native_string() const; bool empty() const; friend bool operator==(const value & l, const value & r); friend bool operator!=(const value & l, const value & r); friend bool operator<=(const value & l, const value & r); friend bool operator>=(const value & l, const value & r); friend bool operator< (const value & l, const value & r); friend bool operator> (const value & l, const value & r); template< class CharT, class Traits > friend std::basic_ostream& operator<<( std::basic_ostream& os, const value& p ); template< class CharT, class Traits > friend std::basic_istream& operator>>( std::basic_istream& is, value& p ); value_iterator begin() const; value_iterator end() const; const value_type * data() const; std::size_t size() const; }; bool operator==(const value_view &, const value_view); bool operator!=(const value_view &, const value_view); bool operator<=(const value_view &, const value_view); bool operator< (const value_view &, const value_view); bool operator> (const value_view &, const value_view); bool operator>=(const value_view &, const value_view); struct key_value_pair { using value_type = char_type; using traits_type = std::char_traits; using string_type = std::basic_string; using string_view_type = basic_cstring_ref; key_value_pair()l key_value_pair( const key_value_pair& p ) = default; key_value_pair( key_value_pair&& p ) noexcept = default; key_value_pair(key_view key, value_view value); key_value_pair(key_view key, std::initializer_list> values); key_value_pair( const string_type& source ); key_value_pair( string_type&& source ); key_value_pair( const value_type * raw ); key_value_pair( value_type * raw ); explicit key_value_pair(key_value_pair_view kv) : value_(kv.c_str()) {} template< class Source > key_value_pair( const Source& source); template< typename Key, typename Value > key_value_pair( const std::pair & kv); key_value_pair(const typename conditional::value, wchar_t, char>::type * raw); template< class InputIt , typename std::iterator_traits::iterator_category> key_value_pair( InputIt first, InputIt last ); ~key_value_pair() = default; key_value_pair& operator=( const key_value_pair& p ) = default; key_value_pair& operator=( key_value_pair&& p ); key_value_pair& operator=( string_type&& source ); template< class Source > key_value_pair& operator=( const Source& source ); key_value_pair& assign( string_type&& source ); template< class Source > key_value_pair& assign( const Source& source ); template< class InputIt > key_value_pair& assign( InputIt first, InputIt last ); void clear(); void swap( key_value_pair& other ) noexcept; const value_type* c_str() const noexcept; const string_type& native() const noexcept; string_view_type native_view() const noexcept; operator string_type() const; operator string_view_type() const; operator typename string_view_type::string_view_type() const; operator key_value_pair_view() const; int compare( const key_value_pair& p ) const noexcept; int compare( const string_type& str ) const; int compare( string_view_type str ) const; int compare( const value_type* s ) const; template< class CharT, class Traits = std::char_traits, class Alloc = std::allocator > std::basic_string basic_string( const Alloc& alloc = Alloc() ) const; std::string string() const {return basic_string();} std::wstring wstring() const {return basic_string();} const string_type & native_string() const; friend bool operator==(const key_value_pair & l, const key_value_pair & r); friend bool operator!=(const key_value_pair & l, const key_value_pair & r); friend bool operator<=(const key_value_pair & l, const key_value_pair & r); friend bool operator>=(const key_value_pair & l, const key_value_pair & r); friend bool operator< (const key_value_pair & l, const key_value_pair & r); friend bool operator> (const key_value_pair & l, const key_value_pair & r); bool empty() const; struct key_view key() const; struct value_view value() const; template< class CharT, class Traits > friend std::basic_ostream& operator<<( std::basic_ostream& os, const key_value_pair& p ); template< class CharT, class Traits > friend std::basic_istream& operator>>( std::basic_istream& is, key_value_pair& p ); const value_type * data() const; std::size_t size() const; template inline auto get() const -> typename conditional::type; }; bool operator==(const key_value_pair_view &, const key_value_pair_view); bool operator!=(const key_value_pair_view &, const key_value_pair_view); bool operator<=(const key_value_pair_view &, const key_value_pair_view); bool operator< (const key_value_pair_view &, const key_value_pair_view); bool operator> (const key_value_pair_view &, const key_value_pair_view); bool operator>=(const key_value_pair_view &, const key_value_pair_view); // Allow tuple-likg getters & structured bindings. template<> key_view key_value_pair::get<0u>() const; template<> value_view key_value_pair::get<1u>() const; // A view object for the current environment of this process. /* * The view might (windows) or might not (posix) be owning; * if it owns it will deallocate the on destruction, like a unique_ptr. * * Note that accessing the environment in this way is not thread-safe. * * @code * * void dump_my_env(current_view env = current()) * { * for (auto & [k, v] : env) * std::cout << k.string() << " = " << v.string() << std::endl; * } * * @endcode * * */ struct current_view { using native_handle_type = environment::native_handle_type; using value_type = key_value_pair_view; current_view() = default; current_view(current_view && nt) = default; native_handle_type native_handle() { return handle_.get(); } struct iterator { using value_type = key_value_pair_view; using difference_type = int; using reference = key_value_pair_view; using pointer = key_value_pair_view; using iterator_category = std::forward_iterator_tag; iterator() = default; iterator(const iterator & ) = default; iterator(const native_iterator &native_handle) : iterator_(native_handle) {} iterator & operator++() { iterator_ = detail::next(iterator_); return *this; } iterator operator++(int) { auto last = *this; iterator_ = detail::next(iterator_); return last; } key_value_pair_view operator*() const { return detail::dereference(iterator_); } friend bool operator==(const iterator & l, const iterator & r) {return l.iterator_ == r.iterator_;} friend bool operator!=(const iterator & l, const iterator & r) {return l.iterator_ != r.iterator_;} private: environment::native_iterator iterator_; }; iterator begin() const {return iterator(handle_.get());} iterator end() const {return iterator(detail::find_end(handle_.get()));} private: std::unique_ptr::type, detail::native_handle_deleter> handle_{environment::detail::load_native_handle()}; }; // Obtain a handle to the current environment inline current_view current() {return current_view();} // Find the home folder in an environment-like type. /* * @param env The environment to search. Defaults to the current environment of this process * * The environment type passed in must be a range with value T that fulfills the following requirements: * * For `T value` * * - std::get<0>(value) must return a type comparable to `key_view`. * - std::get<1>(value) must return a type convertible to filesystem::path. * * @return A filesystem::path to the home directory or an empty path if it cannot be found. * */ template inline filesystem::path home(Environment && env = current()); // Find the executable `name` in an environment-like type. template filesystem::path find_executable(BOOST_PROCESS_V2_NAMESPACE::filesystem::path name, Environment && env = current()); // Get an environment variable from the current process. value get(const key & k, error_code & ec); value get(const key & k); value get(basic_cstring_ref> k, error_code & ec); value get(basic_cstring_ref> k); value get(const char_type * c, error_code & ec); value get(const char_type * c); // Set an environment variable for the current process. void set(const key & k, value_view vw, error_code & ec); void set(const key & k, value_view vw); void set(basic_cstring_ref> k, value_view vw, error_code & ec); void set(basic_cstring_ref> k, value_view vw); void set(const char_type * k, value_view vw, error_code & ec); void set(const char_type * k, value_view vw); template void set(const key & k, const Char * vw, error_code & ec); template void set(const key & k, const Char * vw); template void set(basic_cstring_ref> k, const Char * vw, error_code & ec); template void set(basic_cstring_ref> k, const Char * vw); template void set(const char_type * k, const Char * vw, error_code & ec); template void set(const char_type * k, const Char * vw); // Remove an environment variable from the current process. void unset(const key & k, error_code & ec); void unset(const key & k); void unset(basic_cstring_ref> k, error_code & ec); void unset(basic_cstring_ref> k); void unset(const char_type * c, error_code & ec); void unset(const char_type * c); } ---- === `process_environment` In order to set the environment of a child process, `process_environment` can be used. [source, cpp] .This will set the environment in a subprocess: ---- process proc{executor, find_executable("printenv"), {"foo"}, process_environment{"foo=bar"}}; ---- The environment initializer will persist it's state, so that it can be used multiple times. Do however note the the Operating System is allowed to modify the internal state. [source,cpp] ---- auto exe = find_executable("printenv"); process_environment env = {"FOO=BAR", "BAR=FOO"}; process proc1(executor, exe, {"FOO"}, env); process proc2(executor, exe, {"BAR"}, env); ----