| // Copyright (c) 2016 Klemens D. Morgenstern |
| // |
| // Distributed under the Boost Software License, Version 1.0. (See accompanying |
| // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) |
| |
| |
| #ifndef BOOST_PROCESS_ENVIRONMENT_HPP_ |
| #define BOOST_PROCESS_ENVIRONMENT_HPP_ |
| |
| #include <boost/process/detail/config.hpp> |
| #include <boost/algorithm/string/split.hpp> |
| #include <boost/algorithm/string/case_conv.hpp> |
| #include <boost/iterator/transform_iterator.hpp> |
| #include <boost/filesystem/path.hpp> |
| |
| #if defined(BOOST_POSIX_API) |
| #include <boost/process/detail/posix/environment.hpp> |
| #elif defined(BOOST_WINDOWS_API) |
| #include <boost/process/detail/windows/environment.hpp> |
| #endif |
| |
| namespace boost { namespace process { |
| |
| namespace detail { |
| |
| template<typename Char, typename Environment> |
| struct const_entry |
| { |
| using value_type = Char ; |
| using pointer = const value_type * ; |
| using string_type = std::basic_string<value_type> ; |
| using range = boost::iterator_range<pointer> ; |
| using environment_t = Environment ; |
| |
| std::vector<string_type> to_vector() const |
| { |
| if (_data == nullptr) |
| return std::vector<string_type>(); |
| std::vector<string_type> data; |
| auto str = string_type(_data); |
| struct splitter |
| { |
| bool operator()(wchar_t w) const {return w == api::env_seperator<wchar_t>();} |
| bool operator()(char c) const {return c == api::env_seperator<char> ();} |
| } s; |
| boost::split(data, _data, s); |
| return data; |
| } |
| string_type to_string() const |
| { |
| if (_data != nullptr) |
| return string_type(_data); |
| else |
| return string_type(); |
| } |
| string_type get_name() const {return string_type(_name.begin(), _name.end());} |
| explicit const_entry(string_type&& name, pointer data, environment_t & env_) : |
| _name(std::move(name)), _data(data), _env(&env_) {} |
| |
| explicit const_entry(string_type &&name, environment_t & env) : |
| _name(std::move(name)), _data(nullptr), _env(&env) {} |
| const_entry(const const_entry&) = default; |
| const_entry& operator=(const const_entry&) = default; |
| |
| void reload() |
| { |
| auto p = _env->find(_name); |
| if (p == _env->end()) |
| _data = nullptr; |
| else |
| _data = p->_data; |
| this->_env->reload(); |
| |
| } |
| bool empty() const |
| { |
| return _data == nullptr; |
| } |
| protected: |
| string_type _name; |
| pointer _data; |
| environment_t * _env; |
| }; |
| |
| template<typename Char, typename Environment> |
| struct entry : const_entry<Char, Environment> |
| { |
| using father = const_entry<Char, Environment>; |
| using value_type = typename father::value_type; |
| using string_type = typename father::string_type; |
| using pointer = typename father::pointer; |
| using environment_t = typename father::environment_t; |
| |
| explicit entry(string_type&& name, pointer data, environment_t & env) : |
| father(std::move(name), data, env) {} |
| |
| explicit entry(string_type &&name, environment_t & env_) : |
| father(std::move(name), env_) {} |
| |
| entry(const entry&) = default; |
| entry& operator=(const entry&) = default; |
| |
| void assign(const string_type &value) |
| { |
| this->_env->set(this->_name, value); |
| this->reload(); |
| } |
| void assign(const std::vector<string_type> &value) |
| { |
| string_type data; |
| for (auto &v : value) |
| { |
| if (&v != &value.front()) |
| data += api::env_seperator<value_type>(); |
| data += v; |
| } |
| this->_env->set(this->_name, data); |
| this->reload(); |
| |
| } |
| void assign(const std::initializer_list<string_type> &value) |
| { |
| string_type data; |
| for (auto &v : value) |
| { |
| if (&v != &*value.begin()) |
| data += api::env_seperator<value_type>(); |
| data += v; |
| } |
| this->_env->set(this->_name, data); |
| this->reload(); |
| |
| } |
| void append(const string_type &value) |
| { |
| if (this->_data == nullptr) |
| this->_env->set(this->_name, value); |
| else |
| { |
| string_type st = this->_data; |
| this->_env->set(this->_name, st + api::env_seperator<value_type>() + value); |
| } |
| |
| |
| this->reload(); |
| |
| } |
| void clear() |
| { |
| this->_env->reset(this->_name); |
| this->_env->reload(); |
| this->_data = nullptr; |
| } |
| entry &operator=(const string_type & value) |
| { |
| assign(value); |
| return *this; |
| } |
| entry &operator=(const std::vector<string_type> & value) |
| { |
| assign(value); |
| return *this; |
| } |
| entry &operator=(const std::initializer_list<string_type> & value) |
| { |
| assign(value); |
| return *this; |
| } |
| entry &operator+=(const string_type & value) |
| { |
| append(value); |
| return *this; |
| } |
| |
| }; |
| |
| |
| |
| template<typename Char, typename Environment> |
| struct make_entry |
| { |
| |
| make_entry(const make_entry&) = default; |
| make_entry& operator=(const make_entry&) = default; |
| |
| Environment *env; |
| make_entry(Environment & env) : env(&env) {}; |
| entry<Char, Environment> operator()(const Char* data) const |
| { |
| auto p = data; |
| while ((*p != equal_sign<Char>()) && (*p != null_char<Char>())) |
| p++; |
| auto name = std::basic_string<Char>(data, p); |
| p++; //go behind equal sign |
| |
| return entry<Char, Environment>(std::move(name), p, *env); |
| } |
| }; |
| |
| template<typename Char, typename Environment> |
| struct make_const_entry |
| { |
| |
| make_const_entry(const make_const_entry&) = default; |
| make_const_entry& operator=(const make_const_entry&) = default; |
| |
| Environment *env; |
| make_const_entry(Environment & env) : env(&env) {}; |
| const_entry<Char, Environment> operator()(const Char* data) const |
| { |
| auto p = data; |
| while ((*p != equal_sign<Char>()) && (*p != null_char<Char>())) |
| p++; |
| auto name = std::basic_string<Char>(data, p); |
| p++; //go behind equal sign |
| |
| return const_entry<Char, Environment>(std::move(name), p, *env); |
| } |
| }; |
| |
| } |
| |
| #if !defined (BOOST_PROCESS_DOXYGEN) |
| |
| template<typename Char, template <class> class Implementation = detail::api::basic_environment_impl> |
| class basic_environment_impl : public Implementation<Char> |
| { |
| Char** _get_end() const |
| { |
| auto p = this->_env_impl; |
| while (*p != nullptr) |
| p++; |
| |
| return p; |
| } |
| public: |
| using string_type = std::basic_string<Char>; |
| using implementation_type = Implementation<Char>; |
| using base_type = basic_environment_impl<Char, Implementation>; |
| using entry_maker = detail::make_entry<Char, base_type>; |
| using entry_type = detail::entry <Char, base_type>; |
| using const_entry_type = detail::const_entry <Char, const base_type>; |
| using const_entry_maker = detail::make_const_entry<Char, const base_type>; |
| |
| friend entry_type; |
| friend const_entry_type; |
| |
| using iterator = boost::transform_iterator< entry_maker, Char**, entry_type, entry_type>; |
| using const_iterator = boost::transform_iterator<const_entry_maker, Char**, const_entry_type, const_entry_type>; |
| using size_type = std::size_t; |
| |
| iterator begin() {return iterator(this->_env_impl, entry_maker(*this));} |
| const_iterator begin() const {return const_iterator(this->_env_impl, const_entry_maker(*this));} |
| const_iterator cbegin() const {return const_iterator(this->_env_impl, const_entry_maker(*this));} |
| |
| iterator end() {return iterator(_get_end(), entry_maker(*this));} |
| const_iterator end() const {return const_iterator(_get_end(), const_entry_maker(*this));} |
| const_iterator cend() const {return const_iterator(_get_end(), const_entry_maker(*this));} |
| |
| iterator find( const string_type& key ) |
| { |
| auto p = this->_env_impl; |
| auto st1 = key + ::boost::process::detail::equal_sign<Char>(); |
| while (*p != nullptr) |
| { |
| if (std::equal(st1.begin(), st1.end(), *p)) |
| break; |
| p++; |
| } |
| return iterator(p, entry_maker(*this)); |
| } |
| const_iterator find( const string_type& key ) const |
| { |
| auto p = this->_env_impl; |
| auto st1 = key + ::boost::process::detail::equal_sign<Char>(); |
| while (*p != nullptr) |
| { |
| if (std::equal(st1.begin(), st1.end(), *p)) |
| break; |
| p++; |
| } |
| return const_iterator(p, const_entry_maker(*this)); |
| } |
| |
| std::size_t count(const string_type & st) const |
| { |
| auto p = this->_env_impl; |
| auto st1 = st + ::boost::process::detail::equal_sign<Char>(); |
| while (*p != nullptr) |
| { |
| if (std::equal(st1.begin(), st1.end(), *p)) |
| return 1u; |
| p++; |
| } |
| return 0u; |
| } |
| void erase(const string_type & id) |
| { |
| implementation_type::reset(id); |
| this->reload(); |
| } |
| std::pair<iterator,bool> emplace(const string_type & id, const string_type & value) |
| { |
| auto f = find(id); |
| if (f == end()) |
| { |
| implementation_type::set(id, value); |
| this->reload(); |
| return std::pair<iterator, bool>(find(id), true); |
| } |
| else |
| return std::pair<iterator, bool>(f, false); |
| } |
| using implementation_type::implementation_type; |
| using implementation_type::operator=; |
| using native_handle_type = typename implementation_type::native_handle_type; |
| using implementation_type::native_handle; |
| //copy ctor if impl is copy-constructible |
| bool empty() |
| { |
| return *this->_env_impl == nullptr; |
| } |
| std::size_t size() const |
| { |
| return (_get_end() - this->_env_impl); |
| } |
| void clear() |
| { |
| std::vector<string_type> names; |
| names.resize(size()); |
| std::transform(cbegin(), cend(), names.begin(), [](const const_entry_type & cet){return cet.get_name();}); |
| |
| for (auto & nm : names) |
| implementation_type::reset(nm); |
| |
| this->reload(); |
| } |
| |
| entry_type at( const string_type& key ) |
| { |
| auto f = find(key); |
| if (f== end()) |
| throw std::out_of_range(key + " not found"); |
| return *f; |
| } |
| const_entry_type at( const string_type& key ) const |
| { |
| auto f = find(key); |
| if (f== end()) |
| throw std::out_of_range(key + " not found"); |
| return *f; |
| } |
| entry_type operator[](const string_type & key) |
| { |
| auto p = find(key); |
| if (p != end()) |
| return *p; |
| |
| return entry_type(string_type(key), *this); |
| } |
| }; |
| #endif |
| |
| #if defined(BOOST_PROCESS_DOXYGEN) |
| /**Template representation of environments. It takes a character type (`char` or `wchar_t`) |
| * as template parameter to implement the environment |
| */ |
| template<typename Char> |
| class basic_environment |
| { |
| |
| public: |
| typedef std::basic_string<Char> string_type; |
| typedef boost::transform_iterator< entry_maker, Char**> iterator ; |
| typedef boost::transform_iterator<const_entry_maker, Char**> const_iterator ; |
| typedef std::size_t size_type ; |
| |
| iterator begin() ; ///<Returns an iterator to the beginning |
| const_iterator begin() const ; ///<Returns an iterator to the beginning |
| const_iterator cbegin() const ; ///<Returns an iterator to the beginning |
| |
| iterator end() ; ///<Returns an iterator to the end |
| const_iterator end() const; ///<Returns an iterator to the end |
| const_iterator cend() const; ///<Returns an iterator to the end |
| |
| iterator find( const string_type& key ); ///<Find a variable by its name |
| const_iterator find( const string_type& key ) const; ///<Find a variable by its name |
| |
| std::size_t count(const string_type & st) const; ///<Number of variables |
| void erase(const string_type & id); ///<Erase variable by id. |
| ///Emplace an environment variable. |
| std::pair<iterator,bool> emplace(const string_type & id, const string_type & value); |
| |
| ///Default constructor |
| basic_environment(); |
| ///Copy constructor. |
| basic_environment(const basic_environment & ); |
| ///Move constructor. |
| basic_environment(basic_environment && ); |
| |
| ///Copy assignment. |
| basic_environment& operator=(const basic_environment & ); |
| ///Move assignment. |
| basic_environment& operator=(basic_environment && ); |
| |
| typedef typename detail::implementation_type::native_handle_type native_handle; |
| |
| ///Check if environment has entries. |
| bool empty(); |
| ///Get the number of variables. |
| std::size_t size() const; |
| ///Clear the environment. @attention Use with care, passed environment cannot be empty. |
| void clear(); |
| ///Get the entry with the key. Throws if it does not exist. |
| entry_type at( const string_type& key ); |
| ///Get the entry with the key. Throws if it does not exist. |
| const_entry_type at( const string_type& key ) const; |
| ///Get the entry with the given key. It creates the entry if it doesn't exist. |
| entry_type operator[](const string_type & key); |
| |
| /**Proxy class used for read access to members by [] or .at() |
| * @attention Holds a reference to the environment it was created from. |
| */ |
| template<typename Char, typename Environment> |
| struct const_entry_type |
| { |
| typedef Char value_type; |
| typedef const value_type * pointer; |
| typedef std::basic_string<value_type> string_type; |
| typedef boost::iterator_range<pointer> range; |
| typedef Environment environment_t; |
| |
| ///Split the entry by ";" or ":" and return it as a vector. Used by PATH. |
| std::vector<string_type> to_vector() const |
| ///Get the value as string. |
| string_type to_string() const |
| ///Get the name of this entry. |
| string_type get_name() const {return string_type(_name.begin(), _name.end());} |
| ///Copy Constructor |
| const_entry(const const_entry&) = default; |
| ///Move Constructor |
| const_entry& operator=(const const_entry&) = default; |
| ///Check if the entry is empty. |
| bool empty() const; |
| }; |
| |
| /**Proxy class used for read and write access to members by [] or .at() |
| * @attention Holds a reference to the environment it was created from. |
| */ |
| template<typename Char, typename Environment> |
| struct entry_type |
| { |
| |
| typedef Char value_type; |
| typedef const value_type * pointer; |
| typedef std::basic_string<value_type> string_type; |
| typedef boost::iterator_range<pointer> range; |
| typedef Environment environment_t; |
| |
| ///Split the entry by ";" or ":" and return it as a vector. Used by PATH. |
| std::vector<string_type> to_vector() const |
| ///Get the value as string. |
| string_type to_string() const |
| ///Get the name of this entry. |
| string_type get_name() const {return string_type(_name.begin(), _name.end());} |
| ///Copy Constructor |
| entry(const entry&) = default; |
| ///Move Constructor |
| entry& operator=(const entry&) = default; |
| ///Check if the entry is empty. |
| bool empty() const; |
| |
| ///Assign a string to the value |
| void assign(const string_type &value); |
| ///Assign a set of strings to the entry; they will be separated by ';' or ':'. |
| void assign(const std::vector<string_type> &value); |
| ///Append a string to the end of the entry, it will separated by ';' or ':'. |
| void append(const string_type &value); |
| ///Reset the value |
| void clear(); |
| ///Assign a string to the entry. |
| entry &operator=(const string_type & value); |
| ///Assign a set of strings to the entry; they will be separated by ';' or ':'. |
| entry &operator=(const std::vector<string_type> & value); |
| ///Append a string to the end of the entry, it will separated by ';' or ':'. |
| entry &operator+=(const string_type & value); |
| }; |
| |
| }; |
| |
| /**Template representation of the environment of this process. It takes a template |
| * as template parameter to implement the environment. All instances of this class |
| * refer to the same environment, but might not get updated if another one makes changes. |
| */ |
| template<typename Char> |
| class basic_native_environment |
| { |
| |
| public: |
| typedef std::basic_string<Char> string_type; |
| typedef boost::transform_iterator< entry_maker, Char**> iterator ; |
| typedef boost::transform_iterator<const_entry_maker, Char**> const_iterator ; |
| typedef std::size_t size_type ; |
| |
| iterator begin() ; ///<Returns an iterator to the beginning |
| const_iterator begin() const ; ///<Returns an iterator to the beginning |
| const_iterator cbegin() const ; ///<Returns an iterator to the beginning |
| |
| iterator end() ; ///<Returns an iterator to the end |
| const_iterator end() const; ///<Returns an iterator to the end |
| const_iterator cend() const; ///<Returns an iterator to the end |
| |
| iterator find( const string_type& key ); ///<Find a variable by its name |
| const_iterator find( const string_type& key ) const; ///<Find a variable by its name |
| |
| std::size_t count(const string_type & st) const; ///<Number of variables |
| void erase(const string_type & id); ///<Erase variable by id. |
| ///Emplace an environment variable. |
| std::pair<iterator,bool> emplace(const string_type & id, const string_type & value); |
| |
| ///Default constructor |
| basic_native_environment(); |
| ///Move constructor. |
| basic_native_environment(basic_native_environment && ); |
| ///Move assignment. |
| basic_native_environment& operator=(basic_native_environment && ); |
| |
| typedef typename detail::implementation_type::native_handle_type native_handle; |
| |
| ///Check if environment has entries. |
| bool empty(); |
| ///Get the number of variables. |
| std::size_t size() const; |
| ///Get the entry with the key. Throws if it does not exist. |
| entry_type at( const string_type& key ); |
| ///Get the entry with the key. Throws if it does not exist. |
| const_entry_type at( const string_type& key ) const; |
| ///Get the entry with the given key. It creates the entry if it doesn't exist. |
| entry_type operator[](const string_type & key); |
| |
| /**Proxy class used for read access to members by [] or .at() |
| * @attention Holds a reference to the environment it was created from. |
| */ |
| template<typename Char, typename Environment> |
| struct const_entry_type |
| { |
| typedef Char value_type; |
| typedef const value_type * pointer; |
| typedef std::basic_string<value_type> string_type; |
| typedef boost::iterator_range<pointer> range; |
| typedef Environment environment_t; |
| |
| ///Split the entry by ";" or ":" and return it as a vector. Used by PATH. |
| std::vector<string_type> to_vector() const |
| ///Get the value as string. |
| string_type to_string() const |
| ///Get the name of this entry. |
| string_type get_name() const {return string_type(_name.begin(), _name.end());} |
| ///Copy Constructor |
| const_entry(const const_entry&) = default; |
| ///Move Constructor |
| const_entry& operator=(const const_entry&) = default; |
| ///Check if the entry is empty. |
| bool empty() const; |
| }; |
| |
| /**Proxy class used for read and write access to members by [] or .at() |
| * @attention Holds a reference to the environment it was created from. |
| */ |
| template<typename Char, typename Environment> |
| struct entry_type |
| { |
| |
| typedef Char value_type; |
| typedef const value_type * pointer; |
| typedef std::basic_string<value_type> string_type; |
| typedef boost::iterator_range<pointer> range; |
| typedef Environment environment_t; |
| |
| ///Split the entry by ";" or ":" and return it as a vector. Used by PATH. |
| std::vector<string_type> to_vector() const |
| ///Get the value as string. |
| string_type to_string() const |
| ///Get the name of this entry. |
| string_type get_name() const {return string_type(_name.begin(), _name.end());} |
| ///Copy Constructor |
| entry(const entry&) = default; |
| ///Move Constructor |
| entry& operator=(const entry&) = default; |
| ///Check if the entry is empty. |
| bool empty() const; |
| |
| ///Assign a string to the value |
| void assign(const string_type &value); |
| ///Assign a set of strings to the entry; they will be separated by ';' or ':'. |
| void assign(const std::vector<string_type> &value); |
| ///Append a string to the end of the entry, it will separated by ';' or ':'. |
| void append(const string_type &value); |
| ///Reset the value |
| void clear(); |
| ///Assign a string to the entry. |
| entry &operator=(const string_type & value); |
| ///Assign a set of strings to the entry; they will be separated by ';' or ':'. |
| entry &operator=(const std::vector<string_type> & value); |
| ///Append a string to the end of the entry, it will separated by ';' or ':'. |
| entry &operator+=(const string_type & value); |
| }; |
| |
| }; |
| |
| #endif |
| |
| ///Definition of the environment for the current process. |
| template<typename Char> |
| class basic_native_environment : public basic_environment_impl<Char, detail::api::native_environment_impl> |
| { |
| public: |
| using base_type = basic_environment_impl<Char, detail::api::native_environment_impl>; |
| using base_type::base_type; |
| using base_type::operator=; |
| }; |
| |
| ///Type definition to hold a seperate environment. |
| template<typename Char> |
| class basic_environment : public basic_environment_impl<Char, detail::api::basic_environment_impl> |
| { |
| public: |
| using base_type = basic_environment_impl<Char, detail::api::basic_environment_impl>; |
| using base_type::base_type; |
| using base_type::operator=; |
| }; |
| |
| |
| #if !defined(BOOST_NO_ANSI_APIS) |
| ///Definition of the environment for the current process. |
| typedef basic_native_environment<char> native_environment; |
| #endif |
| ///Definition of the environment for the current process. |
| typedef basic_native_environment<wchar_t> wnative_environment; |
| |
| #if !defined(BOOST_NO_ANSI_APIS) |
| ///Type definition to hold a seperate environment. |
| typedef basic_environment<char> environment; |
| #endif |
| ///Type definition to hold a seperate environment. |
| typedef basic_environment<wchar_t> wenvironment; |
| |
| } |
| |
| ///Namespace containing information of the calling process. |
| namespace this_process |
| { |
| |
| ///Definition of the native handle type. |
| typedef ::boost::process::detail::api::native_handle_t native_handle_type; |
| |
| #if !defined(BOOST_NO_ANSI_APIS) |
| ///Definition of the environment for this process. |
| using ::boost::process::native_environment; |
| #endif |
| ///Definition of the environment for this process. |
| using ::boost::process::wnative_environment; |
| |
| ///Get the process id of the current process. |
| inline int get_id() { return ::boost::process::detail::api::get_id();} |
| ///Get the native handle of the current process. |
| inline native_handle_type native_handle() { return ::boost::process::detail::api::native_handle();} |
| #if !defined(BOOST_NO_ANSI_APIS) |
| ///Get the enviroment of the current process. |
| inline native_environment environment() { return ::boost::process:: native_environment(); } |
| #endif |
| ///Get the enviroment of the current process. |
| inline wnative_environment wenvironment() { return ::boost::process::wnative_environment(); } |
| ///Get the path environment variable of the current process runs. |
| inline std::vector<boost::filesystem::path> path() |
| { |
| #if defined(BOOST_WINDOWS_API) |
| const ::boost::process::wnative_environment ne{}; |
| typedef typename ::boost::process::wnative_environment::const_entry_type value_type; |
| static constexpr auto id = L"PATH"; |
| #else |
| const ::boost::process::native_environment ne{}; |
| typedef typename ::boost::process::native_environment::const_entry_type value_type; |
| static constexpr auto id = "PATH"; |
| #endif |
| |
| auto itr = std::find_if(ne.cbegin(), ne.cend(), |
| [&](const value_type & e) |
| {return id == ::boost::to_upper_copy(e.get_name(), ::boost::process::detail::process_locale());}); |
| |
| if (itr == ne.cend()) |
| return {}; |
| |
| auto vec = itr->to_vector(); |
| |
| std::vector<boost::filesystem::path> val; |
| val.resize(vec.size()); |
| |
| std::copy(vec.begin(), vec.end(), val.begin()); |
| |
| return val; |
| } |
| } |
| } |
| #endif /* INCLUDE_BOOST_PROCESS_DETAIL_ENVIRONMENT_HPP_ */ |