// 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_DETAIL_POSIX_ENVIRONMENT_HPP_ #define BOOST_PROCESS_DETAIL_POSIX_ENVIRONMENT_HPP_ #include #include #include #include #include #include #include namespace boost { namespace process { namespace detail { namespace posix { template class native_environment_impl { static std::vector> _load() { std::vector> val; auto p = environ; while (*p != nullptr) { std::string str = *p; val.push_back(::boost::process::detail::convert(str)); p++; } return val; } static std::vector _load_var(std::vector> & vec) { std::vector val; val.resize(vec.size() + 1); std::transform(vec.begin(), vec.end(), val.begin(), [](std::basic_string & str) { return &str.front(); }); val.back() = nullptr; return val; } std::vector> _buffer = _load(); std::vector _impl = _load_var(_buffer); public: using char_type = Char; using pointer_type = const char_type*; using string_type = std::basic_string; using native_handle_type = char_type **; void reload() { _buffer = _load(); _impl = _load_var(_buffer); } string_type get(const pointer_type id) { return get(string_type(id)); } void set(const pointer_type id, const pointer_type value) { set(string_type(id), string_type(value)); } void reset(const pointer_type id) { reset(string_type(id)); } string_type get(const string_type & id) { std::string id_c = ::boost::process::detail::convert(id); std::string g = ::getenv(id_c.c_str()); return ::boost::process::detail::convert(g.c_str()); } void set(const string_type & id, const string_type & value) { std::string id_c = ::boost::process::detail::convert(id.c_str()); std::string value_c = ::boost::process::detail::convert(value.c_str()); auto res = ::setenv(id_c.c_str(), value_c.c_str(), true); if (res != 0) boost::process::detail::throw_last_error(); } void reset(const string_type & id) { std::string id_c = ::boost::process::detail::convert(id.c_str()); auto res = ::unsetenv(id_c.c_str()); if (res != 0) ::boost::process::detail::throw_last_error(); } native_environment_impl() = default; native_environment_impl(const native_environment_impl& ) = delete; native_environment_impl(native_environment_impl && ) = default; native_environment_impl & operator=(const native_environment_impl& ) = delete; native_environment_impl & operator=(native_environment_impl && ) = default; native_handle_type _env_impl = _impl.data(); native_handle_type native_handle() const {return environ;} }; template<> class native_environment_impl { public: using char_type = char; using pointer_type = const char_type*; using string_type = std::basic_string; using native_handle_type = char_type **; void reload() {this->_env_impl = ::environ;} string_type get(const pointer_type id) { return getenv(id); } void set(const pointer_type id, const pointer_type value) { auto res = ::setenv(id, value, 1); if (res != 0) boost::process::detail::throw_last_error(); reload(); } void reset(const pointer_type id) { auto res = ::unsetenv(id); if (res != 0) boost::process::detail::throw_last_error(); reload(); } string_type get(const string_type & id) {return get(id.c_str());} void set(const string_type & id, const string_type & value) {set(id.c_str(), value.c_str()); } void reset(const string_type & id) {reset(id.c_str());} native_environment_impl() = default; native_environment_impl(const native_environment_impl& ) = delete; native_environment_impl(native_environment_impl && ) = default; native_environment_impl & operator=(const native_environment_impl& ) = delete; native_environment_impl & operator=(native_environment_impl && ) = default; native_handle_type _env_impl = environ; native_handle_type native_handle() const {return ::environ;} }; template struct basic_environment_impl { std::vector> _data {}; static std::vector _load_var(std::vector> & data); std::vector _env_arr{_load_var(_data)}; public: using char_type = Char; using pointer_type = const char_type*; using string_type = std::basic_string; using native_handle_type = Char**; void reload() { _env_arr = _load_var(_data); _env_impl = _env_arr.data(); } string_type get(const pointer_type id) {return get(string_type(id));} void set(const pointer_type id, const pointer_type value) {set(string_type(id), value);} void reset(const pointer_type id) {reset(string_type(id));} string_type get(const string_type & id); void set(const string_type & id, const string_type & value); void reset(const string_type & id); basic_environment_impl(const native_environment_impl & nei); basic_environment_impl() = default; basic_environment_impl(const basic_environment_impl& rhs) : _data(rhs._data) { } basic_environment_impl(basic_environment_impl && ) = default; basic_environment_impl & operator=(const basic_environment_impl& rhs) { _data = rhs._data; _env_arr = _load_var(_data); _env_impl = &*_env_arr.begin(); return *this; } basic_environment_impl & operator=(basic_environment_impl && ) = default; template explicit inline basic_environment_impl( const basic_environment_impl& rhs, const ::boost::process::codecvt_type & cv = ::boost::process::codecvt()) : _data(rhs._data.size()) { std::transform(rhs._data.begin(), rhs._data.end(), _data.begin(), [&](const std::basic_string & st) { return ::boost::process::detail::convert(st, cv); } ); reload(); } template basic_environment_impl & operator=(const basic_environment_impl& rhs) { _data = ::boost::process::detail::convert(rhs._data); _env_arr = _load_var(&*_data.begin()); _env_impl = &*_env_arr.begin(); return *this; } Char ** _env_impl = &*_env_arr.data(); native_handle_type native_handle() const {return &_data.front();} }; template basic_environment_impl::basic_environment_impl(const native_environment_impl & nei) { auto beg = nei.native_handle(); auto end = beg; while (*end != nullptr) end++; this->_data.assign(beg, end); reload(); } template inline auto basic_environment_impl::get(const string_type &id) -> string_type { auto itr = std::find_if(_data.begin(), _data.end(), [&](const string_type & st) { if (st.size() <= id.size()) return false; return std::equal(id.begin(), id.end(), st.begin()) && (st[id.size()] == equal_sign()); } ); if (itr == _data.end()) { return ""; } else return itr->data() + id.size(); //id=Thingy -> +2 points to T } template inline void basic_environment_impl::set(const string_type &id, const string_type &value) { auto itr = std::find_if(_data.begin(), _data.end(), [&](const string_type & st) { if (st.size() <= id.size()) return false; return std::equal(id.begin(), id.end(), st.begin()) && (st[id.size()] == equal_sign()); } ); if (itr != _data.end()) *itr = id + equal_sign() + value; else _data.push_back(id + equal_sign() + value); reload(); } template inline void basic_environment_impl::reset(const string_type &id) { auto itr = std::find_if(_data.begin(), _data.end(), [&](const string_type & st) { if (st.size() <= id.size()) return false; return std::equal(id.begin(), id.end(), st.begin()) && (st[id.size()] == equal_sign()); } ); if (itr != _data.end()) { _data.erase(itr);//and remove it } reload(); } template std::vector basic_environment_impl::_load_var(std::vector> & data) { std::vector ret; ret.reserve(data.size() +1); for (auto & val : data) ret.push_back(&val.front()); ret.push_back(nullptr); return ret; } template constexpr T env_seperator(); template<> constexpr char env_seperator() {return ':'; } template<> constexpr wchar_t env_seperator() {return L':'; } typedef int native_handle_t; inline int get_id() {return getpid(); } inline int native_handle() {return getpid(); } } } } } #endif /* BOOST_PROCESS_DETAIL_WINDOWS_ENV_STORAGE_HPP_ */