503 lines
12 KiB
C++
503 lines
12 KiB
C++
// 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_ */
|