| 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_ */
 |