1 // Copyright (c) 2016 Klemens D. Morgenstern
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)
7 #ifndef BOOST_PROCESS_ENVIRONMENT_HPP_
8 #define BOOST_PROCESS_ENVIRONMENT_HPP_
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>
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>
22 namespace boost { namespace process {
26 template<typename Char, typename Environment>
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 ;
35 std::vector<string_type> to_vector() const
38 return std::vector<string_type>();
39 std::vector<string_type> data;
40 auto str = string_type(_data);
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> ();}
46 boost::split(data, _data, s);
47 return std::move(data);
49 string_type to_string() const
52 return string_type(_data);
56 string_type get_name() const {return string_type(_name.begin(), _name.end());}
57 explicit const_entry(string_type&& name, pointer data, environment_t & env_) :
58 _name(std::move(name)), _data(data), _env(&env_) {}
60 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;
67 auto p = _env->find(_name);
77 return _data == nullptr;
85 template<typename Char, typename Environment>
86 struct entry : const_entry<Char, Environment>
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;
94 explicit entry(string_type&& name, pointer data, environment_t & env) :
95 father(std::move(name), data, env) {}
97 explicit entry(string_type &&name, environment_t & env) :
98 father(std::move(name), env) {}
100 entry(const entry&) = default;
101 entry& operator=(const entry&) = default;
103 void assign(const string_type &value)
105 this->_env->set(this->_name, value);
108 void assign(const std::vector<string_type> &value)
111 for (auto &v : value)
113 if (&v != &value.front())
114 data += api::env_seperator<value_type>();
117 this->_env->set(this->_name, data);
121 void assign(const std::initializer_list<string_type> &value)
124 for (auto &v : value)
126 if (&v != &*value.begin())
127 data += api::env_seperator<value_type>();
130 this->_env->set(this->_name, data);
134 void append(const string_type &value)
136 if (this->_data == nullptr)
137 this->_env->set(this->_name, value);
140 string_type st = this->_data;
141 this->_env->set(this->_name, st + api::env_seperator<value_type>() + value);
150 this->_env->reset(this->_name);
151 this->_env->reload();
152 this->_data = nullptr;
154 entry &operator=(const string_type & value)
159 entry &operator=(const std::vector<string_type> & value)
164 entry &operator=(const std::initializer_list<string_type> & value)
169 entry &operator+=(const string_type & value)
179 template<typename Char, typename Environment>
183 make_entry(const make_entry&) = default;
184 make_entry& operator=(const make_entry&) = default;
187 make_entry(Environment & env) : env(&env) {};
188 entry<Char, Environment> operator()(const Char* data) const
191 while ((*p != equal_sign<Char>()) && (*p != null_char<Char>()))
193 auto name = std::basic_string<Char>(data, p);
194 p++; //go behind equal sign
196 return entry<Char, Environment>(std::move(name), p, *env);
200 template<typename Char, typename Environment>
201 struct make_const_entry
204 make_const_entry(const make_const_entry&) = default;
205 make_const_entry& operator=(const make_const_entry&) = default;
208 make_const_entry(Environment & env) : env(&env) {};
209 const_entry<Char, Environment> operator()(const Char* data) const
212 while ((*p != equal_sign<Char>()) && (*p != null_char<Char>()))
214 auto name = std::basic_string<Char>(data, p);
215 p++; //go behind equal sign
217 return const_entry<Char, Environment>(std::move(name), p, *env);
223 #if !defined (BOOST_PROCESS_DOXYGEN)
225 template<typename Char, template <class> class Implementation = detail::api::basic_environment_impl>
226 class basic_environment_impl : public Implementation<Char>
228 Char** _get_end() const
230 auto p = this->_env_impl;
231 while (*p != nullptr)
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>;
246 friend const_entry_type;
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;
252 iterator begin() {return iterator(this->_env_impl, entry_maker(*this));}
253 const_iterator begin() const {return const_iterator(this->_env_impl, const_entry_maker(*this));}
254 const_iterator cbegin() const {return const_iterator(this->_env_impl, const_entry_maker(*this));}
256 iterator end() {return iterator(_get_end(), entry_maker(*this));}
257 const_iterator end() const {return const_iterator(_get_end(), const_entry_maker(*this));}
258 const_iterator cend() const {return const_iterator(_get_end(), const_entry_maker(*this));}
260 iterator find( const string_type& key )
262 auto p = this->_env_impl;
263 auto st1 = key + ::boost::process::detail::equal_sign<Char>();
264 while (*p != nullptr)
266 if (std::equal(st1.begin(), st1.end(), *p))
270 return iterator(p, entry_maker(*this));
272 const_iterator find( const string_type& key ) const
274 auto p = this->_env_impl;
275 auto st1 = key + ::boost::process::detail::equal_sign<Char>();
276 while (*p != nullptr)
278 if (std::equal(st1.begin(), st1.end(), *p))
282 return const_iterator(p, const_entry_maker(*this));
285 std::size_t count(const string_type & st) const
287 auto p = this->_env_impl;
288 auto st1 = st + ::boost::process::detail::equal_sign<Char>();
289 while (*p != nullptr)
291 if (std::equal(st1.begin(), st1.end(), *p))
297 void erase(const string_type & id)
299 implementation_type::reset(id);
302 std::pair<iterator,bool> emplace(const string_type & id, const string_type & value)
307 implementation_type::set(id, value);
309 return std::pair<iterator, bool>(find(id), true);
312 return std::pair<iterator, bool>(f, false);
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
321 return *this->_env_impl == nullptr;
323 std::size_t size() const
325 return (_get_end() - this->_env_impl);
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();});
333 for (auto & nm : names)
334 implementation_type::reset(nm);
339 entry_type at( const string_type& key )
343 throw std::out_of_range(key + " not found");
346 const_entry_type at( const string_type& key ) const
350 throw std::out_of_range(key + " not found");
353 entry_type operator[](const string_type & key)
359 return entry_type(string_type(key), *this);
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
368 template<typename Char>
369 class basic_environment
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 ;
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
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
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
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);
394 ///Default constructor
397 basic_environment(const basic_environment & );
399 basic_environment(basic_environment && );
402 basic_environment& operator=(const basic_environment & );
404 basic_environment& operator=(basic_environment && );
406 typedef typename detail::implementation_type::native_handle_type native_handle;
408 ///Check if environment has entries.
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.
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);
421 /**Proxy class used for read access to members by [] or .at()
422 * @attention Holds a reference to the environment it was created from.
424 template<typename Char, typename Environment>
425 struct const_entry_type
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;
433 ///Split the entry by ";" or ":" and return it as a vector. Used by PATH.
434 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());}
440 const_entry(const const_entry&) = default;
442 const_entry& operator=(const const_entry&) = default;
443 ///Check if the entry is empty.
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.
450 template<typename Char, typename Environment>
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;
460 ///Split the entry by ";" or ":" and return it as a vector. Used by PATH.
461 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());}
467 entry(const entry&) = default;
469 entry& operator=(const entry&) = default;
470 ///Check if the entry is empty.
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);
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);
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.
495 template<typename Char>
496 class basic_native_environment
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 ;
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
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
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
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);
521 ///Default constructor
522 basic_native_environment();
524 basic_native_environment(basic_native_environment && );
526 basic_native_environment& operator=(basic_native_environment && );
528 typedef typename detail::implementation_type::native_handle_type native_handle;
530 ///Check if environment has entries.
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);
541 /**Proxy class used for read access to members by [] or .at()
542 * @attention Holds a reference to the environment it was created from.
544 template<typename Char, typename Environment>
545 struct const_entry_type
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;
553 ///Split the entry by ";" or ":" and return it as a vector. Used by PATH.
554 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());}
560 const_entry(const const_entry&) = default;
562 const_entry& operator=(const const_entry&) = default;
563 ///Check if the entry is empty.
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.
570 template<typename Char, typename Environment>
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;
580 ///Split the entry by ";" or ":" and return it as a vector. Used by PATH.
581 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());}
587 entry(const entry&) = default;
589 entry& operator=(const entry&) = default;
590 ///Check if the entry is empty.
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);
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);
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>
618 using base_type = basic_environment_impl<Char, detail::api::native_environment_impl>;
619 using base_type::base_type;
620 using base_type::operator=;
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>
628 using base_type = basic_environment_impl<Char, detail::api::basic_environment_impl>;
629 using base_type::base_type;
630 using base_type::operator=;
635 ///Definition of the environment for the current process.
636 typedef basic_native_environment<char> native_environment;
637 ///Definition of the environment for the current process.
638 typedef basic_native_environment<wchar_t> wnative_environment;
640 ///Type definition to hold a seperate environment.
641 typedef basic_environment<char> environment;
642 ///Type definition to hold a seperate environment.
643 typedef basic_environment<wchar_t> wenvironment;
647 ///Namespace containing information of the calling process.
648 namespace this_process
651 ///Definition of the native handle type.
652 typedef ::boost::process::detail::api::native_handle_t native_handle_type;
654 ///Definition of the environment for this process.
655 using ::boost::process::native_environment;
656 ///Definition of the environment for this process.
657 using ::boost::process::wnative_environment;
659 ///Get the process id of the current process.
660 inline int get_id() { return ::boost::process::detail::api::get_id();}
661 ///Get the native handle of the current process.
662 inline native_handle_type native_handle() { return ::boost::process::detail::api::native_handle();}
663 ///Get the enviroment of the current process.
664 inline native_environment environment() { return ::boost::process:: native_environment(); }
665 ///Get the enviroment of the current process.
666 inline wnative_environment wenvironment() { return ::boost::process::wnative_environment(); }
667 ///Get the path environment variable of the current process runs.
668 inline std::vector<boost::filesystem::path> path()
670 #if defined(BOOST_WINDOWS_API)
671 const ::boost::process::wnative_environment ne{};
672 typedef typename ::boost::process::wnative_environment::const_entry_type value_type;
673 const auto id = L"PATH";
675 const ::boost::process::native_environment ne{};
676 typedef typename ::boost::process::native_environment::const_entry_type value_type;
677 const auto id = "PATH";
680 auto itr = std::find_if(ne.cbegin(), ne.cend(),
681 [&](const value_type & e)
682 {return id == ::boost::to_upper_copy(e.get_name(), ::boost::process::detail::process_locale());});
684 if (itr == ne.cend())
687 auto vec = itr->to_vector();
689 std::vector<boost::filesystem::path> val;
690 val.resize(vec.size());
692 std::copy(vec.begin(), vec.end(), val.begin());
698 #endif /* INCLUDE_BOOST_PROCESS_DETAIL_ENVIRONMENT_HPP_ */