Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:50:07

0001 // Copyright (c) 2016 Klemens D. Morgenstern
0002 //
0003 // Distributed under the Boost Software License, Version 1.0. (See accompanying
0004 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
0005 
0006 #ifndef BOOST_PROCESS_DETAIL_WINDOWS_ENV_STORAGE_HPP_
0007 #define BOOST_PROCESS_DETAIL_WINDOWS_ENV_STORAGE_HPP_
0008 
0009 #include <string>
0010 #include <vector>
0011 #include <unordered_map>
0012 #include <boost/winapi/error_codes.hpp>
0013 #include <boost/winapi/environment.hpp>
0014 #include <boost/winapi/get_current_process.hpp>
0015 #include <boost/winapi/get_current_process_id.hpp>
0016 #include <boost/process/detail/config.hpp>
0017 #include <algorithm>
0018 #include <boost/process/locale.hpp>
0019 
0020 namespace boost { namespace process { namespace detail { namespace windows {
0021 
0022 template<typename Char>
0023 class native_environment_impl
0024 {
0025     static void _deleter(Char* p) {boost::winapi::free_environment_strings(p);};
0026     std::unique_ptr<Char[], void(*)(Char*)> _buf{boost::winapi::get_environment_strings<Char>(), &native_environment_impl::_deleter};
0027     static inline std::vector<Char*> _load_var(Char* p);
0028     std::vector<Char*> _env_arr{_load_var(_buf.get())};
0029 public:
0030     using char_type = Char;
0031     using pointer_type = const char_type*;
0032     using string_type = std::basic_string<char_type>;
0033     using native_handle_type = pointer_type;
0034     void reload()
0035     {
0036         _buf.reset(boost::winapi::get_environment_strings<Char>());
0037         _env_arr = _load_var(_buf.get());
0038         _env_impl = &*_env_arr.begin();
0039     }
0040 
0041     string_type get(const pointer_type id);
0042     void        set(const pointer_type id, const pointer_type value);
0043     void      reset(const pointer_type id);
0044 
0045     string_type get(const string_type & id) {return get(id.c_str());}
0046     void        set(const string_type & id, const string_type & value) {set(id.c_str(), value.c_str()); }
0047     void      reset(const string_type & id) {reset(id.c_str());}
0048 
0049     native_environment_impl() = default;
0050     native_environment_impl(const native_environment_impl& ) = delete;
0051     native_environment_impl(native_environment_impl && ) = default;
0052     native_environment_impl & operator=(const native_environment_impl& ) = delete;
0053     native_environment_impl & operator=(native_environment_impl && ) = default;
0054     Char ** _env_impl = &*_env_arr.begin();
0055 
0056     native_handle_type native_handle() const {return _buf.get();}
0057 };
0058 
0059 template<typename Char>
0060 inline auto native_environment_impl<Char>::get(const pointer_type id) -> string_type
0061 {
0062     Char buf[4096];
0063     auto size = boost::winapi::get_environment_variable(id, buf, sizeof(buf));
0064     if (size == 0) //failed
0065     {
0066         auto err =  ::boost::winapi::GetLastError();
0067         if (err == ::boost::winapi::ERROR_ENVVAR_NOT_FOUND_)//well, then we consider that an empty value
0068             return "";
0069         else
0070             throw process_error(std::error_code(err, std::system_category()),
0071                                "GetEnvironmentVariable() failed");
0072     }
0073 
0074     if (size == sizeof(buf)) //the return size gives the size without the null, so I know this went wrong
0075     {
0076         /* limit defined here https://msdn.microsoft.com/en-us/library/windows/desktop/ms683188(v=vs.85).aspx
0077          * but I used 32768, so it is a multiple of 4096.
0078          */
0079         constexpr static std::size_t max_size = 32768;
0080         //Handle variables longer then buf.
0081         std::size_t buf_size = sizeof(buf);
0082         while (buf_size <= max_size)
0083         {
0084             std::vector<Char> buf(buf_size);
0085             auto size = boost::winapi::get_environment_variable(id, buf.data(), buf.size());
0086 
0087             if (size == buf_size) //buffer to small
0088                 buf_size *= 2;
0089             else if (size == 0)
0090                 ::boost::process::detail::throw_last_error("GetEnvironmentVariable() failed");
0091             else
0092                 return std::basic_string<Char>(
0093                         buf.data(), buf.data()+ size);
0094 
0095         }
0096 
0097     }
0098     return std::basic_string<Char>(buf, buf+size);
0099 }
0100 
0101 template<typename Char>
0102 inline void native_environment_impl<Char>::set(const pointer_type id, const pointer_type value)
0103 {
0104     boost::winapi::set_environment_variable(id, value);
0105 }
0106 
0107 template<typename Char>
0108 inline void  native_environment_impl<Char>::reset(const pointer_type id)
0109 {
0110     boost::winapi::set_environment_variable(id, nullptr);
0111 }
0112 
0113 template<typename Char>
0114 std::vector<Char*> native_environment_impl<Char>::_load_var(Char* p)
0115 {
0116     std::vector<Char*> ret;
0117     if (*p != null_char<Char>())
0118     {
0119         ret.push_back(p);
0120         while ((*p != null_char<Char>()) || (*(p+1) !=  null_char<Char>()))
0121         {
0122             if (*p==null_char<Char>())
0123             {
0124                 p++;
0125                 ret.push_back(p);
0126             }
0127             else
0128                 p++;
0129         }
0130     }
0131     p++;
0132     ret.push_back(nullptr);
0133 
0134     return ret;
0135 }
0136 
0137 
0138 template<typename Char>
0139 struct basic_environment_impl
0140 {
0141     std::vector<Char> _data = {null_char<Char>()};
0142     static std::vector<Char*> _load_var(Char* p);
0143     std::vector<Char*> _env_arr{_load_var(_data.data())};
0144 public:
0145     using char_type = Char;
0146     using pointer_type = const char_type*;
0147     using string_type = std::basic_string<char_type>;
0148     using native_handle_type = pointer_type;
0149 
0150     std::size_t size() const { return _data.size();}
0151 
0152     void reload()
0153     {
0154         _env_arr = _load_var(_data.data());
0155         _env_impl = _env_arr.data();
0156     }
0157 
0158     string_type get(const pointer_type id) {return get(string_type(id));}
0159     void        set(const pointer_type id, const pointer_type value) {set(string_type(id), value);}
0160     void      reset(const pointer_type id)  {reset(string_type(id));}
0161 
0162     string_type get(const string_type & id);
0163     void        set(const string_type & id, const string_type & value);
0164     void      reset(const string_type & id);
0165 
0166     inline basic_environment_impl(const native_environment_impl<Char> & nei);
0167     basic_environment_impl() = default;
0168     basic_environment_impl(const basic_environment_impl& rhs)
0169         : _data(rhs._data)
0170     {
0171     }
0172     basic_environment_impl(basic_environment_impl && rhs)
0173         :    _data(std::move(rhs._data)),
0174             _env_arr(std::move(rhs._env_arr)),
0175             _env_impl(_env_arr.data())
0176     {
0177     }
0178     basic_environment_impl &operator=(basic_environment_impl && rhs)
0179     {
0180         _data = std::move(rhs._data);
0181         //reload();
0182         _env_arr  = std::move(rhs._env_arr);
0183         _env_impl = _env_arr.data();
0184 
0185         return *this;
0186     }
0187     basic_environment_impl & operator=(const basic_environment_impl& rhs)
0188     {
0189         _data = rhs._data;
0190         reload();
0191         return *this;
0192     }
0193 
0194     template<typename CharR>
0195     explicit inline  basic_environment_impl(
0196                 const basic_environment_impl<CharR>& rhs,
0197                 const ::boost::process::codecvt_type & cv = ::boost::process::codecvt())
0198         : _data(::boost::process::detail::convert(rhs._data, cv))
0199     {
0200     }
0201 
0202     template<typename CharR>
0203     basic_environment_impl & operator=(const basic_environment_impl<CharR>& rhs)
0204     {
0205         _data = ::boost::process::detail::convert(rhs._data);
0206         _env_arr = _load_var(&*_data.begin());
0207         _env_impl = &*_env_arr.begin();
0208         return *this;
0209     }
0210 
0211     Char ** _env_impl = &*_env_arr.begin();
0212 
0213     native_handle_type native_handle() const {return &*_data.begin();}
0214 };
0215 
0216 
0217 template<typename Char>
0218 basic_environment_impl<Char>::basic_environment_impl(const native_environment_impl<Char> & nei)
0219 {
0220     auto beg = nei.native_handle();
0221     auto p   = beg;
0222     while ((*p != null_char<Char>()) || (*(p+1) !=  null_char<Char>()))
0223         p++;
0224     p++; //pointing to the second nullchar
0225     p++; //to get the pointer behing the second nullchar, so it's end.
0226 
0227     this->_data.assign(beg, p);
0228     this->reload();
0229 }
0230 
0231 
0232 template<typename Char>
0233 inline auto basic_environment_impl<Char>::get(const string_type &id) -> string_type
0234 {
0235     if (id.size() >= _data.size()) //ok, so it is impossible id is in there.
0236         return string_type(_data.data());
0237 
0238     if (std::equal(id.begin(), id.end(), _data.begin()) && (_data[id.size()] == equal_sign<Char>()))
0239         return string_type(_data.data()); //null-char is handled by the string.
0240 
0241     std::vector<Char> seq = {'\0'}; //using a vector, because strings might cause problems with nullchars
0242     seq.insert(seq.end(), id.begin(), id.end());
0243     seq.push_back('=');
0244 
0245     auto itr = std::search(_data.begin(), _data.end(), seq.begin(), seq.end());
0246 
0247     if (itr == _data.end()) //not found
0248         return "";
0249 
0250     itr += seq.size(); //advance to the value behind the '='; the std::string will take care of finding the null-char.
0251 
0252     return string_type(&*itr);
0253 }
0254 
0255 template<typename Char>
0256 inline void basic_environment_impl<Char>::set(const string_type &id, const string_type &value)
0257 {
0258     reset(id);
0259 
0260     std::vector<Char> insertion;
0261 
0262     insertion.insert(insertion.end(), id.begin(),    id.end());
0263     insertion.push_back('=');
0264     insertion.insert(insertion.end(), value.begin(), value.end());
0265     insertion.push_back('\0');
0266 
0267     _data.insert(_data.end() -1, insertion.begin(), insertion.end());
0268 
0269     reload();
0270 }
0271 
0272 template<typename Char>
0273 inline void  basic_environment_impl<Char>::reset(const string_type &id)
0274 {
0275     //ok, we need to check the size of data first
0276     if (id.size() >= _data.size()) //ok, so it is impossible id is in there.
0277         return;
0278 
0279     //check if it's the first one, spares us the search.
0280     if (std::equal(id.begin(), id.end(), _data.begin()) && (_data[id.size()] == equal_sign<Char>()))
0281     {
0282         auto beg = _data.begin();
0283         auto end = beg;
0284 
0285         while (*end != '\0')
0286            end++;
0287 
0288         end++; //to point behind the last null-char
0289 
0290         _data.erase(beg, end); //and remove the thingy
0291 
0292     }
0293 
0294     std::vector<Char> seq = {'\0'}; //using a vector, because strings might cause problems with nullchars
0295     seq.insert(seq.end(), id.begin(), id.end());
0296     seq.push_back('=');
0297 
0298     auto itr = std::search(_data.begin(), _data.end(), seq.begin(), seq.end());
0299 
0300     if (itr == _data.end())
0301         return;//nothing to return if it's empty anyway...
0302 
0303     auto end = itr;
0304 
0305     while (*++end != '\0');
0306 
0307 
0308     _data.erase(itr, end);//and remove it
0309     reload();
0310 
0311 
0312 }
0313 
0314 template<typename Char>
0315 std::vector<Char*> basic_environment_impl<Char>::_load_var(Char* p)
0316 {
0317     std::vector<Char*> ret;
0318     if (*p != null_char<Char>())
0319     {
0320         ret.push_back(p);
0321         while ((*p != null_char<Char>()) || (*(p+1) !=  null_char<Char>()))
0322         {
0323             if (*p==null_char<Char>())
0324             {
0325                 p++;
0326                 ret.push_back(p);
0327             }
0328             else
0329                 p++;
0330         }
0331     }
0332     p++;
0333     ret.push_back(nullptr);
0334     return ret;
0335 }
0336 
0337 
0338 template<typename T> constexpr T env_seperator();
0339 template<> constexpr  char   env_seperator() {return  ';'; }
0340 template<> constexpr wchar_t env_seperator() {return L';'; }
0341 
0342 inline int   get_id()         {return boost::winapi::GetCurrentProcessId();}
0343 inline void* native_handle()  {return boost::winapi::GetCurrentProcess(); }
0344 
0345 typedef void* native_handle_t;
0346 
0347 }
0348 
0349 }
0350 }
0351 }
0352 
0353 
0354 
0355 
0356 #endif /* BOOST_PROCESS_DETAIL_WINDOWS_ENV_STORAGE_HPP_ */