123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354 |
- // 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_WINDOWS_ENV_STORAGE_HPP_
- #define BOOST_PROCESS_DETAIL_WINDOWS_ENV_STORAGE_HPP_
- #include <string>
- #include <vector>
- #include <unordered_map>
- #include <boost/winapi/error_codes.hpp>
- #include <boost/winapi/environment.hpp>
- #include <boost/winapi/get_current_process.hpp>
- #include <boost/winapi/get_current_process_id.hpp>
- #include <boost/process/detail/config.hpp>
- #include <algorithm>
- #include <boost/process/locale.hpp>
- namespace boost { namespace process { namespace detail { namespace windows {
- template<typename Char>
- class native_environment_impl
- {
- static void _deleter(Char* p) {boost::winapi::free_environment_strings(p);};
- std::unique_ptr<Char[], void(*)(Char*)> _buf{boost::winapi::get_environment_strings<Char>(), &native_environment_impl::_deleter};
- static inline std::vector<Char*> _load_var(Char* p);
- std::vector<Char*> _env_arr{_load_var(_buf.get())};
- public:
- using char_type = Char;
- using pointer_type = const char_type*;
- using string_type = std::basic_string<char_type>;
- using native_handle_type = pointer_type;
- void reload()
- {
- _buf.reset(boost::winapi::get_environment_strings<Char>());
- _env_arr = _load_var(_buf.get());
- _env_impl = &*_env_arr.begin();
- }
- string_type get(const pointer_type id);
- void set(const pointer_type id, const pointer_type value);
- void reset(const pointer_type id);
- 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;
- Char ** _env_impl = &*_env_arr.begin();
- native_handle_type native_handle() const {return _buf.get();}
- };
- template<typename Char>
- inline auto native_environment_impl<Char>::get(const pointer_type id) -> string_type
- {
- Char buf[4096];
- auto size = boost::winapi::get_environment_variable(id, buf, sizeof(buf));
- if (size == 0) //failed
- {
- auto err = ::boost::winapi::GetLastError();
- if (err == ::boost::winapi::ERROR_ENVVAR_NOT_FOUND_)//well, then we consider that an empty value
- return "";
- else
- throw process_error(std::error_code(err, std::system_category()),
- "GetEnvironmentVariable() failed");
- }
- if (size == sizeof(buf)) //the return size gives the size without the null, so I know this went wrong
- {
- /*limit defined here https://msdn.microsoft.com/en-us/library/windows/desktop/ms683188(v=vs.85).aspx
- * but I used 32768 so it is a multiple of 4096.
- */
- constexpr static std::size_t max_size = 32768;
- //Handle variables longer then buf.
- std::size_t buf_size = sizeof(buf);
- while (buf_size <= max_size)
- {
- std::vector<Char> buf(buf_size);
- auto size = boost::winapi::get_environment_variable(id, buf.data(), buf.size());
- if (size == buf_size) //buffer to small
- buf_size *= 2;
- else if (size == 0)
- ::boost::process::detail::throw_last_error("GetEnvironmentVariable() failed");
- else
- return std::basic_string<Char>(
- buf.data(), buf.data()+ size + 1);
- }
- }
- return std::basic_string<Char>(buf, buf+size+1);
- }
- template<typename Char>
- inline void native_environment_impl<Char>::set(const pointer_type id, const pointer_type value)
- {
- boost::winapi::set_environment_variable(id, value);
- }
- template<typename Char>
- inline void native_environment_impl<Char>::reset(const pointer_type id)
- {
- boost::winapi::set_environment_variable(id, nullptr);
- }
- template<typename Char>
- std::vector<Char*> native_environment_impl<Char>::_load_var(Char* p)
- {
- std::vector<Char*> ret;
- if (*p != null_char<Char>())
- {
- ret.push_back(p);
- while ((*p != null_char<Char>()) || (*(p+1) != null_char<Char>()))
- {
- if (*p==null_char<Char>())
- {
- p++;
- ret.push_back(p);
- }
- else
- p++;
- }
- }
- p++;
- ret.push_back(nullptr);
- return ret;
- }
- template<typename Char>
- struct basic_environment_impl
- {
- std::vector<Char> _data = {null_char<Char>()};
- static std::vector<Char*> _load_var(Char* p);
- std::vector<Char*> _env_arr{_load_var(_data.data())};
- public:
- using char_type = Char;
- using pointer_type = const char_type*;
- using string_type = std::basic_string<char_type>;
- using native_handle_type = pointer_type;
- std::size_t size() const { return _data.size();}
- void reload()
- {
- _env_arr = _load_var(_data.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);
- inline basic_environment_impl(const native_environment_impl<Char> & nei);
- basic_environment_impl() = default;
- basic_environment_impl(const basic_environment_impl& rhs)
- : _data(rhs._data)
- {
- }
- basic_environment_impl(basic_environment_impl && rhs)
- : _data(std::move(rhs._data)),
- _env_arr(std::move(rhs._env_arr)),
- _env_impl(_env_arr.data())
- {
- }
- basic_environment_impl &operator=(basic_environment_impl && rhs)
- {
- _data = std::move(rhs._data);
- //reload();
- _env_arr = std::move(rhs._env_arr);
- _env_impl = _env_arr.data();
- return *this;
- }
- basic_environment_impl & operator=(const basic_environment_impl& rhs)
- {
- _data = rhs._data;
- reload();
- return *this;
- }
- template<typename CharR>
- explicit inline basic_environment_impl(
- const basic_environment_impl<CharR>& rhs,
- const ::boost::process::codecvt_type & cv = ::boost::process::codecvt())
- : _data(::boost::process::detail::convert(rhs._data, cv))
- {
- }
- template<typename CharR>
- basic_environment_impl & operator=(const basic_environment_impl<CharR>& 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.begin();
- native_handle_type native_handle() const {return &*_data.begin();}
- };
- template<typename Char>
- basic_environment_impl<Char>::basic_environment_impl(const native_environment_impl<Char> & nei)
- {
- auto beg = nei.native_handle();
- auto p = beg;
- while ((*p != null_char<Char>()) || (*(p+1) != null_char<Char>()))
- p++;
- p++; //pointing to the second nullchar
- p++; //to get the pointer behing the second nullchar, so it's end.
- this->_data.assign(beg, p);
- this->reload();
- }
- template<typename Char>
- inline auto basic_environment_impl<Char>::get(const string_type &id) -> string_type
- {
- if (std::equal(id.begin(), id.end(), _data.begin()) && (_data[id.size()] == equal_sign<Char>()))
- return string_type(_data.data()); //null-char is handled by the string.
- std::vector<Char> seq = {'\0'}; //using a vector, because strings might cause problems with nullchars
- seq.insert(seq.end(), id.begin(), id.end());
- seq.push_back('=');
- auto itr = std::search(_data.begin(), _data.end(), seq.begin(), seq.end());
- if (itr == _data.end()) //not found
- return "";
- itr += seq.size(); //advance to the value behind the '='; the std::string will take care of finding the null-char.
- return string_type(&*itr);
- }
- template<typename Char>
- inline void basic_environment_impl<Char>::set(const string_type &id, const string_type &value)
- {
- reset(id);
- std::vector<Char> insertion;
- insertion.insert(insertion.end(), id.begin(), id.end());
- insertion.push_back('=');
- insertion.insert(insertion.end(), value.begin(), value.end());
- insertion.push_back('\0');
- _data.insert(_data.end() -1, insertion.begin(), insertion.end());
- reload();
- }
- template<typename Char>
- inline void basic_environment_impl<Char>::reset(const string_type &id)
- {
- //ok, we need to check the size of data first
- if (id.size() >= _data.size()) //ok, so it's impossible id is in there.
- return;
- //check if it's the first one, spares us the search.
- if (std::equal(id.begin(), id.end(), _data.begin()) && (_data[id.size()] == equal_sign<Char>()))
- {
- auto beg = _data.begin();
- auto end = beg;
- while (*end != '\0')
- end++;
- end++; //to point behind the last null-char
- _data.erase(beg, end); //and remove the thingy
- }
- std::vector<Char> seq = {'\0'}; //using a vector, because strings might cause problems with nullchars
- seq.insert(seq.end(), id.begin(), id.end());
- seq.push_back('=');
- auto itr = std::search(_data.begin(), _data.end(), seq.begin(), seq.end());
- if (itr == _data.end())
- return;//nothing to return if it's empty anyway...
- auto end = itr;
- while (*++end != '\0');
- _data.erase(itr, end);//and remove it
- reload();
- }
- template<typename Char>
- std::vector<Char*> basic_environment_impl<Char>::_load_var(Char* p)
- {
- std::vector<Char*> ret;
- if (*p != null_char<Char>())
- {
- ret.push_back(p);
- while ((*p != null_char<Char>()) || (*(p+1) != null_char<Char>()))
- {
- if (*p==null_char<Char>())
- {
- p++;
- ret.push_back(p);
- }
- else
- p++;
- }
- }
- p++;
- ret.push_back(nullptr);
- return ret;
- }
- template<typename T> constexpr T env_seperator();
- template<> constexpr char env_seperator() {return ';'; }
- template<> constexpr wchar_t env_seperator() {return L';'; }
- inline int get_id() {return boost::winapi::GetCurrentProcessId();}
- inline void* native_handle() {return boost::winapi::GetCurrentProcess(); }
- typedef void* native_handle_t;
- }
- }
- }
- }
- #endif /* BOOST_PROCESS_DETAIL_WINDOWS_ENV_STORAGE_HPP_ */
|