1 // Copyright (c) 2016 Klemens D. Morgenstern
2 //
3 // Distributed under the Boost Software License, Version 1.0. (See accompanying
4 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
5
6
7 #ifndef BOOST_PROCESS_ENVIRONMENT_HPP_
8 #define BOOST_PROCESS_ENVIRONMENT_HPP_
9
10 #include <boost/process/detail/config.hpp>
11 #include <boost/algorithm/string/split.hpp>
12 #include <boost/algorithm/string/case_conv.hpp>
13 #include <boost/iterator/transform_iterator.hpp>
14 #include <boost/filesystem/path.hpp>
15
16 #if defined(BOOST_POSIX_API)
17 #include <boost/process/detail/posix/environment.hpp>
18 #elif defined(BOOST_WINDOWS_API)
19 #include <boost/process/detail/windows/environment.hpp>
20 #endif
21
22 namespace boost { namespace process {
23
24 namespace detail {
25
26 template<typename Char, typename Environment>
27 struct const_entry
28 {
29 using value_type = Char ;
30 using pointer = const value_type * ;
31 using string_type = std::basic_string<value_type> ;
32 using range = boost::iterator_range<pointer> ;
33 using environment_t = Environment ;
34
to_vectorboost::process::detail::const_entry35 std::vector<string_type> to_vector() const
36 {
37 if (_data == nullptr)
38 return std::vector<string_type>();
39 std::vector<string_type> data;
40 auto str = string_type(_data);
41 struct splitter
42 {
43 bool operator()(wchar_t w) const {return w == api::env_seperator<wchar_t>();}
44 bool operator()(char c) const {return c == api::env_seperator<char> ();}
45 } s;
46 boost::split(data, _data, s);
47 return data;
48 }
to_stringboost::process::detail::const_entry49 string_type to_string() const
50 {
51 if (_data != nullptr)
52 return string_type(_data);
53 else
54 return string_type();
55 }
get_nameboost::process::detail::const_entry56 string_type get_name() const {return string_type(_name.begin(), _name.end());}
const_entryboost::process::detail::const_entry57 explicit const_entry(string_type&& name, pointer data, environment_t & env_) :
58 _name(std::move(name)), _data(data), _env(&env_) {}
59
const_entryboost::process::detail::const_entry60 explicit const_entry(string_type &&name, environment_t & env) :
61 _name(std::move(name)), _data(nullptr), _env(&env) {}
62 const_entry(const const_entry&) = default;
63 const_entry& operator=(const const_entry&) = default;
64
reloadboost::process::detail::const_entry65 void reload()
66 {
67 auto p = _env->find(_name);
68 if (p == _env->end())
69 _data = nullptr;
70 else
71 _data = p->_data;
72 this->_env->reload();
73
74 }
emptyboost::process::detail::const_entry75 bool empty() const
76 {
77 return _data == nullptr;
78 }
79 protected:
80 string_type _name;
81 pointer _data;
82 environment_t * _env;
83 };
84
85 template<typename Char, typename Environment>
86 struct entry : const_entry<Char, Environment>
87 {
88 using father = const_entry<Char, Environment>;
89 using value_type = typename father::value_type;
90 using string_type = typename father::string_type;
91 using pointer = typename father::pointer;
92 using environment_t = typename father::environment_t;
93
entryboost::process::detail::entry94 explicit entry(string_type&& name, pointer data, environment_t & env) :
95 father(std::move(name), data, env) {}
96
entryboost::process::detail::entry97 explicit entry(string_type &&name, environment_t & env_) :
98 father(std::move(name), env_) {}
99
100 entry(const entry&) = default;
101 entry& operator=(const entry&) = default;
102
assignboost::process::detail::entry103 void assign(const string_type &value)
104 {
105 this->_env->set(this->_name, value);
106 this->reload();
107 }
assignboost::process::detail::entry108 void assign(const std::vector<string_type> &value)
109 {
110 string_type data;
111 for (auto &v : value)
112 {
113 if (&v != &value.front())
114 data += api::env_seperator<value_type>();
115 data += v;
116 }
117 this->_env->set(this->_name, data);
118 this->reload();
119
120 }
assignboost::process::detail::entry121 void assign(const std::initializer_list<string_type> &value)
122 {
123 string_type data;
124 for (auto &v : value)
125 {
126 if (&v != &*value.begin())
127 data += api::env_seperator<value_type>();
128 data += v;
129 }
130 this->_env->set(this->_name, data);
131 this->reload();
132
133 }
appendboost::process::detail::entry134 void append(const string_type &value)
135 {
136 if (this->_data == nullptr)
137 this->_env->set(this->_name, value);
138 else
139 {
140 string_type st = this->_data;
141 this->_env->set(this->_name, st + api::env_seperator<value_type>() + value);
142 }
143
144
145 this->reload();
146
147 }
clearboost::process::detail::entry148 void clear()
149 {
150 this->_env->reset(this->_name);
151 this->_env->reload();
152 this->_data = nullptr;
153 }
operator =boost::process::detail::entry154 entry &operator=(const string_type & value)
155 {
156 assign(value);
157 return *this;
158 }
operator =boost::process::detail::entry159 entry &operator=(const std::vector<string_type> & value)
160 {
161 assign(value);
162 return *this;
163 }
operator =boost::process::detail::entry164 entry &operator=(const std::initializer_list<string_type> & value)
165 {
166 assign(value);
167 return *this;
168 }
operator +=boost::process::detail::entry169 entry &operator+=(const string_type & value)
170 {
171 append(value);
172 return *this;
173 }
174
175 };
176
177
178
179 template<typename Char, typename Environment>
180 struct make_entry
181 {
182
183 make_entry(const make_entry&) = default;
184 make_entry& operator=(const make_entry&) = default;
185
186 Environment *env;
make_entryboost::process::detail::make_entry187 make_entry(Environment & env) : env(&env) {};
operator ()boost::process::detail::make_entry188 entry<Char, Environment> operator()(const Char* data) const
189 {
190 auto p = data;
191 while ((*p != equal_sign<Char>()) && (*p != null_char<Char>()))
192 p++;
193 auto name = std::basic_string<Char>(data, p);
194 p++; //go behind equal sign
195
196 return entry<Char, Environment>(std::move(name), p, *env);
197 }
198 };
199
200 template<typename Char, typename Environment>
201 struct make_const_entry
202 {
203
204 make_const_entry(const make_const_entry&) = default;
205 make_const_entry& operator=(const make_const_entry&) = default;
206
207 Environment *env;
make_const_entryboost::process::detail::make_const_entry208 make_const_entry(Environment & env) : env(&env) {};
operator ()boost::process::detail::make_const_entry209 const_entry<Char, Environment> operator()(const Char* data) const
210 {
211 auto p = data;
212 while ((*p != equal_sign<Char>()) && (*p != null_char<Char>()))
213 p++;
214 auto name = std::basic_string<Char>(data, p);
215 p++; //go behind equal sign
216
217 return const_entry<Char, Environment>(std::move(name), p, *env);
218 }
219 };
220
221 }
222
223 #if !defined (BOOST_PROCESS_DOXYGEN)
224
225 template<typename Char, template <class> class Implementation = detail::api::basic_environment_impl>
226 class basic_environment_impl : public Implementation<Char>
227 {
_get_end() const228 Char** _get_end() const
229 {
230 auto p = this->_env_impl;
231 while (*p != nullptr)
232 p++;
233
234 return p;
235 }
236 public:
237 using string_type = std::basic_string<Char>;
238 using implementation_type = Implementation<Char>;
239 using base_type = basic_environment_impl<Char, Implementation>;
240 using entry_maker = detail::make_entry<Char, base_type>;
241 using entry_type = detail::entry <Char, base_type>;
242 using const_entry_type = detail::const_entry <Char, const base_type>;
243 using const_entry_maker = detail::make_const_entry<Char, const base_type>;
244
245 friend entry_type;
246 friend const_entry_type;
247
248 using iterator = boost::transform_iterator< entry_maker, Char**, entry_type, entry_type>;
249 using const_iterator = boost::transform_iterator<const_entry_maker, Char**, const_entry_type, const_entry_type>;
250 using size_type = std::size_t;
251
begin()252 iterator begin() {return iterator(this->_env_impl, entry_maker(*this));}
begin() const253 const_iterator begin() const {return const_iterator(this->_env_impl, const_entry_maker(*this));}
cbegin() const254 const_iterator cbegin() const {return const_iterator(this->_env_impl, const_entry_maker(*this));}
255
end()256 iterator end() {return iterator(_get_end(), entry_maker(*this));}
end() const257 const_iterator end() const {return const_iterator(_get_end(), const_entry_maker(*this));}
cend() const258 const_iterator cend() const {return const_iterator(_get_end(), const_entry_maker(*this));}
259
find(const string_type & key)260 iterator find( const string_type& key )
261 {
262 auto p = this->_env_impl;
263 auto st1 = key + ::boost::process::detail::equal_sign<Char>();
264 while (*p != nullptr)
265 {
266 if (std::equal(st1.begin(), st1.end(), *p))
267 break;
268 p++;
269 }
270 return iterator(p, entry_maker(*this));
271 }
find(const string_type & key) const272 const_iterator find( const string_type& key ) const
273 {
274 auto p = this->_env_impl;
275 auto st1 = key + ::boost::process::detail::equal_sign<Char>();
276 while (*p != nullptr)
277 {
278 if (std::equal(st1.begin(), st1.end(), *p))
279 break;
280 p++;
281 }
282 return const_iterator(p, const_entry_maker(*this));
283 }
284
count(const string_type & st) const285 std::size_t count(const string_type & st) const
286 {
287 auto p = this->_env_impl;
288 auto st1 = st + ::boost::process::detail::equal_sign<Char>();
289 while (*p != nullptr)
290 {
291 if (std::equal(st1.begin(), st1.end(), *p))
292 return 1u;
293 p++;
294 }
295 return 0u;
296 }
erase(const string_type & id)297 void erase(const string_type & id)
298 {
299 implementation_type::reset(id);
300 this->reload();
301 }
emplace(const string_type & id,const string_type & value)302 std::pair<iterator,bool> emplace(const string_type & id, const string_type & value)
303 {
304 auto f = find(id);
305 if (f == end())
306 {
307 implementation_type::set(id, value);
308 this->reload();
309 return std::pair<iterator, bool>(find(id), true);
310 }
311 else
312 return std::pair<iterator, bool>(f, false);
313 }
314 using implementation_type::implementation_type;
315 using implementation_type::operator=;
316 using native_handle_type = typename implementation_type::native_handle_type;
317 using implementation_type::native_handle;
318 //copy ctor if impl is copy-constructible
empty()319 bool empty()
320 {
321 return *this->_env_impl == nullptr;
322 }
size() const323 std::size_t size() const
324 {
325 return (_get_end() - this->_env_impl);
326 }
clear()327 void clear()
328 {
329 std::vector<string_type> names;
330 names.resize(size());
331 std::transform(cbegin(), cend(), names.begin(), [](const const_entry_type & cet){return cet.get_name();});
332
333 for (auto & nm : names)
334 implementation_type::reset(nm);
335
336 this->reload();
337 }
338
at(const string_type & key)339 entry_type at( const string_type& key )
340 {
341 auto f = find(key);
342 if (f== end())
343 throw std::out_of_range(key + " not found");
344 return *f;
345 }
at(const string_type & key) const346 const_entry_type at( const string_type& key ) const
347 {
348 auto f = find(key);
349 if (f== end())
350 throw std::out_of_range(key + " not found");
351 return *f;
352 }
operator [](const string_type & key)353 entry_type operator[](const string_type & key)
354 {
355 auto p = find(key);
356 if (p != end())
357 return *p;
358
359 return entry_type(string_type(key), *this);
360 }
361 };
362 #endif
363
364 #if defined(BOOST_PROCESS_DOXYGEN)
365 /**Template representation of environments. It takes a character type (`char` or `wchar_t`)
366 * as template parameter to implement the environment
367 */
368 template<typename Char>
369 class basic_environment
370 {
371
372 public:
373 typedef std::basic_string<Char> string_type;
374 typedef boost::transform_iterator< entry_maker, Char**> iterator ;
375 typedef boost::transform_iterator<const_entry_maker, Char**> const_iterator ;
376 typedef std::size_t size_type ;
377
378 iterator begin() ; ///<Returns an iterator to the beginning
379 const_iterator begin() const ; ///<Returns an iterator to the beginning
380 const_iterator cbegin() const ; ///<Returns an iterator to the beginning
381
382 iterator end() ; ///<Returns an iterator to the end
383 const_iterator end() const; ///<Returns an iterator to the end
384 const_iterator cend() const; ///<Returns an iterator to the end
385
386 iterator find( const string_type& key ); ///<Find a variable by its name
387 const_iterator find( const string_type& key ) const; ///<Find a variable by its name
388
389 std::size_t count(const string_type & st) const; ///<Number of variables
390 void erase(const string_type & id); ///<Erase variable by id.
391 ///Emplace an environment variable.
392 std::pair<iterator,bool> emplace(const string_type & id, const string_type & value);
393
394 ///Default constructor
395 basic_environment();
396 ///Copy constructor.
397 basic_environment(const basic_environment & );
398 ///Move constructor.
399 basic_environment(basic_environment && );
400
401 ///Copy assignment.
402 basic_environment& operator=(const basic_environment & );
403 ///Move assignment.
404 basic_environment& operator=(basic_environment && );
405
406 typedef typename detail::implementation_type::native_handle_type native_handle;
407
408 ///Check if environment has entries.
409 bool empty();
410 ///Get the number of variables.
411 std::size_t size() const;
412 ///Clear the environment. @attention Use with care, passed environment cannot be empty.
413 void clear();
414 ///Get the entry with the key. Throws if it does not exist.
415 entry_type at( const string_type& key );
416 ///Get the entry with the key. Throws if it does not exist.
417 const_entry_type at( const string_type& key ) const;
418 ///Get the entry with the given key. It creates the entry if it doesn't exist.
419 entry_type operator[](const string_type & key);
420
421 /**Proxy class used for read access to members by [] or .at()
422 * @attention Holds a reference to the environment it was created from.
423 */
424 template<typename Char, typename Environment>
425 struct const_entry_type
426 {
427 typedef Char value_type;
428 typedef const value_type * pointer;
429 typedef std::basic_string<value_type> string_type;
430 typedef boost::iterator_range<pointer> range;
431 typedef Environment environment_t;
432
433 ///Split the entry by ";" or ":" and return it as a vector. Used by PATH.
to_vectorboost::process::basic_environment::const_entry_type434 std::vector<string_type> to_vector() const
435 ///Get the value as string.
436 string_type to_string() const
437 ///Get the name of this entry.
438 string_type get_name() const {return string_type(_name.begin(), _name.end());}
439 ///Copy Constructor
440 const_entry(const const_entry&) = default;
441 ///Move Constructor
442 const_entry& operator=(const const_entry&) = default;
443 ///Check if the entry is empty.
444 bool empty() const;
445 };
446
447 /**Proxy class used for read and write access to members by [] or .at()
448 * @attention Holds a reference to the environment it was created from.
449 */
450 template<typename Char, typename Environment>
451 struct entry_type
452 {
453
454 typedef Char value_type;
455 typedef const value_type * pointer;
456 typedef std::basic_string<value_type> string_type;
457 typedef boost::iterator_range<pointer> range;
458 typedef Environment environment_t;
459
460 ///Split the entry by ";" or ":" and return it as a vector. Used by PATH.
to_vectorboost::process::basic_environment::entry_type461 std::vector<string_type> to_vector() const
462 ///Get the value as string.
463 string_type to_string() const
464 ///Get the name of this entry.
465 string_type get_name() const {return string_type(_name.begin(), _name.end());}
466 ///Copy Constructor
467 entry(const entry&) = default;
468 ///Move Constructor
469 entry& operator=(const entry&) = default;
470 ///Check if the entry is empty.
471 bool empty() const;
472
473 ///Assign a string to the value
474 void assign(const string_type &value);
475 ///Assign a set of strings to the entry; they will be separated by ';' or ':'.
476 void assign(const std::vector<string_type> &value);
477 ///Append a string to the end of the entry, it will separated by ';' or ':'.
478 void append(const string_type &value);
479 ///Reset the value
480 void clear();
481 ///Assign a string to the entry.
482 entry &operator=(const string_type & value);
483 ///Assign a set of strings to the entry; they will be separated by ';' or ':'.
484 entry &operator=(const std::vector<string_type> & value);
485 ///Append a string to the end of the entry, it will separated by ';' or ':'.
486 entry &operator+=(const string_type & value);
487 };
488
489 };
490
491 /**Template representation of the environment of this process. It takes a template
492 * as template parameter to implement the environment. All instances of this class
493 * refer to the same environment, but might not get updated if another one makes changes.
494 */
495 template<typename Char>
496 class basic_native_environment
497 {
498
499 public:
500 typedef std::basic_string<Char> string_type;
501 typedef boost::transform_iterator< entry_maker, Char**> iterator ;
502 typedef boost::transform_iterator<const_entry_maker, Char**> const_iterator ;
503 typedef std::size_t size_type ;
504
505 iterator begin() ; ///<Returns an iterator to the beginning
506 const_iterator begin() const ; ///<Returns an iterator to the beginning
507 const_iterator cbegin() const ; ///<Returns an iterator to the beginning
508
509 iterator end() ; ///<Returns an iterator to the end
510 const_iterator end() const; ///<Returns an iterator to the end
511 const_iterator cend() const; ///<Returns an iterator to the end
512
513 iterator find( const string_type& key ); ///<Find a variable by its name
514 const_iterator find( const string_type& key ) const; ///<Find a variable by its name
515
516 std::size_t count(const string_type & st) const; ///<Number of variables
517 void erase(const string_type & id); ///<Erase variable by id.
518 ///Emplace an environment variable.
519 std::pair<iterator,bool> emplace(const string_type & id, const string_type & value);
520
521 ///Default constructor
522 basic_native_environment();
523 ///Move constructor.
524 basic_native_environment(basic_native_environment && );
525 ///Move assignment.
526 basic_native_environment& operator=(basic_native_environment && );
527
528 typedef typename detail::implementation_type::native_handle_type native_handle;
529
530 ///Check if environment has entries.
531 bool empty();
532 ///Get the number of variables.
533 std::size_t size() const;
534 ///Get the entry with the key. Throws if it does not exist.
535 entry_type at( const string_type& key );
536 ///Get the entry with the key. Throws if it does not exist.
537 const_entry_type at( const string_type& key ) const;
538 ///Get the entry with the given key. It creates the entry if it doesn't exist.
539 entry_type operator[](const string_type & key);
540
541 /**Proxy class used for read access to members by [] or .at()
542 * @attention Holds a reference to the environment it was created from.
543 */
544 template<typename Char, typename Environment>
545 struct const_entry_type
546 {
547 typedef Char value_type;
548 typedef const value_type * pointer;
549 typedef std::basic_string<value_type> string_type;
550 typedef boost::iterator_range<pointer> range;
551 typedef Environment environment_t;
552
553 ///Split the entry by ";" or ":" and return it as a vector. Used by PATH.
to_vectorboost::process::basic_native_environment::const_entry_type554 std::vector<string_type> to_vector() const
555 ///Get the value as string.
556 string_type to_string() const
557 ///Get the name of this entry.
558 string_type get_name() const {return string_type(_name.begin(), _name.end());}
559 ///Copy Constructor
560 const_entry(const const_entry&) = default;
561 ///Move Constructor
562 const_entry& operator=(const const_entry&) = default;
563 ///Check if the entry is empty.
564 bool empty() const;
565 };
566
567 /**Proxy class used for read and write access to members by [] or .at()
568 * @attention Holds a reference to the environment it was created from.
569 */
570 template<typename Char, typename Environment>
571 struct entry_type
572 {
573
574 typedef Char value_type;
575 typedef const value_type * pointer;
576 typedef std::basic_string<value_type> string_type;
577 typedef boost::iterator_range<pointer> range;
578 typedef Environment environment_t;
579
580 ///Split the entry by ";" or ":" and return it as a vector. Used by PATH.
to_vectorboost::process::basic_native_environment::entry_type581 std::vector<string_type> to_vector() const
582 ///Get the value as string.
583 string_type to_string() const
584 ///Get the name of this entry.
585 string_type get_name() const {return string_type(_name.begin(), _name.end());}
586 ///Copy Constructor
587 entry(const entry&) = default;
588 ///Move Constructor
589 entry& operator=(const entry&) = default;
590 ///Check if the entry is empty.
591 bool empty() const;
592
593 ///Assign a string to the value
594 void assign(const string_type &value);
595 ///Assign a set of strings to the entry; they will be separated by ';' or ':'.
596 void assign(const std::vector<string_type> &value);
597 ///Append a string to the end of the entry, it will separated by ';' or ':'.
598 void append(const string_type &value);
599 ///Reset the value
600 void clear();
601 ///Assign a string to the entry.
602 entry &operator=(const string_type & value);
603 ///Assign a set of strings to the entry; they will be separated by ';' or ':'.
604 entry &operator=(const std::vector<string_type> & value);
605 ///Append a string to the end of the entry, it will separated by ';' or ':'.
606 entry &operator+=(const string_type & value);
607 };
608
609 };
610
611 #endif
612
613 ///Definition of the environment for the current process.
614 template<typename Char>
615 class basic_native_environment : public basic_environment_impl<Char, detail::api::native_environment_impl>
616 {
617 public:
618 using base_type = basic_environment_impl<Char, detail::api::native_environment_impl>;
619 using base_type::base_type;
620 using base_type::operator=;
621 };
622
623 ///Type definition to hold a seperate environment.
624 template<typename Char>
625 class basic_environment : public basic_environment_impl<Char, detail::api::basic_environment_impl>
626 {
627 public:
628 using base_type = basic_environment_impl<Char, detail::api::basic_environment_impl>;
629 using base_type::base_type;
630 using base_type::operator=;
631 };
632
633
634 #if !defined(BOOST_NO_ANSI_APIS)
635 ///Definition of the environment for the current process.
636 typedef basic_native_environment<char> native_environment;
637 #endif
638 ///Definition of the environment for the current process.
639 typedef basic_native_environment<wchar_t> wnative_environment;
640
641 #if !defined(BOOST_NO_ANSI_APIS)
642 ///Type definition to hold a seperate environment.
643 typedef basic_environment<char> environment;
644 #endif
645 ///Type definition to hold a seperate environment.
646 typedef basic_environment<wchar_t> wenvironment;
647
648 }
649
650 ///Namespace containing information of the calling process.
651 namespace this_process
652 {
653
654 ///Definition of the native handle type.
655 typedef ::boost::process::detail::api::native_handle_t native_handle_type;
656
657 #if !defined(BOOST_NO_ANSI_APIS)
658 ///Definition of the environment for this process.
659 using ::boost::process::native_environment;
660 #endif
661 ///Definition of the environment for this process.
662 using ::boost::process::wnative_environment;
663
664 ///Get the process id of the current process.
get_id()665 inline int get_id() { return ::boost::process::detail::api::get_id();}
666 ///Get the native handle of the current process.
native_handle()667 inline native_handle_type native_handle() { return ::boost::process::detail::api::native_handle();}
668 #if !defined(BOOST_NO_ANSI_APIS)
669 ///Get the enviroment of the current process.
environment()670 inline native_environment environment() { return ::boost::process:: native_environment(); }
671 #endif
672 ///Get the enviroment of the current process.
wenvironment()673 inline wnative_environment wenvironment() { return ::boost::process::wnative_environment(); }
674 ///Get the path environment variable of the current process runs.
path()675 inline std::vector<boost::filesystem::path> path()
676 {
677 #if defined(BOOST_WINDOWS_API)
678 const ::boost::process::wnative_environment ne{};
679 typedef typename ::boost::process::wnative_environment::const_entry_type value_type;
680 static constexpr auto id = L"PATH";
681 #else
682 const ::boost::process::native_environment ne{};
683 typedef typename ::boost::process::native_environment::const_entry_type value_type;
684 static constexpr auto id = "PATH";
685 #endif
686
687 auto itr = std::find_if(ne.cbegin(), ne.cend(),
688 [&](const value_type & e)
689 {return id == ::boost::to_upper_copy(e.get_name(), ::boost::process::detail::process_locale());});
690
691 if (itr == ne.cend())
692 return {};
693
694 auto vec = itr->to_vector();
695
696 std::vector<boost::filesystem::path> val;
697 val.resize(vec.size());
698
699 std::copy(vec.begin(), vec.end(), val.begin());
700
701 return val;
702 }
703 }
704 }
705 #endif /* INCLUDE_BOOST_PROCESS_DETAIL_ENVIRONMENT_HPP_ */
706