503 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C++
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			503 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C++
		
	
	
		
			Executable File
		
	
	
	
	
| // 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_ENV_HPP_
 | |
| #define BOOST_PROCESS_DETAIL_ENV_HPP_
 | |
| 
 | |
| #include <boost/process/environment.hpp>
 | |
| #include <boost/none.hpp>
 | |
| 
 | |
| #if defined(BOOST_POSIX_API)
 | |
| #include <boost/process/detail/posix/env_init.hpp>
 | |
| #elif defined(BOOST_WINDOWS_API)
 | |
| #include <boost/process/detail/windows/env_init.hpp>
 | |
| #endif
 | |
| 
 | |
| /** \file boost/process/env.hpp
 | |
|  *
 | |
|  *    This header which provides the `env` property. It allows the modification of the
 | |
|  *    environment the child process will run in, in a functional style.
 | |
|  *
 | |
|  *  \xmlonly
 | |
| <programlisting>
 | |
| namespace boost {
 | |
|   namespace process {
 | |
|     <emphasis>unspecified</emphasis> <globalname alt="boost::process::env">env</globalname>;
 | |
|   }
 | |
| }
 | |
| </programlisting>
 | |
|  *  \endxmlonly
 | |
|  *
 | |
|  *  For additional information see the platform documentations:
 | |
|  *
 | |
|  *   - [windows](https://msdn.microsoft.com/en-US/library/windows/desktop/ms682653.aspx)
 | |
|  *   - [posix](http://pubs.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap08.html)
 | |
|  *
 | |
|  */
 | |
| 
 | |
| 
 | |
| namespace boost {
 | |
| 
 | |
| namespace process { namespace detail {
 | |
| 
 | |
| 
 | |
| template<typename Char>
 | |
| std::size_t make_env_string_size(const std::basic_string<Char> & ch)
 | |
| {
 | |
|     return ch.size() + 1;
 | |
| }
 | |
| 
 | |
| template<typename Char>
 | |
| std::size_t make_env_string_size(const Char * ch)
 | |
| {
 | |
|     std::size_t sz = 0;
 | |
|     while (ch[sz] != null_char<Char>())
 | |
|         sz++;
 | |
| 
 | |
|     sz++;
 | |
|     return sz;
 | |
| }
 | |
| 
 | |
| template<typename Char, typename Container>
 | |
| inline std::basic_string<Char> make_env_string(const Container & value)
 | |
| {
 | |
|     std::size_t sz = 0;
 | |
|     for (auto & v : value)
 | |
|         sz += make_env_string_size(v);
 | |
| 
 | |
|     std::basic_string<Char> s;
 | |
|     s.reserve(sz); //+1 for ;, end doesn't have one.
 | |
| 
 | |
|     for (auto & val : value)
 | |
|         (s += val) += api::env_seperator<Char>();
 | |
| 
 | |
|     s.resize(s.size() -1); //remove last ';'
 | |
|     return s;
 | |
| }
 | |
| 
 | |
| 
 | |
| template<typename Char>
 | |
| struct env_set
 | |
| {
 | |
|     using string_type = std::basic_string<Char>;
 | |
|     string_type key;
 | |
|     string_type value;
 | |
| };
 | |
| 
 | |
| template<typename Char>
 | |
| struct env_append
 | |
| {
 | |
|     using string_type = std::basic_string<Char>;
 | |
|     string_type key;
 | |
|     string_type value;
 | |
| };
 | |
| 
 | |
| 
 | |
| 
 | |
| template<typename Char>
 | |
| struct env_reset
 | |
| {
 | |
|     using string_type = std::basic_string<Char>;
 | |
|     string_type key;
 | |
| };
 | |
| 
 | |
| 
 | |
| template<> struct is_wchar_t<env_set<wchar_t>>           : std::true_type {};
 | |
| template<> struct is_wchar_t<env_append<wchar_t>>        : std::true_type {};
 | |
| template<> struct is_wchar_t<env_reset<wchar_t>>         : std::true_type {};
 | |
| template<> struct is_wchar_t<basic_environment<wchar_t>> : std::true_type {};
 | |
| 
 | |
| 
 | |
| template<>
 | |
| struct char_converter<char, env_set<wchar_t>>
 | |
| {
 | |
|     static env_set<char> conv(const env_set<wchar_t> & in)
 | |
|     {
 | |
|         return {::boost::process::detail::convert(in.key),
 | |
|                 ::boost::process::detail::convert(in.value)};
 | |
|     }
 | |
| };
 | |
| 
 | |
| template<>
 | |
| struct char_converter<wchar_t, env_set<char>>
 | |
| {
 | |
|     static env_set<wchar_t> conv(const env_set<char> & in)
 | |
|     {
 | |
|         return {::boost::process::detail::convert(in.key),
 | |
|                 ::boost::process::detail::convert(in.value)};
 | |
|     }
 | |
| };
 | |
| 
 | |
| template<>
 | |
| struct char_converter<char, env_append<wchar_t>>
 | |
| {
 | |
|     static env_append<char> conv(const env_append<wchar_t> & in)
 | |
|     {
 | |
|         return {::boost::process::detail::convert(in.key),
 | |
|                 ::boost::process::detail::convert(in.value)};
 | |
|     }
 | |
| };
 | |
| 
 | |
| template<>
 | |
| struct char_converter<wchar_t, env_append<char>>
 | |
| {
 | |
|     static env_append<wchar_t> conv(const env_append<char> & in)
 | |
|     {
 | |
|         return {::boost::process::detail::convert(in.key),
 | |
|                 ::boost::process::detail::convert(in.value)};
 | |
|     }
 | |
| };
 | |
| 
 | |
| template<>
 | |
| struct char_converter<char, env_reset<wchar_t>>
 | |
| {
 | |
|     static env_reset<char> conv(const env_reset<wchar_t> & in)
 | |
|     {
 | |
|         return {::boost::process::detail::convert(in.key)};
 | |
|     }
 | |
| };
 | |
| 
 | |
| template<>
 | |
| struct char_converter<wchar_t, env_reset<char>>
 | |
| {
 | |
|     static env_reset<wchar_t> conv(const env_reset<char> & in)
 | |
|     {
 | |
|         return {::boost::process::detail::convert(in.key)};
 | |
|     }
 | |
| };
 | |
| 
 | |
| 
 | |
| template<typename Char>
 | |
| struct env_init
 | |
| {
 | |
|     basic_environment<Char> env;
 | |
| };
 | |
| 
 | |
| template<>
 | |
| struct char_converter<char, env_init<wchar_t>>
 | |
| {
 | |
|     static env_init<char> conv(const env_init<wchar_t> & in)
 | |
|     {
 | |
|         return {basic_environment<char>(in.env)};
 | |
|     }
 | |
| };
 | |
| 
 | |
| template<>
 | |
| struct char_converter<wchar_t, env_init<char>>
 | |
| {
 | |
|     static env_init<wchar_t> conv(const env_init<char> & in)
 | |
|     {
 | |
|         return {basic_environment<wchar_t>(in.env)};
 | |
|     }
 | |
| };
 | |
| 
 | |
| template<>
 | |
| struct char_converter<char, basic_environment<wchar_t>>
 | |
| {
 | |
|     static basic_environment<char> conv(const basic_environment<wchar_t> & in)
 | |
|     {
 | |
|         return { basic_environment<char>(in) };
 | |
|     }
 | |
| };
 | |
| 
 | |
| template<>
 | |
| struct char_converter<wchar_t, basic_environment<char>>
 | |
| {
 | |
|     static basic_environment<wchar_t> conv(const basic_environment<char> & in)
 | |
|     {
 | |
|         return { basic_environment<wchar_t>(in) };
 | |
|     }
 | |
| };
 | |
| 
 | |
| template<typename Char>
 | |
| struct env_proxy
 | |
| {
 | |
|     using string_type = std::basic_string<Char>;
 | |
|     string_type key;
 | |
| 
 | |
| 
 | |
|     env_set<Char> operator=(const string_type & value)
 | |
|     {
 | |
|         return {std::move(key), value};
 | |
|     }
 | |
|     env_set<Char> operator=(const std::vector<string_type> & value)
 | |
|     {
 | |
|         return {std::move(key), make_env_string<Char>(value)};
 | |
|     }
 | |
|     env_set<Char> operator=(const std::initializer_list<const Char*> & value)
 | |
|     {
 | |
|         return {std::move(key), make_env_string<Char>(value)};
 | |
|     }
 | |
| 
 | |
|     env_append<Char> operator+=(const string_type & value)
 | |
|     {
 | |
|         return {std::move(key), value};
 | |
|     }
 | |
|     env_append<Char> operator+=(const std::vector<string_type> & value)
 | |
|     {
 | |
|         return {std::move(key), make_env_string<Char>(value)};
 | |
|     }
 | |
|     env_append<Char> operator+=(const std::initializer_list<const Char*> & value)
 | |
|     {
 | |
|         return {std::move(key), make_env_string<Char>(value)};
 | |
|     }
 | |
|     env_reset<Char> operator=(boost::none_t)
 | |
|     {
 | |
|         return {std::move(key)};
 | |
|     }
 | |
| };
 | |
| 
 | |
| struct env_
 | |
| {
 | |
|     constexpr env_() {};
 | |
| 
 | |
|     template<typename Char>
 | |
|     env_set<Char> operator()(const std::basic_string<Char> & key,
 | |
|                              const std::basic_string<Char> & value) const
 | |
|     {
 | |
|         return {key, value};
 | |
|     }
 | |
|     template<typename Char>
 | |
|     env_set<Char> operator()(const std::basic_string<Char> & key,
 | |
|                                 const std::vector<std::basic_string<Char>> & value) const
 | |
|     {
 | |
|         return {key, make_env_string<Char>(value)};
 | |
|     }
 | |
|     template<typename Char>
 | |
|     env_set<Char> operator()(const std::basic_string<Char> & key,
 | |
|                              const std::initializer_list<Char*> & value) const
 | |
|     {
 | |
|         return {key, make_env_string<Char>(value)};
 | |
|     }
 | |
|     template<typename Char>
 | |
|     env_reset<Char> operator()(const std::basic_string<Char> & key, boost::none_t)
 | |
|     {
 | |
|         return {key};
 | |
|     }
 | |
|     template<typename Char>
 | |
|     env_proxy<Char> operator[](const std::basic_string<Char> & key) const
 | |
|     {
 | |
|         return {key};
 | |
|     }
 | |
|     template<typename Char>
 | |
|     env_proxy<Char> operator[](const Char* key) const
 | |
|     {
 | |
|         return {key};
 | |
|     }
 | |
|     template<typename Char>
 | |
|     env_init<Char> operator()(const basic_environment<Char> & env) const
 | |
|     {
 | |
|         return {env};
 | |
|     }
 | |
|     template<typename Char>
 | |
|     env_init<Char> operator= (const basic_environment<Char> & env) const
 | |
|     {
 | |
|         return {env};
 | |
|     }
 | |
| };
 | |
| 
 | |
| template<typename Char>
 | |
| struct env_builder
 | |
| {
 | |
|     basic_environment<Char> env;
 | |
|     env_builder() : env{basic_native_environment<Char>()} {}
 | |
| 
 | |
|     void operator()(const basic_environment<Char> & e)
 | |
|     {
 | |
|         env = e;
 | |
|     }
 | |
| 
 | |
|     void operator()(env_init<Char> & ei)
 | |
|     {
 | |
|         env = std::move(ei.env);
 | |
|     }
 | |
|     void operator()(env_set<Char> & es)
 | |
|     {
 | |
|         env[es.key] = es.value;
 | |
|     }
 | |
|     void operator()(env_reset<Char> & es)
 | |
|     {
 | |
|         env.erase(es.key);
 | |
|     }
 | |
|     template<typename T>
 | |
|     void operator()(env_append<T> & es)
 | |
|     {
 | |
|         env[es.key] += es.value;
 | |
|     }
 | |
| 
 | |
|     typedef api::env_init<Char> result_type;
 | |
|     api::env_init<Char> get_initializer()
 | |
|     {
 | |
|         return api::env_init<Char>(std::move(env));
 | |
|     }
 | |
| };
 | |
| 
 | |
| template<>
 | |
| struct initializer_builder<env_tag<char>>
 | |
| {
 | |
|     typedef env_builder<char> type;
 | |
| };
 | |
| 
 | |
| template<>
 | |
| struct initializer_builder<env_tag<wchar_t>>
 | |
| {
 | |
|     typedef env_builder<wchar_t> type;
 | |
| };
 | |
| 
 | |
| }
 | |
| 
 | |
| /**
 | |
| 
 | |
| The `env` property provides a functional way to modify the environment used by
 | |
| the child process. If none is passed the environment is inherited from the father
 | |
| process. Appending means that the environment will be interpreted as a ';' or ':'
 | |
| separated list as used in `PATH`.
 | |
| 
 | |
| On both `posix` and `windows` the environment variables can be lists of strings,
 | |
| separated by ';'. This is typically used for the `PATH` variable.
 | |
| 
 | |
| By default the environment will be inherited from the launching process,
 | |
| which is also true if environment are modified with this initializer.
 | |
| 
 | |
| \section env_details Details
 | |
| 
 | |
| \subsection env_operations Operations
 | |
| 
 | |
| \subsubsection env_set_var Setting variables
 | |
| 
 | |
| To set a variable `id` the value `value` the following syntax can be used.
 | |
| 
 | |
| \code{.cpp}
 | |
| env[id] = value;
 | |
| env(id, value);
 | |
| \endcode
 | |
| 
 | |
| `std::initializer_list` is among the allowed types, so the following syntax is also possible.
 | |
| 
 | |
| \code{.cpp}
 | |
| env[id] = {value1, value2};
 | |
| env(id, {value1, value2});
 | |
| \endcode
 | |
| 
 | |
| \note Creates the variable if it does not exist.
 | |
| 
 | |
| The following lists contain possible value types, with `char_type` being either `char` or `wchar_t`
 | |
| for both `id` and `value`.
 | |
| 
 | |
| \paragraph id id
 | |
| 
 | |
|  - `std::basic_string<char_type>`
 | |
|  - `const char_type *`
 | |
| 
 | |
| \paragraph env_set_var_value value
 | |
| 
 | |
|  - `std::basic_string<char_type>`
 | |
|  - `const char_type * `
 | |
|  - `std::initializer_list<const char_type *>`
 | |
|  - `std::vector<std::basic_string<char_type>>`
 | |
| 
 | |
| 
 | |
| \note Using `std::vector` or `std::initializer_list`
 | |
| 
 | |
| \subsubsection env_append_var Append variables
 | |
| 
 | |
| Appending means, that a variable will be interpreted as a
 | |
| To append  a variable `id` the value `value` the following syntax can be used:
 | |
| 
 | |
| \code{.cpp}
 | |
| env[id] += value;
 | |
| \endcode
 | |
| 
 | |
| `std::initializer_list` is among the allowed types, so the following syntax is also possible.
 | |
| 
 | |
| \code{.cpp}
 | |
| env[id] += {value1, value2};
 | |
| \endcode
 | |
| 
 | |
| \note Creates the variable if it does not exist.
 | |
| 
 | |
| The following lists contain possible value types, with `char_type` being either `char` or `wchar_t`
 | |
| for both `id` and `value`.
 | |
| 
 | |
| \paragraph env_append_var_id id
 | |
| 
 | |
|  - `std::basic_string<char_type>`
 | |
|  - `const char_type *`
 | |
| 
 | |
| \paragraph env_append_var_value value
 | |
| 
 | |
|  - `std::basic_string<char_type>`
 | |
|  - `const char_type *`
 | |
|  - `std::initializer_list<const char_type *>`
 | |
|  - `std::vector<std::basic_string<char_type>>`
 | |
| 
 | |
| 
 | |
| \subsubsection env_reset Reset variables
 | |
| 
 | |
| Reseting signle variables can be done in the following way:
 | |
| 
 | |
| \code{.cpp}
 | |
| env[id] = boost::none;
 | |
| env(id, boost::none);
 | |
| \endcode
 | |
| 
 | |
| \note This does not set the value empty, but removes it from the list.
 | |
| 
 | |
| The following lists contain possible value types, with `char_type` being either `char` or `wchar_t`:
 | |
| 
 | |
| \paragraph env_reset_var_id id
 | |
| 
 | |
|  - `std::basic_string<char_type>`
 | |
|  - `const char_type *`
 | |
| 
 | |
| \subsubsection env_init Initialize the environment
 | |
| 
 | |
| The whole environment can be initialized from an object of type
 | |
| \xmlonly <classname>boost::process::environment</classname> \endxmlonly
 | |
| 
 | |
| \code{.cpp}
 | |
| env=env;
 | |
| env(env);
 | |
| \endcode
 | |
| 
 | |
| \note The passed `environment` can also be default-constructed to get an empty environment.
 | |
| 
 | |
| \paragraph env_init_var_id id
 | |
| 
 | |
|  - `std::basic_string<char_type>`
 | |
|  - `const char_type *`
 | |
| 
 | |
| \paragraph env_init_var_value value
 | |
| 
 | |
|  - `boost::process::basic_environment<char_type>`
 | |
| 
 | |
| \subsection env_example Example
 | |
| 
 | |
| \code{.cpp}
 | |
| spawn("b2", env["PATH"]+="F:/boost", env["SOME_VAR"]=boost::none, env["NEW_VAR"]="VALUE");
 | |
| \endcode
 | |
| 
 | |
| If the overload style should be done by passing an instance of
 | |
| \xmlonly <classname>boost::process::environment</classname> \endxmlonly
 | |
| the above example would look like this.
 | |
| 
 | |
| \code{.cpp}
 | |
| environment e = this_process::environment();
 | |
| e["PATH"]   += "F:/boost";
 | |
| e.erase("SOME_VAR");
 | |
| e["NEW_VAR"] = "VALUE";
 | |
| spawn("b2", e);
 | |
| \endcode
 | |
| 
 | |
| \warning Passing an empty environment will cause undefined behaviour.
 | |
| 
 | |
|  */
 | |
| constexpr boost::process::detail::env_ env{};
 | |
| 
 | |
| 
 | |
| }}
 | |
| 
 | |
| #endif /* INCLUDE_BOOST_PROCESS_DETAIL_ENV_HPP_ */
 |