// 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 #include #if defined(BOOST_POSIX_API) #include #elif defined(BOOST_WINDOWS_API) #include #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 namespace boost { namespace process { unspecified env; } } * \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 std::size_t make_env_string_size(const std::basic_string & ch) { return ch.size() + 1; } template std::size_t make_env_string_size(const Char * ch) { std::size_t sz = 0; while (ch[sz] != null_char()) sz++; sz++; return sz; } template inline std::basic_string make_env_string(const Container & value) { std::size_t sz = 0; for (auto & v : value) sz += make_env_string_size(v); std::basic_string s; s.reserve(sz); //+1 for ;, end doesn't have one. for (auto & val : value) (s += val) += api::env_seperator(); s.resize(s.size() -1); //remove last ';' return s; } template struct env_set { using string_type = std::basic_string; string_type key; string_type value; }; template struct env_append { using string_type = std::basic_string; string_type key; string_type value; }; template struct env_reset { using string_type = std::basic_string; string_type key; }; template<> struct is_wchar_t> : std::true_type {}; template<> struct is_wchar_t> : std::true_type {}; template<> struct is_wchar_t> : std::true_type {}; template<> struct is_wchar_t> : std::true_type {}; template<> struct char_converter> { static env_set conv(const env_set & in) { return {::boost::process::detail::convert(in.key), ::boost::process::detail::convert(in.value)}; } }; template<> struct char_converter> { static env_set conv(const env_set & in) { return {::boost::process::detail::convert(in.key), ::boost::process::detail::convert(in.value)}; } }; template<> struct char_converter> { static env_append conv(const env_append & in) { return {::boost::process::detail::convert(in.key), ::boost::process::detail::convert(in.value)}; } }; template<> struct char_converter> { static env_append conv(const env_append & in) { return {::boost::process::detail::convert(in.key), ::boost::process::detail::convert(in.value)}; } }; template<> struct char_converter> { static env_reset conv(const env_reset & in) { return {::boost::process::detail::convert(in.key)}; } }; template<> struct char_converter> { static env_reset conv(const env_reset & in) { return {::boost::process::detail::convert(in.key)}; } }; template struct env_init { basic_environment env; }; template<> struct char_converter> { static env_init conv(const env_init & in) { return {basic_environment(in.env)}; } }; template<> struct char_converter> { static env_init conv(const env_init & in) { return {basic_environment(in.env)}; } }; template<> struct char_converter> { static basic_environment conv(const basic_environment & in) { return { basic_environment(in) }; } }; template<> struct char_converter> { static basic_environment conv(const basic_environment & in) { return { basic_environment(in) }; } }; template struct env_proxy { using string_type = std::basic_string; string_type key; env_set operator=(const string_type & value) { return {std::move(key), value}; } env_set operator=(const std::vector & value) { return {std::move(key), make_env_string(value)}; } env_set operator=(const std::initializer_list & value) { return {std::move(key), make_env_string(value)}; } env_append operator+=(const string_type & value) { return {std::move(key), value}; } env_append operator+=(const std::vector & value) { return {std::move(key), make_env_string(value)}; } env_append operator+=(const std::initializer_list & value) { return {std::move(key), make_env_string(value)}; } env_reset operator=(boost::none_t) { return {std::move(key)}; } }; struct env_ { constexpr env_() {}; template env_set operator()(const std::basic_string & key, const std::basic_string & value) const { return {key, value}; } template env_set operator()(const std::basic_string & key, const std::vector> & value) const { return {key, make_env_string(value)}; } template env_set operator()(const std::basic_string & key, const std::initializer_list & value) const { return {key, make_env_string(value)}; } template env_reset operator()(const std::basic_string & key, boost::none_t) { return {key}; } template env_proxy operator[](const std::basic_string & key) const { return {key}; } template env_proxy operator[](const Char* key) const { return {key}; } template env_init operator()(const basic_environment & env) const { return {env}; } template env_init operator= (const basic_environment & env) const { return {env}; } }; template struct env_builder { basic_environment env; env_builder() : env{basic_native_environment()} {} void operator()(const basic_environment & e) { env = e; } void operator()(env_init & ei) { env = std::move(ei.env); } void operator()(env_set & es) { env[es.key] = es.value; } void operator()(env_reset & es) { env.erase(es.key); } template void operator()(env_append & es) { env[es.key] += es.value; } typedef api::env_init result_type; api::env_init get_initializer() { return api::env_init(std::move(env)); } }; template<> struct initializer_builder> { typedef env_builder type; }; template<> struct initializer_builder> { typedef env_builder 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` - `const char_type *` \paragraph env_set_var_value value - `std::basic_string` - `const char_type * ` - `std::initializer_list` - `std::vector>` \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` - `const char_type *` \paragraph env_append_var_value value - `std::basic_string` - `const char_type *` - `std::initializer_list` - `std::vector>` \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` - `const char_type *` \subsubsection env_init Initialize the environment The whole environment can be initialized from an object of type \xmlonly boost::process::environment \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` - `const char_type *` \paragraph env_init_var_value value - `boost::process::basic_environment` \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 boost::process::environment \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_ */