You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
502 lines
12 KiB
502 lines
12 KiB
// 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_ */
|
|
|