stabilize build system: depends, installer, boost/bdb fixes, cross targets groundwork

This commit is contained in:
2026-02-24 18:38:47 +00:00
parent da8c28aaeb
commit 65cb2619a7
13106 changed files with 2484322 additions and 1804 deletions
@@ -0,0 +1,279 @@
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
// Copyright (c) 2009 Boris Schaeling
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
// 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_ARGS_HPP
#define BOOST_PROCESS_ARGS_HPP
/** \file boost/process/args.hpp
*
* This header provides the \xmlonly <globalname alt="boost::process::args">args</globalname>\endxmlonly property. It also provides the
* alternative name \xmlonly <globalname alt="boost::process::argv">argv</globalname>\endxmlonly .
*
*
\xmlonly
<programlisting>
namespace boost {
namespace process {
<emphasis>unspecified</emphasis> <globalname alt="boost::process::args">args</globalname>;
<emphasis>unspecified</emphasis> <globalname alt="boost::process::argv">argv</globalname>;
}
}
</programlisting>
\endxmlonly
*/
#include <boost/process/detail/basic_cmd.hpp>
#include <iterator>
namespace boost { namespace process { namespace detail {
struct args_
{
template<typename T>
using remove_reference_t = typename std::remove_reference<T>::type;
template<typename T>
using value_type = typename remove_reference_t<T>::value_type;
template<typename T>
using vvalue_type = value_type<value_type<T>>;
template <class Range>
arg_setter_<vvalue_type<Range>, true> operator()(Range &&range) const
{
return arg_setter_<vvalue_type<Range>, true>(std::forward<Range>(range));
}
template <class Range>
arg_setter_<vvalue_type<Range>, true> operator+=(Range &&range) const
{
return arg_setter_<vvalue_type<Range>, true>(std::forward<Range>(range));
}
template <class Range>
arg_setter_<vvalue_type<Range>, false> operator= (Range &&range) const
{
return arg_setter_<vvalue_type<Range>, false>(std::forward<Range>(range));
}
template<typename Char>
arg_setter_<Char, true> operator()(std::basic_string<Char> && str) const
{
return arg_setter_<Char, true> (str);
}
template<typename Char>
arg_setter_<Char, true> operator+=(std::basic_string<Char> && str) const
{
return arg_setter_<Char, true> (str);
}
template<typename Char>
arg_setter_<Char, false> operator= (std::basic_string<Char> && str) const
{
return arg_setter_<Char, false>(str);
}
template<typename Char>
arg_setter_<Char, true> operator()(const std::basic_string<Char> & str) const
{
return arg_setter_<Char, true> (str);
}
template<typename Char>
arg_setter_<Char, true> operator+=(const std::basic_string<Char> & str) const
{
return arg_setter_<Char, true> (str);
}
template<typename Char>
arg_setter_<Char, false> operator= (const std::basic_string<Char> & str) const
{
return arg_setter_<Char, false>(str);
}
template<typename Char>
arg_setter_<Char, true> operator()(std::basic_string<Char> & str) const
{
return arg_setter_<Char, true> (str);
}
template<typename Char>
arg_setter_<Char, true> operator+=(std::basic_string<Char> & str) const
{
return arg_setter_<Char, true> (str);
}
template<typename Char>
arg_setter_<Char, false> operator= (std::basic_string<Char> & str) const
{
return arg_setter_<Char, false>(str);
}
template<typename Char>
arg_setter_<Char, true> operator()(const Char* str) const
{
return arg_setter_<Char, true> (str);
}
template<typename Char>
arg_setter_<Char, true> operator+=(const Char* str) const
{
return arg_setter_<Char, true> (str);
}
template<typename Char>
arg_setter_<Char, false> operator= (const Char* str) const
{
return arg_setter_<Char, false>(str);
}
// template<typename Char, std::size_t Size>
// arg_setter_<Char, true> operator()(const Char (&str) [Size]) const
// {
// return arg_setter_<Char, true> (str);
// }
// template<typename Char, std::size_t Size>
// arg_setter_<Char, true> operator+=(const Char (&str) [Size]) const
// {
// return arg_setter_<Char, true> (str);
// }
// template<typename Char, std::size_t Size>
// arg_setter_<Char, false> operator= (const Char (&str) [Size]) const
// {
// return arg_setter_<Char, false>(str);
// }
arg_setter_<char, true> operator()(std::initializer_list<const char*> &&range) const
{
return arg_setter_<char>(range.begin(), range.end());
}
arg_setter_<char, true> operator+=(std::initializer_list<const char*> &&range) const
{
return arg_setter_<char, true>(range.begin(), range.end());
}
arg_setter_<char, false> operator= (std::initializer_list<const char*> &&range) const
{
return arg_setter_<char, true>(range.begin(), range.end());
}
arg_setter_<char, true> operator()(std::initializer_list<std::string> &&range) const
{
return arg_setter_<char>(range.begin(), range.end());
}
arg_setter_<char, true> operator+=(std::initializer_list<std::string> &&range) const
{
return arg_setter_<char, true>(range.begin(), range.end());
}
arg_setter_<char, false> operator= (std::initializer_list<std::string> &&range) const
{
return arg_setter_<char, true>(range.begin(), range.end());
}
arg_setter_<wchar_t, true> operator()(std::initializer_list<const wchar_t*> &&range) const
{
return arg_setter_<wchar_t>(range.begin(), range.end());
}
arg_setter_<wchar_t, true> operator+=(std::initializer_list<const wchar_t*> &&range) const
{
return arg_setter_<wchar_t, true>(range.begin(), range.end());
}
arg_setter_<wchar_t, false> operator= (std::initializer_list<const wchar_t*> &&range) const
{
return arg_setter_<wchar_t, true>(range.begin(), range.end());
}
arg_setter_<wchar_t, true> operator()(std::initializer_list<std::wstring> &&range) const
{
return arg_setter_<wchar_t>(range.begin(), range.end());
}
arg_setter_<wchar_t, true> operator+=(std::initializer_list<std::wstring> &&range) const
{
return arg_setter_<wchar_t, true>(range.begin(), range.end());
}
arg_setter_<wchar_t, false> operator= (std::initializer_list<std::wstring> &&range) const
{
return arg_setter_<wchar_t, true>(range.begin(), range.end());
}
};
}
/**
The `args` property allows to explicitly set arguments for the execution. The
name of the executable will always be the first element in the arg-vector.
\section args_details Details
\subsection args_operations Operations
\subsubsection args_set_var Setting values
To set a the argument vector the following syntax can be used.
\code{.cpp}
args = value;
args(value);
\endcode
`std::initializer_list` is among the allowed types, so the following syntax is also possible.
\code{.cpp}
args = {value1, value2};
args({value1, value2});
\endcode
Below the possible types for `value` are listed, with `char_type` being either `char` or `wchar_t`.
\paragraph args_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>>`
Additionally any range of `std::basic_string<char_type>` can be passed.
\subsubsection args_append_var Appending values
To append a the argument vector the following syntax can be used.
\code{.cpp}
args += value;
\endcode
`std::initializer_list` is among the allowed types, so the following syntax is also possible.
\code{.cpp}
args += {value1, value2};
\endcode
Below the possible types for `value` are listed, with `char_type` being either `char` or `wchar_t`.
\paragraph args_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>>`
Additionally any range of `std::basic_string<char_type>` can be passed.
\subsection args_example Example
The overload form is used when more than one string is passed, from the second one forward.
I.e. the following expressions have the same results:
\code{.cpp}
spawn("gcc", "--version");
spawn("gcc", args ="--version");
spawn("gcc", args+="--version");
spawn("gcc", args ={"--version"});
spawn("gcc", args+={"--version"});
\endcode
\note A string will be parsed and set in quotes if it has none and contains spaces.
*/
constexpr boost::process::detail::args_ args{};
///Alias for \xmlonly <globalname alt="boost::process::args">args</globalname> \endxmlonly .
constexpr boost::process::detail::args_ argv{};
}}
#endif
@@ -0,0 +1,130 @@
// 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)
/** \file boost/process/async.hpp
The header which provides the basic asynchrounous features.
It provides the on_exit property, which allows callbacks when the process exits.
It also implements the necessary traits for passing an boost::asio::io_service,
which is needed for asynchronous communication.
It also pulls the [boost::asio::buffer](http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/buffer.html)
into the boost::process namespace for convenience.
\xmlonly
<programlisting>
namespace boost {
namespace process {
<emphasis>unspecified</emphasis> <ulink url="http://www.boost.org/doc/libs/1_61_0/doc/html/boost_asio/reference/buffer.html">buffer</ulink>;
<emphasis>unspecified</emphasis> <globalname alt="boost::process::on_exit">on_exit</globalname>;
}
}
</programlisting>
\endxmlonly
*/
#ifndef BOOST_PROCESS_ASYNC_HPP_
#define BOOST_PROCESS_ASYNC_HPP_
#include <boost/process/detail/traits.hpp>
#include <boost/process/detail/on_exit.hpp>
#include <boost/asio/io_service.hpp>
#include <boost/asio/streambuf.hpp>
#include <boost/asio/buffer.hpp>
#include <type_traits>
#include <boost/fusion/iterator/deref.hpp>
#if defined(BOOST_POSIX_API)
#include <boost/process/detail/posix/io_service_ref.hpp>
#include <boost/process/detail/posix/async_in.hpp>
#include <boost/process/detail/posix/async_out.hpp>
#include <boost/process/detail/posix/on_exit.hpp>
#elif defined(BOOST_WINDOWS_API)
#include <boost/process/detail/windows/io_service_ref.hpp>
#include <boost/process/detail/windows/async_in.hpp>
#include <boost/process/detail/windows/async_out.hpp>
#include <boost/process/detail/windows/on_exit.hpp>
#endif
namespace boost { namespace process { namespace detail {
struct async_tag;
template<typename T>
struct is_io_service : std::false_type {};
template<>
struct is_io_service<api::io_service_ref> : std::true_type {};
template<typename Tuple>
inline asio::io_service& get_io_service(const Tuple & tup)
{
auto& ref = *boost::fusion::find_if<is_io_service<boost::mpl::_>>(tup);
return ref.get();
}
struct async_builder
{
boost::asio::io_service * ios;
void operator()(boost::asio::io_service & ios_) {this->ios = &ios_;};
typedef api::io_service_ref result_type;
api::io_service_ref get_initializer() {return api::io_service_ref (*ios);};
};
template<>
struct initializer_builder<async_tag>
{
typedef async_builder type;
};
}
using ::boost::asio::buffer;
#if defined(BOOST_PROCESS_DOXYGEN)
/** When an io_service is passed, the on_exit property can be used, to be notified
when the child process exits.
The following syntax is valid
\code{.cpp}
on_exit=function;
on_exit(function);
\endcode
with `function` being a callable object with the signature `(int, const std::error_code&)` or an
`std::future<int>`.
\par Example
\code{.cpp}
io_service ios;
child c("ls", on_exit=[](int exit, const std::error_code& ec_in){});
std::future<int> exit_code;
chlid c2("ls", on_exit=exit_code);
\endcode
\note The handler is not invoked when the launch fails.
\warning When used \ref ignore_error it might gte invoked on error.
*/
constexpr static ::boost::process::detail::on_exit_ on_exit{};
#endif
}}
#endif /* INCLUDE_BOOST_PROCESS_DETAIL_ASYNC_HPP_ */
@@ -0,0 +1,215 @@
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
// Copyright (c) 2009 Boris Schaeling
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
//
// 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_ASYNC_PIPE_HPP
#define BOOST_PROCESS_ASYNC_PIPE_HPP
#include <boost/config.hpp>
#include <boost/process/detail/config.hpp>
#if defined(BOOST_POSIX_API)
#include <boost/process/detail/posix/async_pipe.hpp>
#elif defined(BOOST_WINDOWS_API)
#include <boost/process/detail/windows/async_pipe.hpp>
#endif
namespace boost { namespace process {
#if defined(BOOST_PROCESS_DOXYGEN)
/** Class implementing and asnychronous I/O-Object for use with boost.asio.
* It is based on the corresponding I/O Object, that is either boost::asio::windows::stream_handle or
* boost::asio::posix::stream_descriptor.
*
* It can be used directly with boost::asio::async_read or async_write.
*
* \note The object is copyable, but that does invoke a handle duplicate.
*/
class async_pipe
{
public:
/** Typedef for the native handle representation.
* \note This is the handle on the system, not the boost.asio class.
*
*/
typedef platform_specific native_handle_type;
/** Typedef for the handle representation of boost.asio.
*
*/
typedef platform_specific handle_type;
/** Construct a new async_pipe, does automatically open the pipe.
* Initializes source and sink with the same io_service.
* @note Windows creates a named pipe here, where the name is automatically generated.
*/
inline async_pipe(boost::asio::io_service & ios);
/** Construct a new async_pipe, does automatically open the pipe.
* @note Windows creates a named pipe here, where the name is automatically generated.
*/
inline async_pipe(boost::asio::io_service & ios_source,
boost::asio::io_service & ios_sink);
/** Construct a new async_pipe, does automatically open.
* Initializes source and sink with the same io_service.
*
* @note Windows restricts possible names.
*/
inline async_pipe(boost::asio::io_service & ios, const std::string & name);
/** Construct a new async_pipe, does automatically open.
*
* @note Windows restricts possible names.
*/
inline async_pipe(boost::asio::io_service & ios_source,
boost::asio::io_service & ios_sink, const std::string & name);
/** Copy-Constructor of the async pipe.
* @note Windows requires a named pipe for this, if a the wrong type is used an exception is thrown.
*
*/
async_pipe(const async_pipe& lhs);
/** Move-Constructor of the async pipe.
*/
async_pipe(async_pipe&& lhs);
/** Construct the async-pipe from a pipe.
* @note Windows requires a named pipe for this, if a the wrong type is used an exception is thrown.
*
*/
template<class CharT, class Traits = std::char_traits<CharT>>
explicit async_pipe(boost::asio::io_service & ios, const basic_pipe<CharT, Traits> & p);
/** Construct the async-pipe from a pipe, with two different io_service objects.
* @note Windows requires a named pipe for this, if a the wrong type is used an exception is thrown.
*
*/
template<class CharT, class Traits = std::char_traits<CharT>>
explicit async_pipe(boost::asio::io_service & ios_source,
boost::asio::io_service & ios_sink,
const basic_pipe<CharT, Traits> & p);
/** Assign a basic_pipe.
* @note Windows requires a named pipe for this, if a the wrong type is used an exception is thrown.
*
*/
template<class CharT, class Traits = std::char_traits<CharT>>
inline async_pipe& operator=(const basic_pipe<CharT, Traits>& p);
/** Copy Assign a pipe.
* @note Duplicates the handles.
*/
async_pipe& operator=(const async_pipe& lhs);
/** Move assign a pipe */
async_pipe& operator=(async_pipe&& lhs);
/** Destructor. Closes the pipe handles. */
~async_pipe();
/** Explicit cast to basic_pipe. */
template<class CharT, class Traits = std::char_traits<CharT>>
inline explicit operator basic_pipe<CharT, Traits>() const;
/** Cancel the current asynchronous operations. */
void cancel();
/** Close the pipe handles. */
void close();
/** Close the pipe handles. While passing an error_code
*
*/
void close(std::error_code & ec);
/** Check if the pipes are open. */
bool is_open() const;
/** Async close, i.e. close after current operation is completed.
*
* \note There is no guarantee that this will indeed read the entire pipe-buffer
*/
void async_close();
/** Read some data from the handle.
* See the boost.asio documentation for more details.
*/
template<typename MutableBufferSequence>
std::size_t read_some(const MutableBufferSequence & buffers);
/** Write some data to the handle.
* See the boost.asio documentation for more details.
*/
template<typename MutableBufferSequence>
std::size_t write_some(const MutableBufferSequence & buffers);
/** Get the native handle of the source. */
native_handle native_source() const {return const_cast<boost::asio::windows::stream_handle&>(_source).native();}
/** Get the native handle of the sink. */
native_handle native_sink () const {return const_cast<boost::asio::windows::stream_handle&>(_sink ).native();}
/** Start an asynchronous read.
*
* See the [boost.asio documentation](http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/AsyncReadStream.html) for more details.
*/
template<typename MutableBufferSequence,
typename ReadHandler>
detail::dummy async_read_some(
const MutableBufferSequence & buffers,
ReadHandler &&handler);
/** Start an asynchronous write.
* See the [boost.asio documentation](http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/AsyncWriteStream.html) for more details.
*/
template<typename ConstBufferSequence,
typename WriteHandler>
detail::dummy async_write_some(
const ConstBufferSequence & buffers,
WriteHandler && handler);
///Get the asio handle of the pipe sink.
const handle_type & sink () const &;
///Get the asio handle of the pipe source.
const handle_type & source() const &;
///Get the asio handle of the pipe sink. Qualified as rvalue
handle_type && sink () &&;
///Get the asio handle of the pipe source. Qualified as rvalue
handle_type && source() &&;
/// Move the source out of this class and change the io_service. Qualified as rvalue. \attention Will always move.
handle_type source(::boost::asio::io_service& ios) &&;
/// Move the sink out of this class and change the io_service. Qualified as rvalue. \attention Will always move
handle_type sink (::boost::asio::io_service& ios) &&;
/// Copy the source out of this class and change the io_service. \attention Will always copy.
handle_type source(::boost::asio::io_service& ios) const &;
/// Copy the sink out of this class and change the io_service. \attention Will always copy
handle_type sink (::boost::asio::io_service& ios) const &;
};
#else
using ::boost::process::detail::api::async_pipe;
#endif
}}
#endif
@@ -0,0 +1,142 @@
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
// Copyright (c) 2009 Boris Schaeling
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
// 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)
/**
* \file boost/process/async_system.hpp
*
* Defines the asynchrounous version of the system function.
*/
#ifndef BOOST_PROCESS_ASYNC_SYSTEM_HPP
#define BOOST_PROCESS_ASYNC_SYSTEM_HPP
#include <boost/process/detail/config.hpp>
#include <boost/process/async.hpp>
#include <boost/process/child.hpp>
#include <boost/process/detail/async_handler.hpp>
#include <boost/process/detail/execute_impl.hpp>
#include <type_traits>
#include <memory>
#include <boost/asio/async_result.hpp>
#include <boost/system/error_code.hpp>
#include <tuple>
#if defined(BOOST_POSIX_API)
#include <boost/process/posix.hpp>
#endif
namespace boost {
namespace process {
namespace detail
{
template<typename ExitHandler>
struct async_system_handler : ::boost::process::detail::api::async_handler
{
boost::asio::io_service & ios;
boost::asio::detail::async_result_init<
ExitHandler, void(boost::system::error_code, int)> init;
#if defined(BOOST_POSIX_API)
bool errored = false;
#endif
template<typename ExitHandler_>
async_system_handler(
boost::asio::io_service & ios,
ExitHandler_ && exit_handler) : ios(ios), init(std::forward<ExitHandler_>(exit_handler))
{
}
template<typename Exec>
void on_error(Exec&, const std::error_code & ec)
{
#if defined(BOOST_POSIX_API)
errored = true;
#endif
auto & h = init.handler;
ios.post(
[h, ec]() mutable
{
h(boost::system::error_code(ec.value(), boost::system::system_category()), -1);
});
}
BOOST_ASIO_INITFN_RESULT_TYPE(ExitHandler, void (boost::system::error_code, int))
get_result()
{
return init.result.get();
}
template<typename Executor>
std::function<void(int, const std::error_code&)> on_exit_handler(Executor&)
{
#if defined(BOOST_POSIX_API)
if (errored)
return [](int exit_code, const std::error_code & ec){};
#endif
auto & h = init.handler;
return [h](int exit_code, const std::error_code & ec) mutable
{
h(boost::system::error_code(ec.value(), boost::system::system_category()), exit_code);
};
}
};
template<typename ExitHandler>
struct is_error_handler<async_system_handler<ExitHandler>> : std::true_type {};
}
/** This function provides an asynchronous interface to process launching.
It uses the same properties and parameters as the other launching function,
but is similar to the asynchronous functions in [boost.asio](http://www.boost.org/doc/libs/release/doc/html/boost_asio.html)
It uses [asio::async_result](http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/async_result.html) to determine
the return value (from the second parameter, `exit_handler`).
\param ios A reference to an [io_service](http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference.html)
\param exit_handler The exit-handler for the signature `void(boost::system::error_code, int)`
\note This function does not allow custom error handling, since those are done through the `exit_handler`.
*/
#if defined(BOOST_PROCESS_DOXYGEN)
template<typename ExitHandler, typename ...Args>
inline boost::process::detail::dummy
async_system(boost::asio::io_service & ios, ExitHandler && exit_handler, Args && ...args);
#endif
template<typename ExitHandler, typename ...Args>
inline BOOST_ASIO_INITFN_RESULT_TYPE(ExitHandler, void (boost::system::error_code, int))
async_system(boost::asio::io_service & ios, ExitHandler && exit_handler, Args && ...args)
{
detail::async_system_handler<ExitHandler> async_h{ios, std::forward<ExitHandler>(exit_handler)};
typedef typename ::boost::process::detail::has_error_handler<boost::fusion::tuple<Args...>>::type
has_err_handling;
static_assert(!has_err_handling::value, "async_system cannot have custom error handling");
child(ios, std::forward<Args>(args)..., async_h ).detach();
return async_h.get_result();
}
}}
#endif
@@ -0,0 +1,147 @@
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
// Copyright (c) 2009 Boris Schaeling
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
// 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)
/**
* \file boost/process/child.hpp
*
* Defines a child process class.
*/
#ifndef BOOST_PROCESS_CHILD_HPP
#define BOOST_PROCESS_CHILD_HPP
#include <boost/process/detail/config.hpp>
#include <boost/process/detail/child_decl.hpp>
#include <boost/process/detail/execute_impl.hpp>
#if defined(BOOST_POSIX_API)
#include <boost/process/posix.hpp>
#endif
namespace boost {
///The main namespace of boost.process.
namespace process {
template<typename ...Args>
child::child(Args&&...args)
: child(::boost::process::detail::execute_impl(std::forward<Args>(args)...)) {}
#if defined(BOOST_PROCESS_DOXYGEN)
/** The main class to hold a child process. It is simliar to [std::thread](http://en.cppreference.com/w/cpp/thread/thread),
* in that it has a join and detach function.
*
* @attention The destructor will call terminate on the process if not joined or detached without any warning.
*
*/
class child
{
/** Type definition for the native process handle. */
typedef platform_specific native_handle_t;
/** Construct the child from a pid.
*
* @attention There is no guarantee that this will work. The process need the right access rights, which are very platform specific.
*/
explicit child(pid_t & pid) : _child_handle(pid) {};
/** Move-Constructor.*/
child(child && lhs);
/** Construct a child from a property list and launch it
* The standard version is to create a subprocess, which will spawn the process.
*/
template<typename ...Args>
explicit child(Args&&...args);
/** Construct an empty child. */
child() = default;
/** Move assign. */
child& operator=(child && lhs);
/** Detach the child, i.e. let it run after this handle dies. */
void detach();
/** Join the child. This just calls wait, but that way the naming is similar to std::thread */
void join();
/** Check if the child is joinable. */
bool joinable();
/** Destructor.
* @attention Will call terminate (without warning) when the child was neither joined nor detached.
*/
~child();
/** Get the native handle for the child process. */
native_handle_t native_handle() const;
/** Get the exit_code. The return value is without any meaning if the child wasn't waited for or if it was terminated. */
int exit_code() const;
/** Get the Process Identifier. */
pid_t id() const;
/** Check if the child process is running. */
bool running();
/** \overload void running() */
bool running(std::error_code & ec) noexcept;
/** Wait for the child process to exit. */
void wait();
/** \overload void wait() */
void wait(std::error_code & ec) noexcept;
/** Wait for the child process to exit for a period of time.
* \return True if child exited while waiting.
*/
template< class Rep, class Period >
bool wait_for (const std::chrono::duration<Rep, Period>& rel_time);
/** \overload bool wait_for(const std::chrono::duration<Rep, Period>& rel_time) */
bool wait_for (const std::chrono::duration<Rep, Period>& rel_time, std::error_code & ec) noexcept;
/** Wait for the child process to exit until a point in time.
* \return True if child exited while waiting.*/
template< class Clock, class Duration >
bool wait_until(const std::chrono::time_point<Clock, Duration>& timeout_time );
/** \overload bool wait_until(const std::chrono::time_point<Clock, Duration>& timeout_time )*/
bool wait_until(const std::chrono::time_point<Clock, Duration>& timeout_time, std::error_code & ec) noexcept;
/** Check if this handle holds a child process.
* @note That does not mean, that the process is still running. It only means, that the handle does or did exist.
*/
bool valid() const;
/** Same as valid, for convenience. */
explicit operator bool() const;
/** Check if the the chlid process is in any process group. */
bool in_group() const;
/** \overload bool in_group() const */
bool in_group(std::error_code & ec) const noexcept;
/** Terminate the child process.
*
* This function will cause the child process to unconditionally and immediately exit.
* It is implement with [SIGKILL](http://pubs.opengroup.org/onlinepubs/009695399/functions/kill.html) on posix
* and [TerminateProcess](https://technet.microsoft.com/en-us/library/ms686714.aspx) on windows.
*
*/
void terminate();
/** \overload void terminate() */
void terminate(std::error_code & ec) noexcept;
};
#endif
}}
#endif
@@ -0,0 +1,122 @@
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
// Copyright (c) 2009 Boris Schaeling
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
// 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_CMD_LINE_HPP
#define BOOST_PROCESS_DETAIL_CMD_LINE_HPP
#include <boost/detail/winapi/config.hpp>
#include <boost/process/detail/config.hpp>
#include <boost/process/detail/handler_base.hpp>
#include <boost/process/detail/traits/cmd_or_exe.hpp>
#include <boost/process/detail/traits/wchar_t.hpp>
#if defined(BOOST_POSIX_API)
#include <boost/process/detail/posix/cmd.hpp>
#elif defined(BOOST_WINDOWS_API)
#include <boost/process/detail/windows/cmd.hpp>
#endif
/** \file boost/process/cmd.hpp
*
* This header provides the \xmlonly <globalname alt="boost::process::cmd">cmd</globalname>\endxmlonly property.
*
\xmlonly
<programlisting>
namespace boost {
namespace process {
<emphasis>unspecified</emphasis> <globalname alt="boost::process::cmd">cmd</globalname>;
}
}
</programlisting>
\endxmlonly
*/
namespace boost { namespace process { namespace detail {
struct cmd_
{
constexpr cmd_() {}
template<typename Char>
inline api::cmd_setter_<Char> operator()(const Char *s) const
{
return api::cmd_setter_<Char>(s);
}
template<typename Char>
inline api::cmd_setter_<Char> operator= (const Char *s) const
{
return api::cmd_setter_<Char>(s);
}
template<typename Char>
inline api::cmd_setter_<Char> operator()(const std::basic_string<Char> &s) const
{
return api::cmd_setter_<Char>(s);
}
template<typename Char>
inline api::cmd_setter_<Char> operator= (const std::basic_string<Char> &s) const
{
return api::cmd_setter_<Char>(s);
}
};
template<> struct is_wchar_t<api::cmd_setter_<wchar_t>> : std::true_type {};
template<>
struct char_converter<char, api::cmd_setter_<wchar_t>>
{
static api::cmd_setter_<char> conv(const api::cmd_setter_<wchar_t> & in)
{
return { ::boost::process::detail::convert(in.str()) };
}
};
template<>
struct char_converter<wchar_t, api::cmd_setter_<char>>
{
static api::cmd_setter_<wchar_t> conv(const api::cmd_setter_<char> & in)
{
return { ::boost::process::detail::convert(in.str()) };
}
};
}
/** The cmd property allows to explicitly set commands for the execution.
The overload form applies when only one string is passed to a launching function.
The string will be internally parsed and split at spaces.
The following expressions are valid, with `value` being either a C-String or
a `std::basic_string` with `char` or `wchar_t`.
\code{.cpp}
cmd="value";
cmd(value);
\endcode
The property can only be used for assignments.
*/
constexpr static ::boost::process::detail::cmd_ cmd;
}}
#endif
@@ -0,0 +1,117 @@
/*
* async_handler.hpp
*
* Created on: 12.06.2016
* Author: Klemens
*/
#ifndef BOOST_PROCESS_DETAIL_ASYNC_HANDLER_HPP_
#define BOOST_PROCESS_DETAIL_ASYNC_HANDLER_HPP_
#include <type_traits>
#if defined(BOOST_POSIX_API)
#include <boost/process/posix.hpp>
#include <boost/process/detail/posix/async_handler.hpp>
#include <boost/process/detail/posix/asio_fwd.hpp>
#else
#include <boost/process/detail/windows/async_handler.hpp>
#include <boost/process/detail/windows/asio_fwd.hpp>
#endif
namespace boost {
namespace process {
namespace detail {
#if defined(BOOST_POSIX_API)
using ::boost::process::detail::posix::is_async_handler;
using ::boost::process::detail::posix::does_require_io_service;
#else
using ::boost::process::detail::windows::is_async_handler;
using ::boost::process::detail::windows::does_require_io_service;
#endif
template<typename ...Args>
struct has_io_service;
template<typename T, typename ...Args>
struct has_io_service<T, Args...>
{
typedef typename has_io_service<Args...>::type next;
typedef typename std::is_same<
typename std::remove_reference<T>::type,
boost::asio::io_service>::type is_ios;
typedef typename std::conditional<is_ios::value,
std::true_type,
next>::type type;
};
template<typename T>
struct has_io_service<T>
{
typedef typename std::is_same<
typename std::remove_reference<T>::type,
boost::asio::io_service>::type type;
};
template<typename ...Args>
using has_io_service_t = typename has_io_service<Args...>::type;
template<typename ...Args>
struct has_async_handler;
template<typename T, typename ...Args>
struct has_async_handler<T, Args...>
{
typedef typename has_async_handler<Args...>::type next;
typedef typename is_async_handler<T>::type is_ios;
typedef typename std::conditional<is_ios::value,
std::true_type,
next>::type type;
};
template<typename T>
struct has_async_handler<T>
{
typedef typename is_async_handler<T>::type type;
};
template<typename ...Args>
struct needs_io_service;
template<typename T, typename ...Args>
struct needs_io_service<T, Args...>
{
typedef typename needs_io_service<Args...>::type next;
typedef typename does_require_io_service<T>::type is_ios;
typedef typename std::conditional<is_ios::value,
std::true_type,
next>::type type;
};
template<typename T>
struct needs_io_service<T>
{
typedef typename does_require_io_service<T>::type type;
};
template<typename ...Args>
boost::asio::io_service &get_io_service_var(boost::asio::io_service & f, Args&...)
{
return f;
}
template<typename First, typename ...Args>
boost::asio::io_service &get_io_service_var(First&, Args&...args)
{
return get_io_service_var(args...);
}
}
}
}
#endif /* BOOST_PROCESS_DETAIL_ASYNC_HANDLER_HPP_ */
@@ -0,0 +1,292 @@
// 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_BASIC_CMD_HPP_
#define BOOST_PROCESS_DETAIL_BASIC_CMD_HPP_
#include <boost/process/detail/config.hpp>
#include <boost/process/detail/handler_base.hpp>
#include <boost/process/detail/traits/cmd_or_exe.hpp>
#include <boost/process/detail/traits/wchar_t.hpp>
#if defined( BOOST_WINDOWS_API )
#include <boost/process/detail/windows/basic_cmd.hpp>
#include <boost/process/detail/windows/cmd.hpp>
#elif defined( BOOST_POSIX_API )
#include <boost/process/detail/posix/basic_cmd.hpp>
#include <boost/process/detail/posix/cmd.hpp>
#endif
#include <boost/process/shell.hpp>
#include <iterator>
namespace boost { namespace process { namespace detail {
template<typename Char>
struct exe_setter_
{
typedef Char value_type;
typedef std::basic_string<Char> string_type;
string_type exe_;
exe_setter_(string_type && str) : exe_(std::move(str)) {}
exe_setter_(const string_type & str) : exe_(str) {}
};
template<> struct is_wchar_t<exe_setter_<wchar_t>> : std::true_type {};
template<>
struct char_converter<char, exe_setter_<wchar_t>>
{
static exe_setter_<char> conv(const exe_setter_<wchar_t> & in)
{
return {::boost::process::detail::convert(in.exe_)};
}
};
template<>
struct char_converter<wchar_t, exe_setter_<char>>
{
static exe_setter_<wchar_t> conv(const exe_setter_<char> & in)
{
return {::boost::process::detail::convert(in.exe_)};
}
};
template <typename Char, bool Append >
struct arg_setter_
{
using value_type = Char;
using string_type = std::basic_string<value_type>;
std::vector<string_type> _args;
typedef typename std::vector<string_type>::iterator iterator;
typedef typename std::vector<string_type>::const_iterator const_iterator;
template<typename Iterator>
arg_setter_(Iterator && begin, Iterator && end) : _args(begin, end) {}
template<typename Range>
arg_setter_(Range && str) :
_args(std::begin(str),
std::end(str)) {}
iterator begin() {return _args.begin();}
iterator end() {return _args.end();}
const_iterator begin() const {return _args.begin();}
const_iterator end() const {return _args.end();}
arg_setter_(string_type & str) : _args{{str}} {}
arg_setter_(string_type && s) : _args({std::move(s)}) {}
arg_setter_(const string_type & s) : _args({s}) {}
arg_setter_(const value_type* s) : _args({std::move(s)}) {}
template<std::size_t Size>
arg_setter_(const value_type (&s) [Size]) : _args({s}) {}
};
template<> struct is_wchar_t<arg_setter_<wchar_t, true >> : std::true_type {};
template<> struct is_wchar_t<arg_setter_<wchar_t, false>> : std::true_type {};
template<>
struct char_converter<char, arg_setter_<wchar_t, true>>
{
static arg_setter_<char, true> conv(const arg_setter_<wchar_t, true> & in)
{
std::vector<std::string> vec(in._args.size());
std::transform(in._args.begin(), in._args.end(), vec.begin(),
[](const std::wstring & ws)
{
return ::boost::process::detail::convert(ws);
});
return {vec};
}
};
template<>
struct char_converter<wchar_t, arg_setter_<char, true>>
{
static arg_setter_<wchar_t, true> conv(const arg_setter_<char, true> & in)
{
std::vector<std::wstring> vec(in._args.size());
std::transform(in._args.begin(), in._args.end(), vec.begin(),
[](const std::string & ws)
{
return ::boost::process::detail::convert(ws);
});
return {vec};
}
};
template<>
struct char_converter<char, arg_setter_<wchar_t, false>>
{
static arg_setter_<char, false> conv(const arg_setter_<wchar_t, false> & in)
{
std::vector<std::string> vec(in._args.size());
std::transform(in._args.begin(), in._args.end(), vec.begin(),
[](const std::wstring & ws)
{
return ::boost::process::detail::convert(ws);
});
return {vec}; }
};
template<>
struct char_converter<wchar_t, arg_setter_<char, false>>
{
static arg_setter_<wchar_t, false> conv(const arg_setter_<char, false> & in)
{
std::vector<std::wstring> vec(in._args.size());
std::transform(in._args.begin(), in._args.end(), vec.begin(),
[](const std::string & ws)
{
return ::boost::process::detail::convert(ws);
});
return {vec};
}
};
using api::exe_cmd_init;
template<typename Char>
struct exe_builder
{
//set by path, because that will not be interpreted as a cmd
bool not_cmd = false;
bool shell = false;
using string_type = std::basic_string<Char>;
string_type exe;
std::vector<string_type> args;
void operator()(const boost::filesystem::path & data)
{
not_cmd = true;
if (exe.empty())
exe = data.native();
else
args.push_back(data.native());
}
void operator()(const string_type & data)
{
if (exe.empty())
exe = data;
else
args.push_back(data);
}
void operator()(const Char* data)
{
if (exe.empty())
exe = data;
else
args.push_back(data);
}
void operator()(shell_) {shell = true;}
void operator()(std::vector<string_type> && data)
{
if (data.empty())
return;
auto itr = std::make_move_iterator(data.begin());
auto end = std::make_move_iterator(data.end());
if (exe.empty())
{
exe = *itr;
itr++;
}
args.insert(args.end(), itr, end);
}
void operator()(const std::vector<string_type> & data)
{
if (data.empty())
return;
auto itr = data.begin();
auto end = data.end();
if (exe.empty())
{
exe = *itr;
itr++;
}
args.insert(args.end(), itr, end);
}
void operator()(exe_setter_<Char> && data)
{
not_cmd = true;
exe = std::move(data.exe_);
}
void operator()(const exe_setter_<Char> & data)
{
not_cmd = true;
exe = data.exe_;
}
void operator()(arg_setter_<Char, false> && data)
{
args.assign(
std::make_move_iterator(data._args.begin()),
std::make_move_iterator(data._args.end()));
}
void operator()(arg_setter_<Char, true> && data)
{
args.insert(args.end(),
std::make_move_iterator(data._args.begin()),
std::make_move_iterator(data._args.end()));
}
void operator()(const arg_setter_<Char, false> & data)
{
args.assign(data._args.begin(), data._args.end());
}
void operator()(const arg_setter_<Char, true> & data)
{
args.insert(args.end(), data._args.begin(), data._args.end());
}
api::exe_cmd_init<Char> get_initializer()
{
if (not_cmd || !args.empty())
{
if (shell)
return api::exe_cmd_init<Char>::exe_args_shell(std::move(exe), std::move(args));
else
return api::exe_cmd_init<Char>::exe_args(std::move(exe), std::move(args));
}
else
if (shell)
return api::exe_cmd_init<Char>::cmd_shell(std::move(exe));
else
return api::exe_cmd_init<Char>::cmd(std::move(exe));
}
typedef api::exe_cmd_init<Char> result_type;
};
template<>
struct initializer_builder<cmd_or_exe_tag<char>>
{
typedef exe_builder<char> type;
};
template<>
struct initializer_builder<cmd_or_exe_tag<wchar_t>>
{
typedef exe_builder<wchar_t> type;
};
}}}
#endif /* BOOST_PROCESS_DETAIL_EXE_BUILDER_HPP_ */
@@ -0,0 +1,243 @@
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
// Copyright (c) 2009 Boris Schaeling
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
// 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)
/**
* \file boost/process/child.hpp
*
* Defines a child process class.
*/
#ifndef BOOST_PROCESS_CHILD_DECL_HPP
#define BOOST_PROCESS_CHILD_DECL_HPP
#include <boost/process/detail/config.hpp>
#include <chrono>
#include <memory>
#include <boost/none.hpp>
#include <atomic>
#if defined(BOOST_POSIX_API)
#include <boost/process/detail/posix/child_handle.hpp>
#include <boost/process/detail/posix/terminate.hpp>
#include <boost/process/detail/posix/wait_for_exit.hpp>
#include <boost/process/detail/posix/is_running.hpp>
#elif defined(BOOST_WINDOWS_API)
#include <boost/process/detail/windows/child_handle.hpp>
#include <boost/process/detail/windows/terminate.hpp>
#include <boost/process/detail/windows/wait_for_exit.hpp>
#include <boost/process/detail/windows/is_running.hpp>
#endif
namespace boost {
namespace process {
using ::boost::process::detail::api::pid_t;
class child
{
::boost::process::detail::api::child_handle _child_handle;
std::shared_ptr<std::atomic<int>> _exit_status = std::make_shared<std::atomic<int>>(::boost::process::detail::api::still_active);
bool _attached = true;
bool _terminated = false;
bool _exited()
{
return _terminated || !::boost::process::detail::api::is_running(_exit_status->load());
};
public:
typedef ::boost::process::detail::api::child_handle child_handle;
typedef child_handle::process_handle_t native_handle_t;
explicit child(child_handle &&ch, std::shared_ptr<std::atomic<int>> &ptr) : _child_handle(std::move(ch)), _exit_status(ptr) {}
explicit child(child_handle &&ch, const std::shared_ptr<std::atomic<int>> &ptr) : _child_handle(std::move(ch)), _exit_status(ptr) {}
explicit child(child_handle &&ch) : _child_handle(std::move(ch)) {}
explicit child(pid_t & pid) : _child_handle(pid), _attached(false) {};
child(const child&) = delete;
child(child && lhs) noexcept
: _child_handle(std::move(lhs._child_handle)),
_exit_status(std::move(lhs._exit_status)),
_attached (lhs._attached)
{
lhs._attached = false;
}
template<typename ...Args>
explicit child(Args&&...args);
child() {}
child& operator=(const child&) = delete;
child& operator=(child && lhs)
{
_child_handle= std::move(lhs._child_handle);
_exit_status = std::move(lhs._exit_status);
_attached = lhs._attached;
lhs._attached = false;
return *this;
};
void detach() {_attached = false; }
void join() {wait();}
bool joinable() { return _attached;}
~child()
{
std::error_code ec;
if (_attached && !_exited() && running(ec))
terminate(ec);
}
native_handle_t native_handle() const { return _child_handle.process_handle(); }
int exit_code() const {return ::boost::process::detail::api::eval_exit_status(_exit_status->load());}
pid_t id() const {return _child_handle.id(); }
bool running()
{
if (valid() && !_exited())
{
int code;
auto res = boost::process::detail::api::is_running(_child_handle, code);
if (!res && !_exited())
_exit_status->store(code);
return res;
}
return false;
}
void terminate()
{
if (valid() && running())
boost::process::detail::api::terminate(_child_handle);
_terminated = true;
}
void wait()
{
if (!_exited() && valid())
{
int exit_code = 0;
boost::process::detail::api::wait(_child_handle, exit_code);
_exit_status->store(exit_code);
}
}
template< class Rep, class Period >
bool wait_for (const std::chrono::duration<Rep, Period>& rel_time)
{
if (!_exited())
{
int exit_code = 0;
auto b = boost::process::detail::api::wait_for(_child_handle, exit_code, rel_time);
if (!b)
return false;
_exit_status->store(exit_code);
}
return true;
}
template< class Clock, class Duration >
bool wait_until(const std::chrono::time_point<Clock, Duration>& timeout_time )
{
if (!_exited())
{
int exit_code = 0;
auto b = boost::process::detail::api::wait_until(_child_handle, exit_code, timeout_time);
if (!b)
return false;
_exit_status->store(exit_code);
}
return true;
}
bool running(std::error_code & ec) noexcept
{
if (valid() && !_exited())
{
int code;
auto res = boost::process::detail::api::is_running(_child_handle, code, ec);
if (!res && !_exited())
_exit_status->store(code);
return res;
}
return false;
}
void terminate(std::error_code & ec) noexcept
{
if (valid() && running(ec))
boost::process::detail::api::terminate(_child_handle, ec);
_terminated = true;
}
void wait(std::error_code & ec) noexcept
{
if (!_exited() && valid())
{
int exit_code = 0;
boost::process::detail::api::wait(_child_handle, exit_code, ec);
_exit_status->store(exit_code);
}
}
template< class Rep, class Period >
bool wait_for (const std::chrono::duration<Rep, Period>& rel_time, std::error_code & ec) noexcept
{
if (!_exited())
{
int exit_code = 0;
auto b = boost::process::detail::api::wait_for(_child_handle, exit_code, rel_time, ec);
if (!b)
return false;
_exit_status->store(exit_code);
}
return true;
}
template< class Clock, class Duration >
bool wait_until(const std::chrono::time_point<Clock, Duration>& timeout_time, std::error_code & ec) noexcept
{
if (!_exited())
{
int exit_code = 0;
auto b = boost::process::detail::api::wait_until(_child_handle, exit_code, timeout_time, ec);
if (!b)
return false;
_exit_status->store(exit_code);
}
return true;
}
bool valid() const
{
return _child_handle.valid();
}
operator bool() const {return valid();}
bool in_group() const
{
return _child_handle.in_group();
}
bool in_group(std::error_code &ec) const noexcept
{
return _child_handle.in_group(ec);
}
};
}}
#endif
@@ -0,0 +1,99 @@
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
// Copyright (c) 2009 Boris Schaeling
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
// 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)
/**
* \file boost/process/config.hpp
*
* Defines various macros.
*/
#ifndef BOOST_PROCESS_DETAIL_CONFIG_HPP
#define BOOST_PROCESS_DETAIL_CONFIG_HPP
#include <boost/config.hpp>
#include <system_error>
#include <boost/system/api_config.hpp>
#include <boost/process/exception.hpp>
#if defined(BOOST_POSIX_API)
#include <errno.h>
#if defined(__GLIBC__)
#include <features.h>
#else
extern char **environ;
#endif
#elif defined(BOOST_WINDOWS_API)
#include <boost/detail/winapi/get_last_error.hpp>
#else
#error "System API not supported by boost.process"
#endif
namespace boost { namespace process { namespace detail
{
#if !defined(BOOST_PROCESS_PIPE_SIZE)
#define BOOST_PROCESS_PIPE_SIZE 1024
#endif
#if defined(BOOST_POSIX_API)
namespace posix {namespace extensions {}}
namespace api = posix;
inline std::error_code get_last_error() noexcept
{
return std::error_code(errno, std::system_category());
}
//copied from linux spec.
#if defined (__USE_XOPEN_EXTENDED) && !defined (__USE_XOPEN2K8) || defined( __USE_BSD)
#define BOOST_POSIX_HAS_VFORK 1
#endif
#elif defined(BOOST_WINDOWS_API)
namespace windows {namespace extensions {}}
namespace api = windows;
inline std::error_code get_last_error() noexcept
{
return std::error_code(::boost::detail::winapi::GetLastError(), std::system_category());
}
#endif
inline void throw_last_error(const std::string & msg)
{
throw process_error(get_last_error(), msg);
}
inline void throw_last_error()
{
throw process_error(get_last_error());
}
template<typename Char> constexpr Char null_char();
template<> constexpr char null_char<char> (){return '\0';}
template<> constexpr wchar_t null_char<wchar_t> (){return L'\0';}
template<typename Char> constexpr Char equal_sign();
template<> constexpr char equal_sign<char> () {return '='; }
template<> constexpr wchar_t equal_sign<wchar_t> () {return L'='; }
template<typename Char> constexpr Char quote_sign();
template<> constexpr char quote_sign<char> () {return '"'; }
template<> constexpr wchar_t quote_sign<wchar_t> () {return L'"'; }
template<typename Char> constexpr Char space_sign();
template<> constexpr char space_sign<char> () {return ' '; }
template<> constexpr wchar_t space_sign<wchar_t> () {return L' '; }
}}}
#endif
@@ -0,0 +1,284 @@
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
// Copyright (c) 2009 Boris Schaeling
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
// 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)
/**
* \file boost/process/execute.hpp
*
* Defines a function to execute a program.
*/
#ifndef BOOST_PROCESS_EXECUTE_HPP
#define BOOST_PROCESS_EXECUTE_HPP
#include <boost/process/detail/config.hpp>
#include <boost/process/detail/traits.hpp>
#if defined(BOOST_POSIX_API)
#include <boost/process/detail/posix/executor.hpp>
#elif defined(BOOST_WINDOWS_API)
#include <boost/process/detail/windows/executor.hpp>
#endif
#include <boost/process/detail/basic_cmd.hpp>
#include <boost/process/detail/handler.hpp>
#include <boost/fusion/view.hpp>
#include <boost/fusion/container.hpp>
#include <boost/fusion/sequence.hpp>
#include <boost/fusion/tuple.hpp>
#include <boost/fusion/algorithm/transformation/filter_if.hpp>
#include <boost/fusion/adapted/std_tuple.hpp>
#include <boost/fusion/container/vector/convert.hpp>
#include <type_traits>
#include <utility>
namespace boost { namespace process {
class child;
namespace detail {
template<typename ...Args>
struct has_wchar;
template<typename First, typename ...Args>
struct has_wchar<First, Args...>
{
typedef has_wchar<Args...> next;
typedef typename std::remove_cv<
typename std::remove_reference<First>::type>::type res_type;
constexpr static bool my_value = is_wchar_t<res_type>::value;
constexpr static bool value = my_value || next::value;
typedef std::integral_constant<bool, value> type;
};
template<typename First>
struct has_wchar<First>
{
typedef typename std::remove_cv<
typename std::remove_reference<First>::type>::type res_type;
constexpr static bool value = is_wchar_t<res_type>::value;
typedef std::integral_constant<bool, value> type;
};
#if defined(BOOST_WINDOWS_API)
//everything needs to be wchar_t
#if defined(BOOST_NO_ANSI_APIS)
template<bool has_wchar>
struct required_char_type
{
typedef wchar_t type;
};
#else
template<bool has_wchar> struct required_char_type;
template<> struct required_char_type<true>
{
typedef wchar_t type;
};
template<> struct required_char_type<false>
{
typedef char type;
};
#endif
#elif defined(BOOST_POSIX_API)
template<bool has_wchar>
struct required_char_type
{
typedef char type;
};
#endif
template<typename ... Args>
using required_char_type_t = typename required_char_type<
has_wchar<Args...>::value>::type;
template<typename Iterator, typename End, typename ...Args>
struct make_builders_from_view
{
typedef boost::fusion::set<Args...> set;
typedef typename boost::fusion::result_of::deref<Iterator>::type ref_type;
typedef typename std::remove_reference<ref_type>::type res_type;
typedef typename initializer_tag<res_type>::type tag;
typedef typename initializer_builder<tag>::type builder_type;
typedef typename boost::fusion::result_of::has_key<set, builder_type> has_key;
typedef typename boost::fusion::result_of::next<Iterator>::type next_itr;
typedef typename make_builders_from_view<next_itr, End>::type next;
typedef typename
std::conditional<has_key::value,
typename make_builders_from_view<next_itr, End, Args...>::type,
typename make_builders_from_view<next_itr, End, Args..., builder_type>::type
>::type type;
};
template<typename Iterator, typename ...Args>
struct make_builders_from_view<Iterator, Iterator, Args...>
{
typedef boost::fusion::set<Args...> type;
};
template<typename Builders>
struct builder_ref
{
Builders &builders;
builder_ref(Builders & builders) : builders(builders) {};
template<typename T>
void operator()(T && value) const
{
typedef typename initializer_tag<typename std::remove_reference<T>::type>::type tag;
typedef typename initializer_builder<tag>::type builder_type;
boost::fusion::at_key<builder_type>(builders)(std::forward<T>(value));
}
};
template<typename T>
struct get_initializers_result
{
typedef typename T::result_type type;
};
template<>
struct get_initializers_result<boost::fusion::void_>
{
typedef boost::fusion::void_ type;
};
template<typename ...Args>
struct helper_vector
{
};
template<typename T, typename ...Stack>
struct invoke_get_initializer_collect_keys;
template<typename ...Stack>
struct invoke_get_initializer_collect_keys<boost::fusion::vector<>, Stack...>
{
typedef helper_vector<Stack...> type;
};
template<typename First, typename ...Args, typename ...Stack>
struct invoke_get_initializer_collect_keys<boost::fusion::vector<First, Args...>, Stack...>
{
typedef typename invoke_get_initializer_collect_keys<boost::fusion::vector<Args...>, Stack..., First>::type next;
typedef helper_vector<Stack...> stack_t;
typedef typename std::conditional<std::is_same<boost::fusion::void_, First>::value,
stack_t, next>::type type;
};
template<typename Keys>
struct invoke_get_initializer;
template<typename ...Args>
struct invoke_get_initializer<helper_vector<Args...>>
{
typedef boost::fusion::tuple<typename get_initializers_result<Args>::type...> result_type;
template<typename Sequence>
static result_type call(Sequence & seq)
{
return result_type(boost::fusion::at_key<Args>(seq).get_initializer()...);;
}
};
template<typename ...Args>
inline boost::fusion::tuple<typename get_initializers_result<Args>::type...>
get_initializers(boost::fusion::set<Args...> & builders)
{
//typedef boost::fusion::tuple<typename get_initializers_result<Args>::type...> return_type;
typedef typename invoke_get_initializer_collect_keys<boost::fusion::vector<Args...>>::type keys;
return invoke_get_initializer<keys>::call(builders);
}
template<typename Char, typename ... Args>
inline child basic_execute_impl(Args && ... args)
{
//create a tuple from the argument list
boost::fusion::tuple<typename std::remove_reference<Args>::type&...> tup(args...);
auto inits = boost::fusion::filter_if<
boost::process::detail::is_initializer<
typename std::remove_reference<
boost::mpl::_
>::type
>
>(tup);
auto others = boost::fusion::filter_if<
boost::mpl::not_<
boost::process::detail::is_initializer<
typename std::remove_reference<
boost::mpl::_
>::type
>
>
>(tup);
// typename detail::make_builders_from_view<decltype(others)>::type builders;
//typedef typename boost::fusion::result_of::as_vector<decltype(inits)>::type inits_t;
typedef typename boost::fusion::result_of::as_vector<decltype(others)>::type others_t;
// typedef decltype(others) others_t;
typedef typename ::boost::process::detail::make_builders_from_view<
typename boost::fusion::result_of::begin<others_t>::type,
typename boost::fusion::result_of::end <others_t>::type>::type builder_t;
builder_t builders;
::boost::process::detail::builder_ref<builder_t> builder_ref(builders);
boost::fusion::for_each(others, builder_ref);
auto other_inits = ::boost::process::detail::get_initializers(builders);
boost::fusion::joint_view<decltype(other_inits), decltype(inits)> complete_inits(other_inits, inits);
auto exec = boost::process::detail::api::make_executor<Char>(complete_inits);
return exec();
}
template<typename ...Args>
inline child execute_impl(Args&& ... args)
{
typedef required_char_type_t<Args...> req_char_type;
return basic_execute_impl<req_char_type>(
boost::process::detail::char_converter_t<req_char_type, Args>::conv(
std::forward<Args>(args))...
);
}
}}}
#endif
@@ -0,0 +1,75 @@
// 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_HANDLER_HPP_
#define BOOST_PROCESS_DETAIL_HANDLER_HPP_
#include <boost/process/detail/config.hpp>
#if defined(BOOST_POSIX_API)
#include <boost/process/detail/posix/handler.hpp>
#elif defined(BOOST_WINDOWS_API)
#include <boost/process/detail/windows/handler.hpp>
#endif
namespace boost { namespace process { namespace detail {
//extended handler base.
typedef api::handler_base_ext handler;
template <class Handler>
struct on_setup_ : handler
{
explicit on_setup_(Handler handler) : handler_(handler) {}
template <class Executor>
void on_setup(Executor &e)
{
handler_(e);
}
private:
Handler handler_;
};
template <class Handler>
struct on_error_ : handler
{
explicit on_error_(Handler handler) : handler_(handler) {}
template <class Executor>
void on_error(Executor &e, const std::error_code &ec)
{
handler_(e, ec);
}
private:
Handler handler_;
};
template <class Handler>
struct on_success_ : handler
{
explicit on_success_(Handler handler) : handler_(handler) {}
template <class Executor>
void on_success(Executor &e)
{
handler_(e);
}
private:
Handler handler_;
};
}
}}
#endif /* BOOST_PROCESS_DETAIL_HANDLER_HPP_ */
@@ -0,0 +1,49 @@
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
// Copyright (c) 2009 Boris Schaeling
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
// 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_HANDLER_BASE_HPP
#define BOOST_PROCESS_DETAIL_HANDLER_BASE_HPP
#include <system_error>
namespace boost { namespace process { namespace detail {
template<template <class> class Template>
struct make_handler_t
{
constexpr make_handler_t() {}
template<typename Handler>
constexpr Template<Handler> operator()(Handler handler) const {return Template<Handler>(handler);}
template<typename Handler>
constexpr Template<Handler> operator= (Handler handler) const {return Template<Handler>(handler);}
template<typename Handler>
constexpr Template<Handler> operator+=(Handler handler) const {return Template<Handler>(handler);}
};
struct handler_base
{
using resource_type = void;
template <class Executor>
void on_setup(Executor&) const {}
template <class Executor>
void on_error(Executor&, const std::error_code &) const {}
template <class Executor>
void on_success(Executor&) const {}
};
}}}
#endif
@@ -0,0 +1,53 @@
// 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_ON_EXIT_HPP_
#define BOOST_PROCESS_DETAIL_ON_EXIT_HPP_
#include <boost/process/detail/config.hpp>
#if defined(BOOST_POSIX_API)
#include <boost/process/detail/posix/on_exit.hpp>
#elif defined(BOOST_WINDOWS_API)
#include <boost/process/detail/windows/on_exit.hpp>
#endif
#include <future>
#include <memory>
namespace boost { namespace process { namespace detail {
inline std::function<void(int, const std::error_code &)> on_exit_from_future(std::future<int> &f)
{
std::shared_ptr<std::promise<int>> promise = std::make_shared<std::promise<int>>();
f = promise->get_future();
return [promise](int code, const std::error_code & ec)
{
if (ec)
promise->set_exception(
std::make_exception_ptr(process_error(ec, "on_exit failed with error"))
);
else
promise->set_value(code);
};
}
struct on_exit_
{
api::on_exit_ operator= (const std::function<void(int, const std::error_code&)> & f) const {return f;}
api::on_exit_ operator()(const std::function<void(int, const std::error_code&)> & f) const {return f;}
api::on_exit_ operator= (std::future<int> &f) const {return on_exit_from_future(f);}
api::on_exit_ operator()(std::future<int> &f) const {return on_exit_from_future(f);}
};
}
constexpr static ::boost::process::detail::on_exit_ on_exit{};
}}
#endif /* INCLUDE_BOOST_PROCESS_WINDOWS_ON_EXIT_HPP_ */
@@ -0,0 +1,79 @@
// 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_POSIX_ASIO_FWD_HPP_
#define BOOST_PROCESS_DETAIL_POSIX_ASIO_FWD_HPP_
#include <memory>
namespace boost { namespace asio {
class mutable_buffer;
class mutable_buffers_1;
class const_buffer;
class const_buffers_1;
template<typename Allocator>
class basic_streambuf;
typedef basic_streambuf<std::allocator<char>> streambuf;
class io_service;
class signal_set_service;
template <typename SignalSetService>
class basic_signal_set;
typedef basic_signal_set<signal_set_service> signal_set;
template <typename Handler>
class basic_yield_context;
namespace posix {
class stream_descriptor_service;
template <typename StreamDesscriptorService>
class basic_stream_descriptor;
typedef basic_stream_descriptor<stream_descriptor_service> stream_descriptor;
class object_handle_service;
template <typename ObjectHandleService>
class basic_object_handle;
typedef basic_object_handle<object_handle_service> object_handle;
} //posix
} //asio
namespace process { namespace detail { namespace posix {
class async_pipe;
template<typename T>
struct async_in_buffer;
template<int p1, int p2, typename Buffer>
struct async_out_buffer;
template<int p1, int p2, typename Type>
struct async_out_future;
} // posix
} // detail
using ::boost::process::detail::posix::async_pipe;
} // process
} // boost
#endif /* BOOST_PROCESS_DETAIL_POSIX_ASIO_FWD_HPP_ */
@@ -0,0 +1,40 @@
// 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_POSIX_ASYNC_HANDLER_HPP_
#define BOOST_PROCESS_POSIX_ASYNC_HANDLER_HPP_
#include <boost/process/detail/posix/handler.hpp>
#include <type_traits>
namespace boost { namespace process { namespace detail { namespace posix {
struct require_io_service {};
struct async_handler : handler_base_ext, require_io_service
{
};
template<typename T>
struct is_async_handler : std::is_base_of<async_handler, T> {};
template<typename T>
struct is_async_handler<T&> : std::is_base_of<async_handler, T> {};
template<typename T>
struct is_async_handler<const T&> : std::is_base_of<async_handler, T> {};
template<typename T>
struct does_require_io_service : std::is_base_of<require_io_service, T> {};
template<typename T>
struct does_require_io_service<T&> : std::is_base_of<require_io_service, T> {};
template<typename T>
struct does_require_io_service<const T&> : std::is_base_of<require_io_service, T> {};
}}}}
#endif /* BOOST_PROCESS_WINDOWS_ASYNC_HANDLER_HPP_ */
@@ -0,0 +1,95 @@
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
// Copyright (c) 2009 Boris Schaeling
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
//
// 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_POSIX_ASYNC_IN_HPP
#define BOOST_PROCESS_DETAIL_POSIX_ASYNC_IN_HPP
#include <boost/process/detail/handler_base.hpp>
#include <boost/process/detail/posix/async_handler.hpp>
#include <boost/asio/write.hpp>
#include <boost/process/async_pipe.hpp>
#include <memory>
#include <future>
namespace boost { namespace process { namespace detail { namespace posix {
template<typename Buffer>
struct async_in_buffer : ::boost::process::detail::posix::handler_base_ext,
::boost::process::detail::posix::require_io_service
{
Buffer & buf;
std::shared_ptr<std::promise<void>> promise;
async_in_buffer operator>(std::future<void> & fut)
{
promise = std::make_shared<std::promise<void>>();
fut = promise->get_future(); return std::move(*this);
}
std::shared_ptr<boost::process::async_pipe> pipe;
async_in_buffer(Buffer & buf) : buf(buf)
{
}
template <typename Executor>
inline void on_success(Executor &exec)
{
auto pipe = this->pipe;
if (this->promise)
{
auto promise = this->promise;
boost::asio::async_write(*pipe, buf,
[pipe, promise](const boost::system::error_code & ec, std::size_t)
{
if (ec && (ec.value() != EBADF) && (ec.value() != EPERM) && (ec.value() != ENOENT))
{
std::error_code e(ec.value(), std::system_category());
promise->set_exception(std::make_exception_ptr(process_error(e)));
}
else
promise->set_value();
});
}
else
boost::asio::async_write(*pipe, buf,
[pipe](const boost::system::error_code&ec, std::size_t size){});
std::move(*pipe).source().close();
this->pipe = nullptr;
}
template<typename Executor>
void on_error(Executor &, const std::error_code &) const
{
std::move(*pipe).source().close();
}
template<typename Executor>
void on_setup(Executor & exec)
{
pipe = std::make_shared<boost::process::async_pipe>(get_io_service(exec.seq));
}
template <typename Executor>
void on_exec_setup(Executor &exec)
{
if (::dup2(pipe->native_source(), STDIN_FILENO) == -1)
exec.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
::close(pipe->native_source());
}
};
}}}}
#endif
@@ -0,0 +1,170 @@
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
// Copyright (c) 2009 Boris Schaeling
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
//
// 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_POSIX_ASYNC_OUT_HPP
#define BOOST_PROCESS_DETAIL_POSIX_ASYNC_OUT_HPP
#include <boost/process/detail/posix/handler.hpp>
#include <boost/asio/posix/stream_descriptor.hpp>
#include <boost/asio/read.hpp>
#include <boost/process/async_pipe.hpp>
#include <istream>
#include <memory>
#include <exception>
#include <future>
namespace boost { namespace process { namespace detail { namespace posix {
inline int apply_out_handles(int handle, std::integral_constant<int, 1>, std::integral_constant<int, -1>)
{
return ::dup2(handle, STDOUT_FILENO);
}
inline int apply_out_handles(int handle, std::integral_constant<int, 2>, std::integral_constant<int, -1>)
{
return ::dup2(handle, STDERR_FILENO);
}
inline int apply_out_handles(int handle, std::integral_constant<int, 1>, std::integral_constant<int, 2>)
{
if (::dup2(handle, STDOUT_FILENO) == -1)
return -1;
if (::dup2(handle, STDERR_FILENO) == -1)
return -1;
return 0;
}
template<int p1, int p2, typename Buffer>
struct async_out_buffer : ::boost::process::detail::posix::handler_base_ext,
::boost::process::detail::posix::require_io_service
{
Buffer & buf;
std::shared_ptr<boost::process::async_pipe> pipe;
async_out_buffer(Buffer & buf) : buf(buf)
{
}
template <typename Executor>
inline void on_success(Executor &exec)
{
auto pipe = this->pipe;
boost::asio::async_read(*pipe, buf,
[pipe](const boost::system::error_code&, std::size_t size){});
this->pipe = nullptr;
std::move(*pipe).sink().close();
}
template<typename Executor>
void on_error(Executor &, const std::error_code &) const
{
std::move(*pipe).sink().close();
}
template<typename Executor>
void on_setup(Executor & exec)
{
pipe = std::make_shared<boost::process::async_pipe>(get_io_service(exec.seq));
}
template <typename Executor>
void on_exec_setup(Executor &exec)
{
int res = apply_out_handles(pipe->native_sink(),
std::integral_constant<int, p1>(), std::integral_constant<int, p2>());
if (res == -1)
exec.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
::close(pipe->native_sink());
}
};
template<int p1, int p2, typename Type>
struct async_out_future : ::boost::process::detail::posix::handler_base_ext,
::boost::process::detail::posix::require_io_service
{
std::shared_ptr<std::promise<Type>> promise = std::make_shared<std::promise<Type>>();
std::shared_ptr<boost::asio::streambuf> buffer = std::make_shared<boost::asio::streambuf>();
std::shared_ptr<boost::process::async_pipe> pipe;
async_out_future(std::future<Type> & fut)
{
fut = promise->get_future();
}
template <typename Executor>
inline void on_success(Executor &exec)
{
auto pipe = this->pipe;
auto buffer = this->buffer;
auto promise = this->promise;
boost::asio::async_read(*pipe, *buffer,
[pipe, buffer, promise](const boost::system::error_code& ec, std::size_t size)
{
if (ec && (ec.value() != ENOENT))
{
std::error_code e(ec.value(), std::system_category());
promise->set_exception(std::make_exception_ptr(process_error(e)));
}
else
{
std::istream is (buffer.get());
Type arg;
arg.resize(buffer->size());
is.read(&*arg.begin(), buffer->size());
promise->set_value(std::move(arg));
}
});
std::move(*pipe).sink().close();
this->pipe = nullptr;
}
template<typename Executor>
void on_error(Executor &, const std::error_code &) const
{
std::move(*pipe).sink().close();
}
template<typename Executor>
void on_setup(Executor & exec)
{
pipe = std::make_shared<boost::process::async_pipe>(get_io_service(exec.seq));
}
template <typename Executor>
void on_exec_setup(Executor &exec)
{
int res = apply_out_handles(pipe->native_sink(),
std::integral_constant<int, p1>(), std::integral_constant<int, p2>());
if (res == -1)
exec.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
::close(pipe->native_sink());
}
};
}}}}
#endif
@@ -0,0 +1,355 @@
// 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_POSIX_ASYNC_PIPE_HPP_
#define BOOST_PROCESS_DETAIL_POSIX_ASYNC_PIPE_HPP_
#include <boost/process/detail/posix/basic_pipe.hpp>
#include <boost/asio/posix/stream_descriptor.hpp>
#include <system_error>
#include <string>
namespace boost { namespace process { namespace detail { namespace posix {
class async_pipe
{
::boost::asio::posix::stream_descriptor _source;
::boost::asio::posix::stream_descriptor _sink ;
public:
typedef int native_handle_type;
typedef ::boost::asio::posix::stream_descriptor handle_type;
inline async_pipe(boost::asio::io_service & ios) : async_pipe(ios, ios) {}
inline async_pipe(boost::asio::io_service & ios_source,
boost::asio::io_service & ios_sink) : _source(ios_source), _sink(ios_sink)
{
int fds[2];
if (::pipe(fds) == -1)
boost::process::detail::throw_last_error("pipe(2) failed");
_source.assign(fds[0]);
_sink .assign(fds[1]);
};
inline async_pipe(boost::asio::io_service & ios, const std::string & name)
: async_pipe(ios, ios, name) {}
inline async_pipe(boost::asio::io_service & ios_source,
boost::asio::io_service & io_sink, const std::string & name);
inline async_pipe(const async_pipe& lhs);
async_pipe(async_pipe&& lhs) : _source(std::move(lhs._source)), _sink(std::move(lhs._sink))
{
lhs._source.assign (-1);
lhs._sink .assign (-1);
}
template<class CharT, class Traits = std::char_traits<CharT>>
explicit async_pipe(::boost::asio::io_service & ios_source,
::boost::asio::io_service & ios_sink,
const basic_pipe<CharT, Traits> & p)
: _source(ios_source, p.native_source()), _sink(ios_sink, p.native_sink())
{
}
template<class CharT, class Traits = std::char_traits<CharT>>
explicit async_pipe(boost::asio::io_service & ios, const basic_pipe<CharT, Traits> & p)
: async_pipe(ios, ios, p)
{
}
template<class CharT, class Traits = std::char_traits<CharT>>
inline async_pipe& operator=(const basic_pipe<CharT, Traits>& p);
inline async_pipe& operator=(const async_pipe& rhs);
inline async_pipe& operator=(async_pipe&& lhs);
~async_pipe()
{
if (_sink .native() != -1)
::close(_sink.native());
if (_source.native() != -1)
::close(_source.native());
}
template<class CharT, class Traits = std::char_traits<CharT>>
inline explicit operator basic_pipe<CharT, Traits>() const;
void cancel()
{
if (_sink.is_open())
_sink.cancel();
if (_source.is_open())
_source.cancel();
}
void close()
{
if (_sink.is_open())
_sink.close();
if (_source.is_open())
_source.close();
}
void close(boost::system::error_code & ec)
{
if (_sink.is_open())
_sink.close(ec);
if (_source.is_open())
_source.close(ec);
}
bool is_open() const
{
return _sink.is_open() || _source.is_open();
}
void async_close()
{
if (_sink.is_open())
_sink.get_io_service(). post([this]{_sink.close();});
if (_source.is_open())
_source.get_io_service().post([this]{_source.close();});
}
template<typename MutableBufferSequence>
std::size_t read_some(const MutableBufferSequence & buffers)
{
return _source.read_some(buffers);
}
template<typename MutableBufferSequence>
std::size_t write_some(const MutableBufferSequence & buffers)
{
return _sink.write_some(buffers);
}
native_handle_type native_source() const {return const_cast<boost::asio::posix::stream_descriptor&>(_source).native();}
native_handle_type native_sink () const {return const_cast<boost::asio::posix::stream_descriptor&>(_sink ).native();}
template<typename MutableBufferSequence,
typename ReadHandler>
BOOST_ASIO_INITFN_RESULT_TYPE(
ReadHandler, void(boost::system::error_code, std::size_t))
async_read_some(
const MutableBufferSequence & buffers,
ReadHandler &&handler)
{
_source.async_read_some(buffers, std::forward<ReadHandler>(handler));
}
template<typename ConstBufferSequence,
typename WriteHandler>
BOOST_ASIO_INITFN_RESULT_TYPE(
WriteHandler, void(boost::system::error_code, std::size_t))
async_write_some(
const ConstBufferSequence & buffers,
WriteHandler&& handler)
{
_sink.async_write_some(buffers, std::forward<WriteHandler>(handler));
}
const handle_type & sink () const & {return _sink;}
const handle_type & source() const & {return _source;}
handle_type && sink() && { return std::move(_sink); }
handle_type && source()&& { return std::move(_source); }
handle_type source(::boost::asio::io_service& ios) &&
{
::boost::asio::posix::stream_descriptor stolen(ios, _source.release());
return stolen;
}
handle_type sink (::boost::asio::io_service& ios) &&
{
::boost::asio::posix::stream_descriptor stolen(ios, _sink.release());
return stolen;
}
handle_type source(::boost::asio::io_service& ios) const &
{
auto source_in = const_cast<::boost::asio::posix::stream_descriptor &>(_source).native();
return ::boost::asio::posix::stream_descriptor(ios, ::dup(source_in));
}
handle_type sink (::boost::asio::io_service& ios) const &
{
auto sink_in = const_cast<::boost::asio::posix::stream_descriptor &>(_sink).native();
return ::boost::asio::posix::stream_descriptor(ios, ::dup(sink_in));
}
};
async_pipe::async_pipe(boost::asio::io_service & ios_source,
boost::asio::io_service & ios_sink,
const std::string & name) : _source(ios_source), _sink(ios_sink)
{
auto fifo = mkfifo(name.c_str(), 0666 );
if (fifo != 0)
boost::process::detail::throw_last_error("mkfifo() failed");
int read_fd = open(name.c_str(), O_RDWR);
if (read_fd == -1)
boost::process::detail::throw_last_error();
int write_fd = dup(read_fd);
if (write_fd == -1)
boost::process::detail::throw_last_error();
_source.assign(read_fd);
_sink .assign(write_fd);
}
async_pipe::async_pipe(const async_pipe & p) :
_source(const_cast<async_pipe&>(p)._source.get_io_service()),
_sink( const_cast<async_pipe&>(p)._sink.get_io_service())
{
//cannot get the handle from a const object.
auto source_in = const_cast<::boost::asio::posix::stream_descriptor &>(_source).native();
auto sink_in = const_cast<::boost::asio::posix::stream_descriptor &>(_sink).native();
if (source_in == -1)
_source.assign(-1);
else
{
_source.assign(::dup(source_in));
if (_source.native()== -1)
::boost::process::detail::throw_last_error("dup()");
}
if (sink_in == -1)
_sink.assign(-1);
else
{
_sink.assign(::dup(sink_in));
if (_sink.native() == -1)
::boost::process::detail::throw_last_error("dup()");
}
}
async_pipe& async_pipe::operator=(const async_pipe & p)
{
int source;
int sink;
//cannot get the handle from a const object.
auto source_in = const_cast<::boost::asio::posix::stream_descriptor &>(_source).native();
auto sink_in = const_cast<::boost::asio::posix::stream_descriptor &>(_sink).native();
if (source_in == -1)
source = -1;
else
{
source = ::dup(source_in);
if (source == -1)
::boost::process::detail::throw_last_error("dup()");
}
if (sink_in == -1)
sink = -1;
else
{
sink = ::dup(sink_in);
if (sink == -1)
::boost::process::detail::throw_last_error("dup()");
}
_source.assign(source);
_sink. assign(sink);
return *this;
}
async_pipe& async_pipe::operator=(async_pipe && lhs)
{
if (_source.native_handle() == -1)
::close(_source.native());
if (_sink.native_handle() == -1)
::close(_sink.native());
_source.assign(lhs._source.native_handle());
_sink .assign(lhs._sink .native_handle());
lhs._source.assign(-1);
lhs._sink .assign(-1);
return *this;
}
template<class CharT, class Traits>
async_pipe::operator basic_pipe<CharT, Traits>() const
{
int source;
int sink;
//cannot get the handle from a const object.
auto source_in = const_cast<::boost::asio::posix::stream_descriptor &>(_source).native();
auto sink_in = const_cast<::boost::asio::posix::stream_descriptor &>(_sink).native();
if (source_in == -1)
source = -1;
else
{
source = ::dup(source_in);
if (source == -1)
::boost::process::detail::throw_last_error("dup()");
}
if (sink_in == -1)
sink = -1;
else
{
sink = ::dup(sink_in);
if (sink == -1)
::boost::process::detail::throw_last_error("dup()");
}
return basic_pipe<CharT, Traits>{source, sink};
}
inline bool operator==(const async_pipe & lhs, const async_pipe & rhs)
{
return compare_handles(lhs.native_source(), rhs.native_source()) &&
compare_handles(lhs.native_sink(), rhs.native_sink());
}
inline bool operator!=(const async_pipe & lhs, const async_pipe & rhs)
{
return !compare_handles(lhs.native_source(), rhs.native_source()) ||
!compare_handles(lhs.native_sink(), rhs.native_sink());
}
template<class Char, class Traits>
inline bool operator==(const async_pipe & lhs, const basic_pipe<Char, Traits> & rhs)
{
return compare_handles(lhs.native_source(), rhs.native_source()) &&
compare_handles(lhs.native_sink(), rhs.native_sink());
}
template<class Char, class Traits>
inline bool operator!=(const async_pipe & lhs, const basic_pipe<Char, Traits> & rhs)
{
return !compare_handles(lhs.native_source(), rhs.native_source()) ||
!compare_handles(lhs.native_sink(), rhs.native_sink());
}
template<class Char, class Traits>
inline bool operator==(const basic_pipe<Char, Traits> & lhs, const async_pipe & rhs)
{
return compare_handles(lhs.native_source(), rhs.native_source()) &&
compare_handles(lhs.native_sink(), rhs.native_sink());
}
template<class Char, class Traits>
inline bool operator!=(const basic_pipe<Char, Traits> & lhs, const async_pipe & rhs)
{
return !compare_handles(lhs.native_source(), rhs.native_source()) ||
!compare_handles(lhs.native_sink(), rhs.native_sink());
}
}}}}
#endif /* INCLUDE_BOOST_PIPE_DETAIL_WINDOWS_ASYNC_PIPE_HPP_ */
@@ -0,0 +1,177 @@
// 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_POSIX_BASIC_CMD_HPP_
#define BOOST_PROCESS_DETAIL_POSIX_BASIC_CMD_HPP_
#include <boost/process/detail/posix/handler.hpp>
#include <boost/process/detail/posix/cmd.hpp>
#include <boost/algorithm/string/replace.hpp>
#include <boost/process/shell.hpp>
#include <boost/algorithm/string/trim.hpp>
#include <boost/algorithm/string/join.hpp>
#include <string>
#include <vector>
namespace boost
{
namespace process
{
namespace detail
{
namespace posix
{
inline std::string build_cmd_shell(const std::string & exe, std::vector<std::string> && data)
{
std::string st = exe;
for (auto & arg : data)
{
boost::replace_all(arg, "\"", "\\\"");
auto it = std::find(arg.begin(), arg.end(), ' ');//contains space?
if (it != arg.end())//ok, contains spaces.
{
//the first one is put directly onto the output,
//because then I don't have to copy the whole string
arg.insert(arg.begin(), '"' );
arg += '"'; //thats the post one.
}
if (!st.empty())//first one does not need a preceeding space
st += ' ';
st += arg;
}
return st ;
}
inline std::vector<std::string> build_args(const std::string & data)
{
std::vector<std::string> st;
typedef std::string::const_iterator itr_t;
//normal quotes outside can be stripped, inside ones marked as \" will be replaced.
auto make_entry = [](const itr_t & begin, const itr_t & end)
{
std::string data;
if ((*begin == '"') && (*(end-1) == '"'))
data.assign(begin+1, end-1);
else
data.assign(begin, end);
boost::replace_all(data, "\\\"", "\"");
return data;
};
bool in_quote = false;
auto part_beg = data.cbegin();
auto itr = data.cbegin();
for (; itr != data.cend(); itr++)
{
if (*itr == '"')
in_quote ^= true;
if (!in_quote && (*itr == ' '))
{
//alright, got a space
if ((itr != data.cbegin()) && (*(itr -1) != ' ' ))
st.push_back(make_entry(part_beg, itr));
part_beg = itr+1;
}
}
if (part_beg != itr)
st.emplace_back(make_entry(part_beg, itr));
return st;
}
template<typename Char>
struct exe_cmd_init;
template<>
struct exe_cmd_init<char> : boost::process::detail::api::handler_base_ext
{
exe_cmd_init(const exe_cmd_init & ) = delete;
exe_cmd_init(exe_cmd_init && ) = default;
exe_cmd_init(std::string && exe, std::vector<std::string> && args)
: exe(std::move(exe)), args(std::move(args)) {};
template <class Executor>
void on_setup(Executor& exec)
{
if (exe.empty()) //cmd style
{
exec.exe = args.front().c_str();
exec.cmd_style = true;
}
else
exec.exe = &exe.front();
if (!args.empty())
{
cmd_impl = make_cmd();
exec.cmd_line = cmd_impl.data();
}
}
static exe_cmd_init exe_args(std::string && exe, std::vector<std::string> && args) {return exe_cmd_init(std::move(exe), std::move(args));}
static exe_cmd_init cmd (std::string && cmd)
{
auto args = build_args(cmd);
return exe_cmd_init({}, std::move(args));
}
static exe_cmd_init exe_args_shell(std::string&& exe, std::vector<std::string> && args)
{
auto cmd = build_cmd_shell(std::move(exe), std::move(args));
std::vector<std::string> args_ = {"-c", std::move(cmd)};
std::string sh = shell().string();
return exe_cmd_init(std::move(sh), std::move(args_));
}
static exe_cmd_init cmd_shell(std::string&& cmd)
{
std::vector<std::string> args = {"-c", "\"" + cmd + "\""};
std::string sh = shell().string();
return exe_cmd_init(
std::move(sh),
{std::move(args)});
}
private:
inline std::vector<char*> make_cmd();
std::string exe;
std::vector<std::string> args;
std::vector<char*> cmd_impl;
};
std::vector<char*> exe_cmd_init<char>::make_cmd()
{
std::vector<char*> vec;
if (!exe.empty())
vec.push_back(&exe.front());
for (auto & v : args)
vec.push_back(&v.front());
vec.push_back(nullptr);
return vec;
}
}}}}
#endif
@@ -0,0 +1,193 @@
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
// Copyright (c) 2009 Boris Schaeling
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
//
// 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_POSIX_PIPE_HPP
#define BOOST_PROCESS_POSIX_PIPE_HPP
#include <boost/filesystem.hpp>
#include <boost/process/detail/posix/compare_handles.hpp>
#include <system_error>
#include <array>
#include <unistd.h>
#include <fcntl.h>
#include <memory>
namespace boost { namespace process { namespace detail { namespace posix {
template<class CharT, class Traits = std::char_traits<CharT>>
class basic_pipe
{
int _source = -1;
int _sink = -1;
public:
explicit basic_pipe(int source, int sink) : _source(source), _sink(sink) {}
explicit basic_pipe(int source, int sink, const std::string & name) : _source(source), _sink(sink) {}
typedef CharT char_type ;
typedef Traits traits_type;
typedef typename Traits::int_type int_type ;
typedef typename Traits::pos_type pos_type ;
typedef typename Traits::off_type off_type ;
typedef int native_handle_type;
basic_pipe()
{
int fds[2];
if (::pipe(fds) == -1)
boost::process::detail::throw_last_error("pipe(2) failed");
_source = fds[0];
_sink = fds[1];
}
inline basic_pipe(const basic_pipe& rhs);
explicit inline basic_pipe(const std::string& name);
basic_pipe(basic_pipe&& lhs) : _source(lhs._source), _sink(lhs._sink)
{
lhs._source = -1;
lhs._sink = -1;
}
inline basic_pipe& operator=(const basic_pipe& );
basic_pipe& operator=(basic_pipe&& lhs)
{
_source = lhs._source;
_sink = lhs._sink ;
lhs._source = -1;
lhs._sink = -1;
return *this;
}
~basic_pipe()
{
if (_sink != -1)
::close(_sink);
if (_source != -1)
::close(_source);
}
native_handle_type native_source() const {return _source;}
native_handle_type native_sink () const {return _sink;}
void assign_source(native_handle_type h) { _source = h;}
void assign_sink (native_handle_type h) { _sink = h;}
int_type write(const char_type * data, int_type count)
{
auto write_len = ::write(_sink, data, count * sizeof(char_type));
if (write_len == -1)
::boost::process::detail::throw_last_error();
return write_len;
}
int_type read(char_type * data, int_type count)
{
auto read_len = ::read(_source, data, count * sizeof(char_type));
if (read_len == -1)
::boost::process::detail::throw_last_error();
return read_len;
}
bool is_open()
{
return (_source != -1) ||
(_sink != -1);
}
void close()
{
::close(_source);
::close(_sink);
_source = -1;
_sink = -1;
}
};
template<class CharT, class Traits>
basic_pipe<CharT, Traits>::basic_pipe(const basic_pipe & rhs)
{
if (rhs._source != -1)
{
_source = ::dup(rhs._source);
if (_source == -1)
::boost::process::detail::throw_last_error("dup() failed");
}
if (rhs._sink != -1)
{
_sink = ::dup(rhs._sink);
if (_sink == -1)
::boost::process::detail::throw_last_error("dup() failed");
}
}
template<class CharT, class Traits>
basic_pipe<CharT, Traits> &basic_pipe<CharT, Traits>::operator=(const basic_pipe & rhs)
{
if (rhs._source != -1)
{
_source = ::dup(rhs._source);
if (_source == -1)
::boost::process::detail::throw_last_error("dup() failed");
}
if (rhs._sink != -1)
{
_sink = ::dup(rhs._sink);
if (_sink == -1)
::boost::process::detail::throw_last_error("dup() failed");
}
return *this;
}
template<class CharT, class Traits>
basic_pipe<CharT, Traits>::basic_pipe(const std::string & name)
{
auto fifo = mkfifo(name.c_str(), 0666 );
if (fifo != 0)
boost::process::detail::throw_last_error("mkfifo() failed");
int read_fd = open(name.c_str(), O_RDWR);
if (read_fd == -1)
boost::process::detail::throw_last_error();
int write_fd = dup(read_fd);
if (write_fd == -1)
boost::process::detail::throw_last_error();
_sink = write_fd;
_source = read_fd;
::unlink(name.c_str());
}
template<class Char, class Traits>
inline bool operator==(const basic_pipe<Char, Traits> & lhs, const basic_pipe<Char, Traits> & rhs)
{
return compare_handles(lhs.native_source(), rhs.native_source()) &&
compare_handles(lhs.native_sink(), rhs.native_sink());
}
template<class Char, class Traits>
inline bool operator!=(const basic_pipe<Char, Traits> & lhs, const basic_pipe<Char, Traits> & rhs)
{
return !compare_handles(lhs.native_source(), rhs.native_source()) ||
!compare_handles(lhs.native_sink(), rhs.native_sink());
}
}}}}
#endif
@@ -0,0 +1,60 @@
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
// Copyright (c) 2009 Boris Schaeling
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
//
// 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_POSIX_CHILD_HPP
#define BOOST_PROCESS_POSIX_CHILD_HPP
#include <utility>
#include <system_error>
namespace boost { namespace process { namespace detail { namespace posix {
typedef ::pid_t pid_t;
struct child_handle
{
int pid {-1};
explicit child_handle(int pid) : pid(pid)
{}
child_handle() = default;
~child_handle() = default;
child_handle(const child_handle & c) = delete;
child_handle(child_handle && c) : pid(c.pid)
{
c.pid = -1;
}
child_handle &operator=(const child_handle & c) = delete;
child_handle &operator=(child_handle && c)
{
pid = c.pid;
c.pid = -1;
return *this;
}
int id() const
{
return pid;
}
bool in_group() const {return true;}
bool in_group(std::error_code &ec) const noexcept {return true;}
typedef int process_handle_t;
process_handle_t process_handle() const { return pid; }
bool valid() const
{
return pid != -1;
}
};
}}}}
#endif
@@ -0,0 +1,30 @@
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
// Copyright (c) 2009 Boris Schaeling
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
//
// 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_WINDOWS_INITIALIZERS_CLOSE_IN_HPP
#define BOOST_PROCESS_WINDOWS_INITIALIZERS_CLOSE_IN_HPP
#include <boost/process/detail/posix/handler.hpp>
namespace boost { namespace process { namespace detail { namespace posix {
struct close_in : handler_base_ext
{
template <class Executor>
void on_exec_setup(Executor &e) const
{
if (::close(STDIN_FILENO) == -1)
e.set_error(::boost::process::detail::get_last_error(), "close() failed");
}
};
}}}}
#endif
@@ -0,0 +1,55 @@
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
// Copyright (c) 2009 Boris Schaeling
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
//
// 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_POSIX_CLOSE_OUT_HPP
#define BOOST_PROCESS_DETAIL_POSIX_CLOSE_OUT_HPP
#include <boost/process/detail/posix/handler.hpp>
namespace boost { namespace process { namespace detail { namespace posix {
template<int p1, int p2>
struct close_out : handler_base_ext
{
template <class Executor>
inline void on_exec_setup(Executor &e) const;
};
template<>
template<typename Executor>
void close_out<1,-1>::on_exec_setup(Executor &e) const
{
if (::close(STDOUT_FILENO) == -1)
e.set_error(::boost::process::detail::get_last_error(), "close() failed");
}
template<>
template<typename Executor>
void close_out<2,-1>::on_exec_setup(Executor &e) const
{
if (::close(STDERR_FILENO) == -1)
e.set_error(::boost::process::detail::get_last_error(), "close() failed");
}
template<>
template<typename Executor>
void close_out<1,2>::on_exec_setup(Executor &e) const
{
if (::close(STDOUT_FILENO) == -1)
e.set_error(::boost::process::detail::get_last_error(), "close() failed");
if (::close(STDERR_FILENO) == -1)
e.set_error(::boost::process::detail::get_last_error(), "close() failed");
}
}}}}
#endif
@@ -0,0 +1,104 @@
// 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_POSIX_CMD_HPP_
#define BOOST_PROCESS_DETAIL_POSIX_CMD_HPP_
#include <boost/process/detail/config.hpp>
#include <boost/process/detail/posix/handler.hpp>
#include <string>
#include <vector>
namespace boost
{
namespace process
{
namespace detail
{
namespace posix
{
template<typename Char>
inline std::vector<std::basic_string<Char>> build_cmd(const std::basic_string<Char> & value)
{
std::vector<std::basic_string<Char>> ret;
bool in_quotes = false;
auto beg = value.begin();
for (auto itr = value.begin(); itr != value.end(); itr++)
{
if (*itr == quote_sign<Char>())
in_quotes = !in_quotes;
if (!in_quotes && (*itr == space_sign<Char>()))
{
if (itr != beg)
{
ret.emplace_back(beg, itr);
beg = itr + 1;
}
}
}
if (beg != value.end())
ret.emplace_back(beg, value.end());
return ret;
}
template<typename Char>
struct cmd_setter_ : handler_base_ext
{
typedef Char value_type;
typedef std::basic_string<value_type> string_type;
cmd_setter_(string_type && cmd_line) : _cmd_line(api::build_cmd(std::move(cmd_line))) {}
cmd_setter_(const string_type & cmd_line) : _cmd_line(api::build_cmd(cmd_line)) {}
template <class Executor>
void on_setup(Executor& exec)
{
exec.exe = _cmd_impl.front();
exec.cmd_line = &_cmd_impl.front();
exec.cmd_style = true;
}
string_type str() const
{
string_type ret;
std::size_t size = 0;
for (auto & cmd : _cmd_line)
size += cmd.size() + 1;
ret.reserve(size -1);
for (auto & cmd : _cmd_line)
{
if (!ret.empty())
ret += equal_sign<Char>();
ret += cmd;
}
return ret;
}
private:
static inline std::vector<Char*> make_cmd(std::vector<string_type> & args);
std::vector<string_type> _cmd_line;
std::vector<Char*> _cmd_impl = make_cmd(_cmd_line);
};
template<typename Char>
std::vector<Char*> cmd_setter_<Char>::make_cmd(std::vector<std::basic_string<Char>> & args)
{
std::vector<Char*> vec;
for (auto & v : args)
vec.push_back(&v.front());
vec.push_back(nullptr);
return vec;
}
}}}}
#endif
@@ -0,0 +1,42 @@
// 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_POSIX_COMPARE_HANDLES_HPP_
#define BOOST_PROCESS_DETAIL_POSIX_COMPARE_HANDLES_HPP_
#include <boost/process/detail/config.hpp>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
namespace boost { namespace process { namespace detail { namespace posix {
inline bool compare_handles(int lhs, int rhs)
{
if ((lhs == -1) || (rhs == -1))
return false;
if (lhs == rhs)
return true;
struct stat stat1, stat2;
if(fstat(lhs, &stat1) < 0) ::boost::process::detail::throw_last_error("fstat() failed");
if(fstat(rhs, &stat2) < 0) ::boost::process::detail::throw_last_error("fstat() failed");
return (stat1.st_dev == stat2.st_dev) && (stat1.st_ino == stat2.st_ino);
}
}}}}
#endif /* BOOST_PROCESS_DETAIL_POSIX_COMPARE_HANDLES_HPP_ */
@@ -0,0 +1,41 @@
// 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_POSIX_ENV_INIT_HPP_
#define BOOST_PROCESS_DETAIL_POSIX_ENV_INIT_HPP_
#include <boost/process/detail/config.hpp>
#include <boost/process/detail/posix/handler.hpp>
#include <boost/process/environment.hpp>
namespace boost { namespace process { namespace detail { namespace posix {
template<typename Char>
struct env_init;
template<>
struct env_init<char> : handler_base_ext
{
boost::process::environment env;
env_init(boost::process::environment && env) : env(std::move(env)) {};
env_init(const boost::process::environment & env) : env(env) {};
template <class Executor>
void on_setup(Executor &exec) const
{
exec.env = env._env_impl;
}
};
}}}}
#endif /* BOOST_PROCESS_DETAIL_WINDOWS_ENV_INIT_HPP_ */
@@ -0,0 +1,322 @@
// 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_POSIX_ENVIRONMENT_HPP_
#define BOOST_PROCESS_DETAIL_POSIX_ENVIRONMENT_HPP_
#include <string>
#include <vector>
#include <unordered_map>
#include <boost/process/detail/config.hpp>
#include <algorithm>
#include <cstdlib>
#include <boost/process/locale.hpp>
namespace boost { namespace process { namespace detail { namespace posix {
template<typename Char>
class native_environment_impl
{
static std::vector<std::basic_string<Char>> _load()
{
std::vector<std::basic_string<Char>> val;
auto p = environ;
while (*p != nullptr)
{
std::string str = *p;
val.push_back(::boost::process::detail::convert(str));
p++;
}
return val;
}
static std::vector<Char*> _load_var(std::vector<std::basic_string<Char>> & vec)
{
std::vector<Char*> val;
val.resize(vec.size() + 1);
std::transform(vec.begin(), vec.end(), val.begin(),
[](std::basic_string<Char> & str)
{
return &str.front();
});
val.back() = nullptr;
return val;
}
std::vector<std::basic_string<Char>> _buffer = _load();
std::vector<Char*> _impl = _load_var(_buffer);
public:
using char_type = Char;
using pointer_type = const char_type*;
using string_type = std::basic_string<char_type>;
using native_handle_type = char_type **;
void reload()
{
_buffer = _load();
_impl = _load_var(_buffer);
}
string_type get(const pointer_type id) { return get(string_type(id)); }
void set(const pointer_type id, const pointer_type value)
{
set(string_type(id), string_type(value));
}
void reset(const pointer_type id) { reset(string_type(id)); }
string_type get(const string_type & id)
{
std::string id_c = ::boost::process::detail::convert(id);
std::string g = ::getenv(id_c.c_str());
return ::boost::process::detail::convert(g.c_str());
}
void set(const string_type & id, const string_type & value)
{
std::string id_c = ::boost::process::detail::convert(id.c_str());
std::string value_c = ::boost::process::detail::convert(value.c_str());
auto res = ::setenv(id_c.c_str(), value_c.c_str(), true);
if (res != 0)
boost::process::detail::throw_last_error();
}
void reset(const string_type & id)
{
std::string id_c = ::boost::process::detail::convert(id.c_str());
auto res = ::unsetenv(id_c.c_str());
if (res != 0)
::boost::process::detail::throw_last_error();
}
native_environment_impl() = default;
native_environment_impl(const native_environment_impl& ) = delete;
native_environment_impl(native_environment_impl && ) = default;
native_environment_impl & operator=(const native_environment_impl& ) = delete;
native_environment_impl & operator=(native_environment_impl && ) = default;
native_handle_type _env_impl = _impl.data();
native_handle_type native_handle() const {return environ;}
};
template<>
class native_environment_impl<char>
{
public:
using char_type = char;
using pointer_type = const char_type*;
using string_type = std::basic_string<char_type>;
using native_handle_type = char_type **;
void reload() {this->_env_impl = ::environ;}
string_type get(const pointer_type id) { return getenv(id); }
void set(const pointer_type id, const pointer_type value)
{
auto res = ::setenv(id, value, 1);
if (res != 0)
boost::process::detail::throw_last_error();
reload();
}
void reset(const pointer_type id)
{
auto res = ::unsetenv(id);
if (res != 0)
boost::process::detail::throw_last_error();
reload();
}
string_type get(const string_type & id) {return get(id.c_str());}
void set(const string_type & id, const string_type & value) {set(id.c_str(), value.c_str()); }
void reset(const string_type & id) {reset(id.c_str());}
native_environment_impl() = default;
native_environment_impl(const native_environment_impl& ) = delete;
native_environment_impl(native_environment_impl && ) = default;
native_environment_impl & operator=(const native_environment_impl& ) = delete;
native_environment_impl & operator=(native_environment_impl && ) = default;
native_handle_type _env_impl = environ;
native_handle_type native_handle() const {return ::environ;}
};
template<typename Char>
struct basic_environment_impl
{
std::vector<std::basic_string<Char>> _data {};
static std::vector<Char*> _load_var(std::vector<std::basic_string<Char>> & data);
std::vector<Char*> _env_arr{_load_var(_data)};
public:
using char_type = Char;
using pointer_type = const char_type*;
using string_type = std::basic_string<char_type>;
using native_handle_type = Char**;
void reload()
{
_env_arr = _load_var(_data);
_env_impl = _env_arr.data();
}
string_type get(const pointer_type id) {return get(string_type(id));}
void set(const pointer_type id, const pointer_type value) {set(string_type(id), value);}
void reset(const pointer_type id) {reset(string_type(id));}
string_type get(const string_type & id);
void set(const string_type & id, const string_type & value);
void reset(const string_type & id);
basic_environment_impl(const native_environment_impl<Char> & nei);
basic_environment_impl() = default;
basic_environment_impl(const basic_environment_impl& rhs)
: _data(rhs._data)
{
}
basic_environment_impl(basic_environment_impl && ) = default;
basic_environment_impl & operator=(const basic_environment_impl& rhs)
{
_data = rhs._data;
_env_arr = _load_var(_data);
_env_impl = &*_env_arr.begin();
return *this;
}
basic_environment_impl & operator=(basic_environment_impl && ) = default;
template<typename CharR>
explicit inline basic_environment_impl(
const basic_environment_impl<CharR>& rhs,
const ::boost::process::codecvt_type & cv = ::boost::process::codecvt())
: _data(rhs._data.size())
{
std::transform(rhs._data.begin(), rhs._data.end(), _data.begin(),
[&](const std::basic_string<CharR> & st)
{
return ::boost::process::detail::convert(st, cv);
}
);
reload();
}
template<typename CharR>
basic_environment_impl & operator=(const basic_environment_impl<CharR>& rhs)
{
_data = ::boost::process::detail::convert(rhs._data);
_env_arr = _load_var(&*_data.begin());
_env_impl = &*_env_arr.begin();
return *this;
}
Char ** _env_impl = &*_env_arr.data();
native_handle_type native_handle() const {return &_data.front();}
};
template<typename Char>
basic_environment_impl<Char>::basic_environment_impl(const native_environment_impl<Char> & nei)
{
auto beg = nei.native_handle();
auto end = beg;
while (*end != nullptr)
end++;
this->_data.assign(beg, end);
reload();
}
template<typename Char>
inline auto basic_environment_impl<Char>::get(const string_type &id) -> string_type
{
auto itr = std::find_if(_data.begin(), _data.end(),
[&](const string_type & st)
{
if (st.size() <= id.size())
return false;
return std::equal(id.begin(), id.end(), st.begin()) && (st[id.size()] == equal_sign<Char>());
}
);
if (itr == _data.end())
{
return "";
}
else return
itr->data() + id.size(); //id=Thingy -> +2 points to T
}
template<typename Char>
inline void basic_environment_impl<Char>::set(const string_type &id, const string_type &value)
{
auto itr = std::find_if(_data.begin(), _data.end(),
[&](const string_type & st)
{
if (st.size() <= id.size())
return false;
return std::equal(id.begin(), id.end(), st.begin()) && (st[id.size()] == equal_sign<Char>());
}
);
if (itr != _data.end())
*itr = id + equal_sign<Char>() + value;
else
_data.push_back(id + equal_sign<Char>() + value);
reload();
}
template<typename Char>
inline void basic_environment_impl<Char>::reset(const string_type &id)
{
auto itr = std::find_if(_data.begin(), _data.end(),
[&](const string_type & st)
{
if (st.size() <= id.size())
return false;
return std::equal(id.begin(), id.end(), st.begin()) && (st[id.size()] == equal_sign<Char>());
}
);
if (itr != _data.end())
{
_data.erase(itr);//and remove it
}
reload();
}
template<typename Char>
std::vector<Char*> basic_environment_impl<Char>::_load_var(std::vector<std::basic_string<Char>> & data)
{
std::vector<Char*> ret;
ret.reserve(data.size() +1);
for (auto & val : data)
ret.push_back(&val.front());
ret.push_back(nullptr);
return ret;
}
template<typename T> constexpr T env_seperator();
template<> constexpr char env_seperator() {return ':'; }
template<> constexpr wchar_t env_seperator() {return L':'; }
typedef int native_handle_t;
inline int get_id() {return getpid(); }
inline int native_handle() {return getpid(); }
}
}
}
}
#endif /* BOOST_PROCESS_DETAIL_WINDOWS_ENV_STORAGE_HPP_ */
@@ -0,0 +1,36 @@
// 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_POSIX_EXE_HPP_
#define BOOST_PROCESS_DETAIL_POSIX_EXE_HPP_
namespace boost
{
namespace process
{
namespace detail
{
namespace posix
{
template<class StringType, class Executor>
inline void apply_exe(const StringType & exe, Executor & e)
{
e.exe = exe.c_str();
}
}
}
}
}
#endif /* INCLUDE_BOOST_PROCESS_WINDOWS_ARGS_HPP_ */
@@ -0,0 +1,547 @@
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
// Copyright (c) 2009 Boris Schaeling
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
//
// 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_POSIX_EXECUTOR_HPP
#define BOOST_PROCESS_DETAIL_POSIX_EXECUTOR_HPP
#include <boost/process/detail/child_decl.hpp>
#include <boost/process/error.hpp>
#include <boost/process/pipe.hpp>
#include <boost/process/detail/posix/basic_pipe.hpp>
#include <boost/process/detail/posix/use_vfork.hpp>
#include <boost/fusion/algorithm/iteration/for_each.hpp>
#include <cstdlib>
#include <sys/types.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#if !defined(__GLIBC__)
#include <boost/algorithm/string/predicate.hpp>
#include <boost/algorithm/string/split.hpp>
#include <boost/algorithm/string/classification.hpp>
#endif
namespace boost { namespace process { namespace detail { namespace posix {
inline int execvpe(const char* filename, char * const arg_list[], char* env[])
{
#if defined(__GLIBC__)
return ::execvpe(filename, arg_list, env);
#else
//use my own implementation
std::string fn = filename;
if ((fn.find('/') == std::string::npos) && ::access(fn.c_str(), X_OK))
{
auto e = ::environ;
while ((*e != nullptr) && !boost::starts_with(*e, "PATH="))
e++;
if (e != nullptr)
{
std::vector<std::string> path;
boost::split(path, *e, boost::is_any_of(":"));
for (const std::string & pp : path)
{
auto p = pp + "/" + filename;
if (!::access(p.c_str(), X_OK))
{
fn = p;
break;
}
}
}
}
return ::execve(fn.c_str(), arg_list, env);
#endif
}
template<typename Executor>
struct on_setup_t
{
Executor & exec;
on_setup_t(Executor & exec) : exec(exec) {};
template<typename T>
void operator()(T & t) const
{
if (!exec.error())
t.on_setup(exec);
}
};
template<typename Executor>
struct on_error_t
{
Executor & exec;
const std::error_code & error;
on_error_t(Executor & exec, const std::error_code & error) : exec(exec), error(error) {};
template<typename T>
void operator()(T & t) const
{
t.on_error(exec, error);
}
};
template<typename Executor>
struct on_success_t
{
Executor & exec;
on_success_t(Executor & exec) : exec(exec) {};
template<typename T>
void operator()(T & t) const {t.on_success(exec);}
};
template<typename Executor>
struct on_fork_error_t
{
Executor & exec;
const std::error_code & error;
on_fork_error_t(Executor & exec, const std::error_code & error) : exec(exec), error(error) {};
template<typename T>
void operator()(T & t) const
{
t.on_fork_error(exec, error);
}
};
template<typename Executor>
struct on_exec_setup_t
{
Executor & exec;
on_exec_setup_t(Executor & exec) : exec(exec) {};
template<typename T>
void operator()(T & t) const
{
t.on_exec_setup(exec);
}
};
template<typename Executor>
struct on_exec_error_t
{
Executor & exec;
const std::error_code &ec;
on_exec_error_t(Executor & exec, const std::error_code & error) : exec(exec), ec(error) {};
template<typename T>
void operator()(T & t) const
{
t.on_exec_error(exec, ec);
}
};
template<typename Executor>
struct on_fork_success_t
{
Executor & exec;
on_fork_success_t(Executor & exec) : exec(exec) {};
template<typename T>
void operator()(T & t) const
{
t.on_fork_success(exec);
}
};
template<typename Executor> on_setup_t <Executor> call_on_setup (Executor & exec) {return exec;}
template<typename Executor> on_error_t <Executor> call_on_error (Executor & exec, const std::error_code & ec)
{
return on_error_t<Executor> (exec, ec);
}
template<typename Executor> on_success_t<Executor> call_on_success(Executor & exec) {return exec;}
template<typename Executor> on_fork_error_t <Executor> call_on_fork_error (Executor & exec, const std::error_code & ec)
{
return on_fork_error_t<Executor> (exec, ec);
}
template<typename Executor> on_exec_setup_t <Executor> call_on_exec_setup (Executor & exec) {return exec;}
template<typename Executor> on_exec_error_t <Executor> call_on_exec_error (Executor & exec, const std::error_code & ec)
{
return on_exec_error_t<Executor> (exec, ec);
}
template<typename Sequence>
class executor
{
template<typename HasHandler, typename UseVFork>
void internal_error_handle(const std::error_code &ec, const char* msg, HasHandler, boost::mpl::true_, UseVFork) {}
int _pipe_sink = -1;
void write_error(const std::error_code & ec, const char * msg)
{
//I am the child
int len = ec.value();
::write(_pipe_sink, &len, sizeof(int));
len = std::strlen(msg) + 1;
::write(_pipe_sink, &len, sizeof(int));
::write(_pipe_sink, msg, len);
}
void internal_error_handle(const std::error_code &ec, const char* msg, boost::mpl::true_ , boost::mpl::false_, boost::mpl::false_)
{
if (this->pid == 0) //on the fork.
write_error(ec, msg);
else
{
this->_ec = ec;
this->_msg = msg;
}
}
void internal_error_handle(const std::error_code &ec, const char* msg, boost::mpl::false_, boost::mpl::false_, boost::mpl::false_)
{
if (this->pid == 0)
write_error(ec, msg);
else
throw process_error(ec, msg);
}
void internal_error_handle(const std::error_code &ec, const char* msg, boost::mpl::true_ , boost::mpl::false_, boost::mpl::true_)
{
this->_ec = ec;
this->_msg = msg;
}
void internal_error_handle(const std::error_code &ec, const char* msg, boost::mpl::false_, boost::mpl::false_, boost::mpl::true_)
{
if (this->pid == 0)
{
this->_ec = ec;
this->_msg = msg;
}
else
throw process_error(ec, msg);
}
void check_error(boost::mpl::true_) {};
void check_error(boost::mpl::false_)
{
throw process_error(_ec, _msg);
}
typedef typename ::boost::process::detail::has_error_handler<Sequence>::type has_error_handler;
typedef typename ::boost::process::detail::has_ignore_error <Sequence>::type has_ignore_error;
typedef typename ::boost::process::detail::posix::shall_use_vfork<Sequence>::type shall_use_vfork;
inline child invoke(boost::mpl::true_ , boost::mpl::true_ );
inline child invoke(boost::mpl::false_, boost::mpl::true_ );
inline child invoke(boost::mpl::true_ , boost::mpl::false_ );
inline child invoke(boost::mpl::false_, boost::mpl::false_ );
void _write_error(int sink)
{
int data[2] = {_ec.value(),static_cast<int>(_msg.size())};
while (::write(sink, &data[0], sizeof(int) *2) == -1)
{
auto err = errno;
if (err == EBADF)
return;
else if ((err != EINTR) && (err != EAGAIN))
break;
}
while (::write(sink, &_msg.front(), _msg.size()) == -1)
{
auto err = errno;
if (err == EBADF)
return;
else if ((err != EINTR) && (err != EAGAIN))
break;
}
}
void _read_error(int source)
{
int data[2];
_ec.clear();
int count = 0;
while ((count = ::read(source, &data[0], sizeof(int) *2 ) ) == -1)
{
//actually, this should block until it's read.
auto err = errno;
if ((err != EAGAIN ) && (err != EINTR))
set_error(std::error_code(err, std::system_category()), "Error read pipe");
}
if (count == 0)
return ;
std::error_code ec(data[0], std::system_category());
std::string msg(data[1], ' ');
while (::read(source, &msg.front(), msg.size() ) == -1)
{
//actually, this should block until it's read.
auto err = errno;
if ((err == EBADF) || (err == EPERM))//that should occur on success, therefore return.
return;
//EAGAIN not yet forked, EINTR interrupted, i.e. try again
else if ((err != EAGAIN ) && (err != EINTR))
set_error(std::error_code(err, std::system_category()), "Error read pipe");
}
set_error(ec, std::move(msg));
}
std::error_code _ec;
std::string _msg;
public:
executor(Sequence & seq) : seq(seq)
{
}
child operator()()
{
return invoke(has_ignore_error(), shall_use_vfork());
}
Sequence & seq;
const char * exe = nullptr;
char *const* cmd_line = nullptr;
bool cmd_style = false;
char **env = ::environ;
pid_t pid = -1;
std::shared_ptr<std::atomic<int>> exit_status = std::make_shared<std::atomic<int>>(still_active);
const std::error_code & error() const {return _ec;}
void set_error(const std::error_code &ec, const char* msg)
{
internal_error_handle(ec, msg, has_error_handler(), has_ignore_error(), shall_use_vfork());
}
void set_error(const std::error_code &ec, const std::string &msg) {set_error(ec, msg.c_str());};
};
template<typename Sequence>
child executor<Sequence>::invoke(boost::mpl::true_, boost::mpl::false_) //ignore errors
{
boost::fusion::for_each(seq, call_on_setup(*this));
if (_ec)
return child();
this->pid = ::fork();
if (pid == -1)
{
auto ec = boost::process::detail::get_last_error();
boost::fusion::for_each(seq, call_on_fork_error(*this, ec));
return child();
}
else if (pid == 0)
{
boost::fusion::for_each(seq, call_on_exec_setup(*this));
if (cmd_style)
::boost::process::detail::posix::execvpe(exe, cmd_line, env);
else
::execve(exe, cmd_line, env);
auto ec = boost::process::detail::get_last_error();
boost::fusion::for_each(seq, call_on_exec_error(*this, ec));
_exit(EXIT_FAILURE);
}
child c(child_handle(pid), exit_status);
boost::fusion::for_each(seq, call_on_success(*this));
return c;
}
template<typename Sequence>
child executor<Sequence>::invoke(boost::mpl::false_, boost::mpl::false_)
{
int p[2];
if (::pipe(p) == -1)
{
set_error(::boost::process::detail::get_last_error(), "pipe(2) failed");
return child();
}
if (::fcntl(p[1], F_SETFD, FD_CLOEXEC) == -1)
{
set_error(::boost::process::detail::get_last_error(), "fcntl(2) failed");
return child();
}
_ec.clear();
boost::fusion::for_each(seq, call_on_setup(*this));
if (_ec)
{
boost::fusion::for_each(seq, call_on_error(*this, _ec));
return child();
}
this->pid = ::fork();
if (pid == -1)
{
_ec = boost::process::detail::get_last_error();
_msg = "fork() failed";
boost::fusion::for_each(seq, call_on_fork_error(*this, _ec));
boost::fusion::for_each(seq, call_on_error(*this, _ec));
return child();
}
else if (pid == 0)
{
_pipe_sink = p[1];
::close(p[0]);
boost::fusion::for_each(seq, call_on_exec_setup(*this));
if (cmd_style)
::boost::process::detail::posix::execvpe(exe, cmd_line, env);
else
::execve(exe, cmd_line, env);
_ec = boost::process::detail::get_last_error();
_msg = "execve failed";
boost::fusion::for_each(seq, call_on_exec_error(*this, _ec));
_write_error(p[1]);
_exit(EXIT_FAILURE);
return child();
}
child c(child_handle(pid), exit_status);
::close(p[1]);
_read_error(p[0]);
::close(p[0]);
if (_ec)
{
boost::fusion::for_each(seq, call_on_error(*this, _ec));
return child();
}
else
boost::fusion::for_each(seq, call_on_success(*this));
if (_ec)
{
boost::fusion::for_each(seq, call_on_error(*this, _ec));
return child();
}
return c;
}
#if BOOST_POSIX_HAS_VFORK
template<typename Sequence>
child executor<Sequence>::invoke(boost::mpl::true_, boost::mpl::true_) //ignore errors
{
boost::fusion::for_each(seq, call_on_setup(*this));
if (_ec)
return child();
this->pid = ::vfork();
if (pid == -1)
{
auto ec = boost::process::detail::get_last_error();
boost::fusion::for_each(seq, call_on_fork_error(*this, ec));
return child();
}
else if (pid == 0)
{
boost::fusion::for_each(seq, call_on_exec_setup(*this));
::execve(exe, cmd_line, env);
auto ec = boost::process::detail::get_last_error();
boost::fusion::for_each(seq, call_on_exec_error(*this, ec));
_exit(EXIT_FAILURE);
}
child c(child_handle(pid), exit_status);
boost::fusion::for_each(seq, call_on_success(*this));
return c;
}
template<typename Sequence>
child executor<Sequence>::invoke(boost::mpl::false_, boost::mpl::true_)
{
boost::fusion::for_each(seq, call_on_setup(*this));
if (_ec)
{
boost::fusion::for_each(seq, call_on_error(*this, _ec));
return child();
}
_ec.clear();
this->pid = ::vfork();
if (pid == -1)
{
_ec = boost::process::detail::get_last_error();
_msg = "fork() failed";
boost::fusion::for_each(seq, call_on_fork_error(*this, _ec));
boost::fusion::for_each(seq, call_on_error(*this, _ec));
return child();
}
else if (pid == 0)
{
boost::fusion::for_each(seq, call_on_exec_setup(*this));
if (cmd_style)
::boost::process::detail::posix::execvpe(exe, cmd_line, env);
else
::execve(exe, cmd_line, env);
_ec = boost::process::detail::get_last_error();
_msg = "execve failed";
boost::fusion::for_each(seq, call_on_exec_error(*this, _ec));
_exit(EXIT_FAILURE);
return child();
}
child c(child_handle(pid), exit_status);
check_error(has_error_handler());
if (_ec)
{
boost::fusion::for_each(seq, call_on_error(*this, _ec));
return child();
}
else
boost::fusion::for_each(seq, call_on_success(*this));
if (_ec)
{
boost::fusion::for_each(seq, call_on_error(*this, _ec));
return child();
}
return c;
}
#endif
template<typename Char, typename Tup>
inline executor<Tup> make_executor(Tup & tup)
{
return executor<Tup>(tup);
}
}}}}
#endif
@@ -0,0 +1,92 @@
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
// Copyright (c) 2009 Boris Schaeling
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
//
// 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_POSIX_FD_HPP
#define BOOST_PROCESS_DETAIL_POSIX_FD_HPP
#include <boost/process/detail/posix/handler.hpp>
#include <unistd.h>
namespace boost { namespace process { namespace detail { namespace posix {
struct close_fd_ : handler_base_ext
{
close_fd_(int fd) : fd_(fd) {}
template <class PosixExecutor>
void on_exec_setup(PosixExecutor& e) const
{
if (::close(fd_) == -1)
e.set_error(::boost::process::detail::get_last_error(), "close() failed");
}
private:
int fd_;
};
template <class Range>
struct close_fds_ : handler_base_ext
{
public:
close_fds_(const Range &fds) : fds_(fds) {}
template <class PosixExecutor>
void on_exec_setup(PosixExecutor& e) const
{
for (auto & fd_ : fds_)
if (::close(fd_) == -1)
{
e.set_error(::boost::process::detail::get_last_error(), "close() failed");
break;
}
}
private:
Range fds_;
};
template <class FileDescriptor>
struct bind_fd_ : handler_base_ext
{
public:
bind_fd_(int id, const FileDescriptor &fd) : id_(id), fd_(fd) {}
template <class PosixExecutor>
void on_exec_setup(PosixExecutor& e) const
{
if (::dup2(fd_, id_) == -1)
e.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
}
private:
int id_;
FileDescriptor fd_;
};
struct fd_
{
constexpr fd_() {};
close_fd_ close(int _fd) const {return close_fd_(_fd);}
close_fds_<std::vector<int>> close(const std::initializer_list<int> & vec) const {return std::vector<int>(vec);}
template<typename Range>
close_fds_<Range> close(const Range & r) const {return r;}
template <class FileDescriptor>
bind_fd_<FileDescriptor> bind(int id, const FileDescriptor & fd) const {return {id, fd};}
};
}}}}
#endif
@@ -0,0 +1,76 @@
// 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_POSIX_FILE_DESCRIPTOR_HPP_
#define BOOST_PROCESS_DETAIL_POSIX_FILE_DESCRIPTOR_HPP_
#include <fcntl.h>
#include <string>
#include <boost/filesystem/path.hpp>
namespace boost { namespace process { namespace detail { namespace posix {
struct file_descriptor
{
enum mode_t
{
read = 1,
write = 2,
read_write = 3
};
file_descriptor() = default;
explicit file_descriptor(const boost::filesystem::path& p, mode_t mode = read_write)
: file_descriptor(p.native(), mode)
{
}
explicit file_descriptor(const std::string & path , mode_t mode = read_write)
: file_descriptor(path.c_str(), mode) {}
explicit file_descriptor(const char* path, mode_t mode = read_write)
: _handle(create_file(path, mode))
{
}
file_descriptor(const file_descriptor & ) = delete;
file_descriptor(file_descriptor && ) = default;
file_descriptor& operator=(const file_descriptor & ) = delete;
file_descriptor& operator=(file_descriptor && ) = default;
~file_descriptor()
{
if (_handle != -1)
::close(_handle);
}
int handle() const { return _handle;}
private:
static int create_file(const char* name, mode_t mode )
{
switch(mode)
{
case read:
return ::open(name, O_RDONLY);
case write:
return ::open(name, O_WRONLY | O_CREAT, 0660);
case read_write:
return ::open(name, O_RDWR | O_CREAT, 0660);
default:
return -1;
}
}
int _handle = -1;
};
}}}}
#endif /* BOOST_PROCESS_DETAIL_WINDOWS_FILE_DESCRIPTOR_HPP_ */
@@ -0,0 +1,40 @@
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
// Copyright (c) 2009 Boris Schaeling
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
//
// 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_POSIX_FILE_IN_HPP
#define BOOST_PROCESS_DETAIL_POSIX_FILE_IN_HPP
#include <boost/process/pipe.hpp>
#include <boost/process/detail/posix/handler.hpp>
#include <boost/process/detail/posix/file_descriptor.hpp>
#include <cstdio>
#include <unistd.h>
namespace boost { namespace process { namespace detail { namespace posix {
struct file_in : handler_base_ext
{
file_descriptor file;
int handle = file.handle();
template<typename T>
file_in(T&& t) : file(std::forward<T>(t)) {}
file_in(FILE * f) : handle(fileno(f)) {}
template <class WindowsExecutor>
void on_exec_setup(WindowsExecutor &e) const
{
if (::dup2(handle, STDIN_FILENO) == -1)
e.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
}
};
}}}}
#endif
@@ -0,0 +1,65 @@
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
// Copyright (c) 2009 Boris Schaeling
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
// 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_POSIX_FILE_OUT_HPP
#define BOOST_PROCESS_POSIX_FILE_OUT_HPP
#include <boost/process/detail/posix/handler.hpp>
#include <boost/process/detail/posix/file_descriptor.hpp>
#include <unistd.h>
namespace boost { namespace process { namespace detail { namespace posix {
template<int p1, int p2>
struct file_out : handler_base_ext
{
file_descriptor file;
int handle = file.handle();
template<typename T>
file_out(T&& t) : file(std::forward<T>(t), file_descriptor::write), handle(file.handle()) {}
file_out(FILE * f) : handle(fileno(f)) {}
template <typename Executor>
void on_exec_setup(Executor &e) const;
};
template<>
template<typename Executor>
void file_out<1,-1>::on_exec_setup(Executor &e) const
{
if (::dup2(handle, STDOUT_FILENO) == -1)
e.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
}
template<>
template<typename Executor>
void file_out<2,-1>::on_exec_setup(Executor &e) const
{
if (::dup2(handle, STDERR_FILENO) == -1)
e.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
}
template<>
template<typename Executor>
void file_out<1,2>::on_exec_setup(Executor &e) const
{
if (::dup2(handle, STDOUT_FILENO) == -1)
e.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
if (::dup2(handle, STDERR_FILENO) == -1)
e.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
}
}}}}
#endif
@@ -0,0 +1,103 @@
// 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_POSIX_GROUP_HPP_
#define BOOST_PROCESS_DETAIL_POSIX_GROUP_HPP_
#include <boost/process/detail/posix/child_handle.hpp>
#include <system_error>
#include <unistd.h>
namespace boost { namespace process { namespace detail { namespace posix {
struct group_handle
{
pid_t grp = -1;
typedef pid_t handle_t;
handle_t handle() const { return grp; }
explicit group_handle(handle_t h) :
grp(h)
{
}
group_handle() = default;
~group_handle() = default;
group_handle(const group_handle & c) = delete;
group_handle(group_handle && c) : grp(c.grp)
{
c.grp = -1;
}
group_handle &operator=(const group_handle & c) = delete;
group_handle &operator=(group_handle && c)
{
grp = c.grp;
c.grp = -1;
return *this;
}
void add(handle_t proc)
{
if (::setpgid(proc, grp))
throw_last_error();
}
void add(handle_t proc, std::error_code & ec) noexcept
{
if (::setpgid(proc, grp))
ec = get_last_error();
}
bool has(handle_t proc)
{
return ::getpgid(proc) == grp;
}
bool has(handle_t proc, std::error_code & ec) noexcept
{
return ::getpgid(proc) == grp;
}
bool valid() const
{
return grp != -1;
}
};
inline void terminate(group_handle &p)
{
if (::killpg(p.grp, SIGKILL) == -1)
boost::process::detail::throw_last_error("killpg(2) failed");
p.grp = -1;
}
inline void terminate(group_handle &p, std::error_code &ec) noexcept
{
if (::killpg(p.grp, SIGKILL) == -1)
ec = boost::process::detail::get_last_error();
else
ec.clear();
p.grp = -1;
}
inline bool in_group()
{
return true;
}
}}}}
#endif /* BOOST_PROCESS_DETAIL_WINDOWS_GROUP_HPP_ */
@@ -0,0 +1,52 @@
// 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_POSIX_GROUP_REF_HPP_
#define BOOST_PROCESS_DETAIL_POSIX_GROUP_REF_HPP_
#include <boost/process/detail/config.hpp>
#include <boost/process/detail/posix/group_handle.hpp>
#include <boost/process/detail/posix/handler.hpp>
#include <unistd.h>
namespace boost { namespace process {
namespace detail { namespace posix {
struct group_ref : handler_base_ext
{
group_handle & grp;
explicit group_ref(group_handle & g) :
grp(g)
{}
template <class Executor>
void on_exec_setup(Executor& exec) const
{
if (grp.grp == -1)
::setpgid(0, 0);
else
::setpgid(0, grp.grp);
}
template <class Executor>
void on_success(Executor& exec) const
{
if (grp.grp == -1)
grp.grp = exec.pid;
}
};
}}}}
#endif /* BOOST_PROCESS_DETAIL_POSIX_GROUP_REF_HPP_ */
@@ -0,0 +1,74 @@
// 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_POSIX_HANDLER_HPP_
#define BOOST_PROCESS_DETAIL_POSIX_HANDLER_HPP_
#include <boost/process/detail/handler_base.hpp>
namespace boost { namespace process { namespace detail { namespace posix {
//does not extend anything.
struct handler_base_ext : handler_base
{
template<typename Executor>
void on_fork_error (Executor &, const std::error_code&) const {}
template<typename Executor>
void on_exec_setup (Executor &) const {}
template<typename Executor>
void on_exec_error (Executor &, const std::error_code&) const {}
};
template <class Handler>
struct on_fork_error_ : handler_base_ext
{
explicit on_fork_error_(Handler handler) : handler_(handler) {}
template <class Executor>
void on_fork_error(Executor &e, const std::error_code &ec) const
{
handler_(e, ec);
}
private:
Handler handler_;
};
template <class Handler>
struct on_exec_setup_ : handler_base_ext
{
explicit on_exec_setup_(Handler handler) : handler_(handler) {}
template <class Executor>
void on_exec_setup(Executor &e) const
{
handler_(e);
}
private:
Handler handler_;
};
template <class Handler>
struct on_exec_error_ : handler_base_ext
{
explicit on_exec_error_(Handler handler) : handler_(handler) {}
template <class Executor>
void on_exec_error(Executor &e, const std::error_code &ec) const
{
handler_(e, ec);
}
private:
Handler handler_;
};
}}}}
#endif /* BOOST_PROCESS_DETAIL_POSIX_HANDLER_HPP_ */
@@ -0,0 +1,155 @@
// 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_POSIX_IO_SERVICE_REF_HPP_
#define BOOST_PROCESS_POSIX_IO_SERVICE_REF_HPP_
#include <boost/process/detail/posix/handler.hpp>
#include <boost/process/detail/posix/async_handler.hpp>
#include <boost/asio/io_service.hpp>
#include <boost/asio/signal_set.hpp>
#include <boost/fusion/algorithm/iteration/for_each.hpp>
#include <boost/fusion/algorithm/transformation/filter_if.hpp>
#include <boost/fusion/algorithm/transformation/transform.hpp>
#include <boost/fusion/view/transform_view.hpp>
#include <boost/fusion/container/vector/convert.hpp>
#include <functional>
#include <type_traits>
#include <memory>
#include <vector>
#include <sys/wait.h>
namespace boost { namespace process { namespace detail { namespace posix {
template<typename Executor>
struct on_exit_handler_transformer
{
Executor & exec;
on_exit_handler_transformer(Executor & exec) : exec(exec) {}
template<typename Sig>
struct result;
template<typename T>
struct result<on_exit_handler_transformer<Executor>(T&)>
{
typedef typename T::on_exit_handler_t type;
};
template<typename T>
auto operator()(T& t) const -> typename T::on_exit_handler_t
{
return t.on_exit_handler(exec);
}
};
template<typename Executor>
struct async_handler_collector
{
Executor & exec;
std::vector<std::function<void(int, const std::error_code & ec)>> &handlers;
async_handler_collector(Executor & exec,
std::vector<std::function<void(int, const std::error_code & ec)>> &handlers)
: exec(exec), handlers(handlers) {}
template<typename T>
void operator()(T & t) const
{
handlers.push_back(t.on_exit_handler(exec));
};
};
//Also set's up waiting for the exit, so it can close async stuff.
struct io_service_ref : handler_base_ext
{
io_service_ref(boost::asio::io_service & ios) : ios(ios)
{
}
boost::asio::io_service &get() {return ios;};
boost::asio::signal_set *signal_p = nullptr;
template <class Executor>
void on_setup(Executor& exec)
{
//must be on the heap so I can move it into the lambda.
auto asyncs = boost::fusion::filter_if<
is_async_handler<
typename std::remove_reference< boost::mpl::_ > ::type
>>(exec.seq);
//ok, check if there are actually any.
if (boost::fusion::empty(asyncs))
return;
std::vector<std::function<void(int, const std::error_code & ec)>> funcs;
funcs.reserve(boost::fusion::size(asyncs));
boost::fusion::for_each(asyncs, async_handler_collector<Executor>(exec, funcs));
wait_handler wh(std::move(funcs), ios, exec.exit_status);
signal_p = wh.signal_.get();
signal_p->async_wait(std::move(wh));
}
template <class Executor>
void on_error(Executor & exec, const std::error_code & ec) const
{
if (signal_p != nullptr)
{
boost::system::error_code ec;
signal_p->cancel(ec);
}
}
struct wait_handler
{
std::shared_ptr<boost::asio::signal_set> signal_;
std::vector<std::function<void(int, const std::error_code & ec)>> funcs;
std::shared_ptr<std::atomic<int>> exit_status;
wait_handler(const wait_handler & ) = default;
wait_handler(wait_handler && ) = default;
wait_handler(
std::vector<std::function<void(int, const std::error_code & ec)>> && funcs,
boost::asio::io_service & ios,
const std::shared_ptr<std::atomic<int>> &exit_status)
: signal_(new boost::asio::signal_set(ios, SIGCHLD)),
funcs(std::move(funcs)),
exit_status(exit_status)
{
}
void operator()(const boost::system::error_code & ec_in, int /*signal*/)
{
if (ec_in.value() == boost::asio::error::operation_aborted)
return;
int status;
::wait(&status);
std::error_code ec(ec_in.value(), std::system_category());
int val = WEXITSTATUS(status);
exit_status->store(status);
for (auto & func : funcs)
func(val, ec);
}
};
private:
boost::asio::io_service &ios;
};
}}}}
#endif /* BOOST_PROCESS_WINDOWS_IO_SERVICE_REF_HPP_ */
@@ -0,0 +1,78 @@
// Copyright (c) 2106 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_POSIX_IS_RUNNING_HPP
#define BOOST_PROCESS_DETAIL_POSIX_IS_RUNNING_HPP
#include <boost/process/detail/config.hpp>
#include <boost/process/detail/posix/child_handle.hpp>
#include <system_error>
#include <sys/wait.h>
namespace boost { namespace process { namespace detail { namespace posix {
constexpr int still_active = 0x7F;
static_assert(!WIFEXITED(still_active), "Internal Error");
inline bool is_running(const child_handle &p, int & exit_code)
{
int status;
auto ret = ::waitpid(p.pid, &status, WNOHANG|WUNTRACED);
if (ret == -1)
{
if (errno != ECHILD) //because it no child is running, than this one isn't either, obviously.
::boost::process::detail::throw_last_error("is_running error");
return false;
}
else if (ret == 0)
return true;
else //exited
{
if (WIFEXITED(status))
exit_code = status;
return false;
}
}
inline bool is_running(const child_handle &p, int & exit_code, std::error_code &ec) noexcept
{
int status;
auto ret = ::waitpid(p.pid, &status, WNOHANG|WUNTRACED);
if (ret == -1)
{
if (errno != ECHILD) //because it no child is running, than this one isn't either, obviously.
ec = ::boost::process::detail::get_last_error();
return false;
}
else if (ret == 0)
return true;
else
{
ec.clear();
if (WIFEXITED(status))
exit_code = status;
return false;
}
}
inline bool is_running(int code)
{
return !WIFEXITED(code);
}
inline int eval_exit_status(int code)
{
return WEXITSTATUS(code);
}
}}}}
#endif
@@ -0,0 +1,35 @@
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
// Copyright (c) 2009 Boris Schaeling
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
//
// 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_POSIX_NULL_IN_HPP
#define BOOST_PROCESS_DETAIL_POSIX_NULL_IN_HPP
#include <boost/process/pipe.hpp>
#include <boost/process/detail/posix/handler.hpp>
#include <boost/process/detail/posix/file_descriptor.hpp>
#include <unistd.h>
namespace boost { namespace process { namespace detail { namespace posix {
struct null_in : handler_base_ext
{
file_descriptor source{"/dev/null", file_descriptor::read};
public:
template <class Executor>
void on_exec_setup(Executor &e) const
{
if (::dup2(source.handle(), STDIN_FILENO) == -1)
e.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
}
};
}}}}
#endif
@@ -0,0 +1,58 @@
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
// Copyright (c) 2009 Boris Schaeling
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
// 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_POSIX_PIPE_OUT_HPP
#define BOOST_PROCESS_POSIX_PIPE_OUT_HPP
#include <boost/process/detail/posix/handler.hpp>
#include <boost/process/detail/posix/file_descriptor.hpp>
#include <unistd.h>
namespace boost { namespace process { namespace detail { namespace posix {
template<int p1, int p2>
struct null_out : handler_base_ext
{
file_descriptor sink{"/dev/null", file_descriptor::write};
template <typename Executor>
void on_exec_setup(Executor &e) const;
};
template<>
template<typename Executor>
void null_out<1,-1>::on_exec_setup(Executor &e) const
{
if (::dup2(sink.handle(), STDOUT_FILENO) == -1)
e.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
}
template<>
template<typename Executor>
void null_out<2,-1>::on_exec_setup(Executor &e) const
{
if (::dup2(sink.handle(), STDERR_FILENO) == -1)
e.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
}
template<>
template<typename Executor>
void null_out<1,2>::on_exec_setup(Executor &e) const
{
if (::dup2(sink.handle(), STDOUT_FILENO) == -1)
e.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
if (::dup2(sink.handle(), STDERR_FILENO) == -1)
e.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
}
}}}}
#endif
@@ -0,0 +1,35 @@
// 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_POSIX_ON_EXIT_HPP_
#define BOOST_PROCESS_POSIX_ON_EXIT_HPP_
#include <boost/process/detail/config.hpp>
#include <boost/process/detail/handler_base.hpp>
#include <boost/process/detail/posix/async_handler.hpp>
#include <system_error>
#include <functional>
namespace boost { namespace process { namespace detail { namespace posix {
struct on_exit_ : boost::process::detail::posix::async_handler
{
std::function<void(int, const std::error_code&)> handler;
on_exit_(const std::function<void(int, const std::error_code&)> & handler) : handler(handler)
{
}
template<typename Executor>
std::function<void(int, const std::error_code&)> on_exit_handler(Executor & exec)
{
return handler;
};
};
}}}}
#endif /* BOOST_PROCESS_POSIX_ON_EXIT_HPP_ */
@@ -0,0 +1,90 @@
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
// Copyright (c) 2009 Boris Schaeling
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
//
// 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_POSIX_PIPE_IN_HPP
#define BOOST_PROCESS_POSIX_PIPE_IN_HPP
#include <boost/process/pipe.hpp>
#include <boost/process/detail/posix/handler.hpp>
#include <unistd.h>
namespace boost { namespace process { namespace detail { namespace posix {
struct pipe_in : handler_base_ext
{
int source;
int sink; //opposite end
pipe_in(int sink, int source) : source(source), sink(sink) {}
template<typename T>
pipe_in(T & p) : source(p.native_source()), sink(p.native_sink())
{
p.assign_source(-1);
}
template<typename Executor>
void on_error(Executor &, const std::error_code &) const
{
::close(source);
}
template<typename Executor>
void on_success(Executor &) const
{
::close(source);
}
template <class Executor>
void on_exec_setup(Executor &e) const
{
if (::dup2(source, STDIN_FILENO) == -1)
e.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
::close(source);
::close(sink);
}
};
class async_pipe;
struct async_pipe_in : public pipe_in
{
async_pipe &pipe;
template<typename AsyncPipe>
async_pipe_in(AsyncPipe & p) : pipe_in(p.native_sink(), p.native_source()), pipe(p)
{
}
template<typename Pipe, typename Executor>
static void close(Pipe & pipe, Executor &)
{
boost::system::error_code ec;
std::move(pipe).source().close(ec);
}
template<typename Executor>
void on_error(Executor & exec, const std::error_code &)
{
close(pipe, exec);
}
template<typename Executor>
void on_success(Executor &exec)
{
close(pipe, exec);
}
};
}}}}
#endif
@@ -0,0 +1,116 @@
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
// Copyright (c) 2009 Boris Schaeling
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
// 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_POSIX_PIPE_OUT_HPP
#define BOOST_PROCESS_DETAIL_POSIX_PIPE_OUT_HPP
#include <boost/process/pipe.hpp>
#include <boost/process/detail/posix/handler.hpp>
#include <unistd.h>
namespace boost { namespace process { namespace detail { namespace posix {
template<int p1, int p2>
struct pipe_out : handler_base_ext
{
int sink;
int source; //opposite end
pipe_out(int sink, int source) : sink(sink), source(source) {}
template<typename T>
pipe_out(T & p) : sink(p.native_sink()), source(p.native_source())
{
p.assign_sink(-1);
}
template<typename Executor>
void on_error(Executor &, const std::error_code &) const
{
::close(sink);
}
template<typename Executor>
void on_success(Executor &) const
{
::close(sink);
}
template <typename Executor>
void on_exec_setup(Executor &e) const;
};
template<>
template<typename Executor>
void pipe_out<1,-1>::on_exec_setup(Executor &e) const
{
if (::dup2(sink, STDOUT_FILENO) == -1)
e.set_error(::boost::process::detail::get_last_error(), "dup3() failed");
::close(sink);
::close(source);
}
template<>
template<typename Executor>
void pipe_out<2,-1>::on_exec_setup(Executor &e) const
{
if (::dup2(sink, STDERR_FILENO) == -1)
e.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
::close(sink);
::close(source);
}
template<>
template<typename Executor>
void pipe_out<1,2>::on_exec_setup(Executor &e) const
{
if (::dup2(sink, STDOUT_FILENO) == -1)
e.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
if (::dup2(sink, STDERR_FILENO) == -1)
e.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
::close(sink);
::close(source);
}
class async_pipe;
template<int p1, int p2>
struct async_pipe_out : public pipe_out<p1, p2>
{
async_pipe &pipe;
template<typename AsyncPipe>
async_pipe_out(AsyncPipe & p) : pipe_out<p1, p2>(p.native_sink(), p.native_source()), pipe(p)
{
}
template<typename Pipe, typename Executor>
static void close(Pipe & pipe, Executor &)
{
boost::system::error_code ec;
std::move(pipe).sink().close(ec);
}
template<typename Executor>
void on_error(Executor & exec, const std::error_code &)
{
close(pipe, exec);
}
template<typename Executor>
void on_success(Executor &exec)
{
close(pipe, exec);
}
};
}}}}
#endif
@@ -0,0 +1,39 @@
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
// Copyright (c) 2009 Boris Schaeling
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
//
// 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_POSIX_SEARCH_PATH_HPP
#define BOOST_PROCESS_POSIX_SEARCH_PATH_HPP
#include <boost/process/detail/config.hpp>
#include <boost/filesystem.hpp>
#include <boost/tokenizer.hpp>
#include <string>
#include <stdexcept>
#include <stdlib.h>
#include <unistd.h>
namespace boost { namespace process { namespace detail { namespace posix {
inline boost::filesystem::path search_path(
const boost::filesystem::path &filename,
const std::vector<boost::filesystem::path> &path)
{
std::string result;
for (const boost::filesystem::path & pp : path)
{
auto p = pp / filename;
if (!::access(p.c_str(), X_OK))
return p;
}
return "";
}
}}}}
#endif
@@ -0,0 +1,32 @@
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
// Copyright (c) 2009 Boris Schaeling
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
//
// 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_POSIX_SHELL_PATH_HPP
#define BOOST_PROCESS_POSIX_SHELL_PATH_HPP
#include <boost/process/detail/config.hpp>
#include <boost/system/error_code.hpp>
#include <boost/filesystem/path.hpp>
namespace boost { namespace process { namespace detail { namespace posix {
inline boost::filesystem::path shell_path()
{
return "/bin/sh";
}
inline boost::filesystem::path shell_path(std::error_code &ec)
{
ec.clear();
return "/bin/sh";
}
}}}}
#endif
@@ -0,0 +1,79 @@
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
// Copyright (c) 2009 Boris Schaeling
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
// 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_POSIX_SIGNAL_HPP
#define BOOST_PROCESS_POSIX_SIGNAL_HPP
#include <boost/process/detail/posix/handler.hpp>
#include <signal.h>
namespace boost { namespace process { namespace detail { namespace posix {
#if defined(__GLIBC__)
using sighandler_t = ::sighandler_t;
#else
using sighandler_t = void(*)(int);
#endif
struct sig_init_ : handler_base_ext
{
sig_init_ (sighandler_t handler) : _handler(handler) {}
template <class PosixExecutor>
void on_exec_setup(PosixExecutor&)
{
_old = ::signal(SIGCHLD, _handler);
}
template <class Executor>
void on_error(Executor&, const std::error_code &)
{
if (!_reset)
{
::signal(SIGCHLD, _old);
_reset = true;
}
}
template <class Executor>
void on_success(Executor&)
{
if (!_reset)
{
::signal(SIGCHLD, _old);
_reset = true;
}
}
private:
bool _reset = false;
::boost::process::detail::posix::sighandler_t _old{0};
::boost::process::detail::posix::sighandler_t _handler{0};
};
struct sig_
{
constexpr sig_() {}
sig_init_ operator()(::boost::process::detail::posix::sighandler_t h) const {return h;}
sig_init_ operator= (::boost::process::detail::posix::sighandler_t h) const {return h;}
sig_init_ dfl() const {return SIG_DFL;}
sig_init_ ign() const {return SIG_IGN;}
};
}}}}
#endif
@@ -0,0 +1,38 @@
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
// Copyright (c) 2009 Boris Schaeling
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
//
// 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_POSIX_START_DIR_HPP
#define BOOST_PROCESS_DETAIL_POSIX_START_DIR_HPP
#include <boost/process/detail/posix/handler.hpp>
#include <string>
#include <unistd.h>
namespace boost { namespace process { namespace detail { namespace posix {
template<typename Char>
struct start_dir_init : handler_base_ext
{
typedef Char value_type;
typedef std::basic_string<value_type> string_type;
start_dir_init(const string_type &s) : s_(s) {}
template <class PosixExecutor>
void on_exec_setup(PosixExecutor&) const
{
::chdir(s_.c_str());
}
const string_type & str() const {return s_;}
private:
string_type s_;
};
}}}}
#endif
@@ -0,0 +1,44 @@
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
// Copyright (c) 2009 Boris Schaeling
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
//
// 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_POSIX_TERMINATE_HPP
#define BOOST_PROCESS_DETAIL_POSIX_TERMINATE_HPP
#include <boost/process/detail/config.hpp>
#include <boost/process/detail/posix/child_handle.hpp>
#include <system_error>
#include <signal.h>
#include <sys/wait.h>
namespace boost { namespace process { namespace detail { namespace posix {
inline void terminate(const child_handle &p)
{
if (::kill(p.pid, SIGKILL) == -1)
boost::process::detail::throw_last_error("kill(2) failed");
int status;
::waitpid(p.pid, &status, 0); //just to clean it up
}
inline void terminate(const child_handle &p, std::error_code &ec) noexcept
{
if (::kill(p.pid, SIGKILL) == -1)
ec = boost::process::detail::get_last_error();
else
ec.clear();
int status;
::waitpid(p.pid, &status, 0); //just to clean it up
}
}}}}
#endif
@@ -0,0 +1,33 @@
/*
* use_vfork.hpp
*
* Created on: 17.06.2016
* Author: klemens
*/
#ifndef BOOST_PROCESS_DETAIL_POSIX_USE_VFORK_HPP_
#define BOOST_PROCESS_DETAIL_POSIX_USE_VFORK_HPP_
#include <boost/process/detail/posix/handler.hpp>
#include <boost/fusion/sequence/intrinsic/has_key.hpp>
#include <boost/fusion/container/set/convert.hpp>
namespace boost { namespace process { namespace detail { namespace posix {
struct use_vfork_ : handler_base_ext
{
constexpr use_vfork_(){};
};
template<typename Sequence>
struct shall_use_vfork
{
typedef typename boost::fusion::result_of::as_set<Sequence>::type set_type;
typedef typename boost::fusion::result_of::has_key<set_type, const use_vfork_&>::type type;
};
}}}}
#endif /* BOOST_PROCESS_DETAIL_POSIX_USE_VFORK_HPP_ */
@@ -0,0 +1,205 @@
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
// Copyright (c) 2009 Boris Schaeling
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
//
// 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_POSIX_WAIT_FOR_EXIT_HPP
#define BOOST_PROCESS_DETAIL_POSIX_WAIT_FOR_EXIT_HPP
#include <boost/process/detail/config.hpp>
#include <boost/process/detail/posix/child_handle.hpp>
#include <system_error>
#include <sys/types.h>
#include <sys/wait.h>
namespace boost { namespace process { namespace detail { namespace posix {
inline void wait(const child_handle &p, int & exit_code)
{
pid_t ret;
int status;
do
{
ret = ::waitpid(p.pid, &status, 0);
} while (((ret == -1) && (errno == EINTR)) || (ret != -1 && !WIFEXITED(status)));
if (ret == -1)
boost::process::detail::throw_last_error("waitpid(2) failed");
exit_code = status;
}
inline void wait(const child_handle &p, int & exit_code, std::error_code &ec) noexcept
{
pid_t ret;
int status;
do
{
ret = ::waitpid(p.pid, &status, 0);
}
while (((ret == -1) && (errno == EINTR)) || (ret != -1 && !WIFEXITED(status)));
if (ret == -1)
ec = boost::process::detail::get_last_error();
else
{
ec.clear();
exit_code = status;
}
}
template< class Rep, class Period >
inline bool wait_for(
const child_handle &p,
int & exit_code,
const std::chrono::duration<Rep, Period>& rel_time)
{
pid_t ret;
int status;
auto start = std::chrono::system_clock::now();
auto time_out = start + rel_time;
bool time_out_occured = false;
do
{
ret = ::waitpid(p.pid, &status, WUNTRACED | WNOHANG);
if (std::chrono::system_clock::now() >= time_out)
{
time_out_occured = true;
break;
}
}
while (((ret == -1) && errno == EINTR) ||
((ret != -1) && !WIFEXITED(status)));
if (ret == -1)
boost::process::detail::throw_last_error("waitpid(2) failed");
exit_code = status;
return !time_out_occured;
}
template< class Rep, class Period >
inline bool wait_for(
const child_handle &p,
int & exit_code,
const std::chrono::duration<Rep, Period>& rel_time,
std::error_code & ec) noexcept
{
pid_t ret;
int status;
auto start = std::chrono::system_clock::now();
auto time_out = start + rel_time;
bool time_out_occured = false;
do
{
ret = ::waitpid(p.pid, &status, WUNTRACED | WNOHANG);
if (std::chrono::system_clock::now() >= time_out)
{
time_out_occured = true;
break;
}
}
while (((ret == -1) && errno == EINTR) ||
((ret != -1) && !WIFEXITED(status)));
if (ret == -1)
ec = boost::process::detail::get_last_error();
else
{
ec.clear();
exit_code = status;
}
return !time_out_occured;
}
template< class Rep, class Period >
inline bool wait_until(
const child_handle &p,
int & exit_code,
const std::chrono::duration<Rep, Period>& time_out)
{
pid_t ret;
int status;
bool time_out_occured = false;
do
{
ret = ::waitpid(p.pid, &status, WUNTRACED | WNOHANG);
if (std::chrono::system_clock::now() >= time_out)
{
time_out_occured = true;
break;
}
}
while (((ret == -1) && errno == EINTR) ||
((ret != -1) && !WIFEXITED(status)));
if (ret == -1)
boost::process::detail::throw_last_error("waitpid(2) failed");
exit_code = status;
return !time_out_occured;
}
template< class Rep, class Period >
inline bool wait_until(
const child_handle &p,
int & exit_code,
const std::chrono::duration<Rep, Period>& time_out,
std::error_code & ec) noexcept
{
pid_t ret;
int status;
bool time_out_occured = false;
do
{
ret = ::waitpid(p.pid, &status, WUNTRACED | WNOHANG);
if (std::chrono::system_clock::now() >= time_out)
{
time_out_occured = true;
break;
}
}
while (((ret == -1) && errno == EINTR) ||
((ret != -1) && !WIFEXITED(status)));
if (ret == -1)
ec = boost::process::detail::get_last_error();
else
{
ec.clear();
exit_code = status;
}
return !time_out_occured;
}
}}}}
#endif
@@ -0,0 +1,191 @@
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
// Copyright (c) 2009 Boris Schaeling
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
//
// 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_POSIX_WAIT_GROUP_HPP
#define BOOST_PROCESS_DETAIL_POSIX_WAIT_GROUP_HPP
#include <boost/process/detail/config.hpp>
#include <boost/process/detail/posix/group_handle.hpp>
#include <system_error>
#include <sys/types.h>
#include <sys/wait.h>
namespace boost { namespace process { namespace detail { namespace posix {
inline void wait(const group_handle &p)
{
pid_t ret;
int status;
do
{
ret = ::waitpid(-p.grp, &status, 0);
} while (((ret == -1) && (errno == EINTR)) || (ret != -1 && !WIFEXITED(status)));
if (ret == -1)
boost::process::detail::throw_last_error("waitpid(2) failed");
}
inline void wait(const group_handle &p, std::error_code &ec) noexcept
{
pid_t ret;
int status;
do
{
ret = ::waitpid(-p.grp, &status, 0);
}
while (((ret == -1) && (errno == EINTR)) || (ret != -1 && !WIFEXITED(status)));
if (ret == -1)
ec = boost::process::detail::get_last_error();
else
ec.clear();
}
template< class Rep, class Period >
inline bool wait_for(
const group_handle &p,
const std::chrono::duration<Rep, Period>& rel_time)
{
pid_t ret;
int status;
auto start = std::chrono::system_clock::now();
auto time_out = start + rel_time;
bool time_out_occured = false;
do
{
ret = ::waitpid(-p.grp, &status, WUNTRACED | WNOHANG);
if (std::chrono::system_clock::now() >= time_out)
{
time_out_occured = true;
break;
}
}
while (((ret == -1) && errno == EINTR) ||
((ret != -1) && !WIFEXITED(status)));
if (ret == -1)
boost::process::detail::throw_last_error("waitpid(2) failed");
return !time_out_occured;
}
template< class Rep, class Period >
inline bool wait_for(
const group_handle &p,
const std::chrono::duration<Rep, Period>& rel_time,
std::error_code & ec) noexcept
{
pid_t ret;
int status;
auto start = std::chrono::system_clock::now();
auto time_out = start + rel_time;
bool time_out_occured = false;
do
{
ret = ::waitpid(-p.grp, &status, WUNTRACED | WNOHANG);
if (std::chrono::system_clock::now() >= time_out)
{
time_out_occured = true;
break;
}
}
while (((ret == -1) && errno == EINTR) ||
((ret != -1) && !WIFEXITED(status)));
if (ret == -1)
ec = boost::process::detail::get_last_error();
else
ec.clear();
return !time_out_occured;
}
template< class Rep, class Period >
inline bool wait_until(
const group_handle &p,
const std::chrono::duration<Rep, Period>& time_out)
{
pid_t ret;
int status;
auto start = std::chrono::system_clock::now();
bool time_out_occured = false;
do
{
ret = ::waitpid(-p.grp, &status, WUNTRACED | WNOHANG);
if (std::chrono::system_clock::now() >= time_out)
{
time_out_occured = true;
break;
}
}
while (((ret == -1) && errno == EINTR) ||
((ret != -1) && !WIFEXITED(status)));
if (ret == -1)
boost::process::detail::throw_last_error("waitpid(2) failed");
return !time_out_occured;
}
template< class Rep, class Period >
inline bool wait_until(
const group_handle &p,
const std::chrono::duration<Rep, Period>& time_out,
std::error_code & ec) noexcept
{
pid_t ret;
int status;
auto start = std::chrono::system_clock::now();
bool time_out_occured = false;
do
{
ret = ::waitpid(-p.grp, &status, WUNTRACED | WNOHANG);
if (std::chrono::system_clock::now() >= time_out)
{
time_out_occured = true;
break;
}
}
while (((ret == -1) && errno == EINTR) ||
((ret != -1) && !WIFEXITED(status)));
if (ret == -1)
ec = boost::process::detail::get_last_error();
else
ec.clear();
return !time_out_occured;
}
}}}}
#endif
@@ -0,0 +1,36 @@
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
// Copyright (c) 2009 Boris Schaeling
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
// 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_INITIALIZERS_THROW_ON_ERROR_HPP
#define BOOST_PROCESS_DETAIL_INITIALIZERS_THROW_ON_ERROR_HPP
#include <boost/process/detail/config.hpp>
#include <boost/process/detail/handler_base.hpp>
namespace boost { namespace process { namespace detail {
struct throw_on_error_ : ::boost::process::detail::handler
{
template <class Executor>
void on_error(Executor& exec, const std::error_code & ec) const
{
throw process_error(ec, "process creation failed");
}
const throw_on_error_ &operator()() const {return *this;}
};
}
constexpr boost::process::detail::throw_on_error_ throw_on_error;
}}
#endif
@@ -0,0 +1,17 @@
// 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_TRAITS_HPP_
#define BOOST_PROCESS_TRAITS_HPP_
#include <boost/process/detail/traits/decl.hpp>
#include <boost/process/detail/traits/async.hpp>
#include <boost/process/detail/traits/cmd_or_exe.hpp>
#include <boost/process/detail/traits/env.hpp>
#include <boost/process/detail/traits/error.hpp>
#include <boost/process/detail/traits/wchar_t.hpp>
#endif /* BOOST_PROCESS_TRAITS_HPP_ */
@@ -0,0 +1,34 @@
// 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_TRAITS_ASYNC_HPP_
#define BOOST_PROCESS_DETAIL_TRAITS_ASYNC_HPP_
#include <boost/process/detail/config.hpp>
#include <boost/process/detail/traits/decl.hpp>
namespace boost { namespace asio {
class io_service;
}}
namespace boost { namespace process { namespace detail {
struct async_tag {};
template<>
struct initializer_builder<async_tag>;
template<> struct initializer_tag<::boost::asio::io_service> { typedef async_tag type;};
}}}
#endif /* BOOST_PROCESS_DETAIL_HANDLER_HPP_ */
@@ -0,0 +1,85 @@
// 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_TRAITS_CMD_OR_EXE_HPP_
#define BOOST_PROCESS_DETAIL_TRAITS_CMD_OR_EXE_HPP_
#include <string>
#include <vector>
#include <type_traits>
#include <initializer_list>
#include <boost/filesystem/path.hpp>
#include <boost/process/detail/traits/decl.hpp>
namespace boost { namespace process { namespace detail {
template<typename Char>
struct cmd_or_exe_tag {};
struct shell_;
template<> struct initializer_tag<const char* > { typedef cmd_or_exe_tag<char> type;};
template<> struct initializer_tag<const wchar_t* > { typedef cmd_or_exe_tag<wchar_t> type;};
template<> struct initializer_tag<char* > { typedef cmd_or_exe_tag<char> type;};
template<> struct initializer_tag<wchar_t* > { typedef cmd_or_exe_tag<wchar_t> type;};
template<std::size_t Size> struct initializer_tag<const char [Size]> { typedef cmd_or_exe_tag<char> type;};
template<std::size_t Size> struct initializer_tag<const wchar_t [Size]> { typedef cmd_or_exe_tag<wchar_t> type;};
template<std::size_t Size> struct initializer_tag<const char (&)[Size]> { typedef cmd_or_exe_tag<char> type;};
template<std::size_t Size> struct initializer_tag<const wchar_t (&)[Size]> { typedef cmd_or_exe_tag<wchar_t> type;};
template<> struct initializer_tag<std::basic_string<char >> { typedef cmd_or_exe_tag<char> type;};
template<> struct initializer_tag<std::basic_string<wchar_t >> { typedef cmd_or_exe_tag<wchar_t> type;};
template<> struct initializer_tag<std::vector<std::basic_string<char >>> { typedef cmd_or_exe_tag<char> type;};
template<> struct initializer_tag<std::vector<std::basic_string<wchar_t >>> { typedef cmd_or_exe_tag<wchar_t> type;};
template<> struct initializer_tag<std::initializer_list<std::basic_string<char >>> { typedef cmd_or_exe_tag<char> type;};
template<> struct initializer_tag<std::initializer_list<std::basic_string<wchar_t >>> { typedef cmd_or_exe_tag<wchar_t> type;};
template<> struct initializer_tag<std::vector<char *>> { typedef cmd_or_exe_tag<char> type;};
template<> struct initializer_tag<std::vector<wchar_t *>> { typedef cmd_or_exe_tag<wchar_t> type;};
template<> struct initializer_tag<std::initializer_list<char *>> { typedef cmd_or_exe_tag<char> type;};
template<> struct initializer_tag<std::initializer_list<wchar_t *>> { typedef cmd_or_exe_tag<wchar_t> type;};
template<> struct initializer_tag<std::initializer_list<const char *>> { typedef cmd_or_exe_tag<char> type;};
template<> struct initializer_tag<std::initializer_list<const wchar_t *>> { typedef cmd_or_exe_tag<wchar_t> type;};
template<> struct initializer_tag<shell_>
{
typedef cmd_or_exe_tag<typename boost::filesystem::path::value_type> type;
};
template<> struct initializer_tag<boost::filesystem::path>
{
typedef cmd_or_exe_tag<typename boost::filesystem::path::value_type> type;
};
template <typename Char>
struct exe_setter_;
template <typename Char, bool Append = false>
struct arg_setter_;
template <typename Char, bool Append>
struct initializer_tag<arg_setter_<Char, Append>> { typedef cmd_or_exe_tag<Char> type;};
template<typename Char> struct initializer_tag<exe_setter_<Char>> { typedef cmd_or_exe_tag<Char> type;};
template<>
struct initializer_builder<cmd_or_exe_tag<char>>;
template<>
struct initializer_builder<cmd_or_exe_tag<wchar_t>>;
}}}
#endif /* BOOST_PROCESS_DETAIL_STRING_TRAITS_HPP_ */
@@ -0,0 +1,76 @@
// 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_TRAITS_DECL_HPP_
#define BOOST_PROCESS_DETAIL_TRAITS_DECL_HPP_
#include <boost/process/detail/config.hpp>
#include <boost/none.hpp>
#include <type_traits>
#if defined(BOOST_POSIX_API)
#include <boost/process/detail/posix/handler.hpp>
#elif defined(BOOST_WINDOWS_API)
#include <boost/process/detail/windows/handler.hpp>
#endif
namespace boost { namespace process { namespace detail {
template<typename T>
struct is_initializer : std::is_base_of<handler_base, T> {};
template<typename T>
struct is_initializer<T&> : std::is_base_of<handler_base, T> {};
template<typename T>
struct initializer_tag;// { typedef void type; };
//remove const
template<typename T>
struct initializer_tag<const T> { typedef typename initializer_tag<T>::type type; };
//remove &
template<typename T>
struct initializer_tag<T&> { typedef typename initializer_tag<T>::type type; };
//remove const &
template<typename T>
struct initializer_tag<const T&> { typedef typename initializer_tag<T>::type type; };
template<typename T>
struct initializer_builder;
template<typename First, typename ...Args>
struct valid_argument_list;
template<typename First>
struct valid_argument_list<First>
{
constexpr static bool value = is_initializer<First>::value || !std::is_void<typename initializer_tag<First>::type>::value;
typedef std::integral_constant<bool, value> type;
};
template<typename First, typename ...Args>
struct valid_argument_list
{
constexpr static bool my_value = is_initializer<First>::value || !std::is_void<typename initializer_tag<First>::type>::value;
constexpr static bool value = valid_argument_list<Args...>::value && my_value;
typedef std::integral_constant<bool, value> type;
};
}}}
#endif /* BOOST_PROCESS_DETAIL_HANDLER_HPP_ */
@@ -0,0 +1,53 @@
// 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_TRAITS_ENV_HPP_
#define BOOST_PROCESS_DETAIL_TRAITS_ENV_HPP_
#include <boost/process/detail/traits/decl.hpp>
namespace boost { namespace process {
template<typename Char>
class basic_environment;
template<typename Char>
class basic_native_environment;
namespace detail {
template<typename Char>
struct env_tag {};
template<typename Char> struct env_set;
template<typename Char> struct env_append;
template<typename Char> struct env_reset;
template<typename Char> struct env_init;
template<typename Char> struct initializer_tag<env_set<Char>> { typedef env_tag<Char> type; };
template<typename Char> struct initializer_tag<env_append<Char>> { typedef env_tag<Char> type; };
template<typename Char> struct initializer_tag<env_reset<Char>> { typedef env_tag<Char> type;};
template<typename Char> struct initializer_tag<env_init <Char>> { typedef env_tag<Char> type;};
template<typename Char> struct initializer_tag<::boost::process::basic_environment<Char>> { typedef env_tag<Char> type; };
template<typename Char> struct initializer_tag<::boost::process::basic_native_environment<Char>> { typedef env_tag<Char> type; };
template<> struct initializer_builder<env_tag<char>>;
template<> struct initializer_builder<env_tag<wchar_t>>;
}
}}
#endif /* INCLUDE_BOOST_PROCESS_DETAIL_ENV_HPP_ */
@@ -0,0 +1,27 @@
// 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_TRAITS_ERROR_HPP_
#define BOOST_PROCESS_DETAIL_TRAITS_ERROR_HPP_
#include <boost/process/detail/config.hpp>
#include <system_error>
#include <boost/process/detail/traits/decl.hpp>
namespace boost { namespace process { namespace detail {
struct error_tag;
template<>
struct initializer_tag<std::error_code>;
}}}
#endif /* BOOST_PROCESS_DETAIL_HANDLER_HPP_ */
@@ -0,0 +1,37 @@
// 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_TRAITS_GROUP_HPP_
#define BOOST_PROCESS_DETAIL_TRAITS_GROUP_HPP_
#include <boost/process/detail/config.hpp>
#include <boost/process/detail/traits/decl.hpp>
namespace boost { namespace process {
struct group;
namespace detail {
struct group_tag {};
template<>
struct make_initializer_t<group_tag>;
template<> struct initializer_tag_t<::boost::process::group> { typedef group_tag type;};
}}}
#endif /* BOOST_PROCESS_DETAIL_HANDLER_HPP_ */
@@ -0,0 +1,274 @@
// 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_TRAITS_WCHAR_T_HPP_
#define BOOST_PROCESS_DETAIL_TRAITS_WCHAR_T_HPP_
#include <boost/process/detail/traits/decl.hpp>
#include <boost/process/detail/traits/cmd_or_exe.hpp>
#include <boost/process/detail/traits/env.hpp>
#include <boost/process/locale.hpp>
namespace boost { namespace process { namespace detail {
//template
template<typename T> struct is_wchar_t : std::false_type {};
template<> struct is_wchar_t<boost::filesystem::path> : std::is_same<typename boost::filesystem::path::value_type, wchar_t>
{
};
template<> struct is_wchar_t<const wchar_t* > : std::true_type {};
template<> struct is_wchar_t<wchar_t* > : std::true_type {};
template<std::size_t Size> struct is_wchar_t<const wchar_t [Size]> : std::true_type {};
template<std::size_t Size> struct is_wchar_t<const wchar_t (&)[Size]> : std::true_type {};
template<> struct is_wchar_t<std::wstring> : std::true_type {};
template<> struct is_wchar_t<std::vector<std::wstring>> : std::true_type {};
template<> struct is_wchar_t<std::initializer_list<std::wstring>> : std::true_type {};
template<> struct is_wchar_t<std::vector<wchar_t *>> : std::true_type {};
template<> struct is_wchar_t<std::initializer_list<wchar_t *>> : std::true_type {};
template<typename Char, typename T>
struct char_converter
{
static T& conv(T & in)
{
return in;
}
static T&& conv(T&& in)
{
return std::move(in);
}
static const T& conv(const T & in)
{
return in;
}
};
template<typename Char, typename T>
using char_converter_t = char_converter<Char,
typename std::remove_cv<typename std::remove_reference<T>::type>::type>;
template<>
struct char_converter<char, const wchar_t*>
{
static std::string conv(const wchar_t* in)
{
std::size_t size = 0;
while (in[size] != L'\0') size++;
return ::boost::process::detail::convert(in, in + size);
}
};
template<>
struct char_converter<char, wchar_t*>
{
static std::string conv(wchar_t* in)
{
std::size_t size = 0;
while (in[size] != L'\0') size++;
return ::boost::process::detail::convert(in, in + size);
}
};
template<std::size_t Size>
struct char_converter<char, wchar_t[Size]>
{
static std::string conv(const wchar_t(&in)[Size])
{
return ::boost::process::detail::convert(in, in + Size -1);
}
};
template<>
struct char_converter<wchar_t, const char*>
{
static std::wstring conv(const char* in)
{
std::size_t size = 0;
while (in[size] != '\0') size++;
return ::boost::process::detail::convert(in, in + size);
}
};
template<>
struct char_converter<wchar_t, char*>
{
static std::wstring conv(char* in)
{
std::size_t size = 0;
while (in[size] != '\0') size++;
return ::boost::process::detail::convert(in, in + size);
}
};
template<std::size_t Size>
struct char_converter<wchar_t, char[Size]>
{
static std::wstring conv(const char(&in)[Size])
{
return ::boost::process::detail::convert(in, in + Size -1);
}
};
//all the containers.
template<>
struct char_converter<wchar_t, std::string>
{
static std::wstring conv(const std::string & in)
{
return ::boost::process::detail::convert(in);
}
};
template<>
struct char_converter<char, std::wstring>
{
static std::string conv(const std::wstring & in)
{
return ::boost::process::detail::convert(in);
}
};
template<>
struct char_converter<wchar_t, std::vector<std::string>>
{
static std::vector<std::wstring> conv(const std::vector<std::string> & in)
{
std::vector<std::wstring> ret(in.size());
std::transform(in.begin(), in.end(), ret.begin(),
[](const std::string & st)
{
return convert(st);
});
return ret;
}
};
template<>
struct char_converter<wchar_t, std::initializer_list<std::string>>
{
static std::vector<std::wstring> conv(const std::initializer_list<std::string> & in)
{
std::vector<std::wstring> ret(in.size());
std::transform(in.begin(), in.end(), ret.begin(),
[](const std::string & st)
{
return convert(st);
});
return ret;
}
};
template<>
struct char_converter<wchar_t, std::vector<char* >>
{
static std::vector<std::wstring> conv(const std::vector<char* > & in)
{
std::vector<std::wstring> ret(in.size());
std::transform(in.begin(), in.end(), ret.begin(),
[](const char* st)
{
std::size_t sz = 0;
while (st[sz] != '\0') sz++;
return convert(st, st + sz);
});
return ret;
}
};
template<>
struct char_converter<wchar_t, std::initializer_list<char *>>
{
static std::vector<std::wstring> conv(const std::initializer_list<char * > & in)
{
std::vector<std::wstring> ret(in.size());
std::transform(in.begin(), in.end(), ret.begin(),
[](const char* st)
{
std::size_t sz = 0;
while (st[sz] != '\0') sz++;
return convert(st, st + sz);
});
return ret;
}
};
template<>
struct char_converter<char, std::vector<std::wstring>>
{
static std::vector<std::string> conv(const std::vector<std::wstring> & in)
{
std::vector<std::string> ret(in.size());
std::transform(in.begin(), in.end(), ret.begin(),
[](const std::wstring & st)
{
return convert(st);
});
return ret;
}
};
template<>
struct char_converter<char, std::initializer_list<std::wstring>>
{
static std::vector<std::string> conv(const std::initializer_list<std::wstring> & in)
{
std::vector<std::string> ret(in.size());
std::transform(in.begin(), in.end(), ret.begin(),
[](const std::wstring & st)
{
return convert(st);
});
return ret;
}
};
template<>
struct char_converter<char, std::vector<wchar_t* >>
{
static std::vector<std::string> conv(const std::vector<wchar_t* > & in)
{
std::vector<std::string> ret(in.size());
std::transform(in.begin(), in.end(), ret.begin(),
[](const wchar_t* st)
{
std::size_t sz = 0;
while (st[sz] != L'\0') sz++;
return convert(st, st + sz);
});
return ret;
}
};
template<>
struct char_converter<char, std::initializer_list<wchar_t * >>
{
static std::vector<std::string> conv(const std::initializer_list<wchar_t *> & in)
{
std::vector<std::string> ret(in.size());
std::transform(in.begin(), in.end(), ret.begin(),
[](const wchar_t* st)
{
std::size_t sz = 0;
while (st[sz] != L'\0') sz++;
return convert(st, st + sz);
});
return ret;
}
};
}}}
#endif /* BOOST_PROCESS_DETAIL_TRAITS_WCHAR_T_HPP_ */
@@ -0,0 +1,71 @@
// 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_WINDOWS_ASIO_FWD_HPP_
#define BOOST_PROCESS_DETAIL_WINDOWS_ASIO_FWD_HPP_
#include <memory>
namespace boost { namespace asio {
class mutable_buffer;
class mutable_buffers_1;
class const_buffer;
class const_buffers_1;
template<typename Allocator>
class basic_streambuf;
typedef basic_streambuf<std::allocator<char>> streambuf;
class io_service;
template <typename Handler>
class basic_yield_context;
namespace windows {
class stream_handle_service;
template <typename StreamHandleService>
class basic_stream_handle;
typedef basic_stream_handle<stream_handle_service> stream_handle;
class object_handle_service;
template <typename ObjectHandleService>
class basic_object_handle;
typedef basic_object_handle<object_handle_service> object_handle;
} //windows
} //asio
namespace process { namespace detail { namespace windows {
class async_pipe;
template<typename T>
struct async_in_buffer;
template<int p1, int p2, typename Buffer>
struct async_out_buffer;
template<int p1, int p2, typename Type>
struct async_out_future;
} // windows
} // detail
using ::boost::process::detail::windows::async_pipe;
} // process
} // boost
#endif /* BOOST_PROCESS_DETAIL_WINDOWS_ASIO_FWD_HPP_ */
@@ -0,0 +1,40 @@
// 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_WINDOWS_ASYNC_HANDLER_HPP_
#define BOOST_PROCESS_WINDOWS_ASYNC_HANDLER_HPP_
#include <boost/process/detail/windows/handler.hpp>
#include <type_traits>
namespace boost { namespace process { namespace detail { namespace windows {
struct require_io_service {};
struct async_handler : handler_base_ext, require_io_service
{
};
template<typename T>
struct is_async_handler : std::is_base_of<async_handler, T> {};
template<typename T>
struct is_async_handler<T&> : std::is_base_of<async_handler, T> {};
template<typename T>
struct is_async_handler<const T&> : std::is_base_of<async_handler, T> {};
template<typename T>
struct does_require_io_service : std::is_base_of<require_io_service, T> {};
template<typename T>
struct does_require_io_service<T&> : std::is_base_of<require_io_service, T> {};
template<typename T>
struct does_require_io_service<const T&> : std::is_base_of<require_io_service, T> {};
}}}}
#endif /* BOOST_PROCESS_WINDOWS_ASYNC_HANDLER_HPP_ */
@@ -0,0 +1,105 @@
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
// Copyright (c) 2009 Boris Schaeling
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
//
// 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_WINDOWS_INITIALIZERS_ASYNC_IN_HPP
#define BOOST_PROCESS_WINDOWS_INITIALIZERS_ASYNC_IN_HPP
#include <boost/detail/winapi/process.hpp>
#include <boost/detail/winapi/handles.hpp>
#include <boost/detail/winapi/handle_info.hpp>
#include <boost/detail/winapi/error_codes.hpp>
#include <boost/asio/write.hpp>
#include <boost/process/detail/handler_base.hpp>
#include <boost/process/detail/windows/async_handler.hpp>
#include <boost/process/detail/windows/asio_fwd.hpp>
#include <boost/process/async_pipe.hpp>
#include <memory>
#include <future>
namespace boost { namespace process { namespace detail { namespace windows {
template<typename Buffer>
struct async_in_buffer : ::boost::process::detail::windows::handler_base_ext,
::boost::process::detail::windows::require_io_service
{
Buffer & buf;
std::shared_ptr<std::promise<void>> promise;
async_in_buffer operator>(std::future<void> & fut)
{
promise = std::make_shared<std::promise<void>>();
fut = promise->get_future(); return std::move(*this);
}
std::shared_ptr<boost::process::async_pipe> pipe;
async_in_buffer(Buffer & buf) : buf(buf)
{
}
template <typename Executor>
inline void on_success(Executor&)
{
auto pipe = this->pipe;
if (this->promise)
{
auto promise = this->promise;
boost::asio::async_write(*pipe, buf,
[promise](const boost::system::error_code & ec, std::size_t)
{
if (ec && (ec.value() != ::boost::detail::winapi::ERROR_BROKEN_PIPE_))
{
std::error_code e(ec.value(), std::system_category());
promise->set_exception(std::make_exception_ptr(process_error(e)));
}
promise->set_value();
});
}
else
boost::asio::async_write(*pipe, buf,
[pipe](const boost::system::error_code&, std::size_t){});
std::move(*pipe).source().close();
this->pipe = nullptr;
}
template<typename Executor>
void on_error(Executor &, const std::error_code &) const
{
::boost::detail::winapi::CloseHandle(pipe->native_source());
}
template <typename WindowsExecutor>
void on_setup(WindowsExecutor &exec)
{
if (!pipe)
pipe = std::make_shared<boost::process::async_pipe>(get_io_service(exec.seq));
::boost::detail::winapi::HANDLE_ source_handle = std::move(*pipe).source().native_handle();
boost::detail::winapi::SetHandleInformation(source_handle,
boost::detail::winapi::HANDLE_FLAG_INHERIT_,
boost::detail::winapi::HANDLE_FLAG_INHERIT_);
exec.startup_info.hStdInput = source_handle;
exec.startup_info.dwFlags |= boost::detail::winapi::STARTF_USESTDHANDLES_;
exec.inherit_handles = true;
}
};
}}}}
#endif
@@ -0,0 +1,176 @@
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
// Copyright (c) 2009 Boris Schaeling
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
//
// 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_WINDOWS_INITIALIZERS_ASYNC_OUT_HPP
#define BOOST_PROCESS_WINDOWS_INITIALIZERS_ASYNC_OUT_HPP
#include <boost/detail/winapi/process.hpp>
#include <boost/detail/winapi/handles.hpp>
#include <boost/detail/winapi/handle_info.hpp>
#include <boost/asio/read.hpp>
#include <boost/process/detail/handler_base.hpp>
#include <boost/process/detail/windows/asio_fwd.hpp>
#include <boost/detail/winapi/error_codes.hpp>
#include <istream>
#include <memory>
#include <exception>
#include <future>
namespace boost { namespace process { namespace detail { namespace windows {
template <typename Executor>
inline void apply_out_handles(Executor &e, void* handle, std::integral_constant<int, 1>, std::integral_constant<int, -1>)
{
boost::detail::winapi::SetHandleInformation(handle,
boost::detail::winapi::HANDLE_FLAG_INHERIT_,
boost::detail::winapi::HANDLE_FLAG_INHERIT_);
e.startup_info.hStdOutput = handle;
e.startup_info.dwFlags |= ::boost::detail::winapi::STARTF_USESTDHANDLES_;
e.inherit_handles = true;
}
template <typename Executor>
inline void apply_out_handles(Executor &e, void* handle, std::integral_constant<int, 2>, std::integral_constant<int, -1>)
{
boost::detail::winapi::SetHandleInformation(handle,
boost::detail::winapi::HANDLE_FLAG_INHERIT_,
boost::detail::winapi::HANDLE_FLAG_INHERIT_);
e.startup_info.hStdError = handle;
e.startup_info.dwFlags |= ::boost::detail::winapi::STARTF_USESTDHANDLES_;
e.inherit_handles = true;
}
template <typename Executor>
inline void apply_out_handles(Executor &e, void* handle, std::integral_constant<int, 1>, std::integral_constant<int, 2>)
{
boost::detail::winapi::SetHandleInformation(handle,
boost::detail::winapi::HANDLE_FLAG_INHERIT_,
boost::detail::winapi::HANDLE_FLAG_INHERIT_);
e.startup_info.hStdOutput = handle;
e.startup_info.hStdError = handle;
e.startup_info.dwFlags |= ::boost::detail::winapi::STARTF_USESTDHANDLES_;
e.inherit_handles = true;
}
template<int p1, int p2, typename Buffer>
struct async_out_buffer : ::boost::process::detail::windows::handler_base_ext,
::boost::process::detail::windows::require_io_service
{
Buffer & buf;
std::shared_ptr<boost::process::async_pipe> pipe;
async_out_buffer(Buffer & buf) : buf(buf)
{
}
template <typename Executor>
inline void on_success(Executor&)
{
auto pipe = this->pipe;
boost::asio::async_read(*pipe, buf,
[pipe](const boost::system::error_code&, std::size_t){});
std::move(*pipe).sink().close();
this->pipe = nullptr;
}
template<typename Executor>
void on_error(Executor &, const std::error_code &) const
{
std::move(*pipe).sink().close();
}
template <typename WindowsExecutor>
void on_setup(WindowsExecutor &exec)
{
if (!pipe)
pipe = std::make_shared<boost::process::async_pipe>(get_io_service(exec.seq));
apply_out_handles(exec, std::move(*pipe).sink().native_handle(),
std::integral_constant<int, p1>(), std::integral_constant<int, p2>());
}
};
template<int p1, int p2, typename Type>
struct async_out_future : ::boost::process::detail::windows::handler_base_ext,
::boost::process::detail::windows::require_io_service
{
std::shared_ptr<boost::process::async_pipe> pipe;
std::shared_ptr<std::promise<Type>> promise = std::make_shared<std::promise<Type>>();
std::shared_ptr<boost::asio::streambuf> buffer = std::make_shared<boost::asio::streambuf>();
async_out_future(std::future<Type> & fut)
{
fut = promise->get_future();
}
template <typename Executor>
inline void on_success(Executor&)
{
auto pipe = this->pipe;
auto buffer = this->buffer;
auto promise = this->promise;
std::move(*pipe).sink().close();
boost::asio::async_read(*pipe, *buffer,
[pipe, buffer, promise](const boost::system::error_code& ec, std::size_t)
{
if (ec && (ec.value() != ::boost::detail::winapi::ERROR_BROKEN_PIPE_))
{
std::error_code e(ec.value(), std::system_category());
promise->set_exception(std::make_exception_ptr(process_error(e)));
}
else
{
std::istream is (buffer.get());
Type arg;
arg.resize(buffer->size());
is.read(&*arg.begin(), buffer->size());
promise->set_value(std::move(arg));
}
});
this->pipe = nullptr;
this->buffer = nullptr;
this->promise = nullptr;
}
template<typename Executor>
void on_error(Executor &, const std::error_code &) const
{
std::move(*pipe).sink().close();
}
template <typename WindowsExecutor>
void on_setup(WindowsExecutor &exec)
{
if (!pipe)
pipe = std::make_shared<boost::process::async_pipe>(get_io_service(exec.seq));
apply_out_handles(exec, std::move(*pipe).sink().native_handle(),
std::integral_constant<int, p1>(), std::integral_constant<int, p2>());
}
};
}}}}
#endif
@@ -0,0 +1,415 @@
// 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_WINDOWS_ASYNC_PIPE_HPP_
#define BOOST_PROCESS_DETAIL_WINDOWS_ASYNC_PIPE_HPP_
#include <boost/detail/winapi/basic_types.hpp>
#include <boost/detail/winapi/pipes.hpp>
#include <boost/detail/winapi/handles.hpp>
#include <boost/detail/winapi/file_management.hpp>
#include <boost/detail/winapi/get_last_error.hpp>
#include <boost/detail/winapi/access_rights.hpp>
#include <boost/detail/winapi/process.hpp>
#include <boost/process/detail/windows/basic_pipe.hpp>
#include <boost/asio/windows/stream_handle.hpp>
#include <system_error>
#include <string>
namespace boost { namespace process { namespace detail { namespace windows {
inline std::string make_pipe_name()
{
std::string name = "\\\\.\\pipe\\boost_process_auto_pipe_";
auto pid = ::boost::detail::winapi::GetCurrentProcessId();
static unsigned long long cnt = 0;
name += std::to_string(pid);
name += "_";
name += std::to_string(cnt++);
return name;
}
class async_pipe
{
::boost::asio::windows::stream_handle _source;
::boost::asio::windows::stream_handle _sink ;
public:
typedef ::boost::detail::winapi::HANDLE_ native_handle_type;
typedef ::boost::asio::windows::stream_handle handle_type;
inline async_pipe(boost::asio::io_service & ios,
const std::string & name = make_pipe_name())
: async_pipe(ios, ios, name) {}
inline async_pipe(boost::asio::io_service & ios_source,
boost::asio::io_service & ios_sink,
const std::string & name = make_pipe_name());
inline async_pipe(const async_pipe& rhs);
async_pipe(async_pipe&& rhs) : _source(std::move(rhs._source)), _sink(std::move(rhs._sink))
{
rhs._source.assign (::boost::detail::winapi::INVALID_HANDLE_VALUE_);
rhs._sink .assign (::boost::detail::winapi::INVALID_HANDLE_VALUE_);
}
template<class CharT, class Traits = std::char_traits<CharT>>
explicit async_pipe(::boost::asio::io_service & ios_source,
::boost::asio::io_service & ios_sink,
const basic_pipe<CharT, Traits> & p)
: _source(ios_source, p.native_source()), _sink(ios_sink, p.native_sink())
{
}
template<class CharT, class Traits = std::char_traits<CharT>>
explicit async_pipe(boost::asio::io_service & ios, const basic_pipe<CharT, Traits> & p)
: async_pipe(ios, ios, p)
{
}
template<class CharT, class Traits = std::char_traits<CharT>>
inline async_pipe& operator=(const basic_pipe<CharT, Traits>& p);
inline async_pipe& operator=(const async_pipe& rhs);
inline async_pipe& operator=(async_pipe&& rhs);
~async_pipe()
{
if (_sink .native() != ::boost::detail::winapi::INVALID_HANDLE_VALUE_)
::boost::detail::winapi::CloseHandle(_sink.native());
if (_source.native() != ::boost::detail::winapi::INVALID_HANDLE_VALUE_)
::boost::detail::winapi::CloseHandle(_source.native());
}
template<class CharT, class Traits = std::char_traits<CharT>>
inline explicit operator basic_pipe<CharT, Traits>() const;
void cancel()
{
if (_sink.is_open())
_sink.cancel();
if (_source.is_open())
_source.cancel();
}
void close()
{
if (_sink.is_open())
{
_sink.close();
_sink = handle_type(_sink.get_io_service());
}
if (_source.is_open())
{
_source.close();
_source = handle_type(_source.get_io_service());
}
}
void close(boost::system::error_code & ec)
{
if (_sink.is_open())
{
_sink.close(ec);
_sink = handle_type(_sink.get_io_service());
}
if (_source.is_open())
{
_source.close(ec);
_source = handle_type(_source.get_io_service());
}
}
bool is_open() const
{
return _sink.is_open() || _source.is_open();
}
void async_close()
{
if (_sink.is_open())
_sink.get_io_service(). post([this]{_sink.close();});
if (_source.is_open())
_source.get_io_service().post([this]{_source.close();});
}
template<typename MutableBufferSequence>
std::size_t read_some(const MutableBufferSequence & buffers)
{
return _source.read_some(buffers);
}
template<typename MutableBufferSequence>
std::size_t write_some(const MutableBufferSequence & buffers)
{
return _sink.write_some(buffers);
}
native_handle_type native_source() const {return const_cast<boost::asio::windows::stream_handle&>(_source).native();}
native_handle_type native_sink () const {return const_cast<boost::asio::windows::stream_handle&>(_sink ).native();}
template<typename MutableBufferSequence,
typename ReadHandler>
BOOST_ASIO_INITFN_RESULT_TYPE(
ReadHandler, void(boost::system::error_code, std::size_t))
async_read_some(
const MutableBufferSequence & buffers,
ReadHandler &&handler)
{
_source.async_read_some(buffers, std::forward<ReadHandler>(handler));
}
template<typename ConstBufferSequence,
typename WriteHandler>
BOOST_ASIO_INITFN_RESULT_TYPE(
WriteHandler, void(boost::system::error_code, std::size_t))
async_write_some(
const ConstBufferSequence & buffers,
WriteHandler && handler)
{
_sink.async_write_some(buffers, std::forward<WriteHandler>(handler));
}
const handle_type & sink () const & {return _sink;}
const handle_type & source() const & {return _source;}
handle_type && source() && { return std::move(_source); }
handle_type && sink() && { return std::move(_sink); }
handle_type source(::boost::asio::io_service& ios) &&
{
::boost::asio::windows::stream_handle stolen(ios, _source.native_handle());
_source.assign(::boost::detail::winapi::INVALID_HANDLE_VALUE_);
return stolen;
}
handle_type sink (::boost::asio::io_service& ios) &&
{
::boost::asio::windows::stream_handle stolen(ios, _sink.native_handle());
_sink.assign(::boost::detail::winapi::INVALID_HANDLE_VALUE_);
return stolen;
}
handle_type source(::boost::asio::io_service& ios) const &
{
auto proc = ::boost::detail::winapi::GetCurrentProcess();
::boost::detail::winapi::HANDLE_ source;
auto source_in = const_cast<handle_type&>(_source).native();
if (source_in == ::boost::detail::winapi::INVALID_HANDLE_VALUE_)
source = ::boost::detail::winapi::INVALID_HANDLE_VALUE_;
else if (!::boost::detail::winapi::DuplicateHandle(
proc, source_in, proc, &source, 0,
static_cast<::boost::detail::winapi::BOOL_>(true),
::boost::detail::winapi::DUPLICATE_SAME_ACCESS_))
throw_last_error("Duplicate Pipe Failed");
return ::boost::asio::windows::stream_handle(ios, source);
}
handle_type sink (::boost::asio::io_service& ios) const &
{
auto proc = ::boost::detail::winapi::GetCurrentProcess();
::boost::detail::winapi::HANDLE_ sink;
auto sink_in = const_cast<handle_type&>(_sink).native();
if (sink_in == ::boost::detail::winapi::INVALID_HANDLE_VALUE_)
sink = ::boost::detail::winapi::INVALID_HANDLE_VALUE_;
else if (!::boost::detail::winapi::DuplicateHandle(
proc, sink_in, proc, &sink, 0,
static_cast<::boost::detail::winapi::BOOL_>(true),
::boost::detail::winapi::DUPLICATE_SAME_ACCESS_))
throw_last_error("Duplicate Pipe Failed");
return ::boost::asio::windows::stream_handle(ios, sink);
}
};
async_pipe::async_pipe(const async_pipe& p) :
_source(const_cast<handle_type&>(p._source).get_io_service()),
_sink (const_cast<handle_type&>(p._sink).get_io_service())
{
auto proc = ::boost::detail::winapi::GetCurrentProcess();
::boost::detail::winapi::HANDLE_ source;
::boost::detail::winapi::HANDLE_ sink;
//cannot get the handle from a const object.
auto source_in = const_cast<handle_type&>(p._source).native();
auto sink_in = const_cast<handle_type&>(p._sink).native();
if (source_in == ::boost::detail::winapi::INVALID_HANDLE_VALUE_)
source = ::boost::detail::winapi::INVALID_HANDLE_VALUE_;
else if (!::boost::detail::winapi::DuplicateHandle(
proc, source_in, proc, &source, 0,
static_cast<::boost::detail::winapi::BOOL_>(true),
::boost::detail::winapi::DUPLICATE_SAME_ACCESS_))
throw_last_error("Duplicate Pipe Failed");
if (sink_in == ::boost::detail::winapi::INVALID_HANDLE_VALUE_)
sink = ::boost::detail::winapi::INVALID_HANDLE_VALUE_;
else if (!::boost::detail::winapi::DuplicateHandle(
proc, sink_in, proc, &sink, 0,
static_cast<::boost::detail::winapi::BOOL_>(true),
::boost::detail::winapi::DUPLICATE_SAME_ACCESS_))
throw_last_error("Duplicate Pipe Failed");
_source.assign(source);
_sink. assign(sink);
}
async_pipe::async_pipe(boost::asio::io_service & ios_source,
boost::asio::io_service & ios_sink,
const std::string & name) : _source(ios_source), _sink(ios_sink)
{
static constexpr int FILE_FLAG_OVERLAPPED_ = 0x40000000; //temporary
::boost::detail::winapi::HANDLE_ source = ::boost::detail::winapi::create_named_pipe(
name.c_str(),
::boost::detail::winapi::PIPE_ACCESS_INBOUND_
| FILE_FLAG_OVERLAPPED_, //write flag
0, 1, 8192, 8192, 0, nullptr);
if (source == boost::detail::winapi::INVALID_HANDLE_VALUE_)
::boost::process::detail::throw_last_error("create_named_pipe(" + name + ") failed");
_source.assign(source);
::boost::detail::winapi::HANDLE_ sink = boost::detail::winapi::create_file(
name.c_str(),
::boost::detail::winapi::GENERIC_WRITE_, 0, nullptr,
::boost::detail::winapi::OPEN_EXISTING_,
FILE_FLAG_OVERLAPPED_, //to allow read
nullptr);
if (sink == ::boost::detail::winapi::INVALID_HANDLE_VALUE_)
::boost::process::detail::throw_last_error("create_file() failed");
_sink.assign(sink);
}
async_pipe& async_pipe::operator=(const async_pipe & p)
{
auto proc = ::boost::detail::winapi::GetCurrentProcess();
::boost::detail::winapi::HANDLE_ source;
::boost::detail::winapi::HANDLE_ sink;
//cannot get the handle from a const object.
auto &source_in = const_cast<::boost::asio::windows::stream_handle &>(p._source);
auto &sink_in = const_cast<::boost::asio::windows::stream_handle &>(p._sink);
if (source_in.native() == ::boost::detail::winapi::INVALID_HANDLE_VALUE_)
source = ::boost::detail::winapi::INVALID_HANDLE_VALUE_;
else if (!::boost::detail::winapi::DuplicateHandle(
proc, source_in.native(), proc, &source, 0,
static_cast<::boost::detail::winapi::BOOL_>(true),
::boost::detail::winapi::DUPLICATE_SAME_ACCESS_))
throw_last_error("Duplicate Pipe Failed");
if (sink_in.native() == ::boost::detail::winapi::INVALID_HANDLE_VALUE_)
sink = ::boost::detail::winapi::INVALID_HANDLE_VALUE_;
else if (!::boost::detail::winapi::DuplicateHandle(
proc, sink_in.native(), proc, &sink, 0,
static_cast<::boost::detail::winapi::BOOL_>(true),
::boost::detail::winapi::DUPLICATE_SAME_ACCESS_))
throw_last_error("Duplicate Pipe Failed");
//so we also assign the io_service
_source = ::boost::asio::windows::stream_handle(source_in.get_io_service(), source);
_sink = ::boost::asio::windows::stream_handle(source_in.get_io_service(), sink);
return *this;
}
async_pipe& async_pipe::operator=(async_pipe && rhs)
{
if (_source.native_handle() != ::boost::detail::winapi::INVALID_HANDLE_VALUE_)
::boost::detail::winapi::CloseHandle(_source.native());
if (_sink.native_handle() != ::boost::detail::winapi::INVALID_HANDLE_VALUE_)
::boost::detail::winapi::CloseHandle(_sink.native());
_source.assign(rhs._source.native_handle());
_sink .assign(rhs._sink .native_handle());
rhs._source.assign(::boost::detail::winapi::INVALID_HANDLE_VALUE_);
rhs._sink .assign(::boost::detail::winapi::INVALID_HANDLE_VALUE_);
return *this;
}
template<class CharT, class Traits>
async_pipe::operator basic_pipe<CharT, Traits>() const
{
auto proc = ::boost::detail::winapi::GetCurrentProcess();
::boost::detail::winapi::HANDLE_ source;
::boost::detail::winapi::HANDLE_ sink;
//cannot get the handle from a const object.
auto source_in = const_cast<::boost::asio::windows::stream_handle &>(_source).native();
auto sink_in = const_cast<::boost::asio::windows::stream_handle &>(_sink).native();
if (source_in == ::boost::detail::winapi::INVALID_HANDLE_VALUE_)
source = ::boost::detail::winapi::INVALID_HANDLE_VALUE_;
else if (!::boost::detail::winapi::DuplicateHandle(
proc, source_in, proc, &source, 0,
static_cast<::boost::detail::winapi::BOOL_>(true),
::boost::detail::winapi::DUPLICATE_SAME_ACCESS_))
throw_last_error("Duplicate Pipe Failed");
if (sink_in == ::boost::detail::winapi::INVALID_HANDLE_VALUE_)
sink = ::boost::detail::winapi::INVALID_HANDLE_VALUE_;
else if (!::boost::detail::winapi::DuplicateHandle(
proc, sink_in, proc, &sink, 0,
static_cast<::boost::detail::winapi::BOOL_>(true),
::boost::detail::winapi::DUPLICATE_SAME_ACCESS_))
throw_last_error("Duplicate Pipe Failed");
return basic_pipe<CharT, Traits>{source, sink};
}
inline bool operator==(const async_pipe & lhs, const async_pipe & rhs)
{
return compare_handles(lhs.native_source(), rhs.native_source()) &&
compare_handles(lhs.native_sink(), rhs.native_sink());
}
inline bool operator!=(const async_pipe & lhs, const async_pipe & rhs)
{
return !compare_handles(lhs.native_source(), rhs.native_source()) ||
!compare_handles(lhs.native_sink(), rhs.native_sink());
}
template<class Char, class Traits>
inline bool operator==(const async_pipe & lhs, const basic_pipe<Char, Traits> & rhs)
{
return compare_handles(lhs.native_source(), rhs.native_source()) &&
compare_handles(lhs.native_sink(), rhs.native_sink());
}
template<class Char, class Traits>
inline bool operator!=(const async_pipe & lhs, const basic_pipe<Char, Traits> & rhs)
{
return !compare_handles(lhs.native_source(), rhs.native_source()) ||
!compare_handles(lhs.native_sink(), rhs.native_sink());
}
template<class Char, class Traits>
inline bool operator==(const basic_pipe<Char, Traits> & lhs, const async_pipe & rhs)
{
return compare_handles(lhs.native_source(), rhs.native_source()) &&
compare_handles(lhs.native_sink(), rhs.native_sink());
}
template<class Char, class Traits>
inline bool operator!=(const basic_pipe<Char, Traits> & lhs, const async_pipe & rhs)
{
return !compare_handles(lhs.native_source(), rhs.native_source()) ||
!compare_handles(lhs.native_sink(), rhs.native_sink());
}
}}}}
#endif /* INCLUDE_BOOST_PIPE_DETAIL_WINDOWS_ASYNC_PIPE_HPP_ */
@@ -0,0 +1,164 @@
// 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_WINDOWS_BASIC_CMD_HPP_
#define BOOST_PROCESS_DETAIL_WINDOWS_BASIC_CMD_HPP_
#include <boost/algorithm/string/trim.hpp>
#include <boost/algorithm/string/replace.hpp>
#include <boost/process/shell.hpp>
#include <boost/process/detail/windows/handler.hpp>
#include <vector>
#include <string>
#include <iterator>
namespace boost
{
namespace process
{
namespace detail
{
namespace windows
{
inline std::string build_args(const std::string & exe, std::vector<std::string> && data)
{
std::string st = exe;
//put in quotes if it has spaces
{
boost::replace_all(st, "\"", "\\\"");
auto it = std::find(st.begin(), st.end(), ' ');
if (it != st.end())//contains spaces.
{
st.insert(st.begin(), '"');
st += '"';
}
}
for (auto & arg : data)
{
boost::replace_all(arg, "\"", "\\\"");
auto it = std::find(arg.begin(), arg.end(), ' ');//contains space?
if (it != arg.end())//ok, contains spaces.
{
//the first one is put directly onto the output,
//because then I don't have to copy the whole string
arg.insert(arg.begin(), '"');
arg += '"'; //thats the post one.
}
if (!st.empty())//first one does not need a preceeding space
st += ' ';
st += arg;
}
return st;
}
inline std::wstring build_args(const std::wstring & exe, std::vector<std::wstring> && data)
{
std::wstring st = exe;
for (auto & arg : data)
{
boost::replace_all(arg, L"\"", L"\\\"");
auto it = std::find(arg.begin(), arg.end(), ' ');//contains space?
if (it != arg.end())//ok, contains spaces.
{
//the first one is put directly onto the output,
//because then I don't have to copy the whole string
arg.insert(arg.begin(), L'"');
arg += L'"'; //thats the post one.
}
if (!st.empty())//first one does not need a preceeding space
st += L' ';
st += arg;
}
return st;
}
template<typename Char>
struct exe_cmd_init : handler_base_ext
{
using value_type = Char;
using string_type = std::basic_string<value_type>;
static const char* c_arg(char) { return "/c";}
static const wchar_t* c_arg(wchar_t) { return L"/c";}
exe_cmd_init(const string_type & exe, bool cmd_only = false)
: exe(exe), args({}), cmd_only(cmd_only) {};
exe_cmd_init(string_type && exe, bool cmd_only = false)
: exe(std::move(exe)), args({}), cmd_only(cmd_only) {};
exe_cmd_init(string_type && exe, std::vector<string_type> && args)
: exe(std::move(exe)), args(build_args(this->exe, std::move(args))), cmd_only(false) {};
template <class Executor>
void on_setup(Executor& exec) const
{
if (cmd_only && args.empty())
exec.cmd_line = exe.c_str();
else
{
exec.exe = exe.c_str();
exec.cmd_line = args.c_str();
}
}
static exe_cmd_init<Char> exe_args(string_type && exe, std::vector<string_type> && args)
{
return exe_cmd_init<Char>(std::move(exe), std::move(args));
}
static exe_cmd_init<Char> cmd(string_type&& cmd)
{
return exe_cmd_init<Char>(std::move(cmd), true);
}
static exe_cmd_init<Char> exe_args_shell(string_type && exe, std::vector<string_type> && args)
{
std::vector<string_type> args_ = {c_arg(Char()), std::move(exe)};
args_.insert(args_.end(), std::make_move_iterator(args.begin()), std::make_move_iterator(args.end()));
string_type sh = get_shell(Char());
return exe_cmd_init<Char>(std::move(sh), std::move(args_));
}
static std:: string get_shell(char) {return shell(). string(codecvt()); }
static std::wstring get_shell(wchar_t) {return shell().wstring(codecvt());}
static exe_cmd_init<Char> cmd_shell(string_type&& cmd)
{
std::vector<string_type> args = {c_arg(Char()), std::move(cmd)};
string_type sh = get_shell(Char());
return exe_cmd_init<Char>(
std::move(sh),
std::move(args));
}
private:
string_type exe;
string_type args;
bool cmd_only;
};
}
}
}
}
#endif /* INCLUDE_BOOST_PROCESS_WINDOWS_ARGS_HPP_ */
@@ -0,0 +1,225 @@
// 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_WINDOWS_PIPE_HPP
#define BOOST_PROCESS_DETAIL_WINDOWS_PIPE_HPP
#include <boost/detail/winapi/basic_types.hpp>
#include <boost/detail/winapi/error_codes.hpp>
#include <boost/detail/winapi/pipes.hpp>
#include <boost/detail/winapi/handles.hpp>
#include <boost/detail/winapi/file_management.hpp>
#include <boost/detail/winapi/get_last_error.hpp>
#include <boost/detail/winapi/access_rights.hpp>
#include <boost/detail/winapi/process.hpp>
#include <boost/process/detail/windows/compare_handles.hpp>
#include <system_error>
#include <string>
namespace boost { namespace process { namespace detail { namespace windows {
template<class CharT, class Traits = std::char_traits<CharT>>
class basic_pipe
{
::boost::detail::winapi::HANDLE_ _source = ::boost::detail::winapi::INVALID_HANDLE_VALUE_;
::boost::detail::winapi::HANDLE_ _sink = ::boost::detail::winapi::INVALID_HANDLE_VALUE_;
public:
typedef CharT char_type ;
typedef Traits traits_type;
typedef typename Traits::int_type int_type ;
typedef typename Traits::pos_type pos_type ;
typedef typename Traits::off_type off_type ;
typedef ::boost::detail::winapi::HANDLE_ native_handle_type;
explicit basic_pipe(::boost::detail::winapi::HANDLE_ source, ::boost::detail::winapi::HANDLE_ sink)
: _source(source), _sink(sink) {}
inline explicit basic_pipe(const std::string & name);
inline basic_pipe(const basic_pipe& p);
basic_pipe(basic_pipe&& lhs) : _source(lhs._source), _sink(lhs._sink)
{
lhs._source = ::boost::detail::winapi::INVALID_HANDLE_VALUE_;
lhs._sink = ::boost::detail::winapi::INVALID_HANDLE_VALUE_;
}
inline basic_pipe& operator=(const basic_pipe& p);
inline basic_pipe& operator=(basic_pipe&& lhs);
~basic_pipe()
{
if (_sink != ::boost::detail::winapi::INVALID_HANDLE_VALUE_)
::boost::detail::winapi::CloseHandle(_sink);
if (_source != ::boost::detail::winapi::INVALID_HANDLE_VALUE_)
::boost::detail::winapi::CloseHandle(_source);
}
native_handle_type native_source() const {return _source;}
native_handle_type native_sink () const {return _sink;}
void assign_source(native_handle_type h) { _source = h;}
void assign_sink (native_handle_type h) { _sink = h;}
basic_pipe()
{
if (!::boost::detail::winapi::CreatePipe(&_source, &_sink, nullptr, 0))
throw_last_error("CreatePipe() failed");
}
int_type write(const char_type * data, int_type count)
{
::boost::detail::winapi::DWORD_ write_len;
if (!::boost::detail::winapi::WriteFile(
_sink, data, count * sizeof(char_type), &write_len, nullptr
))
{
auto ec = ::boost::process::detail::get_last_error();
if ((ec.value() == ::boost::detail::winapi::ERROR_BROKEN_PIPE_) ||
(ec.value() == ::boost::detail::winapi::ERROR_NO_DATA_))
return 0;
else
throw process_error(ec, "WriteFile failed");
}
return static_cast<int_type>(write_len);
}
int_type read(char_type * data, int_type count)
{
::boost::detail::winapi::DWORD_ read_len;
if (!::boost::detail::winapi::ReadFile(
_source, data, count * sizeof(char_type), &read_len, nullptr
))
{
auto ec = ::boost::process::detail::get_last_error();
if ((ec.value() == ::boost::detail::winapi::ERROR_BROKEN_PIPE_) ||
(ec.value() == ::boost::detail::winapi::ERROR_NO_DATA_))
return 0;
else
throw process_error(ec, "ReadFile failed");
}
return static_cast<int_type>(read_len);
}
bool is_open()
{
return (_source != ::boost::detail::winapi::INVALID_HANDLE_VALUE_) ||
(_sink != ::boost::detail::winapi::INVALID_HANDLE_VALUE_);
}
void close()
{
::boost::detail::winapi::CloseHandle(_source);
::boost::detail::winapi::CloseHandle(_sink);
_source = ::boost::detail::winapi::INVALID_HANDLE_VALUE_;
_sink = ::boost::detail::winapi::INVALID_HANDLE_VALUE_;
}
};
template<class Char, class Traits>
basic_pipe<Char, Traits>::basic_pipe(const basic_pipe & p)
{
auto proc = ::boost::detail::winapi::GetCurrentProcess();
if (p._source == ::boost::detail::winapi::INVALID_HANDLE_VALUE_)
_source = ::boost::detail::winapi::INVALID_HANDLE_VALUE_;
else if (!::boost::detail::winapi::DuplicateHandle(
proc, p._source, proc, &_source, 0,
static_cast<::boost::detail::winapi::BOOL_>(true),
::boost::detail::winapi::DUPLICATE_SAME_ACCESS_))
throw_last_error("Duplicate Pipe Failed");
if (p._sink == ::boost::detail::winapi::INVALID_HANDLE_VALUE_)
_sink = ::boost::detail::winapi::INVALID_HANDLE_VALUE_;
else if (!::boost::detail::winapi::DuplicateHandle(
proc, p._sink, proc, &_sink, 0,
static_cast<::boost::detail::winapi::BOOL_>(true),
::boost::detail::winapi::DUPLICATE_SAME_ACCESS_))
throw_last_error("Duplicate Pipe Failed");
}
template<class Char, class Traits>
basic_pipe<Char, Traits>::basic_pipe(const std::string & name)
{
static constexpr int OPEN_EXISTING_ = 3; //temporary.
static constexpr int FILE_FLAG_OVERLAPPED_ = 0x40000000; //temporary
//static constexpr int FILE_ATTRIBUTE_NORMAL_ = 0x00000080; //temporary
::boost::detail::winapi::HANDLE_ source = ::boost::detail::winapi::create_named_pipe(
name.c_str(),
::boost::detail::winapi::PIPE_ACCESS_INBOUND_
| FILE_FLAG_OVERLAPPED_, //write flag
0, 1, 8192, 8192, 0, nullptr);
if (source == boost::detail::winapi::INVALID_HANDLE_VALUE_)
::boost::process::detail::throw_last_error("create_named_pipe() failed");
::boost::detail::winapi::HANDLE_ sink = boost::detail::winapi::create_file(
name.c_str(),
::boost::detail::winapi::GENERIC_WRITE_, 0, nullptr,
OPEN_EXISTING_,
FILE_FLAG_OVERLAPPED_, //to allow read
nullptr);
if (sink == ::boost::detail::winapi::INVALID_HANDLE_VALUE_)
::boost::process::detail::throw_last_error("create_file() failed");
_source = source;
_sink = sink;
}
template<class Char, class Traits>
basic_pipe<Char, Traits>& basic_pipe<Char, Traits>::operator=(const basic_pipe & p)
{
auto proc = ::boost::detail::winapi::GetCurrentProcess();
if (p._source == ::boost::detail::winapi::INVALID_HANDLE_VALUE_)
_source = ::boost::detail::winapi::INVALID_HANDLE_VALUE_;
else if (!::boost::detail::winapi::DuplicateHandle(
proc, p._source, proc, &_source, 0,
static_cast<::boost::detail::winapi::BOOL_>(true),
::boost::detail::winapi::DUPLICATE_SAME_ACCESS_))
throw_last_error("Duplicate Pipe Failed");
if (p._sink == ::boost::detail::winapi::INVALID_HANDLE_VALUE_)
_sink = ::boost::detail::winapi::INVALID_HANDLE_VALUE_;
else if (!::boost::detail::winapi::DuplicateHandle(
proc, p._sink, proc, &_sink, 0,
static_cast<::boost::detail::winapi::BOOL_>(true),
::boost::detail::winapi::DUPLICATE_SAME_ACCESS_))
throw_last_error("Duplicate Pipe Failed");
return *this;
}
template<class Char, class Traits>
basic_pipe<Char, Traits>& basic_pipe<Char, Traits>::operator=(basic_pipe && lhs)
{
if (_source != ::boost::detail::winapi::INVALID_HANDLE_VALUE_)
::boost::detail::winapi::CloseHandle(_source);
if (_sink != ::boost::detail::winapi::INVALID_HANDLE_VALUE_)
::boost::detail::winapi::CloseHandle(_sink);
_source = lhs._source;
_sink = lhs._sink;
lhs._source = ::boost::detail::winapi::INVALID_HANDLE_VALUE_;
lhs._sink = ::boost::detail::winapi::INVALID_HANDLE_VALUE_;
return *this;
}
template<class Char, class Traits>
inline bool operator==(const basic_pipe<Char, Traits> & lhs, const basic_pipe<Char, Traits> & rhs)
{
return compare_handles(lhs.native_source(), rhs.native_source()) &&
compare_handles(lhs.native_sink(), rhs.native_sink());
}
template<class Char, class Traits>
inline bool operator!=(const basic_pipe<Char, Traits> & lhs, const basic_pipe<Char, Traits> & rhs)
{
return !compare_handles(lhs.native_source(), rhs.native_source()) ||
!compare_handles(lhs.native_sink(), rhs.native_sink());
}
}}}}
#endif
@@ -0,0 +1,98 @@
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
// Copyright (c) 2009 Boris Schaeling
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
//
// 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_WINDOWS_CHILD_HPP
#define BOOST_PROCESS_WINDOWS_CHILD_HPP
#include <boost/move/move.hpp>
#include <boost/detail/winapi/handles.hpp>
#include <boost/detail/winapi/process.hpp>
#include <boost/detail/winapi/jobs.hpp>
namespace boost { namespace process { namespace detail { namespace windows {
typedef int pid_t;
struct child_handle
{
::boost::detail::winapi::PROCESS_INFORMATION_ proc_info{nullptr, nullptr, 0,0};
explicit child_handle(const ::boost::detail::winapi::PROCESS_INFORMATION_ &pi) :
proc_info(pi)
{}
explicit child_handle(pid_t pid) :
proc_info{nullptr, nullptr, 0,0}
{
auto h = ::boost::detail::winapi::OpenProcess(
::boost::detail::winapi::PROCESS_ALL_ACCESS_,
static_cast<::boost::detail::winapi::BOOL_>(0),
pid);
if (h == nullptr)
throw_last_error("OpenProcess() failed");
proc_info.hProcess = h;
proc_info.dwProcessId = pid;
}
child_handle() = default;
~child_handle()
{
::boost::detail::winapi::CloseHandle(proc_info.hProcess);
::boost::detail::winapi::CloseHandle(proc_info.hThread);
}
child_handle(const child_handle & c) = delete;
child_handle(child_handle && c) : proc_info(c.proc_info)
{
c.proc_info.hProcess = ::boost::detail::winapi::invalid_handle_value;
c.proc_info.hThread = ::boost::detail::winapi::invalid_handle_value;
}
child_handle &operator=(const child_handle & c) = delete;
child_handle &operator=(child_handle && c)
{
::boost::detail::winapi::CloseHandle(proc_info.hProcess);
::boost::detail::winapi::CloseHandle(proc_info.hThread);
proc_info = c.proc_info;
c.proc_info.hProcess = ::boost::detail::winapi::invalid_handle_value;
c.proc_info.hThread = ::boost::detail::winapi::invalid_handle_value;
return *this;
}
pid_t id() const
{
return static_cast<int>(proc_info.dwProcessId);
}
typedef ::boost::detail::winapi::HANDLE_ process_handle_t;
process_handle_t process_handle() const { return proc_info.hProcess; }
bool valid() const
{
return (proc_info.hProcess != nullptr) &&
(proc_info.hProcess != ::boost::detail::winapi::INVALID_HANDLE_VALUE_);
}
bool in_group() const
{
::boost::detail::winapi::BOOL_ value;
if (!::boost::detail::winapi::IsProcessInJob(proc_info.hProcess, nullptr, &value))
throw_last_error("IsProcessinJob Failed");
return value!=0;
}
bool in_group(std::error_code &ec) const noexcept
{
::boost::detail::winapi::BOOL_ value;
if (!::boost::detail::winapi::IsProcessInJob(proc_info.hProcess, nullptr, &value))
ec = get_last_error();
return value!=0;
}
};
}}}}
#endif
@@ -0,0 +1,31 @@
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
// Copyright (c) 2009 Boris Schaeling
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
//
// 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_WINDOWS_INITIALIZERS_CLOSE_IN_HPP
#define BOOST_PROCESS_WINDOWS_INITIALIZERS_CLOSE_IN_HPP
#include <boost/detail/winapi/process.hpp>
#include <boost/detail/winapi/handles.hpp>
#include <boost/process/detail/handler_base.hpp>
namespace boost { namespace process { namespace detail { namespace windows {
struct close_in : public ::boost::process::detail::handler_base
{
template <class WindowsExecutor>
void on_setup(WindowsExecutor &e) const
{
e.startup_info.hStdInput = boost::detail::winapi::INVALID_HANDLE_VALUE_;
e.startup_info.dwFlags |= boost::detail::winapi::STARTF_USESTDHANDLES_;
}
};
}}}}
#endif
@@ -0,0 +1,53 @@
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
// Copyright (c) 2009 Boris Schaeling
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
//
// 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_WINDOWS_INITIALIZERS_CLOSE_OUT_HPP
#define BOOST_PROCESS_WINDOWS_INITIALIZERS_CLOSE_OUT_HPP
#include <boost/detail/winapi/process.hpp>
#include <boost/detail/winapi/handles.hpp>
#include <boost/process/detail/handler_base.hpp>
namespace boost { namespace process { namespace detail { namespace windows {
template<int p1, int p2>
struct close_out : public ::boost::process::detail::handler_base
{
template <class WindowsExecutor>
inline void on_setup(WindowsExecutor &e) const;
};
template<>
template<typename WindowsExecutor>
void close_out<1,-1>::on_setup(WindowsExecutor &e) const
{
e.startup_info.hStdOutput = ::boost::detail::winapi::INVALID_HANDLE_VALUE_;
e.startup_info.dwFlags |= ::boost::detail::winapi::STARTF_USESTDHANDLES_;
}
template<>
template<typename WindowsExecutor>
void close_out<2,-1>::on_setup(WindowsExecutor &e) const
{
e.startup_info.hStdError = ::boost::detail::winapi::INVALID_HANDLE_VALUE_;
e.startup_info.dwFlags |= ::boost::detail::winapi::STARTF_USESTDHANDLES_;
}
template<>
template<typename WindowsExecutor>
void close_out<1,2>::on_setup(WindowsExecutor &e) const
{
e.startup_info.hStdOutput = ::boost::detail::winapi::INVALID_HANDLE_VALUE_;
e.startup_info.hStdError = ::boost::detail::winapi::INVALID_HANDLE_VALUE_;
e.startup_info.dwFlags |= ::boost::detail::winapi::STARTF_USESTDHANDLES_;
}
}}}}
#endif
@@ -0,0 +1,49 @@
// 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_WINDOWS_CMD_HPP_
#define BOOST_PROCESS_WINDOWS_CMD_HPP_
#include <string>
namespace boost
{
namespace process
{
namespace detail
{
namespace windows
{
template<typename CharType>
struct cmd_setter_ : ::boost::process::detail::handler_base
{
typedef CharType value_type;
typedef std::basic_string<value_type> string_type;
cmd_setter_(string_type && cmd_line) : _cmd_line(std::move(cmd_line)) {}
cmd_setter_(const string_type & cmd_line) : _cmd_line(cmd_line) {}
template <class Executor>
void on_setup(Executor& exec)
{
exec.cmd_line = _cmd_line.c_str();
}
const string_type & str() const {return _cmd_line;}
private:
string_type _cmd_line;
};
}
}
}
}
#endif /* INCLUDE_BOOST_PROCESS_WINDOWS_ARGS_HPP_ */
@@ -0,0 +1,41 @@
// 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_WINDOWS_COMPARE_HANDLES_HPP_
#define BOOST_PROCESS_DETAIL_WINDOWS_COMPARE_HANDLES_HPP_
#include <boost/detail/winapi/handles.hpp>
#include <boost/detail/winapi/file_management.hpp>
#include <boost/process/detail/config.hpp>
namespace boost { namespace process { namespace detail { namespace windows {
inline bool compare_handles(boost::detail::winapi::HANDLE_ lhs, boost::detail::winapi::HANDLE_ rhs)
{
if ( (lhs == ::boost::detail::winapi::INVALID_HANDLE_VALUE_)
|| (rhs == ::boost::detail::winapi::INVALID_HANDLE_VALUE_))
return false;
if (lhs == rhs)
return true;
::boost::detail::winapi::BY_HANDLE_FILE_INFORMATION_ lhs_info{0,{0,0},{0,0},{0,0},0,0,0,0,0,0};
::boost::detail::winapi::BY_HANDLE_FILE_INFORMATION_ rhs_info{0,{0,0},{0,0},{0,0},0,0,0,0,0,0};
if (!::boost::detail::winapi::GetFileInformationByHandle(lhs, &lhs_info))
::boost::process::detail::throw_last_error("GetFileInformationByHandle");
if (!::boost::detail::winapi::GetFileInformationByHandle(rhs, &rhs_info))
::boost::process::detail::throw_last_error("GetFileInformationByHandle");
return (lhs_info.nFileIndexHigh == rhs_info.nFileIndexHigh)
&& (lhs_info.nFileIndexLow == rhs_info.nFileIndexLow);
}
}}}}
#endif /* BOOST_PROCESS_DETAIL_WINDOWS_COMPARE_HANDLES_HPP_ */
@@ -0,0 +1,54 @@
// 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_WINDOWS_ENV_INIT_HPP_
#define BOOST_PROCESS_DETAIL_WINDOWS_ENV_INIT_HPP_
#include <boost/detail/winapi/error_codes.hpp>
#include <boost/detail/winapi/process.hpp>
#include <boost/process/detail/config.hpp>
#include <boost/process/detail/handler_base.hpp>
#include <boost/process/environment.hpp>
namespace boost { namespace process { namespace detail { namespace windows {
template<typename Char>
struct env_init : public ::boost::process::detail::handler_base
{
boost::process::basic_environment<Char> env;
env_init(boost::process::basic_environment<Char> && env) : env(std::move(env)) {};
env_init(const boost::process::basic_environment<Char> & env) : env(env) {};
constexpr static ::boost::detail::winapi::DWORD_ creation_flag(char) {return 0u;}
constexpr static ::boost::detail::winapi::DWORD_ creation_flag(wchar_t)
{
return ::boost::detail::winapi::CREATE_UNICODE_ENVIRONMENT_;
}
template <class WindowsExecutor>
void on_setup(WindowsExecutor &exec) const
{
auto e = env.native_handle();
if (*e == null_char<char>())
{
exec.set_error(std::error_code(::boost::detail::winapi::ERROR_BAD_ENVIRONMENT_, std::system_category()),
"Empty Environment");
}
exec.env = e;
exec.creation_flags |= creation_flag(Char());
}
};
}}}}
#endif /* BOOST_PROCESS_DETAIL_WINDOWS_ENV_INIT_HPP_ */
@@ -0,0 +1,356 @@
// 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_WINDOWS_ENV_STORAGE_HPP_
#define BOOST_PROCESS_DETAIL_WINDOWS_ENV_STORAGE_HPP_
#include <string>
#include <vector>
#include <unordered_map>
#include <boost/detail/winapi/error_codes.hpp>
#include <boost/detail/winapi/environment.hpp>
#include <boost/process/detail/config.hpp>
#include <boost/detail/winapi/get_current_process.hpp>
#include <boost/detail/winapi/get_current_process_id.hpp>
#include <algorithm>
#include <boost/process/locale.hpp>
namespace boost { namespace process { namespace detail { namespace windows {
template<typename Char>
class native_environment_impl
{
static void _deleter(Char* p) {boost::detail::winapi::free_environment_strings(p);};
std::unique_ptr<Char[], void(*)(Char*)> _buf{boost::detail::winapi::get_environment_strings<Char>(), &native_environment_impl::_deleter};
static inline std::vector<Char*> _load_var(Char* p);
std::vector<Char*> _env_arr{_load_var(_buf.get())};
public:
using char_type = Char;
using pointer_type = const char_type*;
using string_type = std::basic_string<char_type>;
using native_handle_type = pointer_type;
void reload()
{
_buf.reset(boost::detail::winapi::get_environment_strings<Char>());
_env_arr = _load_var(_buf.get());
_env_impl = &*_env_arr.begin();
}
string_type get(const pointer_type id);
void set(const pointer_type id, const pointer_type value);
void reset(const pointer_type id);
string_type get(const string_type & id) {return get(id.c_str());}
void set(const string_type & id, const string_type & value) {set(id.c_str(), value.c_str()); }
void reset(const string_type & id) {reset(id.c_str());}
native_environment_impl() = default;
native_environment_impl(const native_environment_impl& ) = delete;
native_environment_impl(native_environment_impl && ) = default;
native_environment_impl & operator=(const native_environment_impl& ) = delete;
native_environment_impl & operator=(native_environment_impl && ) = default;
Char ** _env_impl = &*_env_arr.begin();
native_handle_type native_handle() const {return _buf.get();}
};
template<typename Char>
inline auto native_environment_impl<Char>::get(const pointer_type id) -> string_type
{
Char buf[4096];
auto size = boost::detail::winapi::get_environment_variable(id, buf, sizeof(buf));
if (size == 0) //failed
{
auto err = ::boost::detail::winapi::GetLastError();
if (err == ::boost::detail::winapi::ERROR_ENVVAR_NOT_FOUND_)//well, then we consider that an empty value
return "";
else
throw process_error(std::error_code(err, std::system_category()),
"GetEnvironmentVariable() failed");
}
if (size == sizeof(buf)) //the return size gives the size without the null, so I know this went wrong
{
/*limit defined here https://msdn.microsoft.com/en-us/library/windows/desktop/ms683188(v=vs.85).aspx
* but I used 32768 so it is a multiple of 4096.
*/
constexpr static std::size_t max_size = 32768;
//Handle variables longer then buf.
std::size_t buf_size = sizeof(buf);
while (buf_size <= max_size)
{
std::vector<Char> buf(buf_size);
auto size = boost::detail::winapi::get_environment_variable(id, buf.data(), buf.size());
if (size == buf_size) //buffer to small
buf_size *= 2;
else if (size == 0)
::boost::process::detail::throw_last_error("GetEnvironmentVariable() failed");
else
return std::basic_string<Char>(
buf.data(), buf.data()+ size + 1);
}
}
return std::basic_string<Char>(buf, buf+size+1);
}
template<typename Char>
inline void native_environment_impl<Char>::set(const pointer_type id, const pointer_type value)
{
boost::detail::winapi::set_environment_variable(id, value);
}
template<typename Char>
inline void native_environment_impl<Char>::reset(const pointer_type id)
{
boost::detail::winapi::set_environment_variable(id, nullptr);
}
template<typename Char>
std::vector<Char*> native_environment_impl<Char>::_load_var(Char* p)
{
std::vector<Char*> ret;
if (*p != null_char<Char>())
{
ret.push_back(p);
while ((*p != null_char<Char>()) || (*(p+1) != null_char<Char>()))
{
if (*p==null_char<Char>())
{
p++;
ret.push_back(p);
}
else
p++;
}
}
p++;
ret.push_back(nullptr);
return ret;
}
template<typename Char>
struct basic_environment_impl
{
std::vector<Char> _data = {null_char<Char>()};
static std::vector<Char*> _load_var(Char* p);
std::vector<Char*> _env_arr{_load_var(_data.data())};
public:
using char_type = Char;
using pointer_type = const char_type*;
using string_type = std::basic_string<char_type>;
using native_handle_type = pointer_type;
std::size_t size() const { return _data.size();}
void reload()
{
_env_arr = _load_var(_data.data());
_env_impl = _env_arr.data();
}
string_type get(const pointer_type id) {return get(string_type(id));}
void set(const pointer_type id, const pointer_type value) {set(string_type(id), value);}
void reset(const pointer_type id) {reset(string_type(id));}
string_type get(const string_type & id);
void set(const string_type & id, const string_type & value);
void reset(const string_type & id);
inline basic_environment_impl(const native_environment_impl<Char> & nei);
basic_environment_impl() = default;
basic_environment_impl(const basic_environment_impl& rhs)
: _data(rhs._data)
{
}
basic_environment_impl(basic_environment_impl && rhs)
: _data(std::move(rhs._data)),
_env_arr(std::move(rhs._env_arr)),
_env_impl(_env_arr.data())
{
}
basic_environment_impl &operator=(basic_environment_impl && rhs)
{
_data = std::move(rhs._data);
//reload();
_env_arr = std::move(rhs._env_arr);
_env_impl = _env_arr.data();
return *this;
}
basic_environment_impl & operator=(const basic_environment_impl& rhs)
{
_data = rhs._data;
reload();
return *this;
}
template<typename CharR>
explicit inline basic_environment_impl(
const basic_environment_impl<CharR>& rhs,
const ::boost::process::codecvt_type & cv = ::boost::process::codecvt())
: _data(::boost::process::detail::convert(rhs._data, cv))
{
}
template<typename CharR>
basic_environment_impl & operator=(const basic_environment_impl<CharR>& rhs)
{
_data = ::boost::process::detail::convert(rhs._data);
_env_arr = _load_var(&*_data.begin());
_env_impl = &*_env_arr.begin();
return *this;
}
Char ** _env_impl = &*_env_arr.begin();
native_handle_type native_handle() const {return &*_data.begin();}
};
template<typename Char>
basic_environment_impl<Char>::basic_environment_impl(const native_environment_impl<Char> & nei)
{
auto beg = nei.native_handle();
auto p = beg;
while ((*p != null_char<Char>()) || (*(p+1) != null_char<Char>()))
p++;
p++; //pointing to the second nullchar
p++; //to get the pointer behing the second nullchar, so it's end.
this->_data.assign(beg, p);
this->reload();
}
template<typename Char>
inline auto basic_environment_impl<Char>::get(const string_type &id) -> string_type
{
if (std::equal(id.begin(), id.end(), _data.begin()) && (_data[id.size()] == equal_sign<Char>()))
return string_type(_data.data()); //null-char is handled by the string.
std::vector<Char> seq = {'\0'}; //using a vector, because strings might cause problems with nullchars
seq.insert(seq.end(), id.begin(), id.end());
seq.push_back('=');
auto itr = std::search(_data.begin(), _data.end(), seq.begin(), seq.end());
if (itr == _data.end()) //not found
return "";
itr += seq.size(); //advance to the value behind the '='; the std::string will take care of finding the null-char.
return string_type(&*itr);
}
template<typename Char>
inline void basic_environment_impl<Char>::set(const string_type &id, const string_type &value)
{
reset(id);
std::vector<Char> insertion;
insertion.insert(insertion.end(), id.begin(), id.end());
insertion.push_back('=');
insertion.insert(insertion.end(), value.begin(), value.end());
insertion.push_back('\0');
_data.insert(_data.end() -1, insertion.begin(), insertion.end());
reload();
}
template<typename Char>
inline void basic_environment_impl<Char>::reset(const string_type &id)
{
//ok, we need to check the size of data first
if (id.size() >= _data.size()) //ok, so it's impossible id is in there.
return;
//check if it's the first one, spares us the search.
if (std::equal(id.begin(), id.end(), _data.begin()) && (_data[id.size()] == equal_sign<Char>()))
{
auto beg = _data.begin();
auto end = beg;
while (*end != '\0')
end++;
end++; //to point behind the last null-char
_data.erase(beg, end); //and remove the thingy
}
std::vector<Char> seq = {'\0'}; //using a vector, because strings might cause problems with nullchars
seq.insert(seq.end(), id.begin(), id.end());
seq.push_back('=');
auto itr = std::search(_data.begin(), _data.end(), seq.begin(), seq.end());
if (itr == _data.end())
return;//nothing to return if it's empty anyway...
auto end = itr;
while (*end != '\0')
end++;
end ++; //to point behind the last null-char
_data.erase(itr, end);//and remove it
reload();
}
template<typename Char>
std::vector<Char*> basic_environment_impl<Char>::_load_var(Char* p)
{
std::vector<Char*> ret;
if (*p != null_char<Char>())
{
ret.push_back(p);
while ((*p != null_char<Char>()) || (*(p+1) != null_char<Char>()))
{
if (*p==null_char<Char>())
{
p++;
ret.push_back(p);
}
else
p++;
}
}
p++;
ret.push_back(nullptr);
return ret;
}
template<typename T> constexpr T env_seperator();
template<> constexpr char env_seperator() {return ';'; }
template<> constexpr wchar_t env_seperator() {return L';'; }
inline int get_id() {return boost::detail::winapi::GetCurrentProcessId();}
inline void* native_handle() {return boost::detail::winapi::GetCurrentProcess(); }
typedef void* native_handle_t;
}
}
}
}
#endif /* BOOST_PROCESS_DETAIL_WINDOWS_ENV_STORAGE_HPP_ */
@@ -0,0 +1,259 @@
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
// Copyright (c) 2009 Boris Schaeling
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
// 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_WINDOWS_EXECUTOR_HPP
#define BOOST_PROCESS_WINDOWS_EXECUTOR_HPP
#include <boost/process/detail/child_decl.hpp>
#include <boost/process/detail/windows/is_running.hpp>
#include <boost/process/detail/traits.hpp>
#include <boost/process/error.hpp>
#include <boost/fusion/algorithm/iteration/for_each.hpp>
#include <boost/detail/winapi/handles.hpp>
#include <boost/detail/winapi/process.hpp>
#include <boost/none.hpp>
#include <system_error>
#include <memory>
#include <atomic>
#include <cstring>
namespace boost { namespace process {
namespace detail { namespace windows {
template<typename CharType> struct startup_info;
#if !defined( BOOST_NO_ANSI_APIS )
template<> struct startup_info<char>
{
typedef ::boost::detail::winapi::STARTUPINFOA_ type;
};
#endif
template<> struct startup_info<wchar_t>
{
typedef ::boost::detail::winapi::STARTUPINFOW_ type;
};
#if BOOST_USE_WINAPI_VERSION >= BOOST_WINAPI_VERSION_WIN6
template<typename CharType> struct startup_info_ex;
#if !defined( BOOST_NO_ANSI_APIS )
template<> struct startup_info_ex<char>
{
typedef ::boost::detail::winapi::STARTUPINFOEXA_ type;
};
#endif
template<> struct startup_info_ex<wchar_t>
{
typedef ::boost::detail::winapi::STARTUPINFOEXW_ type;
};
#endif
#if ( BOOST_USE_WINAPI_VERSION >= BOOST_WINAPI_VERSION_WIN6 )
template<typename CharT>
struct startup_info_impl
{
::boost::detail::winapi::DWORD_ creation_flags = 0;
typedef typename startup_info_ex<CharT>::type startup_info_ex_t;
typedef typename startup_info<CharT>::type startup_info_t;
startup_info_ex_t startup_info_ex
{startup_info_t {sizeof(startup_info_t), nullptr, nullptr, nullptr,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, nullptr,
::boost::detail::winapi::invalid_handle_value,
::boost::detail::winapi::invalid_handle_value,
::boost::detail::winapi::invalid_handle_value},
nullptr
};
startup_info_t & startup_info = startup_info_ex.StartupInfo;
void set_startup_info_ex()
{
startup_info.cb = sizeof(startup_info_ex_t);
creation_flags = ::boost::detail::winapi::EXTENDED_STARTUPINFO_PRESENT_;
}
};
#else
template<typename CharT>
struct startup_info_impl
{
typedef typename startup_info<CharT>::type startup_info_t;
::boost::detail::winapi::DWORD_ creation_flags = 0;
startup_info_t startup_info
{sizeof(startup_info_t), nullptr, nullptr, nullptr,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, nullptr,
::boost::detail::winapi::invalid_handle_value,
::boost::detail::winapi::invalid_handle_value,
::boost::detail::winapi::invalid_handle_value};
};
#endif
template<typename Char, typename Sequence>
class executor : public startup_info_impl<Char>
{
void internal_error_handle(const std::error_code &, const char*, boost::mpl::false_, boost::mpl::true_) {}
void internal_error_handle(const std::error_code &, const char*, boost::mpl::true_, boost::mpl::true_) {}
void internal_error_handle(const std::error_code &ec, const char*, boost::mpl::true_, boost::mpl::false_ )
{
this->_ec = ec;
}
void internal_error_handle(const std::error_code &ec, const char* msg, boost::mpl::false_, boost::mpl::false_ )
{
throw process_error(ec, msg);
}
struct on_setup_t
{
executor & exec;
on_setup_t(executor & exec) : exec(exec) {};
template<typename T>
void operator()(T & t) const
{
if (!exec.error())
t.on_setup(exec);
}
};
struct on_error_t
{
executor & exec;
const std::error_code & error;
on_error_t(executor & exec, const std::error_code & error) : exec(exec), error(error) {};
template<typename T>
void operator()(T & t) const
{
t.on_error(exec, error);
}
};
struct on_success_t
{
executor & exec;
on_success_t(executor & exec) : exec(exec) {};
template<typename T>
void operator()(T & t) const
{
if (!exec.error())
t.on_success(exec);
}
};
typedef typename ::boost::process::detail::has_error_handler<Sequence>::type has_error_handler;
typedef typename ::boost::process::detail::has_ignore_error <Sequence>::type has_ignore_error;
std::error_code _ec{0, std::system_category()};
public:
std::shared_ptr<std::atomic<int>> exit_status = std::make_shared<std::atomic<int>>(still_active);
executor(Sequence & seq) : seq(seq)
{
}
child operator()()
{
on_setup_t on_setup_fn(*this);
boost::fusion::for_each(seq, on_setup_fn);
if (_ec)
{
on_error_t on_error_fn(*this, _ec);
boost::fusion::for_each(seq, on_error_fn);
return child();
}
//NOTE: The non-cast cmd-line string can only be modified by the wchar_t variant which is currently disabled.
int err_code = ::boost::detail::winapi::create_process(
exe, // LPCSTR_ lpApplicationName,
const_cast<Char*>(cmd_line), // LPSTR_ lpCommandLine,
proc_attrs, // LPSECURITY_ATTRIBUTES_ lpProcessAttributes,
thread_attrs, // LPSECURITY_ATTRIBUTES_ lpThreadAttributes,
inherit_handles, // INT_ bInheritHandles,
this->creation_flags, // DWORD_ dwCreationFlags,
reinterpret_cast<void*>(const_cast<Char*>(env)), // LPVOID_ lpEnvironment,
work_dir, // LPCSTR_ lpCurrentDirectory,
&this->startup_info, // LPSTARTUPINFOA_ lpStartupInfo,
&proc_info); // LPPROCESS_INFORMATION_ lpProcessInformation)
child c{child_handle(proc_info), exit_status};
if (err_code != 0)
{
_ec.clear();
on_success_t on_success_fn(*this);
boost::fusion::for_each(seq, on_success_fn);
}
else
set_error(::boost::process::detail::get_last_error(),
" CreateProcess failed");
if ( _ec)
{
on_error_t on_err(*this, _ec);
boost::fusion::for_each(seq, on_err);
return child();
}
else
return c;
}
void set_error(const std::error_code & ec, const char* msg = "Unknown Error.")
{
internal_error_handle(ec, msg, has_error_handler(), has_ignore_error());
}
void set_error(const std::error_code & ec, const std::string msg = "Unknown Error.")
{
internal_error_handle(ec, msg.c_str(), has_error_handler(), has_ignore_error());
}
const std::error_code& error() const {return _ec;}
::boost::detail::winapi::LPSECURITY_ATTRIBUTES_ proc_attrs = nullptr;
::boost::detail::winapi::LPSECURITY_ATTRIBUTES_ thread_attrs = nullptr;
::boost::detail::winapi::BOOL_ inherit_handles = false;
const Char * work_dir = nullptr;
const Char * cmd_line = nullptr;
const Char * exe = nullptr;
const Char * env = nullptr;
Sequence & seq;
::boost::detail::winapi::PROCESS_INFORMATION_ proc_info{nullptr, nullptr, 0,0};
};
template<typename Char, typename Tup>
executor<Char, Tup> make_executor(Tup & tup)
{
return executor<Char, Tup>(tup);
}
}}}}
#endif
@@ -0,0 +1,104 @@
// 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_WINDOWS_FILE_DESCRIPTOR_HPP_
#define BOOST_PROCESS_DETAIL_WINDOWS_FILE_DESCRIPTOR_HPP_
#include <boost/detail/winapi/basic_types.hpp>
#include <boost/detail/winapi/handles.hpp>
#include <boost/detail/winapi/file_management.hpp>
#include <string>
#include <boost/filesystem/path.hpp>
namespace boost { namespace process { namespace detail { namespace windows {
struct file_descriptor
{
enum mode_t
{
read = 1,
write = 2,
read_write = 3
};
static ::boost::detail::winapi::DWORD_ desired_access(mode_t mode)
{
switch(mode)
{
case read:
return ::boost::detail::winapi::GENERIC_READ_;
case write:
return ::boost::detail::winapi::GENERIC_WRITE_;
case read_write:
return ::boost::detail::winapi::GENERIC_READ_
| ::boost::detail::winapi::GENERIC_WRITE_;
default:
return 0u;
}
}
file_descriptor() = default;
file_descriptor(const boost::filesystem::path& p, mode_t mode = read_write)
: file_descriptor(p.native(), mode)
{
}
file_descriptor(const std::string & path , mode_t mode = read_write)
: file_descriptor(path.c_str(), mode) {}
file_descriptor(const std::wstring & path, mode_t mode = read_write)
: file_descriptor(path.c_str(), mode) {}
file_descriptor(const char* path, mode_t mode = read_write)
: _handle(
::boost::detail::winapi::create_file(
path,
desired_access(mode),
::boost::detail::winapi::FILE_SHARE_READ_ |
::boost::detail::winapi::FILE_SHARE_WRITE_,
nullptr,
::boost::detail::winapi::OPEN_ALWAYS_,
::boost::detail::winapi::FILE_ATTRIBUTE_NORMAL_,
nullptr
))
{
}
file_descriptor(const wchar_t * path, mode_t mode = read_write)
: _handle(
::boost::detail::winapi::create_file(
path,
desired_access(mode),
::boost::detail::winapi::FILE_SHARE_READ_ |
::boost::detail::winapi::FILE_SHARE_WRITE_,
nullptr,
::boost::detail::winapi::OPEN_ALWAYS_,
::boost::detail::winapi::FILE_ATTRIBUTE_NORMAL_,
nullptr
))
{
}
file_descriptor(const file_descriptor & ) = delete;
file_descriptor(file_descriptor && ) = default;
file_descriptor& operator=(const file_descriptor & ) = delete;
file_descriptor& operator=(file_descriptor && ) = default;
~file_descriptor()
{
if (_handle != ::boost::detail::winapi::INVALID_HANDLE_VALUE_)
::boost::detail::winapi::CloseHandle(_handle);
}
::boost::detail::winapi::HANDLE_ handle() const { return _handle;}
private:
::boost::detail::winapi::HANDLE_ _handle = ::boost::detail::winapi::INVALID_HANDLE_VALUE_;
};
}}}}
#endif /* BOOST_PROCESS_DETAIL_WINDOWS_FILE_DESCRIPTOR_HPP_ */
@@ -0,0 +1,44 @@
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
// Copyright (c) 2009 Boris Schaeling
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
//
// 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_WINDOWS_FILE_IN_HPP
#define BOOST_PROCESS_DETAIL_WINDOWS_FILE_IN_HPP
#include <boost/detail/winapi/process.hpp>
#include <boost/detail/winapi/handles.hpp>
#include <boost/process/detail/handler_base.hpp>
#include <boost/process/detail/windows/file_descriptor.hpp>
#include <io.h>
namespace boost { namespace process { namespace detail { namespace windows {
struct file_in : public ::boost::process::detail::handler_base
{
file_descriptor file;
::boost::detail::winapi::HANDLE_ handle = file.handle();
template<typename T>
file_in(T&& t) : file(std::forward<T>(t), file_descriptor::read) {}
file_in(FILE * f) : handle(reinterpret_cast<::boost::detail::winapi::HANDLE_>(_get_osfhandle(_fileno(f)))) {}
template <class WindowsExecutor>
void on_setup(WindowsExecutor &e) const
{
boost::detail::winapi::SetHandleInformation(handle,
boost::detail::winapi::HANDLE_FLAG_INHERIT_,
boost::detail::winapi::HANDLE_FLAG_INHERIT_);
e.startup_info.hStdInput = handle;
e.startup_info.dwFlags |= boost::detail::winapi::STARTF_USESTDHANDLES_;
e.inherit_handles = true;
}
};
}}}}
#endif
@@ -0,0 +1,77 @@
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
// Copyright (c) 2009 Boris Schaeling
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
//
// 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_WINDOWS_FILE_OUT_HPP
#define BOOST_PROCESS_DETAIL_WINDOWS_FILE_OUT_HPP
#include <boost/detail/winapi/process.hpp>
#include <boost/detail/winapi/handles.hpp>
#include <boost/detail/winapi/handle_info.hpp>
#include <boost/process/detail/handler_base.hpp>
#include <boost/process/detail/windows/file_descriptor.hpp>
namespace boost { namespace process { namespace detail { namespace windows {
template<int p1, int p2>
struct file_out : public ::boost::process::detail::handler_base
{
file_descriptor file;
::boost::detail::winapi::HANDLE_ handle = file.handle();
template<typename T>
file_out(T&& t) : file(std::forward<T>(t), file_descriptor::write) {}
file_out(FILE * f) : handle(reinterpret_cast<void*>(_get_osfhandle(_fileno(f)))) {}
template <typename WindowsExecutor>
inline void on_setup(WindowsExecutor &e) const;
};
template<>
template<typename WindowsExecutor>
void file_out<1,-1>::on_setup(WindowsExecutor &e) const
{
boost::detail::winapi::SetHandleInformation(handle,
boost::detail::winapi::HANDLE_FLAG_INHERIT_,
boost::detail::winapi::HANDLE_FLAG_INHERIT_);
e.startup_info.hStdOutput = handle;
e.startup_info.dwFlags |= ::boost::detail::winapi::STARTF_USESTDHANDLES_;
e.inherit_handles = true;
}
template<>
template<typename WindowsExecutor>
void file_out<2,-1>::on_setup(WindowsExecutor &e) const
{
boost::detail::winapi::SetHandleInformation(handle,
boost::detail::winapi::HANDLE_FLAG_INHERIT_,
boost::detail::winapi::HANDLE_FLAG_INHERIT_);
e.startup_info.hStdError = handle;
e.startup_info.dwFlags |= ::boost::detail::winapi::STARTF_USESTDHANDLES_;
e.inherit_handles = true;
}
template<>
template<typename WindowsExecutor>
void file_out<1,2>::on_setup(WindowsExecutor &e) const
{
boost::detail::winapi::SetHandleInformation(handle,
boost::detail::winapi::HANDLE_FLAG_INHERIT_,
boost::detail::winapi::HANDLE_FLAG_INHERIT_);
e.startup_info.hStdOutput = handle;
e.startup_info.hStdError = handle;
e.startup_info.dwFlags |= ::boost::detail::winapi::STARTF_USESTDHANDLES_;
e.inherit_handles = true;
}
}}}}
#endif
@@ -0,0 +1,191 @@
// 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_WINDOWS_GROUP_HPP_
#define BOOST_PROCESS_DETAIL_WINDOWS_GROUP_HPP_
#include <boost/process/detail/windows/handler.hpp>
#include <boost/detail/winapi/jobs.hpp>
#include <boost/process/detail/windows/child_handle.hpp>
#include <boost/process/detail/windows/job_workaround.hpp>
#include <system_error>
namespace boost { namespace process { namespace detail { namespace windows {
inline bool break_away_enabled(::boost::detail::winapi::HANDLE_ h)
{
workaround::JOBOBJECT_EXTENDED_LIMIT_INFORMATION_ info;
if (!workaround::query_information_job_object(
h,
workaround::JobObjectExtendedLimitInformation_,
static_cast<void*>(&info),
sizeof(info),
nullptr))
throw_last_error("QueryInformationJobObject() failed");
return (info.BasicLimitInformation.LimitFlags & workaround::JOB_OBJECT_LIMIT_BREAKAWAY_OK_) != 0;
}
inline void enable_break_away(::boost::detail::winapi::HANDLE_ h)
{
workaround::JOBOBJECT_EXTENDED_LIMIT_INFORMATION_ info;
if (!workaround::query_information_job_object(
h,
workaround::JobObjectExtendedLimitInformation_,
static_cast<void*>(&info),
sizeof(info),
nullptr))
throw_last_error("QueryInformationJobObject() failed");
if ((info.BasicLimitInformation.LimitFlags & workaround::JOB_OBJECT_LIMIT_BREAKAWAY_OK_) != 0)
return;
info.BasicLimitInformation.LimitFlags |= workaround::JOB_OBJECT_LIMIT_BREAKAWAY_OK_;
if (!workaround::set_information_job_object(
h,
workaround::JobObjectExtendedLimitInformation_,
static_cast<void*>(&info),
sizeof(info)))
throw_last_error("SetInformationJobObject() failed");
}
inline void enable_break_away(::boost::detail::winapi::HANDLE_ h, std::error_code & ec)
{
workaround::JOBOBJECT_EXTENDED_LIMIT_INFORMATION_ info;
if (!workaround::query_information_job_object(
h,
workaround::JobObjectExtendedLimitInformation_,
static_cast<void*>(&info),
sizeof(info),
nullptr))
{
ec = get_last_error();
return;
}
if ((info.BasicLimitInformation.LimitFlags & workaround::JOB_OBJECT_LIMIT_BREAKAWAY_OK_) != 0)
return;
info.BasicLimitInformation.LimitFlags |= workaround::JOB_OBJECT_LIMIT_BREAKAWAY_OK_;
if (!workaround::set_information_job_object(
h,
workaround::JobObjectExtendedLimitInformation_,
static_cast<void*>(&info),
sizeof(info)))
{
ec = get_last_error();
return;
}
}
struct group_handle
{
::boost::detail::winapi::HANDLE_ _job_object;
typedef ::boost::detail::winapi::HANDLE_ handle_t;
handle_t handle() const { return _job_object; }
explicit group_handle(handle_t h) :
_job_object(h)
{
enable_break_away(_job_object);
}
group_handle() : group_handle(::boost::detail::winapi::CreateJobObjectA(nullptr, nullptr))
{
}
~group_handle()
{
::boost::detail::winapi::CloseHandle(_job_object);
}
group_handle(const group_handle & c) = delete;
group_handle(group_handle && c) : _job_object(c._job_object)
{
c._job_object = ::boost::detail::winapi::invalid_handle_value;
}
group_handle &operator=(const group_handle & c) = delete;
group_handle &operator=(group_handle && c)
{
::boost::detail::winapi::CloseHandle(_job_object);
_job_object = c._job_object;
c._job_object = ::boost::detail::winapi::invalid_handle_value;
return *this;
}
void add(handle_t proc)
{
if (!::boost::detail::winapi::AssignProcessToJobObject(_job_object, proc))
throw_last_error();
}
void add(handle_t proc, std::error_code & ec) noexcept
{
if (!::boost::detail::winapi::AssignProcessToJobObject(_job_object, proc))
ec = get_last_error();
}
bool has(handle_t proc)
{
::boost::detail::winapi::BOOL_ is;
if (!::boost::detail::winapi::IsProcessInJob(proc, _job_object, &is))
throw_last_error();
return is!=0;
}
bool has(handle_t proc, std::error_code & ec) noexcept
{
::boost::detail::winapi::BOOL_ is;
if (!::boost::detail::winapi::IsProcessInJob(proc, _job_object, &is))
ec = get_last_error();
return is!=0;
}
bool valid() const
{
return _job_object != nullptr;
}
};
inline void terminate(const group_handle &p)
{
if (!::boost::detail::winapi::TerminateJobObject(p.handle(), EXIT_FAILURE))
boost::process::detail::throw_last_error("TerminateJobObject() failed");
}
inline void terminate(const group_handle &p, std::error_code &ec) noexcept
{
if (!::boost::detail::winapi::TerminateJobObject(p.handle(), EXIT_FAILURE))
ec = boost::process::detail::get_last_error();
else
ec.clear();
}
inline bool in_group()
{
::boost::detail::winapi::BOOL_ res;
if (!::boost::detail::winapi::IsProcessInJob(boost::detail::winapi::GetCurrentProcess(), nullptr, &res))
throw_last_error("IsProcessInJob failed");
return res!=0;
}
}}}}
#endif /* BOOST_PROCESS_DETAIL_WINDOWS_GROUP_HPP_ */
@@ -0,0 +1,51 @@
// 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_WINDOWS_GROUP_REF_HPP_
#define BOOST_PROCESS_DETAIL_WINDOWS_GROUP_REF_HPP_
#include <boost/process/detail/config.hpp>
#include <boost/process/detail/windows/group_handle.hpp>
#include <boost/detail/winapi/process.hpp>
#include <boost/process/detail/windows/handler.hpp>
namespace boost { namespace process {
namespace detail { namespace windows {
struct group_ref : handler_base_ext
{
::boost::detail::winapi::HANDLE_ handle;
explicit group_ref(group_handle &g) :
handle(g.handle())
{}
template <class Executor>
void on_setup(Executor& exec) const
{
//I can only enable this if the current process supports breakaways.
if (in_group() && break_away_enabled(nullptr))
exec.creation_flags |= boost::detail::winapi::CREATE_BREAKAWAY_FROM_JOB_;
}
template <class Executor>
void on_success(Executor& exec) const
{
if (!::boost::detail::winapi::AssignProcessToJobObject(handle, exec.proc_info.hProcess))
exec.set_error(::boost::process::detail::get_last_error(),
"AssignProcessToJobObject() failed.");
}
};
}}}}
#endif /* BOOST_PROCESS_DETAIL_WINDOWS_GROUP_HPP_ */
@@ -0,0 +1,20 @@
// 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_WINDOWS_HANDLER_HPP_
#define BOOST_PROCESS_DETAIL_WINDOWS_HANDLER_HPP_
#include <boost/process/detail/handler_base.hpp>
namespace boost { namespace process { namespace detail { namespace windows {
//does not extend anything.
struct handler_base_ext : handler_base {};
}}}}
#endif /* BOOST_PROCESS_DETAIL_WINDOWS_HANDLER_HPP_ */
@@ -0,0 +1,160 @@
// 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_WINDOWS_IO_SERVICE_REF_HPP_
#define BOOST_PROCESS_WINDOWS_IO_SERVICE_REF_HPP_
#include <boost/process/detail/handler_base.hpp>
#include <boost/process/detail/windows/async_handler.hpp>
#include <boost/asio/io_service.hpp>
#include <boost/asio/windows/object_handle.hpp>
#include <boost/detail/winapi/process.hpp>
#include <boost/detail/winapi/handles.hpp>
#include <boost/fusion/algorithm/iteration/for_each.hpp>
#include <boost/fusion/algorithm/transformation/filter_if.hpp>
#include <boost/fusion/algorithm/transformation/transform.hpp>
#include <boost/fusion/view/transform_view.hpp>
#include <boost/fusion/container/vector/convert.hpp>
#include <functional>
#include <type_traits>
#include <memory>
#include <atomic>
#include <vector>
#include <boost/type_index.hpp>
namespace boost { namespace process { namespace detail { namespace windows {
template<typename Executor>
struct on_exit_handler_transformer
{
Executor & exec;
on_exit_handler_transformer(Executor & exec) : exec(exec) {}
template<typename Sig>
struct result;
template<typename T>
struct result<on_exit_handler_transformer<Executor>(T&)>
{
typedef typename T::on_exit_handler_t type;
};
template<typename T>
auto operator()(T& t) const -> typename T::on_exit_handler_t
{
return t.on_exit_handler(exec);
}
};
template<typename Executor>
struct async_handler_collector
{
Executor & exec;
std::vector<std::function<void(int, const std::error_code & ec)>> &handlers;
async_handler_collector(Executor & exec,
std::vector<std::function<void(int, const std::error_code & ec)>> &handlers)
: exec(exec), handlers(handlers) {}
template<typename T>
void operator()(T & t) const
{
handlers.push_back(t.on_exit_handler(exec));
}
};
//Also set's up waiting for the exit, so it can close async stuff.
struct io_service_ref : boost::process::detail::handler_base
{
io_service_ref(boost::asio::io_service & ios)
: ios(ios)
{
}
boost::asio::io_service &get() {return ios;};
template <class Executor>
void on_success(Executor& exec) const
{
auto asyncs = boost::fusion::filter_if<
is_async_handler<
typename std::remove_reference< boost::mpl::_ > ::type
>>(exec.seq);
//ok, check if there are actually any.
if (boost::fusion::empty(asyncs))
{
return;
}
::boost::detail::winapi::PROCESS_INFORMATION_ & proc = exec.proc_info;
auto this_proc = ::boost::detail::winapi::GetCurrentProcess();
auto proc_in = proc.hProcess;;
::boost::detail::winapi::HANDLE_ process_handle;
if (!::boost::detail::winapi::DuplicateHandle(
this_proc, proc_in, this_proc, &process_handle, 0,
static_cast<::boost::detail::winapi::BOOL_>(true),
::boost::detail::winapi::DUPLICATE_SAME_ACCESS_))
exec.set_error(::boost::process::detail::get_last_error(),
"Duplicate Pipe Failed");
std::vector<std::function<void(int, const std::error_code & ec)>> funcs;
funcs.reserve(boost::fusion::size(asyncs));
boost::fusion::for_each(asyncs, async_handler_collector<Executor>(exec, funcs));
wait_handler wh(std::move(funcs), ios, process_handle, exec.exit_status);
auto handle_p = wh.handle.get();
handle_p->async_wait(std::move(wh));
}
struct wait_handler
{
std::vector<std::function<void(int, const std::error_code & ec)>> funcs;
std::unique_ptr<boost::asio::windows::object_handle> handle;
std::shared_ptr<std::atomic<int>> exit_status;
wait_handler(const wait_handler & ) = delete;
wait_handler(wait_handler && ) = default;
wait_handler(std::vector<std::function<void(int, const std::error_code & ec)>> && funcs,
boost::asio::io_service & ios, void * handle,
const std::shared_ptr<std::atomic<int>> &exit_status)
: funcs(std::move(funcs)),
handle(new boost::asio::windows::object_handle(ios, handle)),
exit_status(exit_status)
{
}
void operator()(const boost::system::error_code & ec_in)
{
std::error_code ec;
if (ec_in)
ec = std::error_code(ec_in.value(), std::system_category());
::boost::detail::winapi::DWORD_ code;
::boost::detail::winapi::GetExitCodeProcess(handle->native(), &code);
exit_status->store(code);
for (auto & func : funcs)
func(code, ec);
}
};
private:
boost::asio::io_service &ios;
};
}}}}
#endif /* BOOST_PROCESS_WINDOWS_IO_SERVICE_REF_HPP_ */
@@ -0,0 +1,64 @@
// Copyright (c) 2106 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_WINDOWS_IS_RUNNING_HPP
#define BOOST_PROCESS_WINDOWS_IS_RUNNING_HPP
#include <boost/process/detail/config.hpp>
#include <system_error>
#include <cstdlib>
#include <boost/detail/winapi/process.hpp>
namespace boost { namespace process { namespace detail { namespace windows {
constexpr static ::boost::detail::winapi::DWORD_ still_active = 259;
struct child_handle;
inline bool is_running(const child_handle &p, int & exit_code)
{
::boost::detail::winapi::DWORD_ code;
//single value, not needed in the winapi.
if (!::boost::detail::winapi::GetExitCodeProcess(p.process_handle(), &code))
::boost::process::detail::throw_last_error("GetExitCodeProcess() failed");
if (code == still_active)
return true;
else
{
exit_code = code;
return false;
}
}
inline bool is_running(const child_handle &p, int & exit_code, std::error_code &ec) noexcept
{
::boost::detail::winapi::DWORD_ code;
//single value, not needed in the winapi.
if (!::boost::detail::winapi::GetExitCodeProcess(p.process_handle(), &code))
ec = ::boost::process::detail::get_last_error();
else
ec.clear();
if (code == still_active)
return true;
else
{
exit_code = code;
return false;
}
}
inline bool is_running(int code)
{
return code == still_active;
}
inline int eval_exit_status(int in ) {return in;}
}}}}
#endif
@@ -0,0 +1,139 @@
// 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_WINDOWS_JOB_WORKAROUND_HPP_
#define BOOST_PROCESS_DETAIL_WINDOWS_JOB_WORKAROUND_HPP_
#include <boost/detail/winapi/config.hpp>
#include <boost/detail/winapi/basic_types.hpp>
#include <boost/detail/winapi/dll.hpp>
namespace boost { namespace process { namespace detail { namespace windows { namespace workaround {
//this import workaround is to keep it a header-only library. and enums cannot be imported from the winapi.
extern "C"
{
typedef enum _JOBOBJECTINFOCLASS_ {
JobObjectBasicAccountingInformation_ = 1, JobObjectBasicLimitInformation_,
JobObjectBasicProcessIdList_, JobObjectBasicUIRestrictions_,
JobObjectSecurityLimitInformation_, JobObjectEndOfJobTimeInformation_,
JobObjectAssociateCompletionPortInformation_, JobObjectBasicAndIoAccountingInformation_,
JobObjectExtendedLimitInformation_, JobObjectJobSetInformation_,
JobObjectGroupInformation_,
JobObjectNotificationLimitInformation_,
JobObjectLimitViolationInformation_,
JobObjectGroupInformationEx_,
JobObjectCpuRateControlInformation_,
JobObjectCompletionFilter_,
JobObjectCompletionCounter_,
JobObjectReserved1Information_ = 18,
JobObjectReserved2Information_,
JobObjectReserved3Information_,
JobObjectReserved4Information_,
JobObjectReserved5Information_,
JobObjectReserved6Information_,
JobObjectReserved7Information_,
JobObjectReserved8Information_,
MaxJobObjectInfoClass_
} JOBOBJECTINFOCLASS_;
typedef struct _JOBOBJECT_BASIC_LIMIT_INFORMATION_ {
::boost::detail::winapi::LARGE_INTEGER_ PerProcessUserTimeLimit;
::boost::detail::winapi::LARGE_INTEGER_ PerJobUserTimeLimit;
::boost::detail::winapi::DWORD_ LimitFlags;
::boost::detail::winapi::SIZE_T_ MinimumWorkingSetSize;
::boost::detail::winapi::SIZE_T_ MaximumWorkingSetSize;
::boost::detail::winapi::DWORD_ ActiveProcessLimit;
::boost::detail::winapi::ULONG_PTR_ Affinity;
::boost::detail::winapi::DWORD_ PriorityClass;
::boost::detail::winapi::DWORD_ SchedulingClass;
} JOBOBJECT_BASIC_LIMIT_INFORMATION_;
typedef struct _IO_COUNTERS_ {
::boost::detail::winapi::ULONGLONG_ ReadOperationCount;
::boost::detail::winapi::ULONGLONG_ WriteOperationCount;
::boost::detail::winapi::ULONGLONG_ OtherOperationCount;
::boost::detail::winapi::ULONGLONG_ ReadTransferCount;
::boost::detail::winapi::ULONGLONG_ WriteTransferCount;
::boost::detail::winapi::ULONGLONG_ OtherTransferCount;
} IO_COUNTERS_;
typedef struct _JOBOBJECT_EXTENDED_LIMIT_INFORMATION_ {
JOBOBJECT_BASIC_LIMIT_INFORMATION_ BasicLimitInformation;
IO_COUNTERS_ IoInfo;
::boost::detail::winapi::SIZE_T_ ProcessMemoryLimit;
::boost::detail::winapi::SIZE_T_ JobMemoryLimit;
::boost::detail::winapi::SIZE_T_ PeakProcessMemoryUsed;
::boost::detail::winapi::SIZE_T_ PeakJobMemoryUsed;
} JOBOBJECT_EXTENDED_LIMIT_INFORMATION_;
/*BOOL WINAPI QueryInformationJobObject(
_In_opt_ HANDLE hJob,
_In_ JOBOBJECTINFOCLASS JobObjectInfoClass,
_Out_ LPVOID lpJobObjectInfo,
_In_ DWORD cbJobObjectInfoLength,
_Out_opt_ LPDWORD lpReturnLength
);
*/
typedef ::boost::detail::winapi::BOOL_ ( WINAPI *query_information_job_object_p)(
::boost::detail::winapi::HANDLE_,
JOBOBJECTINFOCLASS_,
void *,
::boost::detail::winapi::DWORD_,
::boost::detail::winapi::DWORD_ *);
inline ::boost::detail::winapi::BOOL_ WINAPI query_information_job_object(
::boost::detail::winapi::HANDLE_ hJob,
JOBOBJECTINFOCLASS_ JobObjectInfoClass,
void * lpJobObjectInfo,
::boost::detail::winapi::DWORD_ cbJobObjectInfoLength,
::boost::detail::winapi::DWORD_ *lpReturnLength)
{
static ::boost::detail::winapi::HMODULE_ h = ::boost::detail::winapi::get_module_handle("Kernel32.dll");
static query_information_job_object_p f = reinterpret_cast<query_information_job_object_p>(::boost::detail::winapi::get_proc_address(h, "QueryInformationJobObject"));
return (*f)(hJob, JobObjectInfoClass, lpJobObjectInfo, cbJobObjectInfoLength, lpReturnLength);
}
/*BOOL WINAPI SetInformationJobObject(
_In_ HANDLE hJob,
_In_ JOBOBJECTINFOCLASS JobObjectInfoClass,
_In_ LPVOID lpJobObjectInfo,
_In_ DWORD cbJobObjectInfoLength
);*/
typedef ::boost::detail::winapi::BOOL_ ( WINAPI *set_information_job_object_p)(
::boost::detail::winapi::HANDLE_,
JOBOBJECTINFOCLASS_,
void *,
::boost::detail::winapi::DWORD_);
}
inline ::boost::detail::winapi::BOOL_ WINAPI set_information_job_object(
::boost::detail::winapi::HANDLE_ hJob,
JOBOBJECTINFOCLASS_ JobObjectInfoClass,
void * lpJobObjectInfo,
::boost::detail::winapi::DWORD_ cbJobObjectInfoLength)
{
static ::boost::detail::winapi::HMODULE_ h = ::boost::detail::winapi::get_module_handle("Kernel32.dll");
static set_information_job_object_p f = reinterpret_cast<set_information_job_object_p>(::boost::detail::winapi::get_proc_address(h, "SetInformationJobObject"));
return (*f)(hJob, JobObjectInfoClass, lpJobObjectInfo, cbJobObjectInfoLength);
}
constexpr static ::boost::detail::winapi::DWORD_ JOB_OBJECT_LIMIT_BREAKAWAY_OK_ = 0x00000800;
}}}}}
#endif /* BOOST_PROCESS_DETAIL_WINDOWS_JOB_WORKAROUND_HPP_ */
@@ -0,0 +1,103 @@
// Copyright (c) 2016 Klemens D. Morgenstern
// Copyright (c) 2008 Beman Dawes
//
// 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_WINDOWS_LOCALE_HPP_
#define BOOST_PROCESS_DETAIL_WINDOWS_LOCALE_HPP_
#include <locale>
#include <boost/core/ignore_unused.hpp>
#include <boost/detail/winapi/file_management.hpp>
#include <boost/detail/winapi/character_code_conversion.hpp>
namespace boost
{
namespace process
{
namespace detail
{
namespace windows
{
//copied from boost.filesystem
class windows_file_codecvt
: public std::codecvt< wchar_t, char, std::mbstate_t >
{
public:
explicit windows_file_codecvt(std::size_t refs = 0)
: std::codecvt<wchar_t, char, std::mbstate_t>(refs) {}
protected:
bool do_always_noconv() const noexcept override { return false; }
// seems safest to assume variable number of characters since we don't
// actually know what codepage is active
int do_encoding() const noexcept override { return 0; }
std::codecvt_base::result do_in(std::mbstate_t& state,
const char* from, const char* from_end, const char*& from_next,
wchar_t* to, wchar_t* to_end, wchar_t*& to_next) const override
{
boost::ignore_unused(state);
::boost::detail::winapi::UINT_ codepage = AreFileApisANSI() ?
::boost::detail::winapi::CP_ACP_ :
::boost::detail::winapi::CP_OEMCP_;
int count;
if ((count = ::boost::detail::winapi::MultiByteToWideChar(codepage,
::boost::detail::winapi::MB_PRECOMPOSED_, from,
static_cast<int>(from_end - from), to, static_cast<int>(to_end - to))) == 0)
{
return error; // conversion failed
}
from_next = from_end;
to_next = to + count;
*to_next = L'\0';
return ok;
}
std::codecvt_base::result do_out(std::mbstate_t & state,
const wchar_t* from, const wchar_t* from_end, const wchar_t*& from_next,
char* to, char* to_end, char*& to_next) const override
{
boost::ignore_unused(state);
auto codepage = ::boost::detail::winapi::AreFileApisANSI() ?
::boost::detail::winapi::CP_ACP_ :
::boost::detail::winapi::CP_OEMCP_;
int count;
if ((count = ::boost::detail::winapi::WideCharToMultiByte(codepage,
::boost::detail::winapi::WC_NO_BEST_FIT_CHARS_, from,
static_cast<int>(from_end - from), to, static_cast<int>(to_end - to), 0, 0)) == 0)
{
return error; // conversion failed
}
from_next = from_end;
to_next = to + count;
*to_next = '\0';
return ok;
}
std::codecvt_base::result do_unshift(std::mbstate_t&,
char* /*from*/, char* /*to*/, char* & /*next*/) const override { return ok; }
int do_length(std::mbstate_t&,
const char* /*from*/, const char* /*from_end*/, std::size_t /*max*/) const override { return 0; }
int do_max_length() const noexcept override { return 0; }
};
}
}
}
}
#endif /* BOOST_PROCESS_LOCALE_HPP_ */
@@ -0,0 +1,41 @@
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
// Copyright (c) 2009 Boris Schaeling
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
//
// 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_WINDOWS_INITIALIZERS_NULL_IN_HPP
#define BOOST_PROCESS_WINDOWS_INITIALIZERS_NULL_IN_HPP
#include <boost/detail/winapi/process.hpp>
#include <boost/detail/winapi/handles.hpp>
#include <boost/detail/winapi/handle_info.hpp>
#include <boost/process/detail/handler_base.hpp>
#include <boost/process/detail/windows/file_descriptor.hpp>
namespace boost { namespace process { namespace detail { namespace windows {
struct null_in : public ::boost::process::detail::handler_base
{
file_descriptor source{"NUL", file_descriptor::read};
public:
template <class WindowsExecutor>
void on_setup(WindowsExecutor &e) const
{
boost::detail::winapi::SetHandleInformation(source.handle(),
boost::detail::winapi::HANDLE_FLAG_INHERIT_,
boost::detail::winapi::HANDLE_FLAG_INHERIT_);
e.startup_info.hStdInput = source.handle();
e.startup_info.dwFlags |= boost::detail::winapi::STARTF_USESTDHANDLES_;
e.inherit_handles = true;
}
};
}}}}
#endif
@@ -0,0 +1,75 @@
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
// Copyright (c) 2009 Boris Schaeling
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
//
// 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_WINDOWS_INITIALIZERS_NULL_OUT_HPP
#define BOOST_PROCESS_WINDOWS_INITIALIZERS_NULL_OUT_HPP
#include <boost/detail/winapi/process.hpp>
#include <boost/detail/winapi/handles.hpp>
#include <boost/detail/winapi/handle_info.hpp>
#include <boost/process/detail/handler_base.hpp>
#include <boost/process/detail/windows/file_descriptor.hpp>
namespace boost { namespace process { namespace detail { namespace windows {
template<int p1, int p2>
struct null_out : public ::boost::process::detail::handler_base
{
file_descriptor sink {"NUL", file_descriptor::write}; //works because it gets destroyed AFTER launch.
template <typename WindowsExecutor>
void on_setup(WindowsExecutor &e) const;
};
template<>
template<typename WindowsExecutor>
void null_out<1,-1>::on_setup(WindowsExecutor &e) const
{
boost::detail::winapi::SetHandleInformation(sink.handle(),
boost::detail::winapi::HANDLE_FLAG_INHERIT_,
boost::detail::winapi::HANDLE_FLAG_INHERIT_);
e.startup_info.hStdOutput = sink.handle();
e.startup_info.dwFlags |= ::boost::detail::winapi::STARTF_USESTDHANDLES_;
e.inherit_handles = true;
}
template<>
template<typename WindowsExecutor>
void null_out<2,-1>::on_setup(WindowsExecutor &e) const
{
boost::detail::winapi::SetHandleInformation(sink.handle(),
boost::detail::winapi::HANDLE_FLAG_INHERIT_,
boost::detail::winapi::HANDLE_FLAG_INHERIT_);
e.startup_info.hStdError = sink.handle();
e.startup_info.dwFlags |= ::boost::detail::winapi::STARTF_USESTDHANDLES_;
e.inherit_handles = true;
}
template<>
template<typename WindowsExecutor>
void null_out<1,2>::on_setup(WindowsExecutor &e) const
{
boost::detail::winapi::SetHandleInformation(sink.handle(),
boost::detail::winapi::HANDLE_FLAG_INHERIT_,
boost::detail::winapi::HANDLE_FLAG_INHERIT_);
e.startup_info.hStdOutput = sink.handle();
e.startup_info.hStdError = sink.handle();
e.startup_info.dwFlags |= ::boost::detail::winapi::STARTF_USESTDHANDLES_;
e.inherit_handles = true;
}
}}}}
#endif
@@ -0,0 +1,40 @@
// 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_WINDOWS_ON_EXIT_HPP_
#define BOOST_PROCESS_WINDOWS_ON_EXIT_HPP_
#include <boost/process/detail/config.hpp>
#include <boost/process/detail/handler_base.hpp>
#include <boost/process/detail/windows/async_handler.hpp>
#include <boost/detail/winapi/process.hpp>
#include <system_error>
#include <functional>
namespace boost { namespace process { namespace detail { namespace windows {
struct on_exit_ : boost::process::detail::windows::async_handler
{
std::function<void(int, const std::error_code&)> handler;
on_exit_(const std::function<void(int, const std::error_code&)> & handler) : handler(handler)
{
}
template<typename Executor>
std::function<void(int, const std::error_code&)> on_exit_handler(Executor&)
{
auto handler = this->handler;
return [handler](int exit_code, const std::error_code & ec)
{
handler(static_cast<int>(exit_code), ec);
};
}
};
}}}}
#endif /* INCLUDE_BOOST_PROCESS_WINDOWS_ON_EXIT_HPP_ */
@@ -0,0 +1,89 @@
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
// Copyright (c) 2009 Boris Schaeling
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
//
// 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_WINDOWS_INITIALIZERS_PIPE_IN_HPP
#define BOOST_PROCESS_WINDOWS_INITIALIZERS_PIPE_IN_HPP
#include <boost/detail/winapi/process.hpp>
#include <boost/detail/winapi/handles.hpp>
#include <boost/process/detail/handler_base.hpp>
namespace boost { namespace process { namespace detail { namespace windows {
struct pipe_in : public ::boost::process::detail::handler_base
{
::boost::detail::winapi::HANDLE_ handle;
pipe_in(::boost::detail::winapi::HANDLE_ handle) : handle(handle) {}
template<typename T> //async_pipe
pipe_in(T & p) : handle(p.native_source())
{
p.assign_source(::boost::detail::winapi::INVALID_HANDLE_VALUE_);
}
template <class WindowsExecutor>
void on_setup(WindowsExecutor &e) const
{
boost::detail::winapi::SetHandleInformation(handle,
boost::detail::winapi::HANDLE_FLAG_INHERIT_,
boost::detail::winapi::HANDLE_FLAG_INHERIT_);
e.startup_info.hStdInput = handle;
e.startup_info.dwFlags |= boost::detail::winapi::STARTF_USESTDHANDLES_;
e.inherit_handles = true;
}
template<typename WindowsExecutor>
void on_error(WindowsExecutor &, const std::error_code &) const
{
::boost::detail::winapi::CloseHandle(handle);
}
template<typename WindowsExecutor>
void on_success(WindowsExecutor &) const
{
::boost::detail::winapi::CloseHandle(handle);
}
};
class async_pipe;
struct async_pipe_in : public pipe_in
{
async_pipe &pipe;
template<typename AsyncPipe>
async_pipe_in(AsyncPipe & p) : pipe_in(p.native_source()), pipe(p)
{
}
template<typename Pipe, typename Executor>
static void close(Pipe & pipe, Executor &)
{
boost::system::error_code ec;
std::move(pipe).source().close(ec);
}
template<typename Executor>
void on_error(Executor & exec, const std::error_code &)
{
close(pipe, exec);
}
template<typename Executor>
void on_success(Executor &exec)
{
close(pipe, exec);
}
};
}}}}
#endif
@@ -0,0 +1,122 @@
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
// Copyright (c) 2009 Boris Schaeling
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
// 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_WINDOWS_PIPE_OUT_HPP
#define BOOST_PROCESS_WINDOWS_PIPE_OUT_HPP
#include <boost/detail/winapi/process.hpp>
#include <boost/detail/winapi/handles.hpp>
#include <boost/process/detail/handler_base.hpp>
namespace boost { namespace process { namespace detail { namespace windows {
template<int p1, int p2>
struct pipe_out : public ::boost::process::detail::handler_base
{
::boost::detail::winapi::HANDLE_ handle;
pipe_out(::boost::detail::winapi::HANDLE_ handle) : handle(handle) {}
template<typename T>
pipe_out(T & p) : handle(p.native_sink())
{
p.assign_sink(::boost::detail::winapi::INVALID_HANDLE_VALUE_);
}
template<typename WindowsExecutor>
void on_setup(WindowsExecutor &e) const;
template<typename WindowsExecutor>
void on_error(WindowsExecutor &, const std::error_code &) const
{
::boost::detail::winapi::CloseHandle(handle);
}
template<typename WindowsExecutor>
void on_success(WindowsExecutor &) const
{
::boost::detail::winapi::CloseHandle(handle);
}
};
template<>
template<typename WindowsExecutor>
void pipe_out<1,-1>::on_setup(WindowsExecutor &e) const
{
boost::detail::winapi::SetHandleInformation(handle,
boost::detail::winapi::HANDLE_FLAG_INHERIT_,
boost::detail::winapi::HANDLE_FLAG_INHERIT_);
e.startup_info.hStdOutput = handle;
e.startup_info.dwFlags |= ::boost::detail::winapi::STARTF_USESTDHANDLES_;
e.inherit_handles = true;
}
template<>
template<typename WindowsExecutor>
void pipe_out<2,-1>::on_setup(WindowsExecutor &e) const
{
boost::detail::winapi::SetHandleInformation(handle,
boost::detail::winapi::HANDLE_FLAG_INHERIT_,
boost::detail::winapi::HANDLE_FLAG_INHERIT_);
e.startup_info.hStdError = handle;
e.startup_info.dwFlags |= ::boost::detail::winapi::STARTF_USESTDHANDLES_;
e.inherit_handles = true;
}
template<>
template<typename WindowsExecutor>
void pipe_out<1,2>::on_setup(WindowsExecutor &e) const
{
boost::detail::winapi::SetHandleInformation(handle,
boost::detail::winapi::HANDLE_FLAG_INHERIT_,
boost::detail::winapi::HANDLE_FLAG_INHERIT_);
e.startup_info.hStdOutput = handle;
e.startup_info.hStdError = handle;
e.startup_info.dwFlags |= ::boost::detail::winapi::STARTF_USESTDHANDLES_;
e.inherit_handles = true;
}
template<int p1, int p2>
struct async_pipe_out : public pipe_out<p1, p2>
{
async_pipe &pipe;
template<typename AsyncPipe>
async_pipe_out(AsyncPipe & p) : pipe_out<p1, p2>(p.native_sink()), pipe(p)
{
}
template<typename Pipe, typename Executor>
static void close(Pipe & pipe, Executor &)
{
boost::system::error_code ec;
std::move(pipe).sink().close(ec);
}
template<typename Executor>
void on_error(Executor & exec, const std::error_code &)
{
close(pipe, exec);
}
template<typename Executor>
void on_success(Executor &exec)
{
close(pipe, exec);
}
};
}}}}
#endif
@@ -0,0 +1,54 @@
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
// Copyright (c) 2009 Boris Schaeling
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
//
// 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_WINDOWS_SEARCH_PATH_HPP
#define BOOST_PROCESS_WINDOWS_SEARCH_PATH_HPP
#include <boost/process/detail/config.hpp>
#include <boost/filesystem/path.hpp>
#include <boost/filesystem/operations.hpp>
#include <boost/system/error_code.hpp>
#include <string>
#include <stdexcept>
#include <array>
#include <atomic>
#include <cstdlib>
#include <boost/detail/winapi/shell.hpp>
namespace boost { namespace process { namespace detail { namespace windows {
inline boost::filesystem::path search_path(
const boost::filesystem::path &filename,
const std::vector<boost::filesystem::path> &path)
{
for (const boost::filesystem::path & pp : path)
{
auto full = pp / filename;
std::array<std::string, 4> extensions {{ "", ".exe", ".com", ".bat" }};
for (boost::filesystem::path ext : extensions)
{
auto p = full;
p += ext;
boost::system::error_code ec;
bool file = boost::filesystem::is_regular_file(p, ec);
if (!ec && file &&
::boost::detail::winapi::sh_get_file_info(p.string().c_str(), 0, 0, 0, ::boost::detail::winapi::SHGFI_EXETYPE_))
{
return p;
}
}
}
return "";
}
}}}}
#endif
@@ -0,0 +1,53 @@
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
// Copyright (c) 2009 Boris Schaeling
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
//
// 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_WINDOWS_SHELL_PATH_HPP
#define BOOST_PROCESS_WINDOWS_SHELL_PATH_HPP
#include <boost/process/detail/config.hpp>
#include <system_error>
#include <boost/filesystem/path.hpp>
#include <boost/detail/winapi/basic_types.hpp>
#include <boost/detail/winapi/get_system_directory.hpp>
namespace boost { namespace process { namespace detail { namespace windows {
inline boost::filesystem::path shell_path()
{
::boost::detail::winapi::WCHAR_ sysdir[260];
unsigned int size = ::boost::detail::winapi::get_system_directory(sysdir, sizeof(sysdir));
if (!size)
throw_last_error("GetSystemDirectory() failed");
boost::filesystem::path p = sysdir;
return p / "cmd.exe";
}
inline boost::filesystem::path shell_path(std::error_code &ec) noexcept
{
::boost::detail::winapi::WCHAR_ sysdir[260];
unsigned int size = ::boost::detail::winapi::get_system_directory(sysdir, sizeof(sysdir));
boost::filesystem::path p;
if (!size)
ec = std::error_code(
::boost::detail::winapi::GetLastError(),
std::system_category());
else
{
ec.clear();
p = sysdir;
p /= "cmd.exe";
}
return p;
}
}}}}
#endif
@@ -0,0 +1,39 @@
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
// Copyright (c) 2009 Boris Schaeling
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
// 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_WINDOWS_SHOW_WINDOW_HPP
#define BOOST_PROCESS_WINDOWS_SHOW_WINDOW_HPP
#include <boost/detail/winapi/process.hpp>
#include <boost/detail/winapi/show_window.hpp>
#include <boost/process/detail/handler_base.hpp>
namespace boost { namespace process { namespace detail { namespace windows {
template<::boost::detail::winapi::WORD_ Flags>
struct show_window : ::boost::process::detail::handler_base
{
template <class WindowsExecutor>
void on_setup(WindowsExecutor &e) const
{
e.startup_info.dwFlags |= ::boost::detail::winapi::STARTF_USESHOWWINDOW_;
e.startup_info.wShowWindow |= Flags;
}
};
}}}}
#endif
@@ -0,0 +1,36 @@
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
// Copyright (c) 2009 Boris Schaeling
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
//
// 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_WINDOWS_START_DIR_HPP
#define BOOST_PROCESS_DETAIL_WINDOWS_START_DIR_HPP
#include <string>
#include <boost/process/detail/windows/handler.hpp>
namespace boost { namespace process { namespace detail { namespace windows {
template<typename Char>
struct start_dir_init : handler_base_ext
{
start_dir_init(const std::basic_string<Char> &s) : s_(s) {}
template <class Executor>
void on_setup(Executor& exec) const
{
exec.work_dir = s_.c_str();
}
const std::basic_string<Char> &str() const {return s_;}
private:
std::basic_string<Char> s_;
};
}}}}
#endif
@@ -0,0 +1,49 @@
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
// Copyright (c) 2009 Boris Schaeling
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
//
// 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_WINDOWS_TERMINATE_HPP
#define BOOST_PROCESS_WINDOWS_TERMINATE_HPP
#include <boost/process/detail/config.hpp>
#include <system_error>
#include <cstdlib>
#include <boost/detail/winapi/process.hpp>
#include <boost/detail/winapi/get_last_error.hpp>
namespace boost { namespace process { namespace detail { namespace windows {
struct child_handle;
inline void terminate(child_handle &p)
{
if (!::boost::detail::winapi::TerminateProcess(p.process_handle(), EXIT_FAILURE))
boost::process::detail::throw_last_error("TerminateProcess() failed");
::boost::detail::winapi::CloseHandle(p.proc_info.hProcess);
p.proc_info.hProcess = ::boost::detail::winapi::INVALID_HANDLE_VALUE_;
}
inline void terminate(child_handle &p, std::error_code &ec) noexcept
{
if (!::boost::detail::winapi::TerminateProcess(p.process_handle(), EXIT_FAILURE))
ec = boost::process::detail::get_last_error();
else
{
ec.clear();
::boost::detail::winapi::CloseHandle(p.proc_info.hProcess);
p.proc_info.hProcess = ::boost::detail::winapi::INVALID_HANDLE_VALUE_;
}
}
}}}}
#endif
@@ -0,0 +1,193 @@
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
// Copyright (c) 2009 Boris Schaeling
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
// 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_WINDOWS_WAIT_FOR_EXIT_HPP
#define BOOST_PROCESS_WINDOWS_WAIT_FOR_EXIT_HPP
#include <boost/process/detail/config.hpp>
#include <system_error>
#include <boost/detail/winapi/synchronization.hpp>
#include <boost/detail/winapi/process.hpp>
#include <boost/process/detail/windows/child_handle.hpp>
#include <chrono>
namespace boost { namespace process { namespace detail { namespace windows {
inline void wait(child_handle &p, int & exit_code)
{
if (::boost::detail::winapi::WaitForSingleObject(p.process_handle(),
::boost::detail::winapi::infinite) == ::boost::detail::winapi::wait_failed)
throw_last_error("WaitForSingleObject() failed");
::boost::detail::winapi::DWORD_ _exit_code;
if (!::boost::detail::winapi::GetExitCodeProcess(p.process_handle(), &_exit_code))
throw_last_error("GetExitCodeProcess() failed");
::boost::detail::winapi::CloseHandle(p.proc_info.hProcess);
p.proc_info.hProcess = ::boost::detail::winapi::INVALID_HANDLE_VALUE_;
exit_code = static_cast<int>(_exit_code);
}
inline void wait(child_handle &p, int & exit_code, std::error_code &ec) noexcept
{
::boost::detail::winapi::DWORD_ _exit_code = 1;
if (::boost::detail::winapi::WaitForSingleObject(p.process_handle(),
::boost::detail::winapi::infinite) == ::boost::detail::winapi::wait_failed)
ec = std::error_code(
::boost::detail::winapi::GetLastError(),
std::system_category());
else if (!::boost::detail::winapi::GetExitCodeProcess(p.process_handle(), &_exit_code))
ec = std::error_code(
::boost::detail::winapi::GetLastError(),
std::system_category());
else
ec.clear();
::boost::detail::winapi::CloseHandle(p.proc_info.hProcess);
p.proc_info.hProcess = ::boost::detail::winapi::INVALID_HANDLE_VALUE_;
exit_code = static_cast<int>(_exit_code);
}
template< class Rep, class Period >
inline bool wait_for(
child_handle &p,
int & exit_code,
const std::chrono::duration<Rep, Period>& rel_time)
{
std::chrono::milliseconds ms = std::chrono::duration_cast<std::chrono::milliseconds>(rel_time);
::boost::detail::winapi::DWORD_ wait_code;
wait_code = ::boost::detail::winapi::WaitForSingleObject(p.process_handle(),
static_cast<::boost::detail::winapi::DWORD_>(ms.count()));
if (wait_code == ::boost::detail::winapi::wait_failed)
throw_last_error("WaitForSingleObject() failed");
else if (wait_code == ::boost::detail::winapi::wait_timeout)
return false; //
::boost::detail::winapi::DWORD_ _exit_code;
if (!::boost::detail::winapi::GetExitCodeProcess(p.process_handle(), &_exit_code))
throw_last_error("GetExitCodeProcess() failed");
exit_code = static_cast<int>(_exit_code);
::boost::detail::winapi::CloseHandle(p.proc_info.hProcess);
p.proc_info.hProcess = ::boost::detail::winapi::INVALID_HANDLE_VALUE_;
return true;
}
template< class Rep, class Period >
inline bool wait_for(
child_handle &p,
int & exit_code,
const std::chrono::duration<Rep, Period>& rel_time,
std::error_code &ec) noexcept
{
std::chrono::milliseconds ms = std::chrono::duration_cast<std::chrono::milliseconds>(rel_time);
::boost::detail::winapi::DWORD_ wait_code;
wait_code = ::boost::detail::winapi::WaitForSingleObject(p.process_handle(),
static_cast<::boost::detail::winapi::DWORD_>(ms.count()));
if (wait_code == ::boost::detail::winapi::wait_failed)
ec = std::error_code(
::boost::detail::winapi::GetLastError(),
std::system_category());
else if (wait_code == ::boost::detail::winapi::wait_timeout)
return false; //
::boost::detail::winapi::DWORD_ _exit_code = 1;
if (!::boost::detail::winapi::GetExitCodeProcess(p.process_handle(), &_exit_code))
{
ec = std::error_code(
::boost::detail::winapi::GetLastError(),
std::system_category());
return false;
}
else
ec.clear();
exit_code = static_cast<int>(_exit_code);
::boost::detail::winapi::CloseHandle(p.proc_info.hProcess);
p.proc_info.hProcess = ::boost::detail::winapi::INVALID_HANDLE_VALUE_;
return true;
;
}
template< class Clock, class Duration >
inline bool wait_until(
child_handle &p,
int & exit_code,
const std::chrono::time_point<Clock, Duration>& timeout_time)
{
std::chrono::milliseconds ms =
std::chrono::duration_cast<std::chrono::milliseconds>(
timeout_time - std::chrono::system_clock::now());
::boost::detail::winapi::DWORD_ wait_code;
wait_code = ::boost::detail::winapi::WaitForSingleObject(p.process_handle(),
static_cast<::boost::detail::winapi::DWORD_>(ms.count()));
if (wait_code == ::boost::detail::winapi::wait_failed)
throw_last_error("WaitForSingleObject() failed");
else if (wait_code == ::boost::detail::winapi::wait_timeout)
return false;
::boost::detail::winapi::DWORD_ _exit_code;
if (!::boost::detail::winapi::GetExitCodeProcess(p.process_handle(), &_exit_code))
throw_last_error("GetExitCodeProcess() failed");
exit_code = static_cast<int>(_exit_code);
::boost::detail::winapi::CloseHandle(p.proc_info.hProcess);
p.proc_info.hProcess = ::boost::detail::winapi::INVALID_HANDLE_VALUE_;
return true;
}
template< class Clock, class Duration >
inline bool wait_until(
child_handle &p,
int & exit_code,
const std::chrono::time_point<Clock, Duration>& timeout_time,
std::error_code &ec) noexcept
{
std::chrono::milliseconds ms =
std::chrono::duration_cast<std::chrono::milliseconds>(
timeout_time - std::chrono::system_clock::now());
::boost::detail::winapi::DWORD_ _exit_code = 1;
if (::boost::detail::winapi::WaitForSingleObject(p.process_handle(),
static_cast<::boost::detail::winapi::DWORD_>(ms.count()))
== ::boost::detail::winapi::wait_failed)
ec = std::error_code(
::boost::detail::winapi::GetLastError(),
std::system_category());
else if (!::boost::detail::winapi::GetExitCodeProcess(p.process_handle(), &_exit_code))
ec = std::error_code(
::boost::detail::winapi::GetLastError(),
std::system_category());
else
ec.clear();
exit_code = static_cast<int>(exit_code);
::boost::detail::winapi::CloseHandle(p.proc_info.hProcess);
p.proc_info.hProcess = ::boost::detail::winapi::INVALID_HANDLE_VALUE_;
return true;
;
}
}}}}
#endif
@@ -0,0 +1,121 @@
// 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_WINDOWS_WAIT_GROUP_HPP_
#define BOOST_PROCESS_DETAIL_WINDOWS_WAIT_GROUP_HPP_
#include <boost/process/detail/config.hpp>
#include <boost/detail/winapi/jobs.hpp>
#include <boost/detail/winapi/wait.hpp>
namespace boost { namespace process { namespace detail { namespace windows {
struct group_handle;
inline void wait(const group_handle &p)
{
if (::boost::detail::winapi::WaitForSingleObject(p.handle(),
::boost::detail::winapi::infinite) == ::boost::detail::winapi::wait_failed)
throw_last_error("WaitForSingleObject() failed");
}
inline void wait(const group_handle &p, std::error_code &ec)
{
if (::boost::detail::winapi::WaitForSingleObject(p.handle(),
::boost::detail::winapi::infinite) == ::boost::detail::winapi::wait_failed)
ec = get_last_error();
}
template< class Rep, class Period >
inline bool wait_for(
const group_handle &p,
const std::chrono::duration<Rep, Period>& rel_time)
{
std::chrono::milliseconds ms = std::chrono::duration_cast<std::chrono::milliseconds>(rel_time);
::boost::detail::winapi::DWORD_ wait_code;
wait_code = ::boost::detail::winapi::WaitForSingleObject(p.handle(), ms.count());
if (wait_code == ::boost::detail::winapi::wait_failed)
throw_last_error("WaitForSingleObject() failed");
else if (wait_code == ::boost::detail::winapi::wait_timeout)
return false; //
return true;
}
template< class Rep, class Period >
inline bool wait_for(
const group_handle &p,
const std::chrono::duration<Rep, Period>& rel_time,
std::error_code &ec)
{
std::chrono::milliseconds ms = std::chrono::duration_cast<std::chrono::milliseconds>(rel_time);
::boost::detail::winapi::DWORD_ wait_code;
wait_code = ::boost::detail::winapi::WaitForSingleObject(p.handle(), ms.count());
if (wait_code == ::boost::detail::winapi::wait_failed)
ec = get_last_error();
else if (wait_code == ::boost::detail::winapi::wait_timeout)
return false; //
return true;
}
template< class Clock, class Duration >
inline bool wait_until(
const group_handle &p,
const std::chrono::time_point<Clock, Duration>& timeout_time)
{
std::chrono::milliseconds ms =
std::chrono::duration_cast<std::chrono::milliseconds>(
timeout_time - std::chrono::system_clock::now());
::boost::detail::winapi::DWORD_ wait_code;
wait_code = ::boost::detail::winapi::WaitForSingleObject(p.handle(), ms.count());
if (wait_code == ::boost::detail::winapi::wait_failed)
throw_last_error("WaitForSingleObject() failed");
else if (wait_code == ::boost::detail::winapi::wait_timeout)
return false; //
return true;
}
template< class Clock, class Duration >
inline bool wait_until(
const group_handle &p,
const std::chrono::time_point<Clock, Duration>& timeout_time,
std::error_code &ec)
{
std::chrono::milliseconds ms =
std::chrono::duration_cast<std::chrono::milliseconds>(
timeout_time - std::chrono::system_clock::now());
::boost::detail::winapi::DWORD_ wait_code;
wait_code = ::boost::detail::winapi::WaitForSingleObject(p.handle(), ms.count());
if (wait_code == ::boost::detail::winapi::wait_failed)
ec = get_last_error();
else if (wait_code == ::boost::detail::winapi::wait_timeout)
return false; //
return true;
;
}
}}}}
#endif /* BOOST_PROCESS_DETAIL_WINDOWS_WAIT_GROUP_HPP_ */
@@ -0,0 +1,502 @@
// 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 ':'
seperated list as used in `PATH`.
On both `posix` and `windows` the environment variables can be lists of strings,
seperated 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_ */
@@ -0,0 +1,698 @@
// 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_ENVIRONMENT_HPP_
#define BOOST_PROCESS_ENVIRONMENT_HPP_
#include <boost/process/detail/config.hpp>
#include <boost/algorithm/string/split.hpp>
#include <boost/algorithm/string/case_conv.hpp>
#include <boost/iterator/transform_iterator.hpp>
#include <boost/filesystem/path.hpp>
#if defined(BOOST_POSIX_API)
#include <boost/process/detail/posix/environment.hpp>
#elif defined(BOOST_WINDOWS_API)
#include <boost/process/detail/windows/environment.hpp>
#endif
namespace boost { namespace process {
namespace detail {
template<typename Char, typename Environment>
struct const_entry
{
using value_type = Char ;
using pointer = const value_type * ;
using string_type = std::basic_string<value_type> ;
using range = boost::iterator_range<pointer> ;
using environment_t = Environment ;
std::vector<string_type> to_vector() const
{
if (_data == nullptr)
return std::vector<string_type>();
std::vector<string_type> data;
auto str = string_type(_data);
struct splitter
{
bool operator()(wchar_t w) const {return w == api::env_seperator<wchar_t>();}
bool operator()(char c) const {return c == api::env_seperator<char> ();}
} s;
boost::split(data, _data, s);
return std::move(data);
}
string_type to_string() const
{
if (_data != nullptr)
return string_type(_data);
else
return string_type();
}
string_type get_name() const {return string_type(_name.begin(), _name.end());}
explicit const_entry(string_type&& name, pointer data, environment_t & env_) :
_name(std::move(name)), _data(data), _env(&env_) {}
explicit const_entry(string_type &&name, environment_t & env) :
_name(std::move(name)), _data(nullptr), _env(&env) {}
const_entry(const const_entry&) = default;
const_entry& operator=(const const_entry&) = default;
void reload()
{
auto p = _env->find(_name);
if (p == _env->end())
_data = nullptr;
else
_data = p->_data;
this->_env->reload();
}
bool empty() const
{
return _data == nullptr;
}
protected:
string_type _name;
pointer _data;
environment_t * _env;
};
template<typename Char, typename Environment>
struct entry : const_entry<Char, Environment>
{
using father = const_entry<Char, Environment>;
using value_type = typename father::value_type;
using string_type = typename father::string_type;
using pointer = typename father::pointer;
using environment_t = typename father::environment_t;
explicit entry(string_type&& name, pointer data, environment_t & env) :
father(std::move(name), data, env) {}
explicit entry(string_type &&name, environment_t & env) :
father(std::move(name), env) {}
entry(const entry&) = default;
entry& operator=(const entry&) = default;
void assign(const string_type &value)
{
this->_env->set(this->_name, value);
this->reload();
}
void assign(const std::vector<string_type> &value)
{
string_type data;
for (auto &v : value)
{
if (&v != &value.front())
data += api::env_seperator<value_type>();
data += v;
}
this->_env->set(this->_name, data);
this->reload();
}
void assign(const std::initializer_list<string_type> &value)
{
string_type data;
for (auto &v : value)
{
if (&v != &*value.begin())
data += api::env_seperator<value_type>();
data += v;
}
this->_env->set(this->_name, data);
this->reload();
}
void append(const string_type &value)
{
if (this->_data == nullptr)
this->_env->set(this->_name, value);
else
{
string_type st = this->_data;
this->_env->set(this->_name, st + api::env_seperator<value_type>() + value);
}
this->reload();
}
void clear()
{
this->_env->reset(this->_name);
this->_env->reload();
this->_data = nullptr;
}
entry &operator=(const string_type & value)
{
assign(value);
return *this;
}
entry &operator=(const std::vector<string_type> & value)
{
assign(value);
return *this;
}
entry &operator=(const std::initializer_list<string_type> & value)
{
assign(value);
return *this;
}
entry &operator+=(const string_type & value)
{
append(value);
return *this;
}
};
template<typename Char, typename Environment>
struct make_entry
{
make_entry(const make_entry&) = default;
make_entry& operator=(const make_entry&) = default;
Environment *env;
make_entry(Environment & env) : env(&env) {};
entry<Char, Environment> operator()(const Char* data) const
{
auto p = data;
while ((*p != equal_sign<Char>()) && (*p != null_char<Char>()))
p++;
auto name = std::basic_string<Char>(data, p);
p++; //go behind equal sign
return entry<Char, Environment>(std::move(name), p, *env);
}
};
template<typename Char, typename Environment>
struct make_const_entry
{
make_const_entry(const make_const_entry&) = default;
make_const_entry& operator=(const make_const_entry&) = default;
Environment *env;
make_const_entry(Environment & env) : env(&env) {};
const_entry<Char, Environment> operator()(const Char* data) const
{
auto p = data;
while ((*p != equal_sign<Char>()) && (*p != null_char<Char>()))
p++;
auto name = std::basic_string<Char>(data, p);
p++; //go behind equal sign
return const_entry<Char, Environment>(std::move(name), p, *env);
}
};
}
#if !defined (BOOST_PROCESS_DOXYGEN)
template<typename Char, template <class> class Implementation = detail::api::basic_environment_impl>
class basic_environment_impl : public Implementation<Char>
{
Char** _get_end() const
{
auto p = this->_env_impl;
while (*p != nullptr)
p++;
return p;
}
public:
using string_type = std::basic_string<Char>;
using implementation_type = Implementation<Char>;
using base_type = basic_environment_impl<Char, Implementation>;
using entry_maker = detail::make_entry<Char, base_type>;
using entry_type = detail::entry <Char, base_type>;
using const_entry_type = detail::const_entry <Char, const base_type>;
using const_entry_maker = detail::make_const_entry<Char, const base_type>;
friend entry_type;
friend const_entry_type;
using iterator = boost::transform_iterator< entry_maker, Char**, entry_type, entry_type>;
using const_iterator = boost::transform_iterator<const_entry_maker, Char**, const_entry_type, const_entry_type>;
using size_type = std::size_t;
iterator begin() {return iterator(this->_env_impl, entry_maker(*this));}
const_iterator begin() const {return const_iterator(this->_env_impl, const_entry_maker(*this));}
const_iterator cbegin() const {return const_iterator(this->_env_impl, const_entry_maker(*this));}
iterator end() {return iterator(_get_end(), entry_maker(*this));}
const_iterator end() const {return const_iterator(_get_end(), const_entry_maker(*this));}
const_iterator cend() const {return const_iterator(_get_end(), const_entry_maker(*this));}
iterator find( const string_type& key )
{
auto p = this->_env_impl;
auto st1 = key + ::boost::process::detail::equal_sign<Char>();
while (*p != nullptr)
{
if (std::equal(st1.begin(), st1.end(), *p))
break;
p++;
}
return iterator(p, entry_maker(*this));
}
const_iterator find( const string_type& key ) const
{
auto p = this->_env_impl;
auto st1 = key + ::boost::process::detail::equal_sign<Char>();
while (*p != nullptr)
{
if (std::equal(st1.begin(), st1.end(), *p))
break;
p++;
}
return const_iterator(p, const_entry_maker(*this));
}
std::size_t count(const string_type & st) const
{
auto p = this->_env_impl;
auto st1 = st + ::boost::process::detail::equal_sign<Char>();
while (*p != nullptr)
{
if (std::equal(st1.begin(), st1.end(), *p))
return 1u;
p++;
}
return 0u;
}
void erase(const string_type & id)
{
implementation_type::reset(id);
this->reload();
}
std::pair<iterator,bool> emplace(const string_type & id, const string_type & value)
{
auto f = find(id);
if (f == end())
{
implementation_type::set(id, value);
this->reload();
return std::pair<iterator, bool>(find(id), true);
}
else
return std::pair<iterator, bool>(f, false);
}
using implementation_type::implementation_type;
using implementation_type::operator=;
using native_handle_type = typename implementation_type::native_handle_type;
using implementation_type::native_handle;
//copy ctor if impl is copy-constructible
bool empty()
{
return *this->_env_impl == nullptr;
}
std::size_t size() const
{
return (_get_end() - this->_env_impl);
}
void clear()
{
std::vector<string_type> names;
names.resize(size());
std::transform(cbegin(), cend(), names.begin(), [](const const_entry_type & cet){return cet.get_name();});
for (auto & nm : names)
implementation_type::reset(nm);
this->reload();
}
entry_type at( const string_type& key )
{
auto f = find(key);
if (f== end())
throw std::out_of_range(key + " not found");
return *f;
}
const_entry_type at( const string_type& key ) const
{
auto f = find(key);
if (f== end())
throw std::out_of_range(key + " not found");
return *f;
}
entry_type operator[](const string_type & key)
{
auto p = find(key);
if (p != end())
return *p;
return entry_type(string_type(key), *this);
}
};
#endif
#if defined(BOOST_PROCESS_DOXYGEN)
/**Template representation of environments. It takes a character type (`char` or `wchar_t`)
* as template parameter to implement the environment
*/
template<typename Char>
class basic_environment
{
public:
typedef std::basic_string<Char> string_type;
typedef boost::transform_iterator< entry_maker, Char**> iterator ;
typedef boost::transform_iterator<const_entry_maker, Char**> const_iterator ;
typedef std::size_t size_type ;
iterator begin() ; ///<Returns an iterator to the beginning
const_iterator begin() const ; ///<Returns an iterator to the beginning
const_iterator cbegin() const ; ///<Returns an iterator to the beginning
iterator end() ; ///<Returns an iterator to the end
const_iterator end() const; ///<Returns an iterator to the end
const_iterator cend() const; ///<Returns an iterator to the end
iterator find( const string_type& key ); ///<Find a variable by its name
const_iterator find( const string_type& key ) const; ///<Find a variable by its name
std::size_t count(const string_type & st) const; ///<Number of variables
void erase(const string_type & id); ///<Erase variable by id.
///Emplace an environment variable.
std::pair<iterator,bool> emplace(const string_type & id, const string_type & value);
///Default constructor
basic_environment();
///Copy constructor.
basic_environment(const basic_environment & );
///Move constructor.
basic_environment(basic_environment && );
///Copy assignment.
basic_environment& operator=(const basic_environment & );
///Move assignment.
basic_environment& operator=(basic_environment && );
typedef typename detail::implementation_type::native_handle_type native_handle;
///Check if environment has entries.
bool empty();
///Get the number of variables.
std::size_t size() const;
///Clear the environment. @attention Use with care, passed environment cannot be empty.
void clear();
///Get the entry with the key. Throws if it does not exist.
entry_type at( const string_type& key );
///Get the entry with the key. Throws if it does not exist.
const_entry_type at( const string_type& key ) const;
///Get the entry with the given key. It creates the entry if it doesn't exist.
entry_type operator[](const string_type & key);
/**Proxy class used for read access to members by [] or .at()
* @attention Holds a reference to the environment it was created from.
*/
template<typename Char, typename Environment>
struct const_entry_type
{
typedef Char value_type;
typedef const value_type * pointer;
typedef std::basic_string<value_type> string_type;
typedef boost::iterator_range<pointer> range;
typedef Environment environment_t;
///Split the entry by ";" or ":" and return it as a vector. Used by PATH.
std::vector<string_type> to_vector() const
///Get the value as string.
string_type to_string() const
///Get the name of this entry.
string_type get_name() const {return string_type(_name.begin(), _name.end());}
///Copy Constructor
const_entry(const const_entry&) = default;
///Move Constructor
const_entry& operator=(const const_entry&) = default;
///Check if the entry is empty.
bool empty() const;
};
/**Proxy class used for read and write access to members by [] or .at()
* @attention Holds a reference to the environment it was created from.
*/
template<typename Char, typename Environment>
struct entry_type
{
typedef Char value_type;
typedef const value_type * pointer;
typedef std::basic_string<value_type> string_type;
typedef boost::iterator_range<pointer> range;
typedef Environment environment_t;
///Split the entry by ";" or ":" and return it as a vector. Used by PATH.
std::vector<string_type> to_vector() const
///Get the value as string.
string_type to_string() const
///Get the name of this entry.
string_type get_name() const {return string_type(_name.begin(), _name.end());}
///Copy Constructor
entry(const entry&) = default;
///Move Constructor
entry& operator=(const entry&) = default;
///Check if the entry is empty.
bool empty() const;
///Assign a string to the value
void assign(const string_type &value);
///Assign a set of strings to the entry; they will be seperated by ';' or ':'.
void assign(const std::vector<string_type> &value);
///Append a string to the end of the entry, it will seperated by ';' or ':'.
void append(const string_type &value);
///Reset the value
void clear();
///Assign a string to the entry.
entry &operator=(const string_type & value);
///Assign a set of strings to the entry; they will be seperated by ';' or ':'.
entry &operator=(const std::vector<string_type> & value);
///Append a string to the end of the entry, it will seperated by ';' or ':'.
entry &operator+=(const string_type & value);
};
};
/**Template representation of the environment of this process. It takes a template
* as template parameter to implement the environment. All instances of this class
* refer to the same environment, but might not get updated if another one makes changes.
*/
template<typename Char>
class basic_native_environment
{
public:
typedef std::basic_string<Char> string_type;
typedef boost::transform_iterator< entry_maker, Char**> iterator ;
typedef boost::transform_iterator<const_entry_maker, Char**> const_iterator ;
typedef std::size_t size_type ;
iterator begin() ; ///<Returns an iterator to the beginning
const_iterator begin() const ; ///<Returns an iterator to the beginning
const_iterator cbegin() const ; ///<Returns an iterator to the beginning
iterator end() ; ///<Returns an iterator to the end
const_iterator end() const; ///<Returns an iterator to the end
const_iterator cend() const; ///<Returns an iterator to the end
iterator find( const string_type& key ); ///<Find a variable by its name
const_iterator find( const string_type& key ) const; ///<Find a variable by its name
std::size_t count(const string_type & st) const; ///<Number of variables
void erase(const string_type & id); ///<Erase variable by id.
///Emplace an environment variable.
std::pair<iterator,bool> emplace(const string_type & id, const string_type & value);
///Default constructor
basic_native_environment();
///Move constructor.
basic_native_environment(basic_native_environment && );
///Move assignment.
basic_native_environment& operator=(basic_native_environment && );
typedef typename detail::implementation_type::native_handle_type native_handle;
///Check if environment has entries.
bool empty();
///Get the number of variables.
std::size_t size() const;
///Get the entry with the key. Throws if it does not exist.
entry_type at( const string_type& key );
///Get the entry with the key. Throws if it does not exist.
const_entry_type at( const string_type& key ) const;
///Get the entry with the given key. It creates the entry if it doesn't exist.
entry_type operator[](const string_type & key);
/**Proxy class used for read access to members by [] or .at()
* @attention Holds a reference to the environment it was created from.
*/
template<typename Char, typename Environment>
struct const_entry_type
{
typedef Char value_type;
typedef const value_type * pointer;
typedef std::basic_string<value_type> string_type;
typedef boost::iterator_range<pointer> range;
typedef Environment environment_t;
///Split the entry by ";" or ":" and return it as a vector. Used by PATH.
std::vector<string_type> to_vector() const
///Get the value as string.
string_type to_string() const
///Get the name of this entry.
string_type get_name() const {return string_type(_name.begin(), _name.end());}
///Copy Constructor
const_entry(const const_entry&) = default;
///Move Constructor
const_entry& operator=(const const_entry&) = default;
///Check if the entry is empty.
bool empty() const;
};
/**Proxy class used for read and write access to members by [] or .at()
* @attention Holds a reference to the environment it was created from.
*/
template<typename Char, typename Environment>
struct entry_type
{
typedef Char value_type;
typedef const value_type * pointer;
typedef std::basic_string<value_type> string_type;
typedef boost::iterator_range<pointer> range;
typedef Environment environment_t;
///Split the entry by ";" or ":" and return it as a vector. Used by PATH.
std::vector<string_type> to_vector() const
///Get the value as string.
string_type to_string() const
///Get the name of this entry.
string_type get_name() const {return string_type(_name.begin(), _name.end());}
///Copy Constructor
entry(const entry&) = default;
///Move Constructor
entry& operator=(const entry&) = default;
///Check if the entry is empty.
bool empty() const;
///Assign a string to the value
void assign(const string_type &value);
///Assign a set of strings to the entry; they will be seperated by ';' or ':'.
void assign(const std::vector<string_type> &value);
///Append a string to the end of the entry, it will seperated by ';' or ':'.
void append(const string_type &value);
///Reset the value
void clear();
///Assign a string to the entry.
entry &operator=(const string_type & value);
///Assign a set of strings to the entry; they will be seperated by ';' or ':'.
entry &operator=(const std::vector<string_type> & value);
///Append a string to the end of the entry, it will seperated by ';' or ':'.
entry &operator+=(const string_type & value);
};
};
#endif
///Definition of the environment for the current process.
template<typename Char>
class basic_native_environment : public basic_environment_impl<Char, detail::api::native_environment_impl>
{
public:
using base_type = basic_environment_impl<Char, detail::api::native_environment_impl>;
using base_type::base_type;
using base_type::operator=;
};
///Type definition to hold a seperate environment.
template<typename Char>
class basic_environment : public basic_environment_impl<Char, detail::api::basic_environment_impl>
{
public:
using base_type = basic_environment_impl<Char, detail::api::basic_environment_impl>;
using base_type::base_type;
using base_type::operator=;
};
///Definition of the environment for the current process.
typedef basic_native_environment<char> native_environment;
///Definition of the environment for the current process.
typedef basic_native_environment<wchar_t> wnative_environment;
///Type definition to hold a seperate environment.
typedef basic_environment<char> environment;
///Type definition to hold a seperate environment.
typedef basic_environment<wchar_t> wenvironment;
}
///Namespace containing information of the calling process.
namespace this_process
{
///Definition of the native handle type.
typedef ::boost::process::detail::api::native_handle_t native_handle_type;
///Definition of the environment for this process.
using ::boost::process::native_environment;
///Definition of the environment for this process.
using ::boost::process::wnative_environment;
///Get the process id of the current process.
inline int get_id() { return ::boost::process::detail::api::get_id();}
///Get the native handle of the current process.
inline native_handle_type native_handle() { return ::boost::process::detail::api::native_handle();}
///Get the enviroment of the current process.
inline native_environment environment() { return ::boost::process:: native_environment(); }
///Get the enviroment of the current process.
inline wnative_environment wenvironment() { return ::boost::process::wnative_environment(); }
///Get the path environment variable of the current process runs.
inline std::vector<boost::filesystem::path> path()
{
#if defined(BOOST_WINDOWS_API)
const ::boost::process::wnative_environment ne{};
typedef typename ::boost::process::wnative_environment::const_entry_type value_type;
const auto id = L"PATH";
#else
const ::boost::process::native_environment ne{};
typedef typename ::boost::process::native_environment::const_entry_type value_type;
const auto id = "PATH";
#endif
auto itr = std::find_if(ne.cbegin(), ne.cend(),
[&](const value_type & e)
{return id == ::boost::to_upper_copy(e.get_name(), ::boost::process::detail::process_locale());});
if (itr == ne.cend())
return {};
auto vec = itr->to_vector();
std::vector<boost::filesystem::path> val;
val.resize(vec.size());
std::copy(vec.begin(), vec.end(), val.begin());
return val;
}
}
}
#endif /* INCLUDE_BOOST_PROCESS_DETAIL_ENVIRONMENT_HPP_ */

Some files were not shown because too many files have changed in this diff Show More