File indexing completed on 2025-01-18 09:50:07
0001
0002
0003
0004
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)
0065 {
0066 auto err = ::boost::winapi::GetLastError();
0067 if (err == ::boost::winapi::ERROR_ENVVAR_NOT_FOUND_)
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))
0075 {
0076
0077
0078
0079 constexpr static std::size_t max_size = 32768;
0080
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)
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
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++;
0225 p++;
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())
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());
0240
0241 std::vector<Char> seq = {'\0'};
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())
0248 return "";
0249
0250 itr += seq.size();
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
0276 if (id.size() >= _data.size())
0277 return;
0278
0279
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++;
0289
0290 _data.erase(beg, end);
0291
0292 }
0293
0294 std::vector<Char> seq = {'\0'};
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;
0302
0303 auto end = itr;
0304
0305 while (*++end != '\0');
0306
0307
0308 _data.erase(itr, end);
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